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

Revision 10415, 40.7 kB (checked in by robert, 5 years ago)

From Mathias Froehlich, "We are currently getting issues with locale settings and some osg plugins.
Therefore I have changed all the occurances of atof by asciiToFloat or
asciiToDouble.

I believe that it is safe to do so at least for all the plugins.
Included here are also asciiToFloat conversion of environment variables. One
might argue that these should be locale dependent. But IMO these should be
set and interpreted by osg independent of the current locale.
"

  • 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 Matrix *tmat) const;
332    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
333    inline const int getidx(int i) const { return idx[i];}
334private:
335    void linkholes(const std::vector<Vec3> verts, const dwmaterial *themat, const _face *f2) const;
336    void reverse() { // reverse order of the vertices
337        for (int j=0; j<nv/2; j++) {
338            int it=idx[j];
339            idx[j]=idx[nv-j-1];
340            idx[nv-j-1]=it;
341        }
342    }
343    int nop; // number of openings so far
344    class _face *opening; // openings in this face. number of verts, vertex list for opening
345    int nv; // number of vertices in the face
346    int nset; // number read so far
347    int nVertStart; // start index of vertices in the grand Geometry
348    Vec3 nrm; // surface normal
349    int *idx; // indices into the vertex list for the object
350};
351
352// structure for generating triangles (and tstrips, tfans etc)
353// from a design workshop object.
354
355class prims {
356public:
357    prims() { nbegin=0; // primlengs=NULL; gsidx=NULL;nrmidx=NULL;
358     //   txidx=NULL;nrms=NULL;txcoords=NULL;
359     //   nload=0; nff=0; curmode=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        tmat=NULL;
365    }
366    ~prims() {    /*delete [] primlengs; delete [] nrms;
367        delete [] gsidx; delete [] nrmidx; delete [] txcoords;*/
368    }
369    void addv(avertex *pos) { // tessellation callback
370        vertices->push_back(osg::Vec3(pos->pos[0],pos->pos[1],pos->pos[2]));
371        normals->push_back(pos->nrmv);
372        txcoords->push_back(osg::Vec3(pos->uv[0],pos->uv[1],0.0f));
373    }
374    void End() { // tessellation is done
375        int nverts=vertices->size()-nbegin;
376        osg::DrawArrays *drw=NULL;                               
377            switch (primType) {
378            case GL_TRIANGLES: //gset->setPrimType( osg::GeoSet::TRIANGLES );
379                //gset->setNumPrims( nload/3 );
380                drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,nbegin,nverts);                               
381                gset->addPrimitiveSet(drw);
382                break;
383            case GL_TRIANGLE_STRIP: //gset->setPrimType( osg::GeoSet::TRIANGLE_STRIP );
384                //gset->setPrimLengths( nuprimlengs );
385                drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,nbegin,nverts);                               
386                gset->addPrimitiveSet(drw);
387                break;
388            case GL_TRIANGLE_FAN: //gset->setPrimType( osg::GeoSet::TRIANGLE_FAN );
389                //gset->setPrimLengths( nuprimlengs );
390                drw=new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN,nbegin,nverts);                               
391                gset->addPrimitiveSet(drw);
392                break;
393            case GL_QUADS: //gset->setPrimType( osg::GeoSet::QUADS );
394                //gset->setNumPrims( nload/4 );
395                drw=new osg::DrawArrays(osg::PrimitiveSet::QUADS,nbegin,nverts);                               
396                gset->addPrimitiveSet(drw);
397                break;
398            case GL_QUAD_STRIP: //gset->setPrimType( osg::GeoSet::QUAD_STRIP );
399                drw=new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,nbegin,nverts);                               
400                gset->addPrimitiveSet(drw);
401                break;
402            case GL_POLYGON: //gset->setPrimType( osg::GeoSet::POLYGON );
403                drw=new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nbegin,nverts);                               
404                gset->addPrimitiveSet(drw);
405                break;
406            }
407    }
408    void begin(GLenum op) { // part of a Tessellator callback - starts a new primitive of type op
409        primType=op;
410        nbegin=vertices->size();
411    }
412    void combine( GLdouble coords[3], avertex *d[4],
413        GLfloat w[4], avertex **dataOut , _dwobj *dwob);
414    void linkholes(const std::vector<Vec3> verts, const dwmaterial *themat,
415        const _face *f1, const _face *f2,
416        const int ipr[2], const int nv) {
417        int gsidx[4];
418        gsidx[0]=f1->getidx(ipr[1]); // vertex position index
419        gsidx[1]=f1->getidx(ipr[0]); // vertex position index
420        gsidx[2]=f2->getidx(nv-ipr[0]-1); // vertex position index
421        gsidx[3]=f2->getidx(nv-ipr[1]-1); // vertex position index
422       
423        Matrix mx; // texture matrix transform to plane
424        Vec3 s1,s2;
425        Vec3 nrm; // calculated normal to face
426        s1=verts[gsidx[1]]-verts[gsidx[0]];
427        s2=verts[gsidx[2]]-verts[gsidx[1]];
428        f1->norm(nrm, s2, s1);
429        f1->settrans(mx, nrm, verts,themat);
430        int n1=vertices->size();
431        for (int j=0; j<4; j++) {
432            Vec3 uv;
433            Vec3 coord=(verts[gsidx[j]]);
434            vertices->push_back( coord );
435            uv=mx*verts[gsidx[j]];
436            txcoords->push_back(uv);
437            normals->push_back(nrm);
438        }
439        osg::DrawArrays *drw=NULL;                               
440        drw=new osg::DrawArrays(osg::PrimitiveSet::QUADS,n1,4);
441        gset->addPrimitiveSet(drw);
442    }
443    void tessellate(_face &fc, const std::vector<Vec3> verts, const dwmaterial *themat,GLUtesselator* ts, _dwobj *dwob)
444    {    // generates a set of primitives all of one type (eg tris, qstrip trifan...)
445        fc.setNBegin(vertices->size());
446        fc.tessellate(verts, themat, ts, dwob, tmat);
447    }
448    void buildGeometry() { // at end of all faces, add collection of vertices to geometry
449        gset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); //BIND_PERPRIM); //
450        gset->setNormalArray(normals);
451        gset->setTexCoordArray(0,txcoords);
452        gset->setVertexArray(vertices); // setCoords( vts, nusidx );
453    }
454    void setGeometry(osg::Geometry *gs) {
455        gset=gs;
456    }
457    void settmat(const Matrix *mx) {
458        tmat= mx;
459    }
460private:
461    osg::Geometry *gset;
462    osg::Vec3Array* vertices;
463    osg::Vec3Array* normals;
464    osg::Vec3Array* txc;
465    osg::Vec3Array* txcoords;
466    GLenum primType;
467    int nbegin; // vertex indices for current primitive
468    const Matrix *tmat; // local texture matrix, or may be NULL for default mapping
469};
470
471static prims *prd=NULL; // OK not nice to have a static but the OpenGL Tessellator etc wants to be able to refer
472// to things that are not available via an argument
473// tessellation subroutines - have 'C' prototypes, not a member of any class...
474// But I want ot use the prims class to contain useful information such as texture matrix etc.
475void CALLBACK myFaceBegin(GLenum op)
476{// tess 'primitive begins' call back
477    prd->begin(op);
478}
479void CALLBACK myFaceEnd()
480{// tess primiitve ends call back
481    prd->End();
482}
483void CALLBACK myVertex(void *pv)
484{// tess vertex call back with texture coord == void *pv1,
485        prd->addv((avertex *)pv);
486}
487void CALLBACK combineCallback( GLdouble coords[3], avertex *d[4],
488                         GLfloat w[4], avertex **dataOut , _dwobj *dwob)
489{
490    // dwob needed if there is a combine callback to add the new vertex to group
491    prd->combine(coords, d, w, dataOut,dwob);
492}
493void CALLBACK error (GLenum errno)
494{ // tess error code
495    const unsigned char *errm=gluErrorString(errno);
496    printf("Tessellator error %d %s\n", static_cast<int>(errno),errm);//, errm
497}
498    //==========
499void _face::linkholes(const std::vector<Vec3> verts, const dwmaterial *themat, const _face *f2) const
500{
501    int ipr[2];
502    ipr[0]=nv-1;
503    for (int i=0; i<nv; i++) { // pairs of vertices
504        ipr[1]=nVertStart+i;
505        prd->linkholes(verts, themat, this, f2, ipr, nv);
506        ipr[0]=ipr[1];
507    }
508}
509void _face::link(const int idop, const _face *f2, const int idop2,const std::vector<Vec3> verts, const dwmaterial *themat) const
510{ // to join up opposed faces of a hole; starts using hole[idop] in THIS, ands at f2.Hole[idop2]
511    opening[idop].linkholes(verts, themat, &f2->opening[idop2]);
512}
513//======== Edges link 2 vertices; indicate where a sharp crease can be found ==========
514class _dwedge {
515public:
516    _dwedge(){;}
517    ~_dwedge(){;}
518    void set(int i, int j) { e1=i; e2=j; }
519private:
520    int e1,e2; // ends of the edge - it joins verts[e1] to verts[e2]
521};
522//===================
523class _dwobj {  // class for design workshop read of a single object
524public:
525    _dwobj() { nverts=nfaces=0; openings=NULL;faces=NULL; tmat=NULL; edges=NULL;
526        nopens=nfaceverts=0; fc1=fc2=NULL; colour[0]=colour[1]=colour[2]=colour[3]=1;
527    }
528    ~_dwobj() {/*delete verts; delete faces;delete openings;*/
529        delete fc1;delete fc2;
530    }
531    int readOpenings(FILE *fp, const int nexpected)
532    { // read up to nexpected openings, each opening may have a number of vertices
533        char buff[256];
534        openings=new int[nexpected*2];
535        fc1=new unsigned short[nexpected];
536        fc2=new unsigned short[nexpected];
537        nopens=0;
538        int nvop=0; // current number of vertices in hole in object
539        while (nopens<nexpected) { // for each opening
540            if (dwfgets(buff, sizeof( buff ), fp )) {
541                if (strncmp(buff, "Opening:",8)==0) {
542                } else if (strncmp(buff, "faces:",6)==0) {
543                    sscanf(buff, "faces: %hu %hu", fc1+nopens, fc2+nopens);
544                } else if (strncmp(buff, "numVerts:",9)==0) {
545                    int nvtot=nverts; // total number of hole vertices read so far
546                    nvop=atoi(buff+9);
547                    openings[nopens*2]=faces[fc1[nopens]].setnvop(nvop/2); // prepare opening in face
548                    openings[nopens*2+1]=faces[fc2[nopens]].setnvop(nvop/2);
549                    readVerts(fp, nvop);
550                    for (; nvtot<nverts; nvtot++) {
551                        if (faces[fc1[nopens]].holecomplete()) {
552                            if (!faces[fc2[nopens]].holecomplete()) {
553                                faces[fc2[nopens]].addholevtx(nvtot);
554                            } else { // error
555                            }
556                        } else {
557                            faces[fc1[nopens]].addholevtx(nvtot);
558                        }
559                    }
560                    if (faces[fc2[nopens]].holecomplete()) {
561                        nopens++;
562                    }
563                } else { // general line
564                }
565            }
566        }
567        return nopens;
568    }
569    int readEdges(FILE *fp, const int nexpected)
570    { // read up to nexpected vertex pairs.  These are currently ignored.
571        // will define crease edges in future.
572        edges=new _dwedge[nexpected];
573        nedges=0;
574        if (edges) {
575            char buff[256];
576            while (nedges<nexpected) {
577                if (dwfgets(buff, sizeof( buff ), fp )) {
578                    int i1, i2;
579                    sscanf(buff,"%d %d", &i1, &i2);
580                    edges[nedges].set(i1,i2);
581                    nedges++;
582                }
583            }
584        }
585        return nedges;
586    }
587    int readFaces(FILE *fp, const int nexpected)
588    { // read up to nexpected faces
589        faces=new _face[nexpected];
590        char buff[256];
591        if (faces) {
592            while (nfaces<nexpected) {
593                if (dwfgets(buff, sizeof( buff ), fp )) {
594                    if (strncmp(buff,"numVerts:",9)==0) {
595                        int nv=atoi(buff+9);
596                        faces[nfaces].setnv(nv);
597                    } else {
598                        int idx=atoi(buff);
599                        faces[nfaces].addvtx(idx);
600                        if (faces[nfaces].complete()) {
601                            nfaceverts+=faces[nfaces].getnv();
602                            nfaces++;
603                        }
604                    }
605                }
606            }
607        }
608        return nfaces;
609    }
610    void buildDrawable(Group *grp, const osgDB::ReaderWriter::Options *options);  // convert dwobj into osg geosets
611    void setcolour(const float rgb[3]) {
612        colour[0]=rgb[0]; colour[1]=rgb[1]; colour[2]=rgb[2];
613    }
614    void reset() {    faces=NULL; //verts=NULL;
615        nverts=nfaces=nfaceverts=nopens=nedges=0;
616    }
617    void setmat(dwmaterial *mt) {
618        themat=mt;
619    }
620    int readVerts(FILE *fp, const int nexpected)
621    { // read up to nexpected vertices
622        int ntot=nverts+nexpected;
623        char buff[256];
624        verts.reserve(ntot);
625        while (nverts<ntot) {
626            if (dwfgets(buff, sizeof( buff ), fp )) {
627                float x,y,z;
628                sscanf(buff,"%f %f %f", &x, &y, &z);
629                Vec3 pos(x,-y,z);
630                verts.push_back(pos);
631            }
632            nverts++;
633        }
634//    osg::notify(osg::NOTICE) << nverts<<" inp "<<verts[nverts-1].x()<<
635//        " "<<verts[nverts-1].y()<<" "<<verts[nverts-1].z()<<" "<<verts.size()<< std::endl;
636
637        return nverts;
638    }
639    int addvtx(float x, float y, float z) { // add a single vertex to the object
640        Vec3 pos(x,y,z);
641        verts.push_back(pos); //
642        nverts++;
643        return nverts-1;
644    }
645    void settmat(const Matrix& mx) {
646        tmat= new Matrix(mx);
647    }
648    void makeuv(Vec2 &uv, const double pos[]) {
649        Vec3 p;
650        Vec3 txc;
651        p.set(pos[0],pos[1],pos[2]);
652        txc = (*mx)*p;
653        uv[0]=txc[0];
654        uv[1]=txc[1];
655    }
656    inline void setmx(Matrix *m) { mx=m;}
657private:
658    Vec4 colour;
659    std::vector<Vec3> verts;
660    dwmaterial *themat;
661    unsigned short nverts,nfaces,nedges;
662    unsigned short nfaceverts;
663    unsigned short nopens;
664    _face *faces;
665    _dwedge *edges;
666    int *openings;
667    unsigned short *fc1, *fc2; // openings[i] is in faces[fc1[i]] to faces[fc2[i]]
668    Matrix *tmat;
669    Matrix *mx; // current uvw transform for currently tessealting face
670};
671
672void _face::tessellate(const std::vector<Vec3> verts, const dwmaterial *themat,
673               GLUtesselator *ts, _dwobj *dwob, const Matrix * /*tmat*/) const {
674    int nvall=getallverts();
675    int nused=0;
676    avertex *poses=new avertex[2*nvall]; // passed to Tessellator to redraw
677    Matrix mx; // texture matrix transform to plane
678    settrans(mx, nrm, verts,themat);
679    dwob->setmx(&mx); // may be used by combine callback to define txcoord
680    gluTessBeginPolygon(ts, dwob);
681    gluTessBeginContour(ts); /**/
682    for (int j=0; j<nv; j++) {
683        Vec3 uv;
684        uv=mx*verts[idx[j]];
685        setposes(poses[nused], j, verts);
686        poses[nused].uv[0]=uv[0];
687        poses[nused].uv[1]=uv[1];
688        gluTessVertex(ts, (double *)&(poses[nused]), (double *)(poses+nused));
689        nused++;
690    }
691    gluTessEndContour(ts);
692    for (int k=0; k<nop; k++) { // now holes in the face
693        gluTessBeginContour(ts);
694        for (int j=0; j<opening[k].nv; j++) {
695            Vec3 uv;
696            uv=mx*verts[opening[k].idx[j]];
697            opening[k].setposes(poses[nused], j, verts);
698            poses[nused].nrmv*=-1; // get to agree with base polygon
699            poses[nused].nrmv=nrm;
700            poses[nused].uv[0]=uv[0];
701            poses[nused].uv[1]=uv[1];
702            gluTessVertex(ts, (double *)&(poses[nused]), (double *)(poses+nused));
703            nused++;
704        }
705        gluTessEndContour(ts);/* */
706    }
707    gluTessEndPolygon(ts);
708    delete [] poses;
709}
710void prims::combine( GLdouble coords[3], avertex *d[4],
711                    GLfloat w[4], avertex **dataOut , _dwobj *dwob) {
712    avertex *newv = new avertex(); // (avertex *)calloc(1, sizeof(avertex));
713    newv->pos[0] = coords[0];
714    newv->pos[1] = coords[1];
715    newv->pos[2] = coords[2];
716    newv->uv[0] = newv->uv[1] =0;
717    newv->nrmv[0] = newv->nrmv[1] = newv->nrmv[2] =0;
718    for (int i=0; i<4; i++) {
719        if (d[i]) {
720            newv->uv[0] = w[i]*d[i]->uv[0];
721            newv->uv[1] = w[i]*d[i]->uv[1];
722            newv->nrmv[0] = w[i]*d[i]->nrmv[0];
723            newv->nrmv[1] = w[i]*d[i]->nrmv[1];
724            newv->nrmv[2] = w[i]*d[i]->nrmv[2];
725        }
726    }
727    dwob->makeuv(newv->uv, newv->pos);
728    newv->idx=dwob->addvtx(coords[0], coords[1], coords[2]);
729    *dataOut = newv;
730}
731void _dwobj::buildDrawable(Group *grp, const osgDB::ReaderWriter::Options *options)
732// current DWobject complete; make a drawable, and add it to a osg::Group
733    if (nfaces>0) {
734        if (themat->isType(dwmaterial::PointLight) || themat->isType(dwmaterial::SpotLight)) {
735            Vec4 pos;
736            pos.set(0.0f,0.0f,0.0f,0.0f);
737            for (int i=0; i<nverts; i++) {
738                pos[0]+=verts[i].x();
739                pos[1]+=verts[i].y();
740                pos[2]+=verts[i].z();
741            }
742            pos/=nverts;
743            pos[3]=1.0f;
744            LightSource *ls=themat->makeLight(pos);
745            grp->addChild(ls);
746        } else {
747            Geode *geode = new Geode;
748            int nfnvf=0; // number of vertices for faces plus holes
749            int i; // a general counter
750            for (i=0; i<nfaces; i++) { // for each face
751                faces[i].setnorm(verts); // set its normal and any hole normals
752                nfnvf+=faces[i].getallverts(); // get total vertices in object, defines dimensions of NEW arrays
753            }
754           
755           
756            GLUtesselator* ts=gluNewTess();
757            gluTessCallback(ts, GLU_TESS_BEGIN, (GLU_TESS_CALLBACK) myFaceBegin); 
758            gluTessCallback(ts, GLU_TESS_VERTEX, (GLU_TESS_CALLBACK) myVertex); 
759            gluTessCallback(ts, GLU_TESS_END, (GLU_TESS_CALLBACK) myFaceEnd); 
760            gluTessCallback(ts, GLU_TESS_ERROR, (GLU_TESS_CALLBACK) error); 
761            gluTessCallback(ts, GLU_TESS_COMBINE_DATA, (GLU_TESS_CALLBACK) combineCallback);
762            //  for (int nvf=0; nvf<6; nvf++) { // for each length of face
763            // for Geometry we dont need to collect prim types individually
764            //     prd.setmode(nvf , nfnvf); // filter out only this type of tessellated face
765            prd=new prims;
766            prd->settmat(tmat);
767            osg::Geometry *gset = new osg::Geometry;
768            prd->setGeometry(gset);
769            StateSet *dstate=themat->make(options);           
770            gset->setStateSet( dstate );
771            grp->addChild( geode ); // add to the world outside
772            geode->addDrawable(gset);
773           
774            // each face adds a primitive to the geometry, after it is tessellated
775            for (i=0; i<nfaces; i++) { // for each face, collect up
776                prd->tessellate(faces[i],verts, themat, ts, this);
777            }
778            for (i=0; i<nopens; i++) { // for each hole, join up front & back with Quads
779                if (fc1 && fc2) {
780                    faces[fc1[i]].link(openings[i*2], &faces[fc2[i]],openings[i*2+1],verts, themat);
781                }
782            } // for each opening
783            prd->buildGeometry();
784        gluDeleteTess(ts);
785        delete prd;
786        }
787    } // nfaces>0
788    verts.clear();
789}
790////////// tessellation complete
791
792class ReaderWriterDW : public osgDB::ReaderWriter
793{
794    public:
795   
796        ReaderWriterDW()
797        {
798            supportsExtension("dw","Designer Workbench model format");
799        }
800   
801        virtual const char* className() const { return "Design Workshop Database Reader"; }
802
803        virtual ReadResult readNode(const std::string& file,const osgDB::ReaderWriter::Options* options) const
804        {
805
806            std::string ext = osgDB::getLowerCaseFileExtension(file);
807            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
808
809            std::string fileName = osgDB::findDataFile( file, options );
810            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
811
812
813            _dwobj obj;
814            enum reading {NONE, MATERIAL, OBJECT};
815            //unsigned short nrecs=0; // number of records read after a divider (numVerts, numFaces, numOpenings...)
816            int nexpected=0; // number of records to be read in a block
817            dwmaterial *matpalet=NULL;
818            int nmat=-1; // current element of matpalet being modified
819            int nmn=0; // number of materials found
820            reading rdg=NONE;
821
822            char buff[256];
823
824            notify(INFO)<<   "ReaderWriterDW::readNode( "<<fileName.c_str()<<" )\n";
825#ifdef _MSC_VER
826            notify(osg::NOTICE)<<   "MS Visual C++ version "<<_MSC_VER<<"\n";
827#endif
828
829            FILE *fp;
830
831            if( (fp = osgDB::fopen( fileName.c_str(), "r" )) == (FILE *)0L )
832            {
833                return std::string("Unable to open file \""+fileName+"\"");
834            }
835            Group *grp = new Group;
836
837            // code for setting up the database path so that internally referenced file are searched for on relative paths.
838            osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
839            local_opt->setDatabasePath(osgDB::getFilePath(fileName));
840
841
842            while( !feof( fp ) )
843            { // reads the Design Workshop format in ASCII
844                if (dwfgets( buff, sizeof( buff ), fp )) {
845                    if( buff[0] == '#' )
846                        continue;
847                    else if( strncmp(buff,"numMaterials:",13)==0) { // No of materials
848                        nmn=atoi(buff+14);
849                        matpalet=new dwmaterial[nmn];
850                    } else if( strncmp(buff,"Material:",9)==0) { // No of materials
851                        dwfgets(buff, sizeof( buff ), fp );
852                        nmat++;
853                        rdg=MATERIAL;
854                        int id=atoi(buff);
855                        matpalet[nmat].setid(id); // current material to be modified
856                       
857                    } else if (strncmp(buff, "Phase:",6)==0) {
858                    } else if (strncmp(buff, "CurrPhase:",10)==0) {
859                    } else if (strncmp(buff, "numPhases:",10)==0) {
860                    } else if (strncmp(buff, "Opacity:",8)==0) {
861                        float opacity=osg::asciiToFloat(buff+8);
862                        matpalet[nmat].setopacity(opacity);
863                    } else if (strncmp(buff, "FallOff:",8)==0) {
864                        float fo=osg::asciiToFloat(buff+8);
865                        matpalet[nmat].setFallOff(fo);
866                    } else if (strncmp(buff, "InnerHalfAngle:",15)==0) {
867                        float ha=osg::asciiToFloat(buff+15);
868                        matpalet[nmat].setHalfAngleIn(ha);
869                    } else if (strncmp(buff, "OuterHalfAngle:",15)==0) {
870                        float ha=osg::asciiToFloat(buff+15);
871                        matpalet[nmat].setHalfAngleOut(ha);
872                    } else if (strncmp(buff, "Brightness:",11)==0) {
873                        float br=osg::asciiToFloat(buff+11);
874                        matpalet[nmat].setBright(br);
875                    } else if (strncmp(buff, "Attentuation:",13)==0) { // oops - they can't spell
876                        matpalet[nmat].setAtten(buff+13);
877                    } else if (strncmp(buff, "MaterialType:",13)==0) {
878                        matpalet[nmat].setType(buff+14);
879                    } else if (strncmp(buff, "SpecularReflectivity:",21)==0) {
880                        float spec=osg::asciiToFloat(buff+21);
881                        matpalet[nmat].setspecular(spec);
882                    } else if (strncmp(buff, "SmoothnessExponent:",19)==0) {
883                        float spec=osg::asciiToFloat(buff+19);
884                        matpalet[nmat].setspecexp(spec*128.0f/100.0f); // convert to 0-128 range from percent
885                    } else if (strncmp(buff, "TextureWidthAndHeight:",22)==0) {
886                        char *ct=strchr(buff+22,',');
887                        float repx=osg::asciiToFloat(buff+23), repy=osg::asciiToFloat(ct+1);
888                        matpalet[nmat].settxrep(repx, repy);
889                    } else if (strncmp(buff, "PictureFile:",12)==0) {
890                        char *end=strchr(buff,'\n'); // end of line
891                        if (end) *end='\0'; // removed
892                        matpalet[nmat].setfname(buff);
893                    } else if( strncmp(buff,"Extrusion:",10)==0 ||
894                        strncmp(buff,"Cube:",5)==0 ||
895                        strncmp(buff,"Polyline:",9)==0 ||
896                        strncmp(buff,"Polyhedron:",11)==0) {
897                        rdg=OBJECT;
898                        obj.buildDrawable(grp, options);
899                        obj.reset();
900                    } else if( strncmp(buff,"Mat:",4)==0) {
901                        int mt=atoi(buff+4);
902                        for (int j=0; j<nmn; j++) {
903                            if (matpalet[j].getid() == mt)
904                                obj.setmat(&(matpalet[j]));
905                        }
906                    } else if( strncmp(buff,"Color:",6)==0) {
907                        float rgb[3];
908                        if (rdg==MATERIAL) { // get material colour
909                            sscanf(buff+6,"%f %f %f", &rgb[0], &rgb[1], &rgb[2]);
910                            matpalet[nmat].setcolour(rgb);
911                        } else if (rdg==OBJECT) {
912                            float rgb[3];
913                            sscanf(buff+6,"%f %f %f", &rgb[0], &rgb[1], &rgb[2]);
914                            rgb[0]/=65536.0f; // convert to range 0-1
915                            rgb[1]/=65536.0f; // convert to range 0-1
916                            rgb[2]/=65536.0f; // convert to range 0-1
917                            obj.setcolour(rgb);
918                        }
919                    } else if( strncmp(buff,"numVerts:",9)==0) {
920                        nexpected=atoi(buff+9);
921                        obj.readVerts(fp, nexpected);
922                        nexpected=0;
923                    } else if( strncmp(buff,"numFaces:",9)==0) {
924                        nexpected=atoi(buff+9);
925                        obj.readFaces(fp, nexpected);
926                        nexpected=0;
927                    } else if( strncmp(buff,"numEdges:",9)==0) {
928                        nexpected=atoi(buff+9);
929                        obj.readEdges(fp, nexpected);
930                        //nrecs=0; // a numVerts is followed by nv vetex postiions
931                    } else if( strncmp(buff,"numOpenings:",12)==0) {
932                        nexpected=atoi(buff+12);
933                        //nrecs=0; // a numVerts is followed by nv vetex postiions
934                        if (nexpected>0) obj.readOpenings(fp, nexpected);
935                    } else if( strncmp(buff,"UVW:",4)==0) { // texture application matrix
936                        double mx[3][3];
937                        sscanf(buff+4,"%lf %lf %lf %lf %lf %lf %lf %lf %lf",
938                            &mx[0][0], &mx[0][1], &mx[0][2],
939                            &mx[1][0], &mx[1][1], &mx[1][2],
940                            &mx[2][0], &mx[2][1], &mx[2][2]);
941                       
942                        obj.settmat(Matrix(mx[0][0],mx[0][1],mx[0][2],0.0,
943                                           mx[1][0],mx[1][1],mx[1][2],0.0,
944                                           mx[2][0],mx[2][1],mx[2][2],0.0,
945                                           0.0     ,0.0     ,0.0     ,1.0));
946                    }
947                }
948
949            }
950            fclose( fp );
951            obj.buildDrawable(grp, options); // tidy up any remaining objects
952
953            return grp;
954
955        }
956private:
957};
958
959int dwfgets(char *clin, int max, FILE *fin)
960{ // replace fgets to detect EOL = char 13 as well as Creturn=10 GWM 111100
961    // Macintosh produced files (such as those obtainable
962    //from the great buildings site at www.Artifice.com) use 13 format, PC models use 10.
963    int nread=0;
964    char c1=1;
965    do {
966        if (!feof( fin )) {
967            clin[nread]=c1=fgetc(fin);
968            nread++;
969        }
970    } while (nread<max && c1!= 13 && c1!= 10 &&  feof( fin )== 0 );
971    if (nread>0) clin[nread-1]='\0'; // null terminate and remove training blank
972    return nread;
973}
974
975// now register with osg::Registry to instantiate the above
976// reader/writer.
977REGISTER_OSGPLUGIN(dw, ReaderWriterDW)
Note: See TracBrowser for help on using the browser.