root/OpenSceneGraph/trunk/src/osgPlugins/geo/ReaderWriterGEO.cpp @ 13041

Revision 13041, 102.6 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// GEO format (carbon graphics Inc) loader for the OSG real time scene graph
2// www.carbongraphics.com for more information about the Geo animation+ modeller
3// supports geometry and group & face level animations.
4// Vertex level animation partly supported - defines movement (translate, rotate, colour)!
5// Loader has been divided into two parts
6// 1- general geometry (here) &
7// 2- animation (see geoActions.cpp).
8// ver 1.2 GWM Nov 2003
9
10#include <string>
11
12#include <osg/Image>
13#include <osg/Group>
14#include <osg/LOD>
15#include <osg/Billboard>
16#include <osg/Sequence>
17#include <osg/Switch>
18#include <osg/Geode>
19#include <osg/Depth>
20#include <osg/LineWidth>
21#include <osg/Geometry>
22#include <osg/MatrixTransform>
23#include <osg/Material>
24#include <osg/Notify>
25#include <osg/Texture2D>
26#include <osg/TexEnv>
27#include <osg/StateSet>
28#include <osg/CullFace>
29#include <osg/Point>
30#include "ClipRegion.h"
31
32#include <osgSim/LightPointNode>
33
34#include <osgDB/FileNameUtils>
35#include <osgDB/FileUtils>
36#include <osgDB/fstream>
37#include <osgDB/Registry>
38#include <osgDB/ReadFile>
39#include <osgDB/WriteFile>
40#include <osgDB/Input>
41#include <osgDB/Output>
42#include <osgUtil/Tessellator>
43
44#include <stdio.h>
45
46// specific to GEO
47
48#include "geoFormat.h"
49#include "geoTypes.h"
50#include "geoUnits.h"
51#include "osgGeoAnimation.h"
52#include "osgGeoStructs.h"
53#include "osgGeoNodes.h"
54#include "osgGeoAction.h"
55#include <osgText/Text> // needed for text nodes
56
57
58//
59geoHeaderGeo::geoHeaderGeo()
60{ // animations for the header - actually updates all control variables
61    intVars=new internalVars;
62    useVars=new userVars;
63    extVars=new userVars;
64    color_palette=new colourPalette;
65    _initialTick = _timer.tick();
66}
67
68geoHeaderGeo::geoHeaderGeo(const geoHeaderGeo &geo,const osg::CopyOp& copyop) :
69        geoHeader(geo,copyop)
70{
71    intVars=new internalVars(*geo.intVars);
72    useVars=new userVars(*geo.useVars);
73    extVars=new userVars(*geo.extVars);
74    color_palette=new colourPalette;
75    _initialTick = _timer.tick();
76}
77
78geoHeaderGeo::~geoHeaderGeo()
79{
80    delete intVars;
81    delete useVars;
82    delete extVars;
83
84    if (color_palette)
85    {
86        color_palette->clear();
87        delete color_palette;
88    }
89}
90
91
92const geoValue *geoHeaderGeo::getGeoVar(const unsigned fid) const {
93    const geoValue *st=intVars->getGeoVar(fid);
94    if (!st) {
95        st=useVars->getGeoVar(fid);
96        if (!st) {
97            st=extVars->getGeoVar(fid);
98        }
99    }
100    return st;
101}
102double *geoHeaderGeo::getVar(const unsigned fid) const {
103    double *dv=NULL;
104    dv=intVars->getVar(fid);
105    if (!dv) {
106        dv=useVars->getVar(fid);
107        if (!dv) {
108            dv=extVars->getVar(fid);
109        }
110    }
111    return dv;
112}
113void geoHeaderGeo::addUserVar(const georecord &gr)
114{ // this georecord defines a single variable of type<>
115    useVars->addUserVar(gr);
116}
117//== handler for updating internal variables
118void geoHeaderGeo::update(const osg::FrameStamp *_frameStamp)
119{ // update the scene
120    osg::Timer_t _frameTick = _timer.tick();
121    _lastFrameTick=_frameTick;
122
123    double time = _frameStamp->getSimulationTime();
124    intVars->update( _frameStamp);
125    moveit(time);
126}
127void geoHeaderGeo::moveit(const double t)
128{ // all the local and external variables declared in the geo modeller are here available.
129    if (uvarupdate) {
130        std::vector<geoValue> *lvals=useVars->getvars();
131        for (std::vector<geoValue>::iterator itr=lvals->begin();
132        itr!=lvals->end();
133        ++itr) {// for each user var
134            double vv=uvarupdate(t, itr->getVal(), itr->getName());
135            //        std::cout << " updatee " << itr->getName() << " " << vv << " " << itr->getVar() << std::endl;
136            itr->setVal(vv);
137            //        vv=itr->getVal(); std::cout << " result " << itr->getName() << " " << vv << std::endl;
138        }
139    }
140    if (extvarupdate) {
141        std::vector<geoValue> *lvals=extVars->getvars();
142        for (std::vector<geoValue>::iterator itr=lvals->begin();
143        itr!=lvals->end();
144        ++itr) {// for each user var
145            itr->setVal(extvarupdate(t, itr->getVal(), itr->getName()));
146        }
147    }
148}
149
150class geoHeaderCB: public osg::NodeCallback {
151public:
152    geoHeaderCB() {}
153    ~geoHeaderCB() {}
154    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
155    { // update action vars
156        geoHeaderGeo *gh=(geoHeaderGeo *)node;
157        gh->update(nv->getFrameStamp());
158        nv->setNodeMaskOverride(0xffffffff); // need to make the visitor override the nodemask
159            //    so that it visits 'invisible' nodes to update visibility. Or could use
160            // a visitor with setTraversalMode(TraversalMode==TRAVERSE_ALL_CHILDREN)?
161        traverse(node,nv);
162        //    std::cout<<"update callback - post traverse"<< (float)_frameStamp->getSimulationTime() <<std::endl;
163    }
164private:
165};
166
167
168//=============
169
170class vertexInfo { // holds vertex information for an entire osg::geometry
171public:
172    vertexInfo() {
173        norms=new osg::Vec3Array;
174        coords=new osg::Vec3Array;
175        txcoords=new osg::Vec2Array;
176        colorindices=new osg::IntArray;
177        coordindices=new osg::IntArray;
178        normindices=new osg::IntArray;
179        txindices=new osg::IntArray;
180        colors=new osg::Vec4Array;
181        cpool=NULL; npool=NULL;
182        polycols= new osg::Vec4Array; // polygon colours
183    }
184    typedef std::vector<geoActionBehaviour *> drBehList;
185    void setPools(const std::vector<osg::Vec3> *coord_pool, const std::vector<osg::Vec3> *normal_pool) {
186        cpool=coord_pool; npool=normal_pool;
187    }
188    inline bool hasVertexActions(void) const { return !(BehList.empty()); }
189    inline osg::Vec4Array *getColors() const { return colors.get();}
190    inline osg::Vec3Array *getNorms() const { return norms.get();}
191    inline osg::Vec3Array *getCoords() const { return coords.get();}
192    inline osg::Vec2Array *getTexCoords() const { return txcoords.get();}
193    inline osg::IntArray *getColorIndices() const { return colorindices.get();}
194    inline osg::IntArray *getCoordIndices() const { return coordindices.get();}
195    inline osg::IntArray *getNormIndices() const { return normindices.get();}
196    inline osg::IntArray *getTextureIndices() const { return txindices.get();}
197    void addPolcolour( osg::Vec4 cl) { polycols->push_back(cl);}
198    osg::Vec4Array *getPolcolours() const { return polycols.get();}
199    void addVertexActions(geoBehaviourDrawableCB *gcb) const { // add the actions to callback
200        if ( !(BehList.empty()) ) {
201            for (drBehList::const_iterator rcitr=BehList.begin();
202            rcitr!=BehList.end();
203            ++rcitr)
204            {
205                gcb->addBehaviour(*rcitr);
206            }
207        }
208    }
209    bool addFlat( const georecord *gface)
210    { // this must only be called with a vertex georecord.
211        bool isflat=false;
212        const geoField *gfshade=gface->getField(GEO_DB_POLY_SHADEMODEL); // shaded gouraud, flat...
213        int shademodel=gfshade ? gfshade->getInt() : -1;
214        if (shademodel==GEO_POLY_SHADEMODEL_LIT) { // flat shaded - need the index
215            const geoField *gfd=gface->getField(GEO_DB_POLY_NORMAL);
216            if (gfd) {
217                float *normal= (gfd) ? (gfd->getVec3Arr()):NULL;
218                osg::Vec3 nrm(normal[0], normal[1], normal[2]);
219                norms->push_back(nrm);
220                isflat=true;
221            }
222        }
223        return isflat;
224    }
225    bool addIndices(georecord *gr,    const geoHeaderGeo *ghdr, const float cdef[4], const georecord *gface)
226    { // this must only be called with a vertex georecord.
227        // gr is tha vertex; gface is the face containing the vertex
228        bool hbeh=false; // true if this vertex has a behaviour
229        if (gr->getType()==DB_DSK_VERTEX ||
230            gr->getType()==DB_DSK_FAT_VERTEX ||
231            gr->getType()==DB_DSK_SLIM_VERTEX) {
232            const geoField *gfshade=gface->getField(GEO_DB_POLY_SHADEMODEL); // shaded gouraud, flat...
233            int shademodel=gfshade ? gfshade->getInt() : -1;
234            if (shademodel!=GEO_POLY_SHADEMODEL_LIT && shademodel!=GEO_POLY_SHADEMODEL_FLAT) {
235                const geoField *gfd=gr->getField(GEO_DB_VRTX_NORMAL);
236                if (gfd)
237                {
238                    if (gfd->getType()==DB_UINT)
239                    {
240                        unsigned int idx=gfd->getUInt();
241                        normindices->push_back(idx);
242                        norms->push_back((*npool)[idx]);
243                    }
244                    else if (gfd->getType()==DB_VEC3F)
245                    {
246                        float *p=gfd->getVec3Arr();
247                        osg::Vec3 nrm;
248                        nrm.set(p[0],p[1],p[2]);
249                        norms->push_back(nrm);
250                    }
251                    else
252                    {
253                        OSG_WARN << "No valid vertex index" << std::endl;
254                    }
255                }
256            }
257            osg::Vec3 pos;
258            const geoField *gfd=gr->getField(GEO_DB_VRTX_COORD);
259            if (gfd)
260            {
261                if (gfd->getType()==DB_INT)
262                {
263                    int idx=gfd->getInt();
264                    pos=(*cpool)[idx];
265                    coords->push_back((*cpool)[idx]); //osg::Vec3(cpool[3*idx],cpool[3*idx+1],cpool[3*idx+2]));
266                    coordindices->push_back(coords->size());
267                }
268                else if (gfd->getType()==DB_VEC3F)
269                {
270                    float *p=gfd->getVec3Arr();
271                    pos.set(p[0],p[1],p[2]);
272                    coords->push_back(pos); //osg::Vec3(cpool[3*idx],cpool[3*idx+1],cpool[3*idx+2]));
273                }
274                else
275                {
276                    OSG_WARN << "No valid vertex index" << std::endl;
277                }
278            }
279
280            std::vector< georecord *>bhv=gr->getBehaviour(); // behaviours for vertices, eg tranlate, colour!
281            if (!bhv.empty()) {
282                int ncoord=coords->size();
283                for (std::vector< georecord *>::const_iterator rcitr=bhv.begin();
284                rcitr!=bhv.end();
285                ++rcitr)
286                {
287                    if ((*rcitr)->getType()==DB_DSK_TRANSLATE_ACTION) {
288                        geoMoveVertexBehaviour *mb=new geoMoveVertexBehaviour;
289                        mb->makeBehave((*rcitr),ghdr);
290                        mb->setpos(pos);
291                        mb->setindx(ncoord-1);
292                        BehList.push_back(mb);
293                    }
294                    if ((*rcitr)->getType()==DB_DSK_ROTATE_ACTION) {
295                        geoMoveVertexBehaviour *mb=new geoMoveVertexBehaviour;
296                        mb->makeBehave((*rcitr),ghdr);
297                        mb->setpos(pos);
298                        mb->setindx(ncoord-1);
299                        BehList.push_back(mb);
300                    }
301                    if ((*rcitr)->getType()==DB_DSK_COLOR_RAMP_ACTION) {
302                        const geoField *gfd=gface->getField(GEO_DB_POLY_USE_MATERIAL_DIFFUSE); // true: use material...
303                        bool usemat= gfd ? gfd->getBool() : false;
304                        if (!usemat) { // modify the per vertex colours
305                            gfd=gface->getField(GEO_DB_POLY_SHADEMODEL); // shaded gouraud, flat...
306                            int shademodel=gfd ? gfd->getInt() : GEO_POLY_SHADEMODEL_LIT_GOURAUD;
307                            gfd=gface->getField(GEO_DB_POLY_USE_VERTEX_COLORS); // true: use material...
308                            bool usevert=gfd ? gfd->getBool() : false;
309                            if (usevert || shademodel==GEO_POLY_SHADEMODEL_GOURAUD) { // then the vertex colours are used
310                                geoColourBehaviour *cb=new geoColourBehaviour;
311                                cb->setColorPalette(ghdr->getColorPalette());
312                                cb->setVertIndices(ncoord-1,1); // part of colours array to be modified
313                                bool ok=cb->makeBehave((*rcitr), ghdr);
314                                if (ok) BehList.push_back(cb);
315                            } // if the model does not use vertex colours... there can be no colour animation at vertex level
316                        }
317                    }
318                }
319                hbeh=true;
320            }
321            txindices->push_back(txcoords->size());
322            float *uvc=NULL;
323            gfd=gr->getField(GEO_DB_VRTX_UV_SET_0);
324            if (gfd) {
325                uvc=(float *)gfd->getstore(0);
326
327                if (uvc) { // then there are tx coords
328                    osg::Vec2 uv(uvc[0], uvc[1]);
329                    txcoords->push_back(uv);
330                } else {
331                    txcoords->push_back(osg::Vec2(0,0));
332                }
333            } else {
334                    txcoords->push_back(osg::Vec2(0,0));
335            }
336            gfd=gr->getField(GEO_DB_VRTX_PACKED_COLOR);
337            if (gfd) {
338                unsigned char *cp=gfd->getUCh4Arr();
339                float red=cp[0]/255.0f;
340                float green=cp[1]/255.0f;
341                float blue=cp[2]/255.0f;
342                // may need alpha in future:: float alpha=cp[3]/255.0f;
343                colors->push_back(Vec4(red,green,blue,1.0));
344            } else { // look for a colour index (exclusive!)
345                gfd=gr->getField(GEO_DB_VRTX_COLOR_INDEX);
346                if (gfd) {
347                    uint icp=gfd->getInt();
348                    if (icp<128*(ghdr->getColorPalette())->size()) {
349                        float col[4];
350                        ghdr->getPalette(icp,col);
351                        colors->push_back(Vec4(col[0],col[1],col[2],1.0));
352                    } else {
353                        colors->push_back(Vec4(cdef[0],cdef[1],cdef[2],cdef[3]));
354                    }
355                } else {
356                    colors->push_back(Vec4(cdef[0],cdef[1],cdef[2],cdef[3]));
357                }
358                int idx=colors->size()-1;
359                colorindices->push_back(idx);
360            }
361        }
362        return hbeh;
363    }
364    friend inline std::ostream& operator << (std::ostream& output, const vertexInfo& vf)
365    {
366        const osg::Vec2Array *txa=vf.getTexCoords();
367        osg::IntArray *normindices=vf.getNormIndices();
368        osg::IntArray *txind = vf.getTextureIndices();
369        output << " vertexinfo " << txa->size() << " nrm: " << normindices->size()<<
370            " txinds " << txind->size()<<std::endl;
371        uint i;
372        for (i=0; i< txa->size(); i++) {
373            const osg::Vec2 uvt=(*txa)[i];
374            output << " U " << uvt.x() << " v " <<  uvt.y() << std::endl;
375        }
376        for (i=0; i<normindices->size(); i++) {
377            output << "Nind " << i << " = " <<  (*normindices)[i] << std::endl;
378        }
379        return output;     // to enable cascading, monkey copy from osg\plane or \quat, Ubyte4, vec2,3,4,...
380    }
381private:
382    const std::vector<osg::Vec3> *cpool; // passed in from the geo file
383    const std::vector<osg::Vec3> *npool;
384    osg::ref_ptr<osg::Vec3Array> norms;
385    osg::ref_ptr<osg::Vec3Array> coords;
386    osg::ref_ptr<osg::Vec2Array> txcoords;
387    osg::ref_ptr<osg::Vec4Array> colors;
388    osg::ref_ptr<osg::IntArray> colorindices;
389    osg::ref_ptr<osg::IntArray> coordindices;
390    osg::ref_ptr<osg::IntArray> normindices;
391    osg::ref_ptr<osg::IntArray> txindices;
392    drBehList BehList;
393    osg::ref_ptr<Vec4Array> polycols;
394};
395
396class geoInfo { // identifies properties required to make a new Geometry, and holds collection of vertices, indices, etc
397public:
398    geoInfo(const int txidx=-2, const int sm=1, const int bs=1) { texture=txidx; // will be -1 or 0-number of textures
399        geom=NULL; nstart=0; linewidth=1;
400        bothsides=bs; shademodel=sm;
401    }
402    virtual ~geoInfo() { };
403    inline int getShademodel(void) const { return shademodel;}
404    inline int getBothsides(void) const { return bothsides;}
405    inline int getTexture(void) const { return texture;}
406    inline vertexInfo *getVinf(void) { return &vinf;}
407    void setPools(const std::vector<osg::Vec3> *coord_pool, const std::vector<osg::Vec3> *normal_pool) {
408        vinf.setPools(coord_pool,normal_pool);
409    }
410    float getlinewidth(void) const { return linewidth;}
411    void setlineWidth(const int w) { linewidth=w;}
412    void setGeom(osg::Geometry *nugeom) { geom=nugeom;}
413    osg::Geometry *getGeom() { return geom.get();}
414    uint getStart(uint nv) { uint ns=nstart; nstart+=nv; return ns; }
415    bool operator == (const geoInfo *gt) { // compare two geoInfos for same type of geometry
416        if (gt->texture!=texture) return false;
417        if (gt->bothsides == !bothsides) return false;
418        if (gt->shademodel!=shademodel) return false;
419        // other tests if failed return false
420        return true;
421    }
422private:
423    int texture; // texture index
424    int bothsides; // none, back,front
425    int shademodel;
426    int linewidth;
427    vertexInfo vinf;
428    uint nstart; // start vertex for a primitive
429    osg::ref_ptr<osg::Geometry> geom; // the geometry created for this vinf and texture
430};
431
432
433class ReaderGEO
434{
435    public:
436
437        osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options)
438        {
439
440            osgDB::ifstream fin(fileName.c_str(), std::ios::binary | std::ios::in );
441            if (fin.is_open() )
442            { // read the input file.
443                // code for setting up the database path so that internally referenced file are searched for on relative paths.
444                osg::ref_ptr<osgDB::ReaderWriter::Options> local_opt = options ?
445                    static_cast<osgDB::ReaderWriter::Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) :
446                    new osgDB::ReaderWriter::Options;
447                local_opt->setDatabasePath(osgDB::getFilePath(fileName));
448
449                typedef std::vector<osg::Node*> NodeList;
450                NodeList nodeList;
451                osg::Material *mt=new osg::Material;
452                matlist.push_back(mt);
453                theHeader=NULL;
454
455                // load all nodes in file, placing them in a linear list corresponding to the on disk file.
456                while(!fin.eof())
457                {
458                    georecord gr;
459                    gr.readfile(fin);
460//            OSG_WARN << "end of record " << (int)gr.getType() << std::endl;
461                    if (gr.getType() == DB_DSK_NORMAL_POOL) {
462                        geoField *gfff=gr.getModField(GEO_DB_NORMAL_POOL_VALUES);
463                        gfff->uncompress();// uncompress the normals
464                    }
465                    recs.push_back(gr); // add to a list of all records
466                }
467                fin.close();
468                // now sort the records so that any record followed by a PUSh has a child set = next record, etc
469                std::vector<georecord *> sorted=sort(recs); // tree-list of sorted record pointers
470#ifdef _DEBUG
471                osgDB::Output fout("georex.txt"); //, std::ios_base::out );
472              //  fout << "Debug raw file " << fileName << std::endl;
473              //  output(fout,recs);
474                fout << "Debug Sorted file " << fileName << std::endl;
475                output(fout,sorted);
476                fout.close();
477#endif /**/
478                makeHeader(*(sorted.begin()), local_opt.get());
479
480                nodeList=makeosg(sorted, local_opt.get()); // make a list of osg nodes
481                geotxlist.clear();
482                geomatlist.clear();
483                txlist.clear();
484                txenvlist.clear();
485                matlist.clear();/* */
486                coord_pool.clear();
487                normal_pool.clear();
488                osg::Node * groupnode = NULL;
489                if  (nodeList.empty())
490                {
491                    return osgDB::ReaderWriter::ReadResult("No data loaded from "+fileName);
492                }
493                else if (nodeList.size()==1)
494                {
495                    groupnode = nodeList.front();
496                }
497                else
498                {
499                    osg::Group *group = new Group;
500                    group->setName("import group");
501                    for(NodeList::iterator itr=nodeList.begin();
502                        itr!=nodeList.end();
503                        ++itr)
504                    {
505                        group->addChild(*itr);
506                    }
507                    groupnode=group;
508                }
509                (theHeader.get())->addChild(groupnode);
510                groupnode=theHeader.get();
511#ifdef _DEBUG // output a .osg version
512                osgDB::writeNodeFile(*groupnode,"geoosg.osg");
513#endif /**/
514                recs.clear();
515                return groupnode;
516            }
517            return 0L;
518        }
519        std::vector<georecord *> sort(geoRecordList &recs) { // return a tree-list of sorted record pointers
520            // which mirrors the original .geo file (containers hold push/pop blocks).
521            std::vector<georecord *> sorted;
522            class georecord *curparent=NULL;
523            for (geoRecordList::iterator itr=recs.begin();
524            itr!=recs.end();
525            ++itr) {
526                const geoField *gfd;
527                // OSG_WARN << *itr << std::endl;
528                // now parse for push/pops and add to lists
529
530                switch ((*itr).getType()) {
531                case 101: // old header - not appropriate!
532                    curparent= &(*itr);
533                    sorted.push_back(&(*itr));
534                    OSG_WARN << "Old version 2 header block found - possible error!" << std::endl;
535                    break;
536                case DB_DSK_PUSH:
537                    if (!(curparent->getchildren().empty())) {
538                        curparent= curparent->getLastChild(); // itr-1;
539                    } else {
540                        //curparent=itr-1;
541                    }
542                    break;
543                case DB_DSK_POP:
544                    if (curparent) curparent=curparent->getparent();
545                    break;
546                case DB_DSK_HEADER: // attach to previous
547                    curparent= &(*itr);
548                    sorted.push_back(&(*itr));
549                    cpalrec=NULL;
550                    break;
551                case DB_DSK_INTERNAL_VARS: // attach to parent
552                case DB_DSK_LOCAL_VARS:
553                case DB_DSK_EXTERNAL_VARS:
554                    (curparent)->addBehaviourRecord(&(*itr));
555                    break;
556                case DB_DSK_FLOAT_VAR: // attach to parent
557                case DB_DSK_INT_VAR:
558                case DB_DSK_LONG_VAR:
559                case DB_DSK_DOUBLE_VAR:
560                case DB_DSK_BOOL_VAR:
561                case DB_DSK_FLOAT2_VAR:
562                case DB_DSK_FLOAT3_VAR:
563                case DB_DSK_FLOAT4_VAR:
564                    // else if ((*itr).isVar():
565                    (curparent)->addBehaviourRecord(&(*itr));
566                        break;
567                case DB_DSK_TEXTURE: // attach to parent
568                    geotxlist.push_back(&(*itr));
569                    break;
570                case DB_DSK_MATERIAL: // attach to parent
571                    geomatlist.push_back(&(*itr));
572                    break;
573                case DB_DSK_VIEW: // not needed for Real Time
574                    break;
575                case DB_DSK_COORD_POOL: // global - attach to readerwriterGEO class for whole model
576                    gfd=itr->getField(GEO_DB_COORD_POOL_VALUES);
577                    {
578                        float *crds= (gfd) ? (gfd->getVec3Arr()):NULL;
579                        uint nm=gfd->getNum();
580                        for (uint i=0; i<nm; i++) {
581                            coord_pool.push_back(Vec3(crds[i*3],crds[i*3+1],crds[i*3+2]));
582                        }
583                    }
584                    break;
585                case DB_DSK_NORMAL_POOL: // global - attach to readerwriterGEO
586                    gfd=itr->getField(GEO_DB_NORMAL_POOL_VALUES);
587                    {
588                        float *nrms= (gfd) ? (gfd->getVec3Arr()):NULL;
589                        uint nm=gfd->getNum();
590                        for (uint i=0; i<nm; i++) {
591                            normal_pool.push_back(Vec3(nrms[i*3],nrms[i*3+1],nrms[i*3+2]));
592                        }
593                    }
594                    break;
595                case DB_DSK_COLOR_PALETTE: // global - attach to readerwriterGEO
596                    cpalrec=&(*itr);
597                    break;
598                case DB_DSK_BEHAVIOR: // || (*itr).isAction() // attach to previous
599                case DB_DSK_CLAMP_ACTION:
600                case DB_DSK_RANGE_ACTION:
601                case DB_DSK_ROTATE_ACTION:
602                case DB_DSK_TRANSLATE_ACTION:
603                case DB_DSK_SCALE_ACTION:
604                case DB_DSK_ARITHMETIC_ACTION:
605                case DB_DSK_LOGIC_ACTION:
606                case DB_DSK_CONDITIONAL_ACTION:
607                case DB_DSK_LOOPING_ACTION:
608                case DB_DSK_COMPARE_ACTION:
609                case DB_DSK_VISIBILITY_ACTION:
610                case DB_DSK_STRING_CONTENT_ACTION:
611                case DB_DSK_COLOR_RAMP_ACTION:
612                case DB_DSK_LINEAR_ACTION:
613                case DB_DSK_TASK_ACTION:
614                case DB_DSK_PERIODIC_ACTION:
615#ifdef DB_DSK_PERIODIC2_ACTION
616                case DB_DSK_PERIODIC2_ACTION:
617#endif
618                case DB_DSK_TRIG_ACTION:
619                case DB_DSK_DISCRETE_ACTION:
620                case DB_DSK_INVERSE_ACTION:
621                case DB_DSK_TRUNCATE_ACTION:
622                case DB_DSK_ABS_ACTION:
623                case DB_DSK_IF_THEN_ELSE_ACTION:
624                case DB_DSK_DCS_ACTION:
625                case DB_DSK_SQRT_ACTION:    // an action
626                    if (curparent->getType()==DB_DSK_HEADER)
627                        curparent->addBehaviourRecord(&(*itr));
628                    else {
629                        class georecord *cp=curparent->getLastChild();
630                        if (cp) cp->addBehaviourRecord(&(*itr));
631                    }
632                    break;
633                case DB_DSK_PERSPECTIVE_GRID_INFO: // Feb 2003 not sure what this is yet!
634                    (curparent)->addchild(&(*itr));
635                    break;
636                case DB_DSK_PLANE_TEXTURE_MAPPING_INFO: // not needed for real time
637                case DB_DSK_CYLINDER_TEXTURE_MAPPING_INFO:    // not implemented in 1.0
638                case DB_DSK_SPHERE_TEXTURE_MAPPING_INFO:    // not implemented in 1.0
639                case DB_DSK_GRID_TEXTURE_MAPPING_INFO:    // not implemented in 1.0
640                    (curparent->getLastChild())->addMappingRecord(&(*itr));
641                    break;
642                default:
643                    if (curparent) {
644                        (*itr).setparent(curparent);
645                        curparent->addchild(&(*itr));
646                    }
647                    break;
648                }
649            }
650            return sorted;
651        }
652        void outputPrim(const georecord *grec, osgDB::Output &fout) { // output to file for debug
653            const std::vector<georecord *> gr=grec->getchildren();
654            if (gr.size()>0) {
655                for (std::vector<georecord *>::const_iterator itr=gr.begin();
656                    itr!=gr.end();
657                    ++itr) {
658                    fout << *(*itr) << std::endl;
659                }
660            }
661        }
662 /*       bool allOneSided(const georecord *grec)    {
663            bool one=false;
664            const std::vector<georecord *> gr=grec->getchildren();
665            if (gr.size()>0) {
666                for (std::vector<georecord *>::const_iterator itr=gr.begin();
667                itr!=gr.end() && !one;
668                ++itr) {
669                    if ((*itr)->getType()==DB_DSK_POLYGON) {
670                        const geoField *gfd=(*itr)->getField(GEO_DB_POLY_DSTYLE);
671                        if (gfd) {
672                            int dstyle=gfd->getInt();
673                            one=(dstyle==GEO_POLY_DSTYLE_SOLID_BOTH_SIDES);
674                        }
675                    }
676                }
677            }
678            return one;
679        }*/
680        osg::Geometry *makeNewGeometry(const georecord *grec, geoInfo &ginf, int imat) {
681            const int shademodel=ginf.getShademodel();
682            const int bothsides=ginf.getBothsides();
683            osg::Geometry *nug;
684            int txidx=ginf.getTexture();
685            nug=new osg::Geometry;
686            const vertexInfo *vinf=ginf.getVinf();
687            nug->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
688            nug->setVertexArray(vinf->getCoords());
689            StateSet *dstate=new StateSet;
690            if (bothsides==0) {
691                osg::CullFace *cf = new osg::CullFace; // to define non-default culling
692                cf->setMode(osg::CullFace::BACK);
693                dstate->setAttributeAndModes(cf,osg::StateAttribute::ON);
694            }
695            else if (bothsides==1) {
696                osg::CullFace *cf = new osg::CullFace; // to define non-default culling
697                cf->setMode(osg::CullFace::FRONT);
698                dstate->setAttributeAndModes(cf,osg::StateAttribute::ON);
699            }
700            else if (bothsides==2) {
701                osg::CullFace *cf = new osg::CullFace; // to define non-default culling
702                dstate->setAttributeAndModes(cf,osg::StateAttribute::OFF);
703            }
704            Point *pt=new Point;
705            pt->setSize(4);
706            dstate->setAttribute(pt);
707            if (txidx>=0 && (unsigned int)txidx<txlist.size()) {
708                dstate->setTextureAttribute(0, txenvlist[txidx].get() );
709                dstate->setTextureAttributeAndModes(0,txlist[txidx].get(),osg::StateAttribute::ON);
710                const Image *txim=txlist[txidx]->getImage();
711                if (txim) {
712                    GLint icm=txim->computeNumComponents(txim->getPixelFormat());
713                    if (icm ==2 || icm==4) { // an alpha texture
714                        dstate->setMode(GL_BLEND,StateAttribute::ON);
715                        dstate->setRenderingHint(StateSet::TRANSPARENT_BIN);
716                    }
717                }
718            }
719            if (imat<0 || imat>=(int)matlist.size()) imat=0;
720            const geoField *gfd=grec->getField(GEO_DB_POLY_USE_MATERIAL_DIFFUSE); // true: use material...
721            bool usemat= gfd ? gfd->getBool() : false;
722            if (!usemat) {
723                matlist[imat]->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
724                dstate->setMode(GL_COLOR_MATERIAL, osg::StateAttribute::ON);
725            }
726            dstate->setAttribute(matlist[imat].get());
727            Vec4 col=matlist[imat]->getAmbient(Material::FRONT);
728            if (col[3]<0.99) {
729                dstate->setMode(GL_BLEND,StateAttribute::ON);
730                dstate->setRenderingHint(StateSet::TRANSPARENT_BIN);
731            }
732
733            if (shademodel==GEO_POLY_SHADEMODEL_LIT ||
734                shademodel==GEO_POLY_SHADEMODEL_LIT_GOURAUD) dstate->setMode( GL_LIGHTING, osg::StateAttribute::ON );
735            else
736                dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
737            { // reclaim the colours
738                gfd=grec->getField(GEO_DB_POLY_USE_MATERIAL_DIFFUSE); // true: use material...
739                bool usemat= gfd ? gfd->getBool() : false;
740                if (!usemat) { // get the per vertex colours OR per face colours.
741                    gfd=grec->getField(GEO_DB_POLY_USE_VERTEX_COLORS); // true: use material...
742                    bool usevert=gfd ? gfd->getBool() : false;
743                    if (usevert || shademodel==GEO_POLY_SHADEMODEL_GOURAUD) {
744                        Vec4Array *cls=vinf->getColors();
745                        if (cls) {
746                            nug->setColorArray(cls);
747                            nug->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
748                        }
749                    } else {
750                        if (shademodel==GEO_POLY_SHADEMODEL_LIT_GOURAUD) {
751                            nug->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
752                        } else if (shademodel==GEO_POLY_SHADEMODEL_LIT) {
753                            nug->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
754                        }
755                        osg::Vec4Array *polycols=vinf->getPolcolours();
756                        nug->setColorArray(polycols);
757                        nug->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE);
758                    }
759                }
760            }
761            osg::LineWidth *lw=new osg::LineWidth;
762            lw->setWidth(ginf.getlinewidth());
763            dstate->setAttributeAndModes(lw,osg::StateAttribute::ON);
764            nug->setStateSet( dstate );
765            ginf.setGeom(nug);
766            return nug;
767        }
768        int getprim(const georecord *grec, geoInfo &gi)
769        { // fills vinf with txcoords = texture coordinates, txindex=txindex etc
770            // for one primitive (one tri, quad, pol, tristrip....
771            vertexInfo *vinf=gi.getVinf();
772            int nv=0;
773            const std::vector<georecord *> gr=grec->getchildren();
774            const geoField *gfd=grec->getField(GEO_DB_POLY_PACKED_COLOR); // the colour
775            float defcol[4]; // a default colour for vertices
776            defcol[0]=defcol[1]=defcol[2]=defcol[3]=1.0f;
777            if (gfd) {
778                unsigned char *cls=gfd->getUCh4Arr();
779                defcol[0]=cls[0]/255.0f;
780                defcol[1]=cls[1]/255.0f;
781                defcol[2]=cls[2]/255.0f;
782                defcol[3]=1.0f;
783            } else {
784                gfd=grec->getField(GEO_DB_POLY_COLOR_INDEX); // the colour
785                if (gfd) {
786                    int icp= gfd ? gfd->getInt() : 0;
787                    theHeader->getPalette(icp,defcol);
788                } else {
789                    defcol[0]=defcol[1]=defcol[2]=defcol[3]=1.0f;
790                }
791            }
792
793            if (gr.size()>0) {
794                vinf->addFlat(grec); // for flat normal shading
795                for (std::vector<georecord *>::const_iterator itr=gr.begin();
796                    itr!=gr.end();
797                    ++itr) {
798                    vinf->addIndices((*itr), theHeader.get(), defcol, grec);
799                    nv++;
800                }
801            }
802            return nv;
803        }
804        void outputGeode(const georecord& grec, osgDB::Output &fout) { //
805            const std::vector<georecord *> gr=grec.getchildren();
806            if (gr.size()>0) {
807                fout.moveIn();
808                for (std::vector<georecord *>::const_iterator itr=gr.begin();
809                itr!=gr.end();
810                ++itr) {
811                    fout.indent() << *(*itr) << std::endl;
812                    if ((*itr)->getType()==DB_DSK_POLYGON) {
813                        outputPrim((*itr),fout);
814                    }
815                }
816                 fout.moveOut();
817            }
818        }
819        osg::MatrixTransform *makeText(georecord *gr) { // make transform, geode & text
820            osg::MatrixTransform *numt=NULL;
821            std::string    ttfPath("fonts/times.ttf");
822            // unused
823            //int    gFontSize1=2;
824            osgText::Text *text= new  osgText::Text;
825            text->setFont(ttfPath);
826            const geoField *gfd=gr->getField(GEO_DB_NODE_NAME);
827            const char *name=gfd ? gfd->getChar() : "a text";
828            gfd=gr->getField(GEO_DB_TEXT_STRING);
829            const char *content=gfd ? gfd->getChar() : " ";
830            text->setText(std::string(content));
831            //gfd=gr->getField(GEO_DB_TEXT_SCALE_X);
832            //const float scx=gfd ? gfd->getFloat() : 1.0f;
833            //gfd=gr->getField(GEO_DB_TEXT_SCALE_Y);
834            //const float scy=gfd ? gfd->getFloat() : 1.0f;
835            gfd=gr->getField(GEO_DB_TEXT_JUSTIFICATION); // GEO_DB_TEXT_DIRECTION);
836            int tjus=gfd? gfd->getInt() : GEO_TEXT_LEFT_JUSTIFY;
837            switch(tjus) {
838                case GEO_TEXT_LEFT_JUSTIFY:  text->setAlignment(osgText::Text::LEFT_BOTTOM); break;
839                case GEO_TEXT_CENTER_JUSTIFY:  text->setAlignment(osgText::Text::CENTER_BOTTOM); break;
840                case GEO_TEXT_RIGHT_JUSTIFY:  text->setAlignment(osgText::Text::RIGHT_BOTTOM); break;
841            }
842            gfd=gr->getField(GEO_DB_TEXT_PACKED_COLOR);
843            if (gfd) {
844                unsigned char *cp=gfd->getUCh4Arr();
845                float red=(float)cp[0]/255.0f;
846                float green=(float)cp[1]/255.0f;
847                float blue=(float)cp[2]/255.0f;
848                text->setColor(osg::Vec4(red,green,blue,1.0f));
849            } else { // lok for a colour index (exclusive!)
850                gfd=gr->getField(GEO_DB_TEXT_COLOR_INDEX);
851                if (gfd) {
852                    int icp=gfd->getInt();
853                    float col[4];
854                    theHeader->getPalette(icp,col);
855                    text->setColor(osg::Vec4(col[0],col[1],col[2],1.0));
856                }
857            }
858            osg::Geode *geod=new osg::Geode;
859            osg::StateSet *textState = new osg::StateSet();
860            textState->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
861            geod->setStateSet( textState );
862            numt=new osg::MatrixTransform;
863            numt->setName(name);
864            gfd=gr->getField(GEO_DB_TEXT_MATRIX);
865            if (gfd) {
866                float *fmat=gfd->getMat44Arr();
867                // text->setPosition(osg::Vec3(fmat[12],fmat[13],fmat[14]));
868                numt->setMatrix(Matrix(fmat));
869            }
870            numt->addChild(geod);
871            geod->addDrawable(text);
872            {
873                std::vector< georecord *>bhv=gr->getBehaviour();
874                if (!bhv.empty()) { // then check for a string content/colour.. action
875                    bool ok=false;
876                    geoBehaviourDrawableCB *gcb=new geoBehaviourDrawableCB;
877                    text->setUpdateCallback(gcb);
878                    for (std::vector< georecord *>::const_iterator rcitr=bhv.begin();
879                    rcitr!=bhv.end();
880                    ++rcitr)
881                    {
882                        if ((*rcitr)->getType()==DB_DSK_STRING_CONTENT_ACTION) {
883                            geoStrContentBehaviour *cb=new geoStrContentBehaviour;
884                            gfd=(*rcitr)->getField(GEO_DB_STRING_CONTENT_ACTION_INPUT_VAR);
885                            if (gfd) {
886                                ok=cb->makeBehave((*rcitr), theHeader.get());
887                                if (ok) gcb->addBehaviour(cb);
888                                else delete cb;
889                                // ok=false;
890                            }
891                        }
892                    }
893                }
894            }
895            return numt;
896        }
897        void addPolyActions(std::vector< georecord *>bhv, geoInfo &gi , const uint nv) {
898            const vertexInfo *vinf=gi.getVinf();
899            const uint nstart=gi.getStart(nv);
900            if (hasColorAction(bhv) || vinf->hasVertexActions()) {
901                osg::Geometry *nugeom=gi.getGeom();
902                geoBehaviourDrawableCB *gcb=new geoBehaviourDrawableCB;
903                nugeom->setUpdateCallback(gcb);
904                nugeom->setUseDisplayList(false); // as we are updating arrays, cannot change colours
905                for (std::vector< georecord *>::const_iterator rcitr=bhv.begin();
906                rcitr!=bhv.end();
907                ++rcitr)
908                {
909                    if ((*rcitr)->getType()==DB_DSK_COLOR_RAMP_ACTION) {
910                        geoColourBehaviour *cb=new geoColourBehaviour;
911                        cb->setColorPalette(theHeader->getColorPalette());
912                        if (nugeom->getColorBinding()==osg::Geometry::BIND_PER_VERTEX) {
913                            cb->setVertIndices(nstart,nv); // part of colours array to be modified
914                        } else if (nugeom->getColorBinding()==osg::Geometry::BIND_PER_PRIMITIVE) { // per primitive
915                            const uint nst=nugeom->getNumPrimitiveSets();
916                            cb->setVertIndices(nst,1); // part of colours array to be modified
917                        } else { // overall
918                            cb->setVertIndices(0,1); // part of colours array to be modified
919                        }
920                        bool ok=cb->makeBehave((*rcitr), theHeader.get());
921                        if (ok) gcb->addBehaviour(cb);
922                        else delete cb;
923                    }
924                }
925                vinf->addVertexActions(gcb);
926            }
927        }
928        void makeLightPointNode(const georecord *grec, osgSim::LightPointNode *lpn) {
929          // light points.. require OSG professional license
930        // OR LGPL software.
931            const std::vector<georecord *> gr=grec->getchildren();
932            for (std::vector<georecord *>::const_iterator itr=gr.begin();
933                itr!=gr.end();
934                ++itr)
935            {
936                if ((*itr)->getType()==DB_DSK_VERTEX ||
937                    (*itr)->getType()==DB_DSK_FAT_VERTEX ||
938                    (*itr)->getType()==DB_DSK_SLIM_VERTEX)
939                { // light point vertices
940                    osg::Vec3 pos;
941                    const geoField *gfd=(*itr)->getField(GEO_DB_VRTX_COORD);
942                    if (gfd) {
943                        if (gfd->getType()==DB_INT)
944                        {
945                                int idx=gfd->getInt();
946                                pos=coord_pool[idx];
947                        }
948                        else if (gfd->getType()==DB_VEC3F)
949                        {
950                            float *p=gfd->getVec3Arr();
951                            pos.set(p[0],p[1],p[2]);
952                        }
953                        else {
954                            OSG_WARN << "No valid vertex index" << std::endl;
955                        }
956                    }
957
958                    gfd=(*itr)->getField(GEO_DB_VRTX_PACKED_COLOR);
959                    if (gfd) {
960                        unsigned char *cls=gfd->getUCh4Arr();
961                        float red=cls[0]/255.0f;
962                        float green=cls[1]/255.0f;
963                        float blue=cls[2]/255.0f;
964                        //float alpha=1.0f; // cls[3]*frac/255.0f;
965                        osg::Vec4 colour(red,green,blue,1.0f);
966                        lpn->addLightPoint(osgSim::LightPoint(true,pos,colour,1.0f,1.0f,0,0,osgSim::LightPoint::BLENDED));
967                    } else { // get colour from palette
968                        gfd=(*itr)->getField(GEO_DB_VRTX_COLOR_INDEX); // use color pool...
969                        int icp= gfd ? gfd->getInt() : 0;
970                        float col[4];
971                        theHeader->getPalette(icp, col);
972                        lpn->addLightPoint(osgSim::LightPoint(pos, osg::Vec4(col[0],col[1],col[2],1.0f)));
973                    }
974                }
975            }
976        }
977        void makeLightPointGeometry(const georecord *grec, Group *nug) {
978            const std::vector<georecord *> gr=grec->getchildren();
979            for (std::vector<georecord *>::const_iterator itr=gr.begin();
980                itr!=gr.end();
981                ++itr)
982            {
983                if ((*itr)->getType()==DB_DSK_LIGHTPT) { // light points ONLY
984                    geoInfo ginf(0,0, 1);
985                    ginf.setPools(&coord_pool, &normal_pool); // holds all types of coords, indices etc
986                    osgSim::LightPointNode *gd=new osgSim::LightPointNode;
987                 // to be implemented   const geoField *gfd=(*itr)->getField(GEO_DB_LIGHTPT_TYPE); // omni, uni, bi
988                    makeLightPointNode((*itr),gd); // add vertex positions to light point set
989                    nug->addChild(gd);
990                }
991            }
992        }
993        int makeAnimatedGeometry(const georecord& grec, const int imat,Group *nug) {
994            // animated polygons - create a matrix & geode & poly & add to group nug
995            const std::vector<georecord *> gr=grec.getchildren();
996            int nanimations=0;
997            const geoField *gfd=grec.getField(GEO_DB_RENDERGROUP_CULLING); // back, front, none
998            unsigned int bothsides=gfd ? gfd->getUInt() : 0;
999//            int bothsides =allOneSided(&grec);
1000            for (std::vector<georecord *>::const_iterator itr=gr.begin();
1001            itr!=gr.end();
1002            ++itr) {
1003                std::vector< georecord *>bhv=(*itr)->getBehaviour(); // behaviours attached to facets, eg colour!
1004                if ((*itr)->getType()==DB_DSK_POLYGON && !bhv.empty()) { // animated facets go here
1005                    nanimations++;
1006                    if (hasMotionAction(bhv)) { // make matrix if motion needed.
1007                        const geoField *gfd=(*itr)->getField(GEO_DB_POLY_TEX0);
1008                        int txidx= gfd ? gfd->getInt() : -1;
1009                        gfd=(*itr)->getField(GEO_DB_POLY_SHADEMODEL); // shaded gouraud, flat...
1010                        int shademodel=gfd ? gfd->getInt() : GEO_POLY_SHADEMODEL_LIT_GOURAUD;
1011                        gfd=(*itr)->getField(GEO_DB_POLY_USE_MATERIAL_DIFFUSE); // true: use material...
1012                        bool usemat= gfd ? gfd->getBool() : false;
1013                        geoInfo ginf(txidx,shademodel, bothsides);
1014                        ginf.setPools(&coord_pool, &normal_pool); // holds all types of coords, indices etc
1015                        MatrixTransform *mtr=makeBehave(*itr);
1016                        Geode *gd=new Geode;
1017                        gfd=(*itr)->getField(GEO_DB_POLY_DSTYLE); // solid, wire...
1018                        int dstyle= gfd ? gfd->getInt() : GEO_POLY_DSTYLE_SOLID;
1019                        if (!usemat &&
1020                            (shademodel== GEO_POLY_SHADEMODEL_LIT ||shademodel== GEO_POLY_SHADEMODEL_LIT_GOURAUD) ) { // get the per vertex colours OR per face colours.
1021                            gfd=(*itr)->getField(GEO_DB_POLY_PACKED_COLOR); // the colour
1022                            if (gfd) {
1023                                unsigned char *cls=gfd->getUCh4Arr();
1024                                float red=cls[0]/255.0f;
1025                                float green=cls[1]/255.0f;
1026                                float blue=cls[2]/255.0f;
1027                                float alpha=1.0f; // cls[3]*frac/255.0f;
1028                                ginf.getVinf()->addPolcolour(osg::Vec4(red,green,blue,alpha));
1029                            } else { // get colour from palette
1030                                gfd=(*itr)->getField(GEO_DB_POLY_COLOR_INDEX); // use color pool...
1031                                int icp= gfd ? gfd->getInt() : 0;
1032                                float col[4];
1033                                theHeader->getPalette(icp, col);
1034                                ginf.getVinf()->addPolcolour(osg::Vec4(col[0],col[1],col[2],1.0));
1035                            }
1036                        }
1037                        nug->addChild(mtr);
1038                        mtr->addChild(gd);
1039                        osg::Geometry *nugeom=makeNewGeometry((*itr), ginf, imat);
1040                        int nv=getprim((*itr),ginf);
1041                        gd->addDrawable(nugeom); // now add the polygon
1042                        if (dstyle==GEO_POLY_DSTYLE_SOLID_BOTH_SIDES || dstyle == GEO_POLY_DSTYLE_SOLID) nugeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,0,nv));
1043                        if (dstyle==GEO_POLY_DSTYLE_OPEN_WIRE) nugeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP,0,nv));
1044                        if (dstyle==GEO_POLY_DSTYLE_CLOSED_WIRE) nugeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,nv));
1045                        if (dstyle==GEO_POLY_DSTYLE_POINTS) nugeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS,0,nv));
1046                        addPolyActions(bhv, ginf ,nv);
1047                    }
1048                }
1049
1050            }
1051            return nanimations;
1052        }
1053        bool hasColorAction(std::vector< georecord *>bhv) { // true if one of the actions changes colour
1054            bool ok=false;
1055        //    if (bhv) {
1056                for (std::vector< georecord *>::const_iterator rcitr=bhv.begin();
1057                rcitr!=bhv.end() && !ok;
1058                ++rcitr)
1059                {
1060                    switch ((*rcitr)->getType()) {
1061                    case DB_DSK_COLOR_RAMP_ACTION:
1062                        ok=true;
1063                        break;
1064                    default:
1065                        break;
1066                    }
1067                }
1068        //    }
1069            return ok;
1070        }
1071        bool hasMotionAction(std::vector< georecord *>bhv) { // true if one of the actions is a motion
1072            bool ok=false;
1073        //    if (bhv) {
1074                for (std::vector< georecord *>::const_iterator rcitr=bhv.begin();
1075                rcitr!=bhv.end() && !ok;
1076                ++rcitr)
1077                {
1078                    switch ((*rcitr)->getType()) {
1079                    case DB_DSK_ROTATE_ACTION:
1080                    case DB_DSK_SCALE_ACTION:
1081                    case DB_DSK_TRANSLATE_ACTION:
1082                        ok=true;
1083                        break;
1084                    default:
1085                        break;
1086                    }
1087                }
1088                //    }
1089                return ok;
1090        }
1091        geoInfo *getGeometry(const georecord *grec,Geode *nug, std::vector<class geoInfo> *ia,
1092            const unsigned int imat, const int shademodel, const int bothsides) {
1093            int igidx=0, igeom=-1;
1094            const geoField *gfd=grec->getField(GEO_DB_POLY_TEX0);
1095            int txidx= gfd ? gfd->getInt() : -1;
1096            for (std::vector<class geoInfo>::iterator itrint=ia->begin();
1097            itrint!=ia->end() && igeom<0;
1098            ++itrint) { // find a geometry that shares this texture.
1099                // also test for other properties of a unique material:
1100                // - use material/vertex colours;
1101                geoInfo gu(txidx,shademodel, bothsides);
1102                if (gu==&(*itrint) && !(*itrint).getGeom()->getUpdateCallback()) igeom=igidx;
1103                igidx++;
1104            }
1105            std::vector< georecord *>bhv=grec->getBehaviour(); // behaviours attached to facets, eg colour!
1106            if (igeom<0 || hasColorAction(bhv)) { // we need a new geometry for this due to new texture/material combo or an action
1107                gfd=grec->getField(GEO_DB_POLY_SHADEMODEL); // shaded gouraud, flat...
1108                int shademodel=gfd ? gfd->getInt() : GEO_POLY_SHADEMODEL_LIT_GOURAUD;
1109                geoInfo gi(txidx,shademodel, bothsides);
1110                gi.setPools(&coord_pool, &normal_pool);
1111                gfd=grec->getField(GEO_DB_POLY_LINE_WIDTH); // integer line width...
1112                if (gfd) {
1113                    int w=gfd->getInt();
1114                    gi.setlineWidth(w);
1115                }
1116                osg::Geometry *nugeom=makeNewGeometry(grec, gi, imat);
1117                nug->addDrawable(nugeom);
1118                igeom=ia->size();
1119                ia->push_back(gi); // look up table for which texture corresponds to which geom
1120            }
1121            return (&((*ia)[igeom]));
1122        }
1123        int makeGeometry(const georecord &grec, const unsigned int imat,Geode *nug)
1124        {    // makegeometry makes a set of Geometrys attached to current parent (Geode nug)
1125            const std::vector<georecord *> gr=grec.getchildren();
1126            // std::vector<osg::Geometry *> geom;
1127            if (gr.size()>0) {
1128                std::vector<class geoInfo> ia; // list of texture indices & vinfo found in this geode; sort into new
1129                const geoField *gfd=grec.getField(GEO_DB_RENDERGROUP_CULLING); // back, front, none
1130                unsigned int bothsides=gfd ? gfd->getUInt() : 0;
1131                //  vertexInfo vinf(&coord_pool, &normal_pool); // holds all types of coords, indices etc
1132//                bool bothsides=allOneSided(&grec);
1133                for (std::vector<georecord *>::const_iterator itr=gr.begin();
1134                itr!=gr.end();
1135                ++itr) {
1136                    std::vector< georecord *>bhv=(*itr)->getBehaviour(); // behaviours attached to facets, eg colour!
1137                    if ( !hasMotionAction(bhv)) { // animated facets go elsewhere
1138                        if ((*itr)->getType()==DB_DSK_POLYGON) { // a normal facet
1139                            const geoField *gfd=(*itr)->getField(GEO_DB_POLY_DSTYLE); // solid, wire...
1140                            int dstyle= gfd ? gfd->getInt() : GEO_POLY_DSTYLE_SOLID;
1141                            gfd=(*itr)->getField(GEO_DB_POLY_SHADEMODEL); // shaded gouraud, flat...
1142                            int shademodel=gfd ? gfd->getInt() : GEO_POLY_SHADEMODEL_LIT_GOURAUD;
1143                            geoInfo *gi=getGeometry((*itr), nug, &ia, imat,shademodel, bothsides);
1144
1145                            //shade models GEO_POLY_SHADEMODEL_FLAT GEO_POLY_SHADEMODEL_GOURAUD
1146                            //    GEO_POLY_SHADEMODEL_LIT GEO_POLY_SHADEMODEL_LIT_GOURAUD
1147                            gfd=(*itr)->getField(GEO_DB_POLY_USE_MATERIAL_DIFFUSE); // true: use material...
1148                            bool usemat= gfd ? gfd->getBool() : false;
1149                            if (!usemat ||
1150                                shademodel== GEO_POLY_SHADEMODEL_LIT /*||shademodel== GEO_POLY_SHADEMODEL_LIT_GOURAUD) */ ) { // get the per vertex colours OR per face colours.
1151                                gfd=(*itr)->getField(GEO_DB_POLY_PACKED_COLOR); // the colour
1152                                if (gfd) {
1153                                    unsigned char *cls=gfd->getUCh4Arr();
1154                                    float red=cls[0]/255.0f;
1155                                    float green=cls[1]/255.0f;
1156                                    float blue=cls[2]/255.0f;
1157                                    float alpha=1.0f; // cls[3]*frac/255.0f;
1158                                    gi->getVinf()->addPolcolour(osg::Vec4(red,green,blue,alpha));
1159                                } else { // get colour from palette
1160                                    gfd=(*itr)->getField(GEO_DB_POLY_COLOR_INDEX); // use color pool...
1161                                    int icp= gfd ? gfd->getInt() : 0;
1162                                    float col[4];
1163                                    theHeader->getPalette(icp, col);
1164                                    gi->getVinf()->addPolcolour(osg::Vec4(col[0],col[1],col[2],1.0));
1165                                }
1166                            }
1167                            int nv=getprim((*itr), *gi);
1168                            {
1169                                const vertexInfo *vinf=gi->getVinf();
1170                                if (vinf->getNorms() && vinf->getNorms()->size()>0) {
1171                                    gi->getGeom()->setNormalArray(vinf->getNorms());
1172                                    gi->getGeom()->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
1173                                } else {
1174                                    gi->getGeom()->setNormalBinding(osg::Geometry::BIND_OFF);
1175                                }
1176                            }
1177                            if (hasColorAction(bhv)) addPolyActions(bhv, *gi, nv);
1178
1179                            if (dstyle==GEO_POLY_DSTYLE_SOLID_BOTH_SIDES || dstyle == GEO_POLY_DSTYLE_SOLID) {
1180                                osg::DrawArrays *drw=new osg::DrawArrays(osg::PrimitiveSet::POLYGON,gi->getStart(nv),nv);
1181                                gi->getGeom()->addPrimitiveSet(drw);
1182                            }
1183                            if (dstyle == GEO_POLY_DSTYLE_OPEN_WIRE) {
1184                                osg::DrawArrays *drw=new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP,gi->getStart(nv),nv);
1185                                gi->getGeom()->addPrimitiveSet(drw);
1186                            }
1187                            if (dstyle == GEO_POLY_DSTYLE_CLOSED_WIRE) {
1188                                osg::DrawArrays *drw=new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,gi->getStart(nv),nv);
1189                                gi->getGeom()->addPrimitiveSet(drw);
1190                            }
1191                            if (dstyle==GEO_POLY_DSTYLE_POINTS) {
1192                                osg::DrawArrays *drw=new osg::DrawArrays(osg::PrimitiveSet::POINTS,gi->getStart(nv),nv);
1193                                gi->getGeom()->addPrimitiveSet(drw);
1194                            }
1195                        }
1196                    }
1197                }
1198                {
1199                    int igeom=0;
1200                    for (std::vector<geoInfo>::iterator itr=ia.begin();
1201                    itr!=ia.end();
1202                    ++itr) {
1203                        if ((*itr).getTexture() >=0) {
1204                            osg::Vec2Array *txa=ia[igeom].getVinf()->getTexCoords();
1205                            if (txa->size() > 0 ) {
1206                                ((*itr).getGeom())->setTexCoordArray(0, txa);
1207                            }
1208                        }
1209                        igeom++;
1210                    }
1211                }
1212            }
1213            return gr.size();
1214        }
1215        void makeTexts(const georecord& grec, Group *nug)
1216        {    // makeTexts adds a set of text+transform Geometrys attached to current parent (Group nug)
1217            const std::vector<georecord *> gr=grec.getchildren();
1218            std::vector<osg::Geometry *> geom;
1219            if (gr.size()>0) {
1220                std::vector<int> ia; // list of texture indices found in this geode; sort into new
1221                for (std::vector<georecord *>::const_iterator itr=gr.begin();
1222                itr!=gr.end();
1223                ++itr) {
1224                    if ((*itr)->getType()==DB_DSK_TEXT) {
1225                        osg::MatrixTransform *text=makeText((*itr));
1226                        if (text) nug->addChild(text);
1227                    }
1228                }
1229                // OSG_WARN << vinf;
1230            }
1231            return;
1232        }
1233        Group *makeTextGeode(const georecord *gr)
1234        {
1235             // in geo text is defined with a matrix included in the geo.geode (gr is this geo.geode)
1236            // - we need to create this tree to render text
1237#if 1
1238            return NULL; // temporary disable april 2003
1239#else
1240            Group *nug=new Group;
1241            const geoField *gfd=gr->getField(GEO_DB_RENDERGROUP_MAT);
1242            // may be used in future const unsigned int imat=gfd ? gfd->getInt():0;
1243            gfd=gr->getField(GEO_DB_NODE_NAME);
1244            if (gfd) {
1245                nug->setName(gfd->getChar());
1246            }
1247            makeTexts((*gr),nug);
1248            if (nug->getNumChildren() <=0) {
1249                nug=NULL;
1250            }
1251            return nug;
1252#endif
1253        }
1254
1255        Group *makeLightPointGeodes(const georecord *gr) {
1256            Group *nug=new Group;
1257            const geoField *gfd=gr->getField(GEO_DB_NODE_NAME);
1258            if (gfd) {
1259                char *name = gfd->getChar();
1260                nug->setName(name);
1261            }
1262            makeLightPointGeometry(gr,nug);
1263            if (nug->getNumChildren() <=0) {
1264                nug=NULL;
1265            }
1266            return nug;
1267        }
1268        Group *makeAnimatedGeodes(const georecord *gr)
1269        { // create a group full of animated geodes.  Used for any animations applied to facets!
1270            // movement actions require a transform node to be inserted, and this cannot be
1271            // derived from Geode.  So create a group, add matrix transform(s) for each animated polygon
1272            const geoField *gfd=gr->getField(GEO_DB_RENDERGROUP_MAT);
1273            const int imat=gfd ? gfd->getInt():0;
1274       //     gfd=gr->getField(GEO_DB_RENDERGROUP_IS_BILLBOARD);
1275         //   bool isbillb = gfd ? gfd->getBool() : false;
1276            Group *nug=new Group;
1277       /*     if (isbillb) {
1278                Billboard *bilb= new Billboard ;
1279                bilb->setAxis(Vec3(0,0,1));
1280                bilb->setNormal(Vec3(0,-1,0));
1281                nug=bilb;
1282            } else {
1283                nug=new Geode;
1284            } */
1285            gfd=gr->getField(GEO_DB_NODE_NAME);
1286            if (gfd) {
1287                char *name = gfd->getChar();
1288                nug->setName(name);
1289            }
1290            int nans=makeAnimatedGeometry((*gr),imat,nug);
1291            if (nans <=0) {
1292                nug=NULL;
1293            }
1294            return nug;
1295        }
1296        Geode *makeGeode(const georecord &gr)
1297        {
1298            const geoField *gfd=gr.getField(GEO_DB_RENDERGROUP_MAT);
1299            const unsigned int imat=gfd ? gfd->getInt():0;
1300            gfd=gr.getField(GEO_DB_RENDERGROUP_BILLBOARD);
1301            bool isbillb = gfd ? gfd->getBool() : false;
1302            osg::Geode *nug;
1303            if (isbillb) {
1304                Billboard *bilb= new Billboard ;
1305                bilb->setAxis(Vec3(0,0,1));
1306                bilb->setNormal(Vec3(0,-1,0));
1307                nug=bilb;
1308            } else {
1309                nug=new Geode;
1310            }
1311            int nchild=makeGeometry(gr,imat,nug);
1312            if (nchild>0) { // complete the geode
1313                gfd=gr.getField(GEO_DB_NODE_NAME);
1314                if (gfd) {
1315                    nug->setName(gfd->getChar());
1316                }
1317                return nug;
1318            } else {
1319                return NULL;
1320            }
1321        }
1322        osg::Group *makePage(const georecord *gr)
1323        {
1324            osg::Group *gp=new Group;
1325            const geoField *gfd=gr->getField(GEO_DB_NODE_NAME);
1326            if (gfd) {
1327                gp->setName(gfd->getChar());
1328            }
1329            return gp;
1330        }
1331        osg::Group *setmatrix(const georecord *gr) { // find one of the types of matrix supported
1332            const geoField *gfd=gr->getField(GEO_DB_GRP_MATRIX_TRANSFORM);
1333            if (!gfd) gfd=gr->getField(GEO_DB_GRP_TRANSLATE_TRANSFORM);
1334            if (!gfd) gfd=gr->getField(GEO_DB_GRP_ROTATE_TRANSFORM);
1335            if (!gfd) gfd=gr->getField(GEO_DB_GRP_SCALE_TRANSFORM);
1336            if (gfd) {
1337                MatrixTransform *tr=new MatrixTransform;
1338                osg::Matrix mx;
1339                float * m44=gfd->getMat44Arr();
1340                mx.set(m44); // hope uses same convention as OSG else will need to use set(m44[0],m44[1]...)
1341                tr->setMatrix(mx);
1342                return tr;
1343            } else {
1344                return NULL;
1345            }
1346        }
1347        osg::Group *makeGroup(const georecord *gr) { // group or Static transform
1348            osg::Group *gp=setmatrix(gr);
1349            if (!gp) {
1350                gp=new osg::Group;
1351            }
1352            const geoField *gfd=gr->getField(GEO_DB_NODE_NAME);
1353            if (gfd) {
1354                gp->setName(gfd->getChar());
1355            }
1356            return gp;
1357        }
1358        osg::Group *makeSwitch(const georecord *gr)
1359        {
1360            osg::Switch *sw=new Switch;
1361            const geoField *gfd=gr->getField(GEO_DB_SWITCH_CURRENT_MASK);
1362            sw->setAllChildrenOff();
1363            if (gfd) {
1364                int imask;
1365
1366                imask=gfd->getInt();
1367
1368                // set the bits in the osg::Switch.
1369                int selector_mask = 0x1;
1370                for(int pos=0;pos<32;++pos)
1371                {
1372                    sw->setValue(pos,((imask&selector_mask)!=0));
1373                    selector_mask <<= 1;
1374                }
1375                OSG_WARN << gr << " imask " << imask << std::endl;
1376            } else {
1377                sw->setSingleChildOn(0);
1378                OSG_WARN << gr << " Switch has No mask- only 1 child " << std::endl;
1379            }
1380            gfd=gr->getField(GEO_DB_NODE_NAME);
1381            if (gfd) {
1382                sw->setName(gfd->getChar());
1383            }
1384            return sw;
1385        }
1386
1387        osg::Sequence *makeSequence(const georecord *gr)
1388        {
1389            Sequence *sq=new Sequence;
1390            const geoField *gfd=gr->getField(GEO_DB_NODE_NAME);
1391            if (gfd) {
1392                sq->setName(gfd->getChar());
1393            }
1394            return sq;
1395        }
1396        osg::LOD *makeLOD(const georecord *gr)
1397        {
1398            osg::LOD *gp=new LOD;
1399            const geoField *gfd=gr->getField(GEO_DB_LOD_IN);
1400            float in  = gfd ? gfd->getFloat() : 100.0;
1401            gfd=gr->getField(GEO_DB_LOD_OUT);
1402            float out = gfd ? gfd->getFloat() : 0.0;
1403            gp->setRange(0,out,in);
1404            gfd=gr->getField(GEO_DB_NODE_NAME);
1405            if (gfd) {
1406                gp->setName(gfd->getChar());
1407            }
1408            return gp;
1409        }
1410        osg::Drawable* createClipSurface(float xMin,float xMax,float yMin,float yMax,float z)
1411        {            // set up the Geometry that defines the clipped region.
1412            osg::Geometry* geom = new osg::Geometry;
1413
1414            osg::Vec3Array* coords = new osg::Vec3Array(4);
1415            (*coords)[0].set(xMin,yMax,z);
1416            (*coords)[1].set(xMin,yMin,z);
1417            (*coords)[2].set(xMax,yMin,z);
1418            (*coords)[3].set(xMax,yMax,z);
1419            geom->setVertexArray(coords);
1420
1421            geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
1422
1423            return geom;
1424        }
1425        Group *makeClipRegion(const georecord *gr) {
1426            GeoClipRegion *clp=new GeoClipRegion;
1427            const geoField *gfd=gr->getField(GEO_DB_NODE_NAME);
1428            if (gfd) {
1429                clp->setName(gfd->getChar());
1430            }
1431            gfd=gr->getField(140);
1432            float *lleft = (gfd) ? (gfd->getVec3Arr()):NULL;
1433            gfd=gr->getField(141);
1434            float *uright= (gfd) ? (gfd->getVec3Arr()):NULL;
1435            if (uright && lleft) {
1436                Geode *geod=new Geode;
1437                Drawable *drw=createClipSurface(lleft[0],uright[0],lleft[1],uright[1],lleft[2]);
1438                geod->addDrawable(drw);
1439                clp->addClipNode(geod);
1440            }
1441            return clp;
1442        }
1443
1444        geoHeader *makeHeader(const georecord *gr, const osgDB::ReaderWriter::Options* options) {
1445            if (!theHeader.valid()) theHeader=new geoHeaderGeo();
1446            // the header contains variables as well as a transform for the XYZup cases
1447            const geoField *gfd;
1448            if (cpalrec) { // global - attach to geoheader
1449                gfd=cpalrec->getField(GEO_DB_COLOR_PALETTE_HIGHEST_INTENSITIES);
1450                if (gfd) {
1451                    unsigned char *cpal=gfd->getstore(0);
1452                    for (uint i=1; i<gfd->getNum(); i++) {
1453                        theHeader->addColour(cpal);
1454                        cpal+=4;
1455                    }
1456                }
1457            }
1458            gfd=gr->getField(GEO_DB_HDR_UP_AXIS);
1459            osg::Quat q;
1460            int iup=gfd ? gfd->getInt() : GEO_DB_UP_AXIS_Y;
1461
1462            switch (iup) {
1463            case GEO_DB_UP_AXIS_X:
1464                    q.set(0,1,0,1);
1465                    q/=q.length();
1466                    theHeader->setAttitude(q);
1467                break;
1468            case GEO_DB_UP_AXIS_Y:
1469                    q.set(1,0,0,1);
1470                    q/=q.length();
1471//                    theHeader->setMatrix(Matrix::rotate(pi2,  osg::Vec3(1,0,0 )));//setAttitude(q);
1472                    theHeader->setAttitude(q);
1473                break;
1474            case GEO_DB_UP_AXIS_Z: // no change
1475                    q.set(0,0,0,1);
1476                    q/=q.length();
1477                    theHeader->setAttitude(q); // set(q);
1478                break;
1479            }
1480            std::vector<georecord *>::const_iterator itr;
1481            for (itr=geotxlist.begin(); itr<geotxlist.end(); itr++) {
1482                makeTexture(*itr, options);
1483            }
1484            std::vector< georecord *>bhv=gr->getBehaviour();
1485            if (!bhv.empty()) { // then add internal, user, extern variables
1486                for (std::vector< georecord *>::const_iterator rcitr=bhv.begin();
1487                rcitr!=bhv.end();
1488                ++rcitr)
1489                {
1490                    if ((*rcitr)->getType()==DB_DSK_INTERNAL_VARS) {
1491                        theHeader->addInternalVars(**rcitr);
1492                //        theHeader->setUpdateCallback(theHeader->getInternalVars());
1493                    }
1494                    if ((*rcitr)->getType()==DB_DSK_FLOAT_VAR) {
1495                        if (theHeader.valid()) theHeader->addUserVar((**rcitr));
1496                    }
1497                }
1498                theHeader->setUpdateCallback(new geoHeaderCB);
1499            }
1500            for (itr=geomatlist.begin(); itr< geomatlist.end(); itr++) {
1501                 osg::Material *mt=new osg::Material;
1502                 (*itr)->setMaterial(mt);
1503                 matlist.push_back(mt);
1504            }
1505            return theHeader.get();
1506        }
1507        void makeTexture(const georecord *gr, const osgDB::ReaderWriter::Options* options) {
1508            // scans the fields of this record and puts a new texture & environment into 'pool' stor
1509            const geoField *gfd=gr->getField(GEO_DB_TEX_FILE_NAME);
1510            const char *name = gfd->getChar();
1511            if (name) {
1512                osg::ref_ptr<osg::Texture2D> tx = new Texture2D;
1513                osg::ref_ptr<osg::Image> ctx = osgDB::readImageFile(name,options);
1514                if (ctx.valid()) {
1515                    ctx->setFileName(name);
1516                    tx->setImage(ctx.get());
1517                }
1518                gfd=gr->getField(GEO_DB_TEX_WRAPS);
1519                osg::Texture2D::WrapMode wm=Texture2D::REPEAT;
1520                if (gfd) {
1521                    unsigned iwrap= gfd->getUInt();
1522                    wm = (iwrap==GEO_DB_TEX_CLAMP) ? Texture2D::CLAMP : Texture2D::REPEAT;
1523                }
1524                tx->setWrap(Texture2D::WRAP_S, wm);
1525                gfd=gr->getField(GEO_DB_TEX_WRAPT);
1526                wm=Texture2D::REPEAT;
1527                if (gfd) {
1528                    unsigned iwrap= gfd->getUInt();
1529                    wm = (iwrap==GEO_DB_TEX_CLAMP) ? Texture2D::CLAMP : Texture2D::REPEAT;
1530                }
1531                tx->setWrap(Texture2D::WRAP_T, wm);
1532                txlist.push_back(tx.get());
1533                osg::TexEnv* texenv = new osg::TexEnv;
1534                osg::TexEnv::Mode md=osg::TexEnv::MODULATE;
1535                gfd=gr->getField(GEO_DB_TEX_ENV);
1536                texenv->setMode(md);
1537                if (gfd) {
1538                    unsigned imod=gfd->getUInt();
1539                    switch (imod) {
1540                    case GEO_DB_TEX_MODULATE:
1541                        md=osg::TexEnv::MODULATE;
1542                        break;
1543                    case GEO_DB_TEX_DECAL:
1544                        md=osg::TexEnv::DECAL;
1545                        break;
1546                    case GEO_DB_TEX_BLEND:
1547                        md=osg::TexEnv::BLEND;
1548                        break;
1549                    }
1550                }
1551                gfd=gr->getField(GEO_DB_TEX_MINFILTER);
1552                osg::Texture::FilterMode filt=osg::Texture::NEAREST_MIPMAP_NEAREST;
1553                if (gfd) {
1554                    unsigned imod=gfd->getUInt();
1555                    switch (imod) {
1556                    case GEO_DB_TEX_NEAREST_MIPMAP_NEAREST:
1557                        filt=osg::Texture::LINEAR_MIPMAP_LINEAR;
1558                        break;
1559                    case GEO_DB_TEX_LINEAR_MIPMAP_NEAREST:
1560                        filt=osg::Texture::LINEAR_MIPMAP_NEAREST;
1561                        break;
1562                    case GEO_DB_TEX_NEAREST_MIPMAP_LINEAR:
1563                        filt=osg::Texture::NEAREST_MIPMAP_LINEAR;
1564                        break;
1565                    case GEO_DB_TEX_LINEAR_MIPMAP_LINEAR:
1566                        filt=osg::Texture::NEAREST_MIPMAP_NEAREST;
1567                        break;
1568                    }
1569                }
1570                tx->setFilter(osg::Texture::MIN_FILTER, filt);
1571                gfd=gr->getField(GEO_DB_TEX_MAGFILTER);
1572                if (gfd) {
1573                    unsigned imod=gfd->getUInt();
1574                    switch (imod) {
1575                    case GEO_DB_TEX_NEAREST:
1576                        filt=osg::Texture::LINEAR;
1577                        break;
1578                    case GEO_DB_TEX_LINEAR:
1579                        filt=osg::Texture::NEAREST;
1580                        break;
1581                    }
1582                }
1583                txenvlist.push_back(texenv);
1584            }
1585        }
1586        MatrixTransform *makeBehave(const georecord *gr)
1587        {
1588            MatrixTransform *mtr=NULL;
1589            bool ok=false; // true if the matrix transform is required
1590            std::vector< georecord *>bhv=gr->getBehaviour();
1591            if (!bhv.empty()) { // then add a DCS/matrix_transform
1592                mtr=new MatrixTransform;
1593                geoBehaviourCB *gcb=new geoBehaviourCB;
1594                mtr->setUpdateCallback(gcb);
1595
1596                for (std::vector< georecord *>::const_iterator rcitr=bhv.begin();
1597                rcitr!=bhv.end();
1598                ++rcitr)
1599                {
1600                    switch ((*rcitr)->getType()) {
1601                    case DB_DSK_BEHAVIOR: {
1602                        const geoField *gfd=(*rcitr)->getField(GEO_DB_BEHAVIOR_NAME);
1603                        if (gfd) {
1604                            mtr->setName(gfd->getChar());
1605                        }
1606                                          }
1607                        break;
1608                    case DB_DSK_ROTATE_ACTION: {
1609                        geoMoveBehaviour *cb= new geoMoveBehaviour;
1610                        ok=cb->makeBehave((*rcitr), theHeader.get());
1611                        if (ok) gcb->addBehaviour(cb);
1612                        else delete cb;
1613                                               }
1614                        break;
1615
1616                    case DB_DSK_SCALE_ACTION: {
1617                        geoMoveBehaviour *sb=new geoMoveBehaviour;
1618                        ok=sb->makeBehave((*rcitr), theHeader.get());
1619                        if (ok) gcb->addBehaviour(sb);
1620                        else delete sb;
1621                                              }
1622                        break;
1623                    case DB_DSK_TRANSLATE_ACTION: {
1624                        geoMoveBehaviour *cb= new geoMoveBehaviour;
1625                        ok=cb->makeBehave((*rcitr), theHeader.get());
1626                        if (ok) gcb->addBehaviour(cb);
1627                        else delete cb;
1628                                                  }
1629                        break;
1630
1631                    case DB_DSK_COMPARE_ACTION: {
1632                        geoCompareBehaviour *cb=new geoCompareBehaviour;
1633                        ok=cb->makeBehave((*rcitr), theHeader.get());
1634                        if (ok) gcb->addBehaviour(cb);
1635                        else delete cb;
1636                                                }
1637                        break;
1638                    case DB_DSK_ARITHMETIC_ACTION: {
1639                        geoArithBehaviour *cb=new geoArithBehaviour;
1640                        ok=cb->makeBehave((*rcitr), theHeader.get());
1641                        if (ok) gcb->addBehaviour(cb);
1642                        else delete cb;
1643                                                   }
1644                        break;
1645                    case DB_DSK_CLAMP_ACTION: {
1646                        geoClampBehaviour *cb=new geoClampBehaviour;
1647                        ok=cb->makeBehave((*rcitr), theHeader.get());
1648                        if (ok) gcb->addBehaviour(cb);
1649                        else delete cb;
1650                                              }
1651                        break;
1652                    case DB_DSK_RANGE_ACTION: {
1653                        geoRangeBehaviour *cb=new geoRangeBehaviour;
1654                        ok=cb->makeBehave((*rcitr), theHeader.get());
1655                        if (ok) gcb->addBehaviour(cb);
1656                        else delete cb;
1657                                              }
1658                        break;
1659                    case DB_DSK_VISIBILITY_ACTION: {
1660                        geoVisibBehaviour *vb = new geoVisibBehaviour;
1661                        ok=vb->makeBehave((*rcitr), theHeader.get());
1662                        if (ok) gcb->addBehaviour(vb);
1663                        else delete vb;
1664                                                   }
1665                        break;
1666                        // ar3 types
1667                    case DB_DSK_TRIG_ACTION: {
1668                        geoAr3Behaviour *vb = new geoAr3Behaviour;
1669                        ok=vb->makeBehave((*rcitr), theHeader.get());
1670                        if (ok) gcb->addBehaviour(vb);
1671                        else delete vb;
1672                                             }
1673                        break;
1674                    case DB_DSK_INVERSE_ACTION: {
1675                        geoAr3Behaviour *vb = new geoAr3Behaviour;
1676                        ok=vb->makeBehave((*rcitr), theHeader.get());
1677                        if (ok) gcb->addBehaviour(vb);
1678                        else delete vb;
1679                                                }
1680                        break;
1681                    case DB_DSK_LINEAR_ACTION: {
1682                        geoAr3Behaviour *vb = new geoAr3Behaviour;
1683                        ok=vb->makeBehave((*rcitr), theHeader.get());
1684                        if (ok) gcb->addBehaviour(vb);
1685                        else delete vb;
1686                                               }
1687                        break;
1688                    case DB_DSK_PERIODIC_ACTION: {
1689                        geoAr3Behaviour *vb = new geoAr3Behaviour;
1690                        ok=vb->makeBehave((*rcitr), theHeader.get());
1691                        if (ok) gcb->addBehaviour(vb);
1692                        else delete vb;
1693                                                 }
1694                        break;
1695#ifdef DB_DSK_PERIODIC2_ACTION
1696                    case DB_DSK_PERIODIC2_ACTION: {
1697                        geoAr3Behaviour *vb = new geoAr3Behaviour;
1698                        ok=vb->makeBehave((*rcitr), theHeader.get());
1699                        if (ok) gcb->addBehaviour(vb);
1700                        else delete vb;
1701                                                  }
1702                        break;
1703#endif
1704                    case DB_DSK_TRUNCATE_ACTION: {
1705                        geoAr3Behaviour *vb = new geoAr3Behaviour;
1706                        ok=vb->makeBehave((*rcitr), theHeader.get());
1707                        if (ok) gcb->addBehaviour(vb);
1708                        else delete vb;
1709                                                 }
1710                        break;
1711                    case DB_DSK_ABS_ACTION: {
1712                        geoAr3Behaviour *vb = new geoAr3Behaviour;
1713                        ok=vb->makeBehave((*rcitr), theHeader.get());
1714                        if (ok) gcb->addBehaviour(vb);
1715                        else delete vb;
1716                                            }
1717                        break;
1718                        /*
1719                    case DB_DSK_DCS_ACTION: */
1720                    case DB_DSK_DISCRETE_ACTION: {
1721                        geoDiscreteBehaviour *db = new geoDiscreteBehaviour;
1722                        ok=db->makeBehave((*rcitr), theHeader.get());
1723                        if (ok) gcb->addBehaviour(db);
1724                        else delete db;
1725                                                 }
1726                        break;
1727                    case DB_DSK_STRING_CONTENT_ACTION: {// cant be shared with this
1728                        // ok=false; can be a mixed action, rotate & string content
1729                                                       }
1730                        break;
1731                    case DB_DSK_IF_THEN_ELSE_ACTION:
1732                        {
1733                            geoAr3Behaviour *vb = new geoAr3Behaviour;
1734                            ok=vb->makeBehave((*rcitr), theHeader.get());
1735                            if (ok) gcb->addBehaviour(vb);
1736                            else delete vb;
1737                        }
1738                        break;
1739                    }
1740                }
1741            }
1742            if (!ok) {
1743                mtr=NULL;
1744            }
1745            return mtr;
1746        }
1747        std::vector<Node *> makeosg(const std::vector<georecord *> gr, const osgDB::ReaderWriter::Options* options) {
1748            // recursive traversal of records and extract osg::Nodes equivalent
1749            Group *geodeholder=NULL;
1750            std::vector<Node *> nodelist;
1751            if (gr.size()>0) {
1752                for (std::vector<georecord *>::const_iterator itr=gr.begin();
1753                itr!=gr.end();
1754                ++itr) {
1755                    const georecord *gr=*itr;
1756                    Group *mtr=makeBehave(gr);
1757                    if (gr->getType()== DB_DSK_RENDERGROUP) { // geodes can require >1 geometry for example if polygons have different texture indices.
1758                        // and for example if the node has a colour or other fine behaviour
1759                        Geode *geode=makeGeode(*gr); // geode of geometrys
1760                        Group *animatedGeodes= makeAnimatedGeodes(gr);
1761                        Group *lightptGeodes= makeLightPointGeodes(gr);
1762                        Group *textgeode=makeTextGeode(gr); // group of matrices & texts
1763                        const geoField *gfd=gr->getField(GEO_DB_GRP_ZBUFFER);
1764                        if (gfd) {
1765                            bool onoff=gfd->getBool();
1766                            if (!onoff) { // no z buffer - force to use unsorted renderBin
1767                                StateSet *dstate=new StateSet;
1768                                osg::Depth* depth = new osg::Depth;
1769                                depth->setFunction(osg::Depth::ALWAYS);
1770                                dstate->setAttribute(depth);
1771                                dstate->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
1772                                dstate->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN + 1,"RenderBin");
1773                        //        dstate->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN + 12,  "UnSortedBin");
1774                                if (geode) geode->setStateSet( dstate );
1775                                if (animatedGeodes) animatedGeodes->setStateSet( dstate );
1776                                if (lightptGeodes) lightptGeodes->setStateSet( dstate );
1777                                if (textgeode) textgeode->setStateSet( dstate );
1778                            }
1779                        }
1780
1781                        if (mtr) {
1782                            if (geode) mtr->addChild(geode);
1783                            if (animatedGeodes) mtr->addChild(animatedGeodes);
1784                            if (lightptGeodes) mtr->addChild(lightptGeodes);
1785                            if (textgeode) mtr->addChild(textgeode);
1786                            nodelist.push_back(mtr);
1787                            mtr=NULL;
1788                        } else {
1789                            if (!geodeholder && (geode || textgeode)) {
1790                                geodeholder=new osg::Group;
1791                                geodeholder->setName("geodeHolder");
1792                            }
1793                            if (geode) geodeholder->addChild(geode);
1794                            if (animatedGeodes) geodeholder->addChild(animatedGeodes);
1795                            if (lightptGeodes) geodeholder->addChild(lightptGeodes);
1796                            if (textgeode) geodeholder->addChild(textgeode);
1797                        }
1798                    } else {
1799                        Group *holder=NULL;
1800                        const geoField *gfd;
1801                        switch (gr->getType()) {
1802                        case 101:
1803                        case DB_DSK_HEADER:
1804                            holder=new osg::Group; // makeGroup(gr);
1805                            if (mtr) {
1806                                mtr->addChild(holder);
1807                                holder=mtr;
1808                            }
1809                            (*itr)->setNode(holder);
1810                            break;
1811/*                            holder= theHeader.get(); // makeHeader(gr);//
1812                            (*itr)->setNode(holder);
1813                            if (mtr) {
1814                                holder->addChild(mtr);
1815                                osg::Group *grp=makeGroup(gr);
1816                                mtr->addChild(grp);
1817                                holder=mtr;
1818                            }
1819                            break; */
1820                        case DB_DSK_TEXTURE:
1821                            makeTexture(gr, options);
1822                            break;
1823                        case DB_DSK_BASE_GROUP: // start of a group plus extra features
1824                            holder=makeClipRegion(gr);
1825                            if (mtr) {
1826                                mtr->addChild(holder);
1827                                holder=mtr;
1828                            }
1829                            (*itr)->setNode(holder);
1830                            break;
1831                        case DB_DSK_GROUP:
1832                            holder=makeGroup(gr);
1833                            if (mtr) {
1834                                mtr->addChild(holder);
1835                                holder=mtr;
1836                            }
1837                            (*itr)->setNode(holder);
1838                            break;
1839                        case DB_DSK_LOD:
1840                            holder=makeLOD(gr);
1841                            (*itr)->setNode(holder);
1842                            break;
1843                        case DB_DSK_SEQUENCE:
1844                            holder=makeSequence(gr);
1845                            (*itr)->setNode(holder);
1846                            break;
1847                        case DB_DSK_SWITCH:
1848                            holder=makeSwitch(gr);
1849                            (*itr)->setNode(holder);
1850                            break;
1851                        case DB_DSK_CUBE:
1852                            holder=new Group;
1853                            (*itr)->setNode(holder);
1854                            gfd=gr->getField(GEO_DB_NODE_NAME);
1855                            if (gfd) {
1856                                holder->setName(gfd->getChar());
1857                            }
1858                            break;
1859                        case DB_DSK_SPHERE:
1860                            holder=new Group;
1861                            (*itr)->setNode(holder);
1862                            gfd=gr->getField(GEO_DB_NODE_NAME);
1863                            if (gfd) {
1864                                holder->setName(gfd->getChar());
1865                            }
1866                            break;
1867                        case DB_DSK_CONE:
1868                            holder=new Group;
1869                            (*itr)->setNode(holder);
1870                            gfd=gr->getField(GEO_DB_NODE_NAME);
1871                            if (gfd) {
1872                                holder->setName(gfd->getChar());
1873                            }
1874                            break;
1875                        case DB_DSK_CYLINDER:
1876                            holder=new Group;
1877                            (*itr)->setNode(holder);
1878                            gfd=gr->getField(GEO_DB_NODE_NAME);
1879                            if (gfd) {
1880                                holder->setName(gfd->getChar());
1881                            }
1882                            break;
1883                        case DB_DSK_INSTANCE:
1884                            {
1885                                MatrixTransform *mtr=new MatrixTransform;
1886                                gfd=gr->getField(GEO_DB_NODE_NAME);
1887                                if (gfd) {
1888                                    mtr->setName(gfd->getChar());
1889                                }
1890                                gfd=gr->getField(GEO_DB_GRP_MATRIX_TRANSFORM); // was: GEO_DB_INSTANCE_TRANSFORM);
1891                                if (gfd) {
1892                                    float *fmat=gfd->getMat44Arr();
1893                                    mtr->setMatrix(Matrix(fmat));
1894                                }
1895                                gfd=gr->getField(GEO_DB_INSTANCE_DEF);
1896                                if (gfd) { // get the fID of a node
1897                                    uint fid=gfd->getUInt();
1898                                    georecord *grec=getInstance(fid);
1899                                    if (grec) {
1900                                        osg::Node *nd=grec->getNode();
1901                                        if (nd) { // node already loaded, so instance
1902                                            mtr->addChild(nd);
1903                                            holder=mtr;
1904                                        } else { // store unsatisfied instance matrix in georecord...
1905                                            grec->addInstance(mtr);
1906                                        }
1907                                    }
1908                                }
1909                            }
1910                            break;
1911                        case DB_DSK_PAGE:
1912                            holder=makePage(gr);
1913                            (*itr)->setNode(holder);
1914                            break;
1915                        case DB_DSK_PERSPECTIVE_GRID_INFO:
1916                            { // relates to how model is viewed in Geo modeller
1917                                osg::Group *gp=new Group;
1918                                holder=gp;
1919                            }
1920                            break;
1921                        case DB_DSK_FLOAT_VAR:
1922                        case DB_DSK_INT_VAR:
1923                        case DB_DSK_LONG_VAR:
1924                        case DB_DSK_DOUBLE_VAR:
1925                        case DB_DSK_BOOL_VAR:
1926                        case DB_DSK_FLOAT2_VAR:
1927                        case DB_DSK_FLOAT3_VAR:
1928                        case DB_DSK_FLOAT4_VAR:
1929                        case DB_DSK_INTERNAL_VARS:
1930                        case DB_DSK_LOCAL_VARS:
1931                        case DB_DSK_EXTERNAL_VARS:
1932                        case DB_DSK_CLAMP_ACTION:
1933                        case DB_DSK_RANGE_ACTION:
1934                        case DB_DSK_ROTATE_ACTION:
1935                        case DB_DSK_TRANSLATE_ACTION:
1936                        case DB_DSK_SCALE_ACTION:
1937                        case DB_DSK_ARITHMETIC_ACTION:
1938                        case DB_DSK_LOGIC_ACTION:
1939                        case DB_DSK_CONDITIONAL_ACTION:
1940                        case DB_DSK_LOOPING_ACTION:
1941                        case DB_DSK_COMPARE_ACTION:
1942                        case DB_DSK_VISIBILITY_ACTION:
1943                        case DB_DSK_STRING_CONTENT_ACTION:
1944                        default: {
1945                            osg::Group *gp=new Group;
1946                            OSG_WARN << "Unhandled item " << gr->getType() <<
1947                               "address " << (*itr) << std::endl;
1948                            holder=gp;
1949                            }
1950                            break;
1951                        }
1952                        if (holder) nodelist.push_back(holder);
1953
1954                        std::vector<Node *> child=makeosg((*itr)->getchildren(), options);
1955                        GeoClipRegion *clip=dynamic_cast<GeoClipRegion *>(holder);
1956                        for (std::vector<Node *>::iterator itr=child.begin();
1957                            itr!=child.end();
1958                            ++itr) {
1959                                if (clip) clip->addClippedChild(*itr);
1960                                else holder->addChild(*itr);
1961                        }
1962                    }
1963                }
1964            }
1965            if (geodeholder) {
1966                osgUtil::Tessellator tessellator;
1967                for(unsigned int ige=0;ige<geodeholder->getNumChildren();++ige) {
1968                    osg::Geode *geode=dynamic_cast<osg::Geode*>(geodeholder->getChild(ige));
1969                    if (geode) {
1970                        for(unsigned int i=0;i<geode->getNumDrawables();++i)
1971                        {
1972                            osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode->getDrawable(i));
1973                            if (geom) tessellator.retessellatePolygons(*geom);
1974                        }
1975                    }
1976                }
1977                nodelist.push_back(geodeholder);
1978            }
1979            return nodelist;
1980        }
1981        void output(osgDB::Output &fout,std::vector<georecord> gr)
1982        { // debugging - print the tree of records
1983            if (gr.size()>0) {
1984                for (std::vector<georecord>::iterator itr=gr.begin();
1985                    itr!=gr.end();
1986                    ++itr) {
1987                    fout.indent() << "Node type " << (*itr).getType() << " ";
1988                    fout.indent() << (*itr) << std::endl;
1989                }
1990            }
1991        }
1992        void output(osgDB::Output &fout,std::vector<georecord *> gr)
1993        { // debugging - print the tree of records
1994            fout.moveIn();
1995            if (gr.size()>0) {
1996                for (std::vector<georecord *>::iterator itr=gr.begin();
1997                    itr!=gr.end();
1998                    ++itr) {
1999                    fout.indent() << "Node type " << (*itr)->getType() << " ";
2000                    fout.indent() << (**itr) << std::endl;
2001                    fout.indent() << std::endl;
2002                    output(fout,(*itr)->getchildren());
2003                }
2004            }
2005            fout.moveOut();
2006        }
2007        georecord *getInstance(uint fid) { // find record with instance fid
2008            for (geoRecordList::iterator itr=recs.begin();
2009                itr!=recs.end();
2010                ++itr) {
2011                    const geoField *gfd;
2012                switch ((*itr).getType()) {
2013                case DB_DSK_GROUP:
2014                    gfd=(*itr).getField(GEO_DB_GRP_INSTANCE_DEF);
2015                    if (gfd) {
2016                        uint fidnod=gfd->getUInt();
2017                        if (fidnod==fid) return &(*itr);
2018                    }
2019                    break;
2020                case DB_DSK_LOD:
2021                    gfd=(*itr).getField(GEO_DB_INSTANCE_DEF);
2022                    if (gfd) {
2023                        uint fidnod=gfd->getUInt();
2024                        if (fidnod==fid) return &(*itr);
2025                    }
2026                    break;
2027                case DB_DSK_SEQUENCE:
2028                    gfd=(*itr).getField(GEO_DB_INSTANCE_DEF);
2029                    if (gfd) {
2030                        uint fidnod=gfd->getUInt();
2031                        if (fidnod==fid) return &(*itr);
2032                    }
2033                    break;
2034                case DB_DSK_SWITCH:
2035                    gfd=(*itr).getField(GEO_DB_INSTANCE_DEF);
2036                    if (gfd) {
2037                        uint fidnod=gfd->getUInt();
2038                        if (fidnod==fid) return &(*itr);
2039                    }
2040                    break;
2041                case DB_DSK_RENDERGROUP:
2042                    gfd=(*itr).getField(GEO_DB_INSTANCE_DEF);
2043                    if (gfd) {
2044                        uint fidnod=gfd->getUInt();
2045                        if (fidnod==fid) return &(*itr);
2046                    }
2047                    break;
2048                }
2049            }
2050            return NULL;
2051        }
2052
2053private:
2054    geoRecordList recs; // the records read from file
2055    std::vector<osg::Vec3> coord_pool; // current vertex ooords
2056    std::vector<osg::Vec3> normal_pool; // current pool of normal vectors
2057    osg::ref_ptr<geoHeaderGeo> theHeader; // an OSG class - has animation vars etc
2058    std::vector<georecord *> geotxlist; // list of geo::textures for this model
2059    std::vector<georecord *> geomatlist; // list of geo::materials for this model
2060    std::vector< osg::ref_ptr<osg::Texture2D> > txlist; // list of osg::textures for this model
2061    std::vector< osg::ref_ptr<osg::TexEnv> > txenvlist; // list of texture environments for the textures
2062    std::vector< osg::ref_ptr<osg::Material> > matlist; // list of materials for current model
2063    georecord *cpalrec; // colour palette record
2064};
2065
2066//=======
2067void internalVars::addInternalVars(const georecord &gr){
2068    const georecord::geoFieldList gfl=gr.getFields();
2069    for (georecord::geoFieldList::const_iterator itr=gfl.begin();
2070    itr!=gfl.end();
2071    ++itr)
2072    {// for each variable
2073        if ((*itr).getToken() >0) {
2074            geoValue *nm=new geoValue((*itr).getToken(),(*itr).getUInt());
2075            vars.push_back(*nm);
2076        }
2077    }
2078}
2079
2080void userVars::addUserVar(const georecord &gr) {
2081    const georecord::geoFieldList gfl=gr.getFields();
2082    if (gr.getType() == DB_DSK_FLOAT_VAR) {
2083        unsigned int tok=0; // ? what for?
2084        const geoField *gfd= gr.getField(GEO_DB_FLOAT_VAR_FID);
2085        unsigned int fid=gfd ? gfd->getUInt():0;
2086        geoValue *nm=new geoValue(tok,fid);
2087
2088        gfd= gr.getField(GEO_DB_FLOAT_VAR_NAME);
2089        const char *name=gfd->getChar();
2090        nm->setName(name);
2091
2092        gfd= gr.getField(GEO_DB_FLOAT_VAR_VALUE);
2093        nm->setVal(gfd ? gfd->getFloat():0.0f);
2094
2095        //gfd= gr.getField(GEO_DB_FLOAT_VAR_DEFAULT);
2096        //nm->setdefault(gfd ? gfd->getFloat():0.0f);
2097        //float fdef=gfd ? gfd->getFloat():0.0f;
2098
2099        gfd= gr.getField(GEO_DB_FLOAT_VAR_CONSTRAINED);
2100        if (gfd) {
2101            nm->setConstrained();
2102            gfd= gr.getField(GEO_DB_FLOAT_VAR_MIN);
2103            if (gfd) {
2104                nm->setMinRange(gfd->getFloat());
2105            }
2106            gfd= gr.getField(GEO_DB_FLOAT_VAR_MAX);
2107            if (gfd) {
2108                nm->setMaxRange(gfd->getFloat());
2109            }
2110        }
2111        gfd= gr.getField(GEO_DB_FLOAT_VAR_STEP);
2112        //float fstp=gfd ? gfd->getFloat():0;
2113        vars.push_back(*nm);
2114    }
2115}
2116
2117void internalVars::update(const osg::FrameStamp *_frameStamp) {
2118    double stmptime=_frameStamp->getSimulationTime();
2119    int iord=0;
2120    for (std::vector<geoValue>::const_iterator itr=vars.begin(); //gfl.begin();
2121    itr!=vars.end(); // gfl.end();
2122    ++itr, iord++)
2123    {// for each field
2124        unsigned int typ=itr->getToken();
2125        switch (typ) {
2126        case GEO_DB_INTERNAL_VAR_FRAMECOUNT:
2127            vars[iord].setVal((float)_frameStamp->getFrameNumber());
2128            break;
2129        case GEO_DB_INTERNAL_VAR_CURRENT_TIME:
2130            {
2131                static double timestart=-1;
2132                if (timestart<0) {
2133                    time_t long_time;
2134                    struct tm *newtime;
2135
2136                    long_time=time( NULL );                // * Get time as long integer.
2137                    newtime = localtime( &long_time ); // * Convert to local time.
2138                    timestart=newtime->tm_hour*3600 +newtime->tm_min*60+ newtime->tm_sec;
2139                }
2140                double timeofday=timestart+_frameStamp->getSimulationTime();
2141                vars[iord].setVal(timeofday);
2142            }
2143            break;
2144        case GEO_DB_INTERNAL_VAR_ELAPSED_TIME:
2145            vars[iord].setVal(_frameStamp->getSimulationTime());
2146            break;
2147        case GEO_DB_INTERNAL_VAR_SINE:
2148            vars[iord].setVal(sin(stmptime));
2149            break;
2150        case GEO_DB_INTERNAL_VAR_COSINE:
2151            vars[iord].setVal(cos(stmptime));
2152            break;
2153        case GEO_DB_INTERNAL_VAR_TANGENT:
2154            vars[iord].setVal(tan(stmptime));
2155            break;
2156        case GEO_DB_INTERNAL_VAR_MOUSE_X: // this is all windowing system dependent
2157            //    vars[iord]=_frameStamp->getSimulationTime();
2158            break;
2159        case GEO_DB_INTERNAL_VAR_MOUSE_Y:
2160            //    vars[iord]=_frameStamp->getSimulationTime();
2161            break;
2162        case GEO_DB_INTERNAL_VAR_LEFT_MOUSE:
2163            //    vars[iord]=_frameStamp->getSimulationTime();
2164            break;
2165        case GEO_DB_INTERNAL_VAR_MIDDLE_MOUSE:
2166            //    vars[iord]=_frameStamp->getSimulationTime();
2167            break;
2168        case GEO_DB_INTERNAL_VAR_RIGHT_MOUSE:
2169            //    vars[iord]=_frameStamp->getSimulationTime();
2170            break;
2171        case GEO_DB_INTERNAL_VAR_TEMP_FLOAT:
2172            //    vars[iord]=_frameStamp->getSimulationTime();
2173            break;
2174        case GEO_DB_INTERNAL_VAR_TEMP_INT:
2175            //    vars[iord]=_frameStamp->getSimulationTime();
2176            break;
2177        case GEO_DB_INTERNAL_VAR_TEMP_BOOL:
2178            //    vars[iord]=_frameStamp->getSimulationTime();
2179            break;
2180        case GEO_DB_INTERNAL_VAR_TEMP_STRING:
2181            //    vars[iord]=_frameStamp->getSimulationTime();
2182            break;
2183        }
2184    }
2185    //    std::cout<<"update callback - post traverse"<< (float)_frameStamp->getSimulationTime() <<std::endl;
2186}
2187
2188void geoField::parseExt(std::ifstream &fin) const { // Feb 2003 parse onme extension fields
2189    static int nread=0; // debug only
2190    // unused
2191    //geoExtensionDefRec *geoExt=(geoExtensionDefRec *)storage;
2192    for (uint i=0; i<numItems; i++) {
2193        geoExtensionDefRec rec;
2194            fin.read((char *)&rec,sizeof(rec));
2195            geoField ginner; // inside reading
2196            ginner.readfile(fin,0);
2197    }
2198    nread++;
2199}
2200void geoField::readfile(std::ifstream &fin, const uint id) { // is part of a record id
2201    unsigned char tokid, type;
2202    unsigned short nits;
2203    if (!fin.eof()) {
2204        fin.read((char *)&tokid,1);fin.read((char *)&type,1);
2205        fin.read((char *)&nits,sizeof(unsigned short));
2206    //    OSG_WARN << "geoField " << (int)tokid << " type " << (int)type << " nit " << (int)nits << std::endl;
2207        if (type == DB_EXTENDED_FIELD_STRUCT) { // change for true extended type
2208            fin.read((char *)&tokenId,sizeof(tokenId));fin.read((char *)&TypeId,sizeof(TypeId));
2209            fin.read((char *)&numItems,sizeof(unsigned int));
2210        } else {
2211            tokenId=tokid; TypeId=type;
2212            numItems=nits;
2213        }
2214        if (id== 0 && tokenId == GEO_DB_NODE_EXTENDED && numItems==1) { // Feb 2003 parse extension template records
2215            if (TypeId == DB_SHORT ||
2216                TypeId == DB_USHORT) {
2217                short upad;
2218                fin.read((char *)&upad,SIZEOF_SHORT); // skip the padding on extension template
2219                upad=1;
2220            } else if (TypeId == DB_CHAR ||
2221                TypeId == DB_UCHAR) {
2222                char cpad[4];
2223                fin.read(cpad,SIZEOF_CHAR); // skip the padding
2224            } else {
2225            }
2226        }
2227        if (id== DB_DSK_HEADER && tokenId == GEO_DB_HDR_EXT_TEMPLATE) { // Feb 2003 parse extension records
2228        //    OSG_WARN << "header extension template " << (int)getType() << std::endl;
2229            parseExt(fin); // multiple structs occur here
2230        } else {
2231            if (numItems>0) {
2232                storageRead(fin); // allocate & fill the storage
2233                if (tokenId == GEO_DB_NODE_EXT) { // added Nov 2003 to parse extension nodes
2234                    if (TypeId == DB_SHORT ||TypeId == DB_USHORT) fin.ignore(2); // skip padding
2235                //    if (TypeId == DB_CHAR ||TypeId == DB_UCHAR) fin.ignore(3); // skip padding
2236                }
2237                if (tokenId == GEO_DB_NODE_EXTENDED) {
2238                    if (id==DB_DSK_POLYGON || id==DB_DSK_RENDERGROUP || id==DB_DSK_GROUP
2239                         || id==DB_DSK_LOD || id==DB_DSK_MESH || id==DB_DSK_CUBE
2240                         || id==DB_DSK_SPHERE || id==DB_DSK_CONE || id==DB_DSK_CYLINDER
2241                         || id==DB_DSK_TEXTURE || id==DB_DSK_MATERIAL || id==DB_DSK_VIEW) {
2242                        if (TypeId == DB_SHORT ||TypeId == DB_USHORT) fin.ignore(2); // skip padding
2243                    }
2244                }
2245            }
2246        }
2247    }
2248}
2249
2250
2251class ReaderWriterGEO : public osgDB::ReaderWriter
2252{
2253    public:
2254
2255        ReaderWriterGEO()
2256        {
2257            supportsExtension("gem","CarbonGraphics Geo model format");
2258            supportsExtension("geo","CarbonGraphics Geo model format");
2259        }
2260
2261        virtual const char* className() const { return "GEO Reader/Writer"; }
2262
2263        virtual bool acceptsExtension(const std::string& extension) const
2264        {
2265            return osgDB::equalCaseInsensitive(extension,"gem") || osgDB::equalCaseInsensitive(extension,"geo");
2266        }
2267
2268        virtual ReadResult readObject(const std::string& fileName, const Options* opt) const { return readNode(fileName,opt); }
2269
2270        virtual ReadResult readNode(const std::string& file, const Options* options) const
2271        {
2272            std::string ext = osgDB::getLowerCaseFileExtension(file);
2273            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
2274
2275            std::string fileName = osgDB::findDataFile( file, options );
2276            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
2277
2278            ReaderGEO reader;
2279            return reader.readNode(fileName,options);
2280        }
2281
2282};
2283
2284
2285// now register with Registry to instantiate the above
2286// reader/writer.
2287REGISTER_OSGPLUGIN(geo, ReaderWriterGEO)
Note: See TracBrowser for help on using the browser.