root/OpenSceneGraph/trunk/src/osgPlugins/dw/ReaderWriterDW.cpp @ 13041

Revision 13041, 40.1 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4// reading a design workshop file utility
5// (c) GW Michel, 2001-2003.
6// (c) 2003 - modified to use Geometry rather than old GeoSet.
7// Design Workshop format files can be downloaded from www.artifice.com
8// Design Workshop editor can be downloaded from www.artifice.com = Mac & Win95/98/NT versions are available.
9// DW Lite is completely free, produces textured 3D models
10// aimed mostly at the architectural world.  Flat polygons are generally produced
11// No ability to produce smooth shading, unfortunately.
12// But it is the best bangs per buck. (Anything/nothing = infinite value, and this is quite a lot/nothing)
13
14#include <osg/CullFace>
15#include <osg/Geode>
16#include <osg/Group>
17#include <osg/Geometry>
18#include <osg/Light>
19#include <osg/LightSource>
20#include <osg/Material>
21#include <osg/Texture2D>
22#include <osg/TexEnv>
23#include <osg/StateSet>
24#include <osg/Notify>
25
26#include <osgDB/FileNameUtils>
27#include <osgDB/Registry>
28#include <osgDB/ReadFile>
29#include <osgDB/FileUtils>
30
31#include <osg/GLU>
32
33using namespace osg;
34
35#ifndef WIN32
36    #define CALLBACK
37#endif
38
39class _dwobj; // predefine for later call
40int dwfgets(char *clin, int max, FILE *fin); // , end of line= 13 as well as Creturn=10
41
42class dwmaterial {// design workshop material, to be translated to OGL
43public:
44    typedef enum {Properties,TiledTexture,FullFace, SpotLight,PointLight} mttype;
45    dwmaterial() { type=Properties;
46        opacity=1; specular=0; specexp=0; fname="";TextureWidth=1; TextureHeight=1;
47        ctx=NULL; tx=NULL; id=0; dstate=NULL;colour[0]=colour[1]=colour[2]=colour[3]=1;
48        bright=halfIn=halfOut=falloff=0;atyp=NONE;
49        _lightnum=1;
50    }
51    ~dwmaterial() { }
52    void settexture(const osgDB::ReaderWriter::Options *options) {
53        if (!dstate) dstate = new StateSet;
54        if (isTextured()) { // shares common textures
55            if (!ctx || !tx) { // new texture needed
56                if (fname.length()>0) {
57                    ctx=osgDB::readRefImageFile(fname.c_str(),options);
58                    if (ctx.valid()) {
59                        ctx->setFileName(fname);
60                        tx=new Texture2D(ctx.get());
61                        tx->setWrap(Texture2D::WRAP_S, Texture2D::REPEAT);
62                        tx->setWrap(Texture2D::WRAP_T, Texture2D::REPEAT);
63                    }
64                    osg::TexEnv* texenv = new osg::TexEnv;
65                    texenv->setMode(osg::TexEnv::MODULATE);
66                    dstate->setTextureAttribute(0, texenv );
67                }
68            }
69            if (ctx.valid() && tx.valid()) { // texture exists
70                dstate->setTextureAttributeAndModes(0,tx.get(),osg::StateAttribute::ON);
71            }
72        }
73    }
74    StateSet *make(const osgDB::ReaderWriter::Options *options) { // returns the OSG material
75        if (!dstate) { // if it does not exist, then make it
76            dstate = new StateSet;
77            osg::Material* osgMaterial = new osg::Material;
78            dstate->setAttribute(osgMaterial);
79            if (opacity<0.99) {
80                osgMaterial->setTransparency(Material::FRONT_AND_BACK, opacity);
81                dstate->setMode(GL_BLEND,StateAttribute::ON);
82                dstate->setRenderingHint(StateSet::TRANSPARENT_BIN);
83                colour[3]=opacity;
84            }
85            osgMaterial->setAmbient(Material::FRONT_AND_BACK,colour);
86            osgMaterial->setDiffuse(Material::FRONT_AND_BACK,colour);
87
88            Vec4 colspec=colour*specular;
89            colspec[3]=colour[3];
90            osgMaterial->setSpecular(Material::FRONT_AND_BACK,colspec);
91            osgMaterial->setShininess(Material::FRONT_AND_BACK,specexp);
92
93            dstate->setMode( GL_LIGHTING, StateAttribute::ON );
94            dstate->setMode( GL_CULL_FACE, StateAttribute::ON );
95
96            osg::CullFace *cf = new osg::CullFace; // to define non-default culling
97            cf->setMode(osg::CullFace::BACK);
98            dstate->setAttribute(cf);
99
100            dstate->setTextureMode(0,GL_TEXTURE_2D,StateAttribute::OFF);
101            settexture(options);
102        }
103        return dstate;
104    }
105    inline int isType(mttype t1) const {return     (type==t1 ); }
106    inline int isTextured() {return     (type==TiledTexture || type==FullFace ); }
107    void setcolour(const float rgb[3]) {
108        colour[0]=rgb[0]; colour[1]=rgb[1]; colour[2]=rgb[2];
109    }
110    void settxrep(const float repx, const float repy) {
111        TextureWidth=repx;
112        TextureHeight=repy;
113    }
114    inline float getRepWid() const { return TextureWidth;}
115    inline float getRepHt() const { return TextureHeight;}
116    inline int isFullFace() const { return  type==FullFace;}
117    inline int getid() const { return  id;}
118    inline void setid(const int i) { id=i;}
119    inline void setopacity(float o) { opacity=o;}
120    inline void setspecular(float o) { specular=o;}
121    inline void setspecexp(float o) { specexp=o;}
122    void setType(const char *buff) {
123        if (strncmp(buff,"Tiled_Texture",13)==0)
124            type=dwmaterial::TiledTexture;
125        else if (strncmp(buff,"Spot_Light",11)==0)
126            type=dwmaterial::SpotLight;
127        else if (strncmp(buff,"Point_Light",11)==0)
128            type=dwmaterial::PointLight;
129        else if (strncmp(buff,"Properties",11)==0)
130            type=dwmaterial::Properties;
131        else if (strncmp(buff,"Full_Face_Texture",16)==0)
132            type=dwmaterial::FullFace;
133    }
134    void setfname(const char *buff) {
135        //fname=new char[strlen(buff+13)+5];
136        fname= (buff+13);
137        fname+= ".tga";
138    }
139    LightSource *makeLight(const Vec4 pos)
140    {
141        Light *lt= new Light;
142        Vec4 cdef;
143        cdef[0]=cdef[1]=cdef[2]=0.0f; cdef[3]=0.0f;
144        lt->setLightNum(_lightnum++);
145        lt->setSpecular(colour*bright/2.0f);
146        lt->setDiffuse(colour*bright/4.0f);
147        lt->setAmbient(cdef);
148        if (atyp==NONE) ;
149        else if (atyp==INVERSE_DIST) {
150            lt->setLinearAttenuation(1.0f);
151            lt->setConstantAttenuation(0.01f);
152        }
153        lt->setPosition(pos);
154        LightSource *ls=new LightSource();
155        ls->setLight(lt);
156        return ls;
157    }
158    void setAtten(const char *buff) {
159        if (strstr(buff,"kQ3AttenuationTypeNone")) atyp=NONE;
160        else if (strstr(buff,"kQ3AttenuationTypeInverseDistance")) atyp=INVERSE_DIST;
161        //    else if (strstr(buff,"kQ3AttenuationTypeNone")) ;
162    }
163    void setBright(const float br) { bright=br;}
164    void setHalfAngleIn(const float ha) { halfIn=ha;}
165    void setHalfAngleOut(const float ha) { halfOut=ha;}
166    void setFallOff(const float fo) { falloff=fo;}
167    const Vec4 getcolour() { return colour;}
168private:
169    int id;
170    Vec4 colour; // the ambient/diffuse+alpha colour
171    mttype type;
172    float opacity, specular, specexp; // transp, specularity properties
173    float TextureWidth, TextureHeight;
174    std::string fname; // picture file
175    enum atten {NONE, INVERSE_DIST, INVERSE_SQUARE} atyp;
176    float bright,halfIn,halfOut,falloff; // light brightness
177    osg::ref_ptr<osg::Image> ctx;
178    osg::ref_ptr<osg::Texture2D> tx;
179    int _lightnum;
180    StateSet *dstate; // used to represent the dw material in OSG
181};
182// structure to use as data for tessellation
183
184typedef struct {
185    double pos[3]; // must be double for the tessellator to detect vertices
186    Vec2 uv; // texture coordainte - may not be used?
187    Vec3 nrmv; // surface normal
188    int idx; // index in the verts[] array
189} avertex;
190
191class _face {
192public:
193    _face() { nVertStart=0; opening=NULL; idx=NULL; nv=0; nop=0; nset=0; nrm[0]=nrm[1]=nrm[2]=0;}
194    ~_face() { delete [] idx;}
195    void setnv(const int n){ nv=n; idx=new int[n];}
196    void addvtx(const int n){
197        if (nset < nv) {
198            idx[nset]=n;
199            nset++;
200        }
201    }
202    void addholevtx(const int nvtot) {
203        if (opening) {
204            opening[nop-1].addvtx(nvtot);
205        }
206    }
207    void setNBegin(int n1) {nVertStart=n1;}
208    void norm(Vec3 &n, const Vec3 side, const Vec3 s2) const {
209        n=s2^side; // perpendicular
210        n.normalize(); // unit norm
211    }
212    const Vec3 getnorm(void) const { return nrm; } // use the predefined normal
213    void getside12(Vec3 &s1, Vec3 &s2, const std::vector<Vec3> verts) const {
214        int ic=0; // counter for later vertices to ensure not coincident
215        int i1=idx[0]; // first vertex of face
216        int i2=idx[1]; // second, must be non-coincident
217        while (i2==i1 && ic<nv-1) {
218            ic++;
219            i2=idx[ic];
220        }
221        int i3=idx[ic]; // third, must be non-coincident
222        while (ic<nv-1 && (i3==i2 || i3==i1)) {
223            ic++;
224            i3=idx[ic];
225        }
226        if(ic>=nv) {
227            printf("Invalid vertices %d of %d. I1-3 %d %d %d.\n", ic, nv, i1, i2, i3);
228        }
229        if(i1>=static_cast<int>(verts.size()) || i2>=static_cast<int>(verts.size()) || i3>=static_cast<int>(verts.size())) {
230            printf("Invalid indices %d, %d, %d max allowed %d.\n", i1,i2,i3,static_cast<int>(verts.size()));//, errm
231        }
232        s1=(verts[i2]-verts[i1]); // side 1 of face
233        s2=(verts[i3]-verts[i2]); // side 2 of face
234    }
235    void getnorm(const std::vector<Vec3> verts) {
236        Vec3 side, s2; // used in cross product to find normal
237        getside12(side,s2, verts);
238        norm(nrm, s2, side);
239    }
240    void settrans(Matrix &mx, const Vec3 nrm, const std::vector<Vec3> verts, const dwmaterial *mat) const {
241        // define the matrix perpendcular to normal for mapping textures
242        float wid=mat->getRepWid();
243        float ht=mat->getRepHt();
244        Vec3 r1, r2,r3; // 3 rows of rotation matrix
245        if (mat->isFullFace()) { // set wid, ht from polygon
246            Vec3 s2; // want transformed u coordinate parallel to 'r1'
247            getside12(r1,s2, verts); // r1 = edge of first side
248//         printf("fullface s2 %f %f %f\n", s2.x(),s2.y(),s2.z());//, errm
249            r3=nrm;
250            float len=r1.length();
251            r1=r1/len;
252            r2=r3^r1;
253            r1=r1/len;
254            r2=r2/s2.length();
255       } else {
256            // mat.nrm= (0,0,1)  AND mat (0,1,0) => (0,a,b)
257            // the transformation is unitary - preserves lengths; and
258            // converts points on a plane into (s,t, constant) coords for use with texturing
259            // Rinv.(0,0,1) = (nrm) implies R since Rinv=R(transpose)
260            r3=nrm; // already a unit vector
261            // mat.(010) = (0ab) -> Minv.(0ab) = (010); and this row DOT nrm=0
262            if (r3.z() < 0.99f && r3.z() > -0.99f) { // not face parallel to ground - choose r1 perpendicular to nrm & 001
263                r2.set(0,0,1); // therefore r1 is in plane of face.
264                r1=r2^r3;
265                r1.normalize();
266            } else { // parallel to ground - make perpendicular to edge 1 of face
267                r1=verts[idx[1]]-verts[idx[0]];
268                r1.normalize();
269            }
270            r2=r3^r1;
271        }
272        for (int j=0; j<3; j++) { // and create the transpose matrix (inverse of rotation matrix)
273            mx(0,j)=r1[j];
274            mx(1,j)=r2[j];
275            mx(2,j)=r3[j];
276        }
277        //        mx.postTrans(mx,0.5f,0.5f,0.0f);
278        if (mat->isFullFace()) { // set offset such that mx*verts[idx[0]] -> uv=(0,0)
279            Vec3 pos;
280            pos=mx*verts[idx[0]];
281            mx(0,3)=-pos.x();
282            mx(1,3)=-pos.y();
283            mx(2,3)=-pos.z();
284        } else { // scale inversely to the texture preferred repeat size
285            mx(0,0)*=1.0f/wid;
286            mx(1,0)*=1.0f/wid;
287            mx(0,1)*=1.0f/ht;
288            mx(1,1)*=1.0f/ht;
289            mx(0,3)=0.5f/wid;
290            mx(1,3)=0.5f/ht;
291        }
292        //        mx.postScale(mx,1.0f/themat->TextureWidth, 1.0f/themat->TextureHeight,1);
293    }
294    inline int setnvop(const unsigned short n) { // add a new hole in this face with n vertices
295        _face *oldop=opening;
296        opening=new _face[nop+1];
297        for (int i=0; i<nop; i++) opening[i].move(&oldop[i]);
298        delete [] oldop;
299        opening[nop].setnv(n);
300        nop++;
301        return (nop-1);
302    }
303    void move(class _face *oldop) { *this=*oldop; oldop->idx=NULL;}
304    inline int getnv() { return nv;}
305    inline int getvert(const int j) { return idx[j];}
306    inline int complete() { return (idx && nv>0 && nset==nv);} // face has all defined
307    inline int holecomplete() { if (!opening) return 1; // no hole, so it is complete
308        return opening[nop-1].complete();} // latest opening in face has all vertices defined
309    int getallverts(void) const { int ntot=nv;
310        for (int i=0; i<nop; i++) ntot+=opening[i].getnv();
311        return ntot;
312    }
313    void setnorm(const std::vector<Vec3> verts) { // set the face normal
314        getnorm(verts);
315        for (int i=0; i<nop; i++) {
316            opening[i].setnorm(verts);
317            if (nrm*opening[i].nrm > 0.0f) { // normals are parallel - reverse order of vertices
318                opening[i].reverse();
319                opening[i].setnorm(verts);
320            }
321        }
322    }
323    void setposes(avertex &poses, const int j, const std::vector<Vec3> verts) const {
324        poses.pos[0]=verts[idx[j]].x();
325        poses.pos[1]=verts[idx[j]].y();
326        poses.pos[2]=verts[idx[j]].z();
327        poses.nrmv=nrm;
328        poses.idx=idx[j];
329    }
330    void tessellate(const std::vector<Vec3>& verts, const dwmaterial *themat,
331          GLUtesselator *ts, _dwobj *dwob, const RefMatrix *tmat) const;
332
333    void link(const int idop, const _face *f2, const int idop2,const std::vector<Vec3> verts, const dwmaterial *themat) const; // to join up opposed faces of a hole
334    inline const int getidx(int i) const { return idx[i];}
335private:
336    void linkholes(const std::vector<Vec3> verts, const dwmaterial *themat, const _face *f2) const;
337    void reverse() { // reverse order of the vertices
338        for (int j=0; j<nv/2; j++) {
339            int it=idx[j];
340            idx[j]=idx[nv-j-1];
341            idx[nv-j-1]=it;
342        }
343    }
344    int nop; // number of openings so far
345    class _face *opening; // openings in this face. number of verts, vertex list for opening
346    int nv; // number of vertices in the face
347    int nset; // number read so far
348    int nVertStart; // start index of vertices in the grand Geometry
349    Vec3 nrm; // surface normal
350    int *idx; // indices into the vertex list for the object
351};
352
353// structure for generating triangles (and tstrips, tfans etc)
354// from a design workshop object.
355
356class prims {
357public:
358    prims() {
359        nbegin=0;
360        vertices = new osg::Vec3Array;
361        normals = new osg::Vec3Array;
362        txc = new osg::Vec3Array;
363        txcoords=new osg::Vec3Array; // new Vec2[6*nfnvf]; // one texture coord per vertex
364    }
365    ~prims() {
366    }
367    void addv(avertex *pos) { // tessellation callback
368        vertices->push_back(osg::Vec3(pos->pos[0],pos->pos[1],pos->pos[2]));
369        normals->push_back(pos->nrmv);
370        txcoords->push_back(osg::Vec3(pos->uv[0],pos->uv[1],0.0f));
371    }
372    void End() { // tessellation is done
373        int nverts=vertices->size()-nbegin;
374        osg::DrawArrays *drw=NULL;
375            switch (primType) {
376            case GL_TRIANGLES: //gset->setPrimType( osg::GeoSet::TRIANGLES );
377                //gset->setNumPrims( nload/3 );
378                drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,nbegin,nverts);
379                gset->addPrimitiveSet(drw);
380                break;
381            case GL_TRIANGLE_STRIP: //gset->setPrimType( osg::GeoSet::TRIANGLE_STRIP );
382                //gset->setPrimLengths( nuprimlengs );
383                drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,nbegin,nverts);
384                gset->addPrimitiveSet(drw);
385                break;
386            case GL_TRIANGLE_FAN: //gset->setPrimType( osg::GeoSet::TRIANGLE_FAN );
387                //gset->setPrimLengths( nuprimlengs );
388                drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN,nbegin,nverts);
389                gset->addPrimitiveSet(drw);
390                break;
391            case GL_QUADS: //gset->setPrimType( osg::GeoSet::QUADS );
392                //gset->setNumPrims( nload/4 );
393                drw=new osg::DrawArrays(osg::PrimitiveSet::QUADS,nbegin,nverts);
394                gset->addPrimitiveSet(drw);
395                break;
396            case GL_QUAD_STRIP: //gset->setPrimType( osg::GeoSet::QUAD_STRIP );
397                drw=new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,nbegin,nverts);
398                gset->addPrimitiveSet(drw);
399                break;
400            case GL_POLYGON: //gset->setPrimType( osg::GeoSet::POLYGON );
401                drw=new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nbegin,nverts);
402                gset->addPrimitiveSet(drw);
403                break;
404            }
405    }
406    void begin(GLenum op) { // part of a Tessellator callback - starts a new primitive of type op
407        primType=op;
408        nbegin=vertices->size();
409    }
410    void combine( GLdouble coords[3], avertex *d[4],
411        GLfloat w[4], avertex **dataOut , _dwobj *dwob);
412    void linkholes(const std::vector<Vec3> verts, const dwmaterial *themat,
413        const _face *f1, const _face *f2,
414        const int ipr[2], const int nv) {
415        int gsidx[4];
416        gsidx[0]=f1->getidx(ipr[1]); // vertex position index
417        gsidx[1]=f1->getidx(ipr[0]); // vertex position index
418        gsidx[2]=f2->getidx(nv-ipr[0]-1); // vertex position index
419        gsidx[3]=f2->getidx(nv-ipr[1]-1); // vertex position index
420
421        Matrix mx; // texture matrix transform to plane
422        Vec3 s1,s2;
423        Vec3 nrm; // calculated normal to face
424        s1=verts[gsidx[1]]-verts[gsidx[0]];
425        s2=verts[gsidx[2]]-verts[gsidx[1]];
426        f1->norm(nrm, s2, s1);
427        f1->settrans(mx, nrm, verts,themat);
428        int n1=vertices->size();
429        for (int j=0; j<4; j++) {
430            Vec3 uv;
431            Vec3 coord=(verts[gsidx[j]]);
432            vertices->push_back( coord );
433            uv=mx*verts[gsidx[j]];
434            txcoords->push_back(uv);
435            normals->push_back(nrm);
436        }
437        osg::DrawArrays *drw=NULL;
438        drw=new osg::DrawArrays(osg::PrimitiveSet::QUADS,n1,4);
439        gset->addPrimitiveSet(drw);
440    }
441    void tessellate(_face &fc, const std::vector<Vec3>& verts, const dwmaterial *themat,GLUtesselator* ts, _dwobj *dwob)
442    {    // generates a set of primitives all of one type (eg tris, qstrip trifan...)
443        fc.setNBegin(vertices->size());
444        fc.tessellate(verts, themat, ts, dwob, tmat.get());
445    }
446    void buildGeometry() { // at end of all faces, add collection of vertices to geometry
447        gset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); //BIND_PERPRIM); //
448        gset->setNormalArray(normals.get());
449        gset->setTexCoordArray(0,txcoords.get());
450        gset->setVertexArray(vertices.get()); // setCoords( vts, nusidx );
451    }
452    void setGeometry(osg::Geometry *gs) {
453        gset=gs;
454    }
455    void settmat(const RefMatrix *mx) {
456        tmat= mx;
457    }
458private:
459    osg::ref_ptr<osg::Geometry> gset;
460    osg::ref_ptr<osg::Vec3Array> vertices;
461    osg::ref_ptr<osg::Vec3Array> normals;
462    osg::ref_ptr<osg::Vec3Array> txc;
463    osg::ref_ptr<osg::Vec3Array> txcoords;
464    GLenum primType;
465    int nbegin; // vertex indices for current primitive
466    osg::ref_ptr<const RefMatrix> tmat; // local texture matrix, or may be NULL for default mapping
467};
468
469static prims *prd=NULL; // OK not nice to have a static but the OpenGL Tessellator etc wants to be able to refer
470// to things that are not available via an argument
471// tessellation subroutines - have 'C' prototypes, not a member of any class...
472// But I want ot use the prims class to contain useful information such as texture matrix etc.
473void CALLBACK myFaceBegin(GLenum op)
474{// tess 'primitive begins' call back
475    prd->begin(op);
476}
477void CALLBACK myFaceEnd()
478{// tess primiitve ends call back
479    prd->End();
480}
481void CALLBACK myVertex(void *pv)
482{// tess vertex call back with texture coord == void *pv1,
483        prd->addv((avertex *)pv);
484}
485void CALLBACK combineCallback( GLdouble coords[3], avertex *d[4],
486                         GLfloat w[4], avertex **dataOut , _dwobj *dwob)
487{
488    // dwob needed if there is a combine callback to add the new vertex to group
489    prd->combine(coords, d, w, dataOut,dwob);
490}
491void CALLBACK error (GLenum errno)
492{ // tess error code
493    const unsigned char *errm=gluErrorString(errno);
494    printf("Tessellator error %d %s\n", static_cast<int>(errno),errm);//, errm
495}
496    //==========
497void _face::linkholes(const std::vector<Vec3> verts, const dwmaterial *themat, const _face *f2) const
498{
499    int ipr[2];
500    ipr[0]=nv-1;
501    for (int i=0; i<nv; i++) { // pairs of vertices
502        ipr[1]=nVertStart+i;
503        prd->linkholes(verts, themat, this, f2, ipr, nv);
504        ipr[0]=ipr[1];
505    }
506}
507void _face::link(const int idop, const _face *f2, const int idop2,const std::vector<Vec3> verts, const dwmaterial *themat) const
508{ // to join up opposed faces of a hole; starts using hole[idop] in THIS, ands at f2.Hole[idop2]
509    opening[idop].linkholes(verts, themat, &f2->opening[idop2]);
510}
511//======== Edges link 2 vertices; indicate where a sharp crease can be found ==========
512class _dwedge {
513public:
514    _dwedge(){;}
515    ~_dwedge(){;}
516    void set(int i, int j) { e1=i; e2=j; }
517private:
518    int e1,e2; // ends of the edge - it joins verts[e1] to verts[e2]
519};
520//===================
521class _dwobj {  // class for design workshop read of a single object
522public:
523    _dwobj() { nverts=nfaces=0; openings=NULL;faces=NULL; tmat=NULL; edges=NULL;
524        nopens=nfaceverts=0; fc1=fc2=NULL; colour[0]=colour[1]=colour[2]=colour[3]=1;
525    }
526    ~_dwobj() {/*delete verts; delete faces;delete openings;*/
527        delete [] fc1;delete [] fc2;
528    }
529    int readOpenings(FILE *fp, const int nexpected)
530    { // read up to nexpected openings, each opening may have a number of vertices
531        char buff[256];
532        openings=new int[nexpected*2];
533        fc1=new unsigned short[nexpected];
534        fc2=new unsigned short[nexpected];
535        nopens=0;
536        int nvop=0; // current number of vertices in hole in object
537        while (nopens<nexpected) { // for each opening
538            if (dwfgets(buff, sizeof( buff ), fp )) {
539                if (strncmp(buff, "Opening:",8)==0) {
540                } else if (strncmp(buff, "faces:",6)==0) {
541                    sscanf(buff, "faces: %hu %hu", fc1+nopens, fc2+nopens);
542                } else if (strncmp(buff, "numVerts:",9)==0) {
543                    int nvtot=nverts; // total number of hole vertices read so far
544                    nvop=atoi(buff+9);
545                    openings[nopens*2]=faces[fc1[nopens]].setnvop(nvop/2); // prepare opening in face
546                    openings[nopens*2+1]=faces[fc2[nopens]].setnvop(nvop/2);
547                    readVerts(fp, nvop);
548                    for (; nvtot<nverts; nvtot++) {
549                        if (faces[fc1[nopens]].holecomplete()) {
550                            if (!faces[fc2[nopens]].holecomplete()) {
551                                faces[fc2[nopens]].addholevtx(nvtot);
552                            } else { // error
553                            }
554                        } else {
555                            faces[fc1[nopens]].addholevtx(nvtot);
556                        }
557                    }
558                    if (faces[fc2[nopens]].holecomplete()) {
559                        nopens++;
560                    }
561                } else { // general line
562                }
563            }
564        }
565        return nopens;
566    }
567    int readEdges(FILE *fp, const int nexpected)
568    { // read up to nexpected vertex pairs.  These are currently ignored.
569        // will define crease edges in future.
570        edges=new _dwedge[nexpected];
571        nedges=0;
572        if (edges) {
573            char buff[256];
574            while (nedges<nexpected) {
575                if (dwfgets(buff, sizeof( buff ), fp )) {
576                    int i1, i2;
577                    sscanf(buff,"%d %d", &i1, &i2);
578                    edges[nedges].set(i1,i2);
579                    nedges++;
580                }
581            }
582        }
583        return nedges;
584    }
585    int readFaces(FILE *fp, const int nexpected)
586    { // read up to nexpected faces
587        faces=new _face[nexpected];
588        char buff[256];
589        if (faces) {
590            while (nfaces<nexpected) {
591                if (dwfgets(buff, sizeof( buff ), fp )) {
592                    if (strncmp(buff,"numVerts:",9)==0) {
593                        int nv=atoi(buff+9);
594                        faces[nfaces].setnv(nv);
595                    } else {
596                        int idx=atoi(buff);
597                        faces[nfaces].addvtx(idx);
598                        if (faces[nfaces].complete()) {
599                            nfaceverts+=faces[nfaces].getnv();
600                            nfaces++;
601                        }
602                    }
603                }
604            }
605        }
606        return nfaces;
607    }
608    void buildDrawable(Group *grp, const osgDB::ReaderWriter::Options *options);  // convert dwobj into osg geosets
609    void setcolour(const float rgb[3]) {
610        colour[0]=rgb[0]; colour[1]=rgb[1]; colour[2]=rgb[2];
611    }
612    void reset() {    faces=NULL; //verts=NULL;
613        nverts=nfaces=nfaceverts=nopens=nedges=0;
614    }
615    void setmat(dwmaterial *mt) {
616        themat=mt;
617    }
618    int readVerts(FILE *fp, const int nexpected)
619    { // read up to nexpected vertices
620        int ntot=nverts+nexpected;
621        char buff[256];
622        verts.reserve(ntot);
623        while (nverts<ntot) {
624            if (dwfgets(buff, sizeof( buff ), fp )) {
625                float x,y,z;
626                sscanf(buff,"%f %f %f", &x, &y, &z);
627                Vec3 pos(x,-y,z);
628                verts.push_back(pos);
629            }
630            nverts++;
631        }
632//    OSG_NOTICE << nverts<<" inp "<<verts[nverts-1].x()<<
633//        " "<<verts[nverts-1].y()<<" "<<verts[nverts-1].z()<<" "<<verts.size()<< std::endl;
634
635        return nverts;
636    }
637    int addvtx(float x, float y, float z) { // add a single vertex to the object
638        Vec3 pos(x,y,z);
639        verts.push_back(pos); //
640        nverts++;
641        return nverts-1;
642    }
643    void settmat(const Matrix& mx) {
644        tmat= new RefMatrix(mx);
645    }
646    void makeuv(Vec2 &uv, const double pos[]) {
647        Vec3 p;
648        Vec3 txc;
649        p.set(pos[0],pos[1],pos[2]);
650        txc = (*mx)*p;
651        uv[0]=txc[0];
652        uv[1]=txc[1];
653    }
654    inline void setmx(RefMatrix *m) { mx=m;}
655private:
656    Vec4 colour;
657    std::vector<Vec3> verts;
658    dwmaterial *themat;
659    unsigned short nverts,nfaces,nedges;
660    unsigned short nfaceverts;
661    unsigned short nopens;
662    _face *faces;
663    _dwedge *edges;
664    int *openings;
665    unsigned short *fc1, *fc2; // openings[i] is in faces[fc1[i]] to faces[fc2[i]]
666    osg::ref_ptr<RefMatrix> tmat;
667    osg::ref_ptr<RefMatrix> mx; // current uvw transform for currently tessealting face
668};
669
670void _face::tessellate(const std::vector<Vec3>& verts, const dwmaterial *themat,
671               GLUtesselator *ts, _dwobj *dwob, const RefMatrix * /*tmat*/) const {
672    int nvall=getallverts();
673    int nused=0;
674    avertex *poses=new avertex[2*nvall]; // passed to Tessellator to redraw
675    Matrix mx; // texture matrix transform to plane
676    settrans(mx, nrm, verts,themat);
677    dwob->setmx(new RefMatrix(mx)); // may be used by combine callback to define txcoord
678    gluTessBeginPolygon(ts, dwob);
679    gluTessBeginContour(ts); /**/
680    for (int j=0; j<nv; j++) {
681        Vec3 uv;
682        uv=mx*verts[idx[j]];
683        setposes(poses[nused], j, verts);
684        poses[nused].uv[0]=uv[0];
685        poses[nused].uv[1]=uv[1];
686        gluTessVertex(ts, (double *)&(poses[nused]), (double *)(poses+nused));
687        nused++;
688    }
689    gluTessEndContour(ts);
690    for (int k=0; k<nop; k++) { // now holes in the face
691        gluTessBeginContour(ts);
692        for (int j=0; j<opening[k].nv; j++) {
693            Vec3 uv;
694            uv=mx*verts[opening[k].idx[j]];
695            opening[k].setposes(poses[nused], j, verts);
696            poses[nused].nrmv*=-1; // get to agree with base polygon
697            poses[nused].nrmv=nrm;
698            poses[nused].uv[0]=uv[0];
699            poses[nused].uv[1]=uv[1];
700            gluTessVertex(ts, (double *)&(poses[nused]), (double *)(poses+nused));
701            nused++;
702        }
703        gluTessEndContour(ts);/* */
704    }
705    gluTessEndPolygon(ts);
706    delete [] poses;
707}
708void prims::combine( GLdouble coords[3], avertex *d[4],
709                    GLfloat w[4], avertex **dataOut , _dwobj *dwob) {
710    avertex *newv = new avertex(); // (avertex *)calloc(1, sizeof(avertex));
711    newv->pos[0] = coords[0];
712    newv->pos[1] = coords[1];
713    newv->pos[2] = coords[2];
714    newv->uv[0] = newv->uv[1] =0;
715    newv->nrmv[0] = newv->nrmv[1] = newv->nrmv[2] =0;
716    for (int i=0; i<4; i++) {
717        if (d[i]) {
718            newv->uv[0] = w[i]*d[i]->uv[0];
719            newv->uv[1] = w[i]*d[i]->uv[1];
720            newv->nrmv[0] = w[i]*d[i]->nrmv[0];
721            newv->nrmv[1] = w[i]*d[i]->nrmv[1];
722            newv->nrmv[2] = w[i]*d[i]->nrmv[2];
723        }
724    }
725    dwob->makeuv(newv->uv, newv->pos);
726    newv->idx=dwob->addvtx(coords[0], coords[1], coords[2]);
727    *dataOut = newv;
728}
729void _dwobj::buildDrawable(Group *grp, const osgDB::ReaderWriter::Options *options)
730// current DWobject complete; make a drawable, and add it to a osg::Group
731    if (nfaces>0) {
732        if (themat->isType(dwmaterial::PointLight) || themat->isType(dwmaterial::SpotLight)) {
733            Vec4 pos;
734            pos.set(0.0f,0.0f,0.0f,0.0f);
735            for (int i=0; i<nverts; i++) {
736                pos[0]+=verts[i].x();
737                pos[1]+=verts[i].y();
738                pos[2]+=verts[i].z();
739            }
740            pos/=nverts;
741            pos[3]=1.0f;
742            LightSource *ls=themat->makeLight(pos);
743            grp->addChild(ls);
744        } else {
745            Geode *geode = new Geode;
746            int nfnvf=0; // number of vertices for faces plus holes
747            int i; // a general counter
748            for (i=0; i<nfaces; i++) { // for each face
749                faces[i].setnorm(verts); // set its normal and any hole normals
750                nfnvf+=faces[i].getallverts(); // get total vertices in object, defines dimensions of NEW arrays
751            }
752
753
754            GLUtesselator* ts=gluNewTess();
755            gluTessCallback(ts, GLU_TESS_BEGIN, (GLU_TESS_CALLBACK) myFaceBegin);
756            gluTessCallback(ts, GLU_TESS_VERTEX, (GLU_TESS_CALLBACK) myVertex);
757            gluTessCallback(ts, GLU_TESS_END, (GLU_TESS_CALLBACK) myFaceEnd);
758            gluTessCallback(ts, GLU_TESS_ERROR, (GLU_TESS_CALLBACK) error);
759            gluTessCallback(ts, GLU_TESS_COMBINE_DATA, (GLU_TESS_CALLBACK) combineCallback);
760            //  for (int nvf=0; nvf<6; nvf++) { // for each length of face
761            // for Geometry we dont need to collect prim types individually
762            //     prd.setmode(nvf , nfnvf); // filter out only this type of tessellated face
763            prd=new prims;
764            prd->settmat(tmat.get());
765            osg::Geometry *gset = new osg::Geometry;
766            prd->setGeometry(gset);
767            StateSet *dstate=themat->make(options);
768            gset->setStateSet( dstate );
769            grp->addChild( geode ); // add to the world outside
770            geode->addDrawable(gset);
771
772            // each face adds a primitive to the geometry, after it is tessellated
773            for (i=0; i<nfaces; i++) { // for each face, collect up
774                prd->tessellate(faces[i],verts, themat, ts, this);
775            }
776            for (i=0; i<nopens; i++) { // for each hole, join up front & back with Quads
777                if (fc1 && fc2) {
778                    faces[fc1[i]].link(openings[i*2], &faces[fc2[i]],openings[i*2+1],verts, themat);
779                }
780            } // for each opening
781            prd->buildGeometry();
782        gluDeleteTess(ts);
783        delete prd;
784        }
785    } // nfaces>0
786    verts.clear();
787}
788////////// tessellation complete
789
790class ReaderWriterDW : public osgDB::ReaderWriter
791{
792    public:
793
794        ReaderWriterDW()
795        {
796            supportsExtension("dw","Designer Workbench model format");
797        }
798
799        virtual const char* className() const { return "Design Workshop Database Reader"; }
800
801        virtual ReadResult readNode(const std::string& file,const osgDB::ReaderWriter::Options* options) const
802        {
803
804            std::string ext = osgDB::getLowerCaseFileExtension(file);
805            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
806
807            std::string fileName = osgDB::findDataFile( file, options );
808            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
809
810
811            _dwobj obj;
812            enum reading {NONE, MATERIAL, OBJECT};
813            //unsigned short nrecs=0; // number of records read after a divider (numVerts, numFaces, numOpenings...)
814            int nexpected=0; // number of records to be read in a block
815            dwmaterial *matpalet=NULL;
816            int nmat=-1; // current element of matpalet being modified
817            int nmn=0; // number of materials found
818            reading rdg=NONE;
819
820            char buff[256];
821
822            OSG_INFO<<   "ReaderWriterDW::readNode( "<<fileName.c_str()<<" )\n";
823#ifdef _MSC_VER
824            OSG_INFO<<   "MS Visual C++ version "<<_MSC_VER<<"\n";
825#endif
826
827            FILE *fp;
828
829            if( (fp = osgDB::fopen( fileName.c_str(), "r" )) == (FILE *)0L )
830            {
831                return std::string("Unable to open file \""+fileName+"\"");
832            }
833            Group *grp = new Group;
834
835            // code for setting up the database path so that internally referenced file are searched for on relative paths.
836            osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
837            local_opt->setDatabasePath(osgDB::getFilePath(fileName));
838
839
840            while( !feof( fp ) )
841            { // reads the Design Workshop format in ASCII
842                if (dwfgets( buff, sizeof( buff ), fp )) {
843                    if( buff[0] == '#' )
844                        continue;
845                    else if( strncmp(buff,"numMaterials:",13)==0) { // No of materials
846                        nmn=atoi(buff+14);
847                        matpalet=new dwmaterial[nmn];
848                    } else if( strncmp(buff,"Material:",9)==0) { // No of materials
849                        dwfgets(buff, sizeof( buff ), fp );
850                        nmat++;
851                        rdg=MATERIAL;
852                        int id=atoi(buff);
853                        matpalet[nmat].setid(id); // current material to be modified
854
855                    } else if (strncmp(buff, "Phase:",6)==0) {
856                    } else if (strncmp(buff, "CurrPhase:",10)==0) {
857                    } else if (strncmp(buff, "numPhases:",10)==0) {
858                    } else if (strncmp(buff, "Opacity:",8)==0) {
859                        float opacity=osg::asciiToFloat(buff+8);
860                        matpalet[nmat].setopacity(opacity);
861                    } else if (strncmp(buff, "FallOff:",8)==0) {
862                        float fo=osg::asciiToFloat(buff+8);
863                        matpalet[nmat].setFallOff(fo);
864                    } else if (strncmp(buff, "InnerHalfAngle:",15)==0) {
865                        float ha=osg::asciiToFloat(buff+15);
866                        matpalet[nmat].setHalfAngleIn(ha);
867                    } else if (strncmp(buff, "OuterHalfAngle:",15)==0) {
868                        float ha=osg::asciiToFloat(buff+15);
869                        matpalet[nmat].setHalfAngleOut(ha);
870                    } else if (strncmp(buff, "Brightness:",11)==0) {
871                        float br=osg::asciiToFloat(buff+11);
872                        matpalet[nmat].setBright(br);
873                    } else if (strncmp(buff, "Attentuation:",13)==0) { // oops - they can't spell
874                        matpalet[nmat].setAtten(buff+13);
875                    } else if (strncmp(buff, "MaterialType:",13)==0) {
876                        matpalet[nmat].setType(buff+14);
877                    } else if (strncmp(buff, "SpecularReflectivity:",21)==0) {
878                        float spec=osg::asciiToFloat(buff+21);
879                        matpalet[nmat].setspecular(spec);
880                    } else if (strncmp(buff, "SmoothnessExponent:",19)==0) {
881                        float spec=osg::asciiToFloat(buff+19);
882                        matpalet[nmat].setspecexp(spec*128.0f/100.0f); // convert to 0-128 range from percent
883                    } else if (strncmp(buff, "TextureWidthAndHeight:",22)==0) {
884                        char *ct=strchr(buff+22,',');
885                        float repx=osg::asciiToFloat(buff+23), repy=osg::asciiToFloat(ct+1);
886                        matpalet[nmat].settxrep(repx, repy);
887                    } else if (strncmp(buff, "PictureFile:",12)==0) {
888                        char *end=strchr(buff,'\n'); // end of line
889                        if (end) *end='\0'; // removed
890                        matpalet[nmat].setfname(buff);
891                    } else if( strncmp(buff,"Extrusion:",10)==0 ||
892                        strncmp(buff,"Cube:",5)==0 ||
893                        strncmp(buff,"Polyline:",9)==0 ||
894                        strncmp(buff,"Polyhedron:",11)==0) {
895                        rdg=OBJECT;
896                        obj.buildDrawable(grp, options);
897                        obj.reset();
898                    } else if( strncmp(buff,"Mat:",4)==0) {
899                        int mt=atoi(buff+4);
900                        for (int j=0; j<nmn; j++) {
901                            if (matpalet[j].getid() == mt)
902                                obj.setmat(&(matpalet[j]));
903                        }
904                    } else if( strncmp(buff,"Color:",6)==0) {
905                        float rgb[3];
906                        if (rdg==MATERIAL) { // get material colour
907                            sscanf(buff+6,"%f %f %f", &rgb[0], &rgb[1], &rgb[2]);
908                            matpalet[nmat].setcolour(rgb);
909                        } else if (rdg==OBJECT) {
910                            float rgb[3];
911                            sscanf(buff+6,"%f %f %f", &rgb[0], &rgb[1], &rgb[2]);
912                            rgb[0]/=65536.0f; // convert to range 0-1
913                            rgb[1]/=65536.0f; // convert to range 0-1
914                            rgb[2]/=65536.0f; // convert to range 0-1
915                            obj.setcolour(rgb);
916                        }
917                    } else if( strncmp(buff,"numVerts:",9)==0) {
918                        nexpected=atoi(buff+9);
919                        obj.readVerts(fp, nexpected);
920                        nexpected=0;
921                    } else if( strncmp(buff,"numFaces:",9)==0) {
922                        nexpected=atoi(buff+9);
923                        obj.readFaces(fp, nexpected);
924                        nexpected=0;
925                    } else if( strncmp(buff,"numEdges:",9)==0) {
926                        nexpected=atoi(buff+9);
927                        obj.readEdges(fp, nexpected);
928                        //nrecs=0; // a numVerts is followed by nv vetex postiions
929                    } else if( strncmp(buff,"numOpenings:",12)==0) {
930                        nexpected=atoi(buff+12);
931                        //nrecs=0; // a numVerts is followed by nv vetex postiions
932                        if (nexpected>0) obj.readOpenings(fp, nexpected);
933                    } else if( strncmp(buff,"UVW:",4)==0) { // texture application matrix
934                        double mx[3][3];
935                        sscanf(buff+4,"%lf %lf %lf %lf %lf %lf %lf %lf %lf",
936                            &mx[0][0], &mx[0][1], &mx[0][2],
937                            &mx[1][0], &mx[1][1], &mx[1][2],
938                            &mx[2][0], &mx[2][1], &mx[2][2]);
939
940                        obj.settmat(Matrix(mx[0][0],mx[0][1],mx[0][2],0.0,
941                                           mx[1][0],mx[1][1],mx[1][2],0.0,
942                                           mx[2][0],mx[2][1],mx[2][2],0.0,
943                                           0.0     ,0.0     ,0.0     ,1.0));
944                    }
945                }
946
947            }
948            fclose( fp );
949            obj.buildDrawable(grp, options); // tidy up any remaining objects
950
951            return grp;
952
953        }
954private:
955};
956
957int dwfgets(char *clin, int max, FILE *fin)
958{ // replace fgets to detect EOL = char 13 as well as Creturn=10 GWM 111100
959    // Macintosh produced files (such as those obtainable
960    //from the great buildings site at www.Artifice.com) use 13 format, PC models use 10.
961    int nread=0;
962    char c1=1;
963    do {
964        if (!feof( fin )) {
965            clin[nread]=c1=fgetc(fin);
966            nread++;
967        }
968    } while (nread<max && c1!= 13 && c1!= 10 &&  feof( fin )== 0 );
969    if (nread>0) clin[nread-1]='\0'; // null terminate and remove training blank
970    return nread;
971}
972
973// now register with osg::Registry to instantiate the above
974// reader/writer.
975REGISTER_OSGPLUGIN(dw, ReaderWriterDW)
Note: See TracBrowser for help on using the browser.