From Geoff Michel, conversion from GeoSet to Geometry.

This commit is contained in:
Robert Osfield 2003-05-25 16:08:57 +00:00
parent 087944d343
commit 289ae01420

View File

@ -1,7 +1,8 @@
#include <stdio.h>
#include <string.h>
// reading a design workshop file utility
// (c) GW Michel, 2001-2002.
// (c) GW Michel, 2001-2003.
// (c) 2003 - modified to use Geometry rather than old GeoSet.
// Design Workshop format files can be downloaded from www.artifice.com
// Design Workshop editor can be downloaded from www.artifice.com = Mac & Win95/98/NT versions are available.
// DW Lite is completely free, produces textured 3D models
@ -12,6 +13,7 @@
#include <osg/CullFace>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Geometry>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/Material>
@ -51,9 +53,7 @@ public:
if (isTextured()) { // shares common textures
if (!ctx || !tx) { // new texture needed
if (fname.length()>0) {
// char *nm=osgDB::findFileInPath(fname.c_str(),"C:/osgraph");
ctx=osgDB::readImageFile(fname.c_str());
//ctx=osgDB::readImageFile(nm);
if (ctx) {
ctx->setFileName(fname);
tx=new Texture2D;
@ -190,7 +190,7 @@ typedef struct {
class _face {
public:
_face() { opening=NULL; idx=NULL; nv=0; nop=0; nset=0; nrm[0]=nrm[1]=nrm[2]=0;}
_face() { nVertStart=0; opening=NULL; idx=NULL; nv=0; nop=0; nset=0; nrm[0]=nrm[1]=nrm[2]=0;}
~_face() { delete [] idx;}
void setnv(const int n){ nv=n; idx=new int[n];}
void addvtx(const int n){
@ -204,6 +204,7 @@ public:
opening[nop-1].addvtx(nvtot);
}
}
void setNBegin(int n1) {nVertStart=n1;}
void norm(Vec3 &n, const Vec3 side, const Vec3 s2) const {
n=s2^side; // perpendicular
n.normalize(); // unit norm
@ -343,6 +344,7 @@ private:
class _face *opening; // openings in this face. number of verts, vertex list for opening
int nv; // number of vertices in the face
int nset; // number read so far
int nVertStart; // start index of vertices in the grand Geometry
Vec3 nrm; // surface normal
int *idx; // indices into the vertex list for the object
};
@ -352,242 +354,142 @@ private:
class prims {
public:
prims() { nbegin=0; primlengs=NULL;gsidx=NULL;nrmidx=NULL;
txidx=NULL;nrms=NULL;txcoords=NULL; tmat=NULL;
nload=0; nff=0; curmode=0;
prims() { nbegin=0; // primlengs=NULL; gsidx=NULL;nrmidx=NULL;
// txidx=NULL;nrms=NULL;txcoords=NULL;
// nload=0; nff=0; curmode=0;
vertices = new osg::Vec3Array;
normals = new osg::Vec3Array;
txc = new osg::Vec3Array;
txcoords=new osg::Vec3Array; // new Vec2[6*nfnvf]; // one texture coord per vertex
tmat=NULL;
}
~prims() { /*delete [] primlengs; delete [] nrms;
delete [] gsidx; delete [] nrmidx; delete [] txcoords;*/
}
bool isGLtype() { return nbegtype[nbegin]==curmode;}
void addv(avertex *pos) { // tesselation callback
nrmidx[nload]=nload; // all normals for this face are same, flat shade
gsidx[nload]=pos->idx; // vertex position index
nrms[nload]=pos->nrmv;
txcoords[nload].set(pos->uv[0],pos->uv[1]);
txidx[nload]=nload; // matrix transformed txc
ntesverts[nbegin]++;
nload++;
vertices->push_back(osg::Vec3(pos->pos[0],pos->pos[1],pos->pos[2]));
normals->push_back(pos->nrmv);
txcoords->push_back(osg::Vec3(pos->uv[0],pos->uv[1],0.0f));
}
void End() {
if (nbegin<20 && ntesverts[nbegin]>0) {
primlengs[nff+nbegin]=ntesverts[nbegin];
nbegin++;
} else {
printf("nbegin %d\n", nbegin);//, errm
}
void End() { // tesselation is done
int nverts=vertices->size()-nbegin;
osg::DrawArrays *drw=NULL;
switch (primType) {
case GL_TRIANGLES: //gset->setPrimType( osg::GeoSet::TRIANGLES );
//gset->setNumPrims( nload/3 );
drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,nbegin,nverts);
gset->addPrimitiveSet(drw);
break;
case GL_TRIANGLE_STRIP: //gset->setPrimType( osg::GeoSet::TRIANGLE_STRIP );
//gset->setPrimLengths( nuprimlengs );
drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,nbegin,nverts);
gset->addPrimitiveSet(drw);
break;
case GL_TRIANGLE_FAN: //gset->setPrimType( osg::GeoSet::TRIANGLE_FAN );
//gset->setPrimLengths( nuprimlengs );
drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN,nbegin,nverts);
gset->addPrimitiveSet(drw);
break;
case GL_QUADS: //gset->setPrimType( osg::GeoSet::QUADS );
//gset->setNumPrims( nload/4 );
drw=new osg::DrawArrays(osg::PrimitiveSet::QUADS,nbegin,nverts);
gset->addPrimitiveSet(drw);
break;
case GL_QUAD_STRIP: //gset->setPrimType( osg::GeoSet::QUAD_STRIP );
drw=new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,nbegin,nverts);
gset->addPrimitiveSet(drw);
break;
case GL_POLYGON: //gset->setPrimType( osg::GeoSet::POLYGON );
drw=new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nbegin,nverts);
gset->addPrimitiveSet(drw);
break;
}
}
void begin(GLenum op) { // part of a tesselator callback - starts a new primitive of type op
if (nbegin<20) { // reSet counters
nbegtype[nbegin]=op;
ntesverts[nbegin]=0;
} else {
printf("begin: nbegin %d too large\n", nbegin);//, errm
}
switch (op) {
case GL_TRIANGLES:
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
case GL_QUADS:
case GL_QUAD_STRIP:
case GL_POLYGON:
break;
default:
// commenting out since this value is a local and
// is not used, RO July 2001.
// int i=0;
break;
}
primType=op;
nbegin=vertices->size();
}
void combine( GLdouble coords[3], avertex *d[4],
GLfloat w[4], avertex **dataOut , _dwobj *dwob);
void linkholes(const std::vector<Vec3> verts, const dwmaterial *themat,
const _face *f1, const _face *f2,
const int ipr[2], const int /*idx*/[], const int nv) {
gsidx[nload]=f1->getidx(ipr[1]); // vertex position index
gsidx[nload+1]=f1->getidx(ipr[0]); // vertex position index
gsidx[nload+2]=f2->getidx(nv-ipr[0]-1); // vertex position index
gsidx[nload+3]=f2->getidx(nv-ipr[1]-1); // vertex position index
const int ipr[2], const int nv) {
int gsidx[4];
int nbeg=verts.size()-4; // first vertex in vec3array
gsidx[0]=f1->getidx(ipr[1]); // vertex position index
gsidx[1]=f1->getidx(ipr[0]); // vertex position index
gsidx[2]=f2->getidx(nv-ipr[0]-1); // vertex position index
gsidx[3]=f2->getidx(nv-ipr[1]-1); // vertex position index
Matrix mx; // texture matrix transform to plane
Vec3 s1,s2;
Vec3 nrm;
s1=verts[gsidx[nload+1]]-verts[gsidx[nload]];
s2=verts[gsidx[nload+2]]-verts[gsidx[nload+1]];
Vec3 nrm; // calculated normal to face
s1=verts[gsidx[1]]-verts[gsidx[0]];
s2=verts[gsidx[2]]-verts[gsidx[1]];
f1->norm(nrm, s2, s1);
f1->settrans(mx, nrm, verts,themat);
int n1=vertices->size();
for (int j=0; j<4; j++) {
Vec3 uv;
uv=mx*verts[gsidx[nload]];
txcoords[nload].set(uv[0],uv[1]);
nrmidx[nload]=nload;
txidx[nload]=nload; // matrix transformed txc
nrms[nload]=nrm; // for per vertex normals
nload++;
Vec3 coord=(verts[gsidx[j]]);
vertices->push_back( coord );
uv=mx*verts[gsidx[j]];
txcoords->push_back(uv);
normals->push_back(nrm);
}
nff++;
osg::DrawArrays *drw=NULL;
drw=new osg::DrawArrays(osg::PrimitiveSet::QUADS,n1,4);
gset->addPrimitiveSet(drw);
}
void setmode(int md, const int nfnvf) { // define the GL primitive type & number of expected vertices
GLenum mode[]= {GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN,
GL_QUADS, GL_QUAD_STRIP, GL_POLYGON};
curmode=mode[md];
gsidx=new unsigned short[6*nfnvf];
nrmidx=new unsigned short[6*nfnvf];
txidx=new unsigned short[6*nfnvf];
txcoords=new Vec2[6*nfnvf]; // one texture coord per vertex
nrms=new Vec3[6*nfnvf]; // one normal per face or per vertex
primlengs=new int[nfnvf]; // primitive lengths
nff=0;
nload=0;
}
void tesselate(const _face &fc, const std::vector<Vec3> verts, const dwmaterial *themat,GLUtesselator* ts, _dwobj *dwob)
void tesselate(_face &fc, const std::vector<Vec3> verts, const dwmaterial *themat,GLUtesselator* ts, _dwobj *dwob)
{ // generates a set of primitives all of one type (eg tris, qstrip trifan...)
nbegin=0; // number of triangle strips etc generated
fc.setNBegin(vertices->size());
fc.tesselate(verts, themat, ts, dwob, tmat);
nff+=nbegin; // the number of primitives generated
}
void buildDrawable(Group *grp, const std::vector<Vec3> verts, dwmaterial *themat, const int nverts)
{
// Geoff this needs to be update to create osg::Geometry rather than GeoSet...
#if 0
if (nload>0 && nff>0) { // there are some strips of this type
Geode *geode = new Geode;
GeoSet *gset = new GeoSet;
unsigned short *nunrmidx=new unsigned short[nload];
unsigned short *nutxidx = new unsigned short[nload];
unsigned short *nusidx = new unsigned short[nload];
Vec3 *nunrms=new Vec3[nload]; // one normal per face (nff) or per vertex (nload)
int *nuprimlengs=new int[nff]; // primitive lengths
Vec2 *nutxc=new Vec2[nload];
int i; // general counter
for (i=0; i<nload; i++) {
nutxc[i]=txcoords[i];
nusidx[i]=gsidx[i];
nutxidx[i]=txidx[i];
nunrmidx[i]=nrmidx[i];
nunrms[i]=nrms[i];
}
delete [] nrmidx;
delete [] txidx;
delete [] gsidx;
delete [] txcoords;
delete [] nrms; // recycle memory /**/
nrms=NULL;
txcoords=NULL;
nrmidx=txidx=gsidx=NULL;
for (i=0; i<nff; i++) {
nuprimlengs[i]=primlengs[i];
}
delete [] primlengs;
primlengs=NULL;
txcoords=NULL;
Vec3 *vts=new Vec3[nverts]; // allocate a new storage area -
// this may get destroyed if multiple combines are made by the tesselator
// extending the array of vertices and freeing some memory GWM Feb 2002,
for (i=0; i<nverts; i++) {
vts[i]=verts[i];
}
geode->addDrawable(gset);
grp->addChild( geode ); // add to the world outside
gset->setNumPrims( nff );
switch (curmode) {
case GL_TRIANGLES: gset->setPrimType( osg::GeoSet::TRIANGLES );
gset->setNumPrims( nload/3 );
break;
case GL_TRIANGLE_STRIP: gset->setPrimType( osg::GeoSet::TRIANGLE_STRIP );
gset->setPrimLengths( nuprimlengs );
break;
case GL_TRIANGLE_FAN: gset->setPrimType( osg::GeoSet::TRIANGLE_FAN );
gset->setPrimLengths( nuprimlengs );
break;
case GL_QUADS: gset->setPrimType( osg::GeoSet::QUADS );
gset->setNumPrims( nload/4 );
break;
case GL_QUAD_STRIP: gset->setPrimType( osg::GeoSet::QUAD_STRIP );
break;
case GL_POLYGON: gset->setPrimType( osg::GeoSet::POLYGON );
break;
}
gset->setNormalBinding(osg::GeoSet::BIND_PERVERTEX); //BIND_PERPRIM); //
gset->setNormals(nunrms, nunrmidx);
gset->setTextureCoords(nutxc,nutxidx);
gset->setCoords( vts, nusidx );
if (themat->isType(dwmaterial::PointLight) || themat->isType(dwmaterial::SpotLight)) {
Vec4 pos;
pos.set(0.0f,0.0f,0.0f,0.0f);
for (int i=0; i<nverts; i++) {
pos[0]+=verts[i].x();
pos[1]+=verts[i].y();
pos[2]+=verts[i].z();
}
pos/=nverts;
pos[3]=1.0f;
LightSource *ls=themat->makeLight(pos);
grp->addChild(ls);
} else {
StateSet *dstate=themat->make();
gset->setStateSet( dstate );
}
} else {
delete [] primlengs;
delete [] nrms;
delete [] gsidx;
delete [] nrmidx;
delete [] txcoords;
delete [] txidx;
primlengs=NULL; gsidx=NULL; nrmidx=NULL;
txidx=NULL; nrms=NULL; txcoords=NULL;;
}
#endif
void buildGeometry() { // at end of all faces, add collection of vertices to geometry
gset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); //BIND_PERPRIM); //
gset->setNormalArray(normals);
gset->setTexCoordArray(0,txcoords);
gset->setVertexArray(vertices); // setCoords( vts, nusidx );
}
void setGeometry(osg::Geometry *gs) {
gset=gs;
}
void settmat(const Matrix *mx) {
tmat= mx;
}
private:
int nbegin;
int ntesverts[20]; // number of vertices in each primitive list - up to 20 restarts
GLenum nbegtype[20]; // up to 20 restarts
GLenum curmode;
int nload; // numebr of vertices loaded into these arrays
int nff; // primitive loaded
int *primlengs;
unsigned short *gsidx;
unsigned short *nrmidx;
unsigned short *txidx;
Vec3 *nrms; // one normal per face
Vec2 *txcoords; // one texture coord per vertex
osg::Geometry *gset;
osg::Vec3Array* vertices;
osg::Vec3Array* normals;
osg::Vec3Array* txc;
osg::Vec3Array* txcoords;
GLenum primType;
int nbegin; // vertex indices for current primitive
const Matrix *tmat; // local texture matrix, or may be NULL for default mapping
};
static prims prd;
// tesselation subroutines
static prims *prd=NULL; // OK not nice to have a static but the OpenGL tesselator etc wants to be able to refer
// to things that are not available via an argument
// tesselation subroutines - have 'C' prototypes, not a member of any class...
// But I want ot use the prims class to contain useful information such as texture matrix etc.
void CALLBACK myFaceBegin(GLenum op)
{// tess vertex call back
prd.begin(op);
//glBegin(op);
{// tess 'primitive begins' call back
prd->begin(op);
}
void CALLBACK myFaceEnd()
{// tess vertex call back
if ( prd.isGLtype()) { // a prim of type == nvf ending; next counter needed
prd.End();
}
//glEnd();
{// tess primiitve ends call back
prd->End();
}
void CALLBACK myVertex(void *pv)
{// tess vertex call back with texture coord == void *pv1,
if (prd.isGLtype()) { // a prim of type == nvf being created; use this vertex
prd.addv((avertex *)pv);
}
prd->addv((avertex *)pv);
}
void CALLBACK combineCallback( GLdouble coords[3], avertex *d[4],
GLfloat w[4], avertex **dataOut , _dwobj *dwob)
{
// dwob needed if there is a combine callback to add the new vertex to group
prd.combine(coords, d, w, dataOut,dwob);
prd->combine(coords, d, w, dataOut,dwob);
}
void CALLBACK error (GLenum errno)
{ // tess error code
@ -600,8 +502,8 @@ void _face::linkholes(const std::vector<Vec3> verts, const dwmaterial *themat, c
int ipr[2];
ipr[0]=nv-1;
for (int i=0; i<nv; i++) { // pairs of vertices
ipr[1]=i;
prd.linkholes(verts, themat, this, f2, ipr, idx, nv);
ipr[1]=nVertStart+i;
prd->linkholes(verts, themat, this, f2, ipr, nv);
ipr[0]=ipr[1];
}
}
@ -623,7 +525,6 @@ class _dwobj { // class for design workshop read of a single object
public:
_dwobj() { nverts=nfaces=0; openings=NULL;faces=NULL; tmat=NULL; edges=NULL;
nopens=nfaceverts=0; fc1=fc2=NULL; colour[0]=colour[1]=colour[2]=colour[3]=1;
// oldv=verts=NULL;
}
~_dwobj() {/*delete verts; delete faces;delete openings;*/
delete fc1;delete fc2;
@ -782,9 +683,6 @@ void _face::tesselate(const std::vector<Vec3> verts, const dwmaterial *themat,
gluTessBeginContour(ts); /**/
for (int j=0; j<nv; j++) {
Vec3 uv;
/*if (tmat)
uv=(*tmat)*verts[idx[j]];
else */
uv=mx*verts[idx[j]];
setposes(poses[nused], j, verts);
poses[nused].uv[0]=uv[0];
@ -797,8 +695,6 @@ void _face::tesselate(const std::vector<Vec3> verts, const dwmaterial *themat,
gluTessBeginContour(ts);
for (int j=0; j<opening[k].nv; j++) {
Vec3 uv;
/*if (tmat) uv=(*tmat)*verts[opening[k].idx[j]];
else */
uv=mx*verts[opening[k].idx[j]];
opening[k].setposes(poses[nused], j, verts);
poses[nused].nrmv*=-1; // get to agree with base polygon
@ -815,76 +711,86 @@ void _face::tesselate(const std::vector<Vec3> verts, const dwmaterial *themat,
}
void prims::combine( GLdouble coords[3], avertex *d[4],
GLfloat w[4], avertex **dataOut , _dwobj *dwob) {
if (nbegin<20 && isGLtype()) { // a prim of type == nvf being created; use this vertex
avertex *newv = new avertex(); // (avertex *)calloc(1, sizeof(avertex));
newv->pos[0] = coords[0];
newv->pos[1] = coords[1];
newv->pos[2] = coords[2];
newv->uv[0] = newv->uv[1] =0;
newv->nrmv[0] = newv->nrmv[1] = newv->nrmv[2] =0;
for (int i=0; i<4; i++) {
if (d[i]) {
newv->uv[0] = w[i]*d[i]->uv[0];
newv->uv[1] = w[i]*d[i]->uv[1];
newv->nrmv[0] = w[i]*d[i]->nrmv[0];
newv->nrmv[1] = w[i]*d[i]->nrmv[1];
newv->nrmv[2] = w[i]*d[i]->nrmv[2];
}
}
dwob->makeuv(newv->uv, newv->pos);
newv->idx=dwob->addvtx(coords[0], coords[1], coords[2]);
*dataOut = newv;
} else {
*dataOut = NULL;
}
avertex *newv = new avertex(); // (avertex *)calloc(1, sizeof(avertex));
newv->pos[0] = coords[0];
newv->pos[1] = coords[1];
newv->pos[2] = coords[2];
newv->uv[0] = newv->uv[1] =0;
newv->nrmv[0] = newv->nrmv[1] = newv->nrmv[2] =0;
for (int i=0; i<4; i++) {
if (d[i]) {
newv->uv[0] = w[i]*d[i]->uv[0];
newv->uv[1] = w[i]*d[i]->uv[1];
newv->nrmv[0] = w[i]*d[i]->nrmv[0];
newv->nrmv[1] = w[i]*d[i]->nrmv[1];
newv->nrmv[2] = w[i]*d[i]->nrmv[2];
}
}
dwob->makeuv(newv->uv, newv->pos);
newv->idx=dwob->addvtx(coords[0], coords[1], coords[2]);
*dataOut = newv;
}
void _dwobj::buildDrawable(Group *grp)
{ // current DWobject complete; make a drawable, and add it to a osg::Group
if (nfaces>0) {
int nvf;
int nfnvf=0; // number of vertices for faces plus holes
int i; // a general counter
for (i=0; i<nfaces; i++) { // for each face
faces[i].setnorm(verts); // set its normal and any hole normals
nfnvf+=faces[i].getallverts(); // get total vertices in object, defines dimensions of NEW arrays
}
GLUtesselator* ts=gluNewTess();
gluTessCallback(ts, GLU_TESS_BEGIN, (void (CALLBACK *) ())myFaceBegin);
gluTessCallback(ts, GLU_TESS_VERTEX, (GLvoid (CALLBACK *) ())myVertex);
gluTessCallback(ts, GLU_TESS_END, (GLvoid (CALLBACK *) ())myFaceEnd);
gluTessCallback(ts, GLU_TESS_ERROR, (GLvoid (CALLBACK *) ())error);
gluTessCallback(ts, GLU_TESS_COMBINE_DATA, (GLvoid (CALLBACK *) ()) &combineCallback);
prd.settmat(tmat);
for (nvf=0; nvf<6; nvf++) { // for each length of face
prd.setmode(nvf , nfnvf); // filter out only this type of tesselated face
if (themat->isType(dwmaterial::PointLight) || themat->isType(dwmaterial::SpotLight)) {
Vec4 pos;
pos.set(0.0f,0.0f,0.0f,0.0f);
for (int i=0; i<nverts; i++) {
pos[0]+=verts[i].x();
pos[1]+=verts[i].y();
pos[2]+=verts[i].z();
}
pos/=nverts;
pos[3]=1.0f;
LightSource *ls=themat->makeLight(pos);
grp->addChild(ls);
} else {
Geode *geode = new Geode;
int nfnvf=0; // number of vertices for faces plus holes
int i; // a general counter
for (i=0; i<nfaces; i++) { // for each face
faces[i].setnorm(verts); // set its normal and any hole normals
nfnvf+=faces[i].getallverts(); // get total vertices in object, defines dimensions of NEW arrays
}
GLUtesselator* ts=gluNewTess();
gluTessCallback(ts, GLU_TESS_BEGIN, (void (CALLBACK *) ())myFaceBegin);
gluTessCallback(ts, GLU_TESS_VERTEX, (GLvoid (CALLBACK *) ())myVertex);
gluTessCallback(ts, GLU_TESS_END, (GLvoid (CALLBACK *) ())myFaceEnd);
gluTessCallback(ts, GLU_TESS_ERROR, (GLvoid (CALLBACK *) ())error);
gluTessCallback(ts, GLU_TESS_COMBINE_DATA, (GLvoid (CALLBACK *) ()) &combineCallback);
// for (int nvf=0; nvf<6; nvf++) { // for each length of face
// for Geometry we dont need to collect prim types individually
// prd.setmode(nvf , nfnvf); // filter out only this type of tesselated face
prd=new prims;
prd->settmat(tmat);
osg::Geometry *gset = new osg::Geometry;
prd->setGeometry(gset);
StateSet *dstate=themat->make();
gset->setStateSet( dstate );
grp->addChild( geode ); // add to the world outside
geode->addDrawable(gset);
for (i=0; i<nfaces; i++) { // for each face
prd.tesselate(faces[i],verts, themat, ts, this);
// each face adds a primitive to the geometry, after it is tesselated
for (i=0; i<nfaces; i++) { // for each face, collect up
prd->tesselate(faces[i],verts, themat, ts, this);
}
for (i=0; i<nopens && nvf==3; i++) { // for each hole, join up front & back with Quads
faces[fc1[i]].link(openings[i*2], &faces[fc2[i]],openings[i*2+1],verts, themat);
}
prd.buildDrawable(grp, verts, themat, nverts);
// if (oldv) delete [] oldv;
// oldv=NULL;
}
for (i=0; i<nopens; i++) { // for each hole, join up front & back with Quads
if (fc1 && fc2) {
faces[fc1[i]].link(openings[i*2], &faces[fc2[i]],openings[i*2+1],verts, themat);
}
} // for each opening
prd->buildGeometry();
gluDeleteTess(ts);
} // primitive types
delete prd;
}
} // nfaces>0
verts.clear();
}
////////// tesselation complete
// not currently used so commenting out, RO July 2001.
// static const char *keywords[] = {
// "numMaterials:","Material:","MaterialType:","TextureWidthAndHeight:","PictureFile:",
// "Extrusion:","Cube:","Mat:", "Color:","numVerts:",
// "numFaces:","numEdges:","numOpenings:", "Opacity:", "SpecularReflectivity:",
// "SmoothnessExponent:", "UVW:", "Brightness:", "Attentuation:","FallOffInnerHalfAngle:",
// "OuterHalfAngle:","Brightness:","Attentuation:", "Phase:", "CurrPhase:", "numPhases:"
// };
class ReaderWriterDW : public osgDB::ReaderWriter
{
public: