root/OpenSceneGraph/branches/OpenSceneGraph-2.8/src/osgPlugins/ac/ac3d.cpp @ 11238

Revision 11238, 47.8 kB (checked in by paulmartz, 5 years ago)

2.8 branch: Minor bug fixes for ac and 3dc plugins. Merges these revisions from trunk: 10010, 10758, and 11175.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// 30 Oct 2002
2// AC3D loader for models generated by the AC3D modeller (www.ac3d.org)
3// part of this source code were supplied by the AC3D project (Andy Colebourne)
4// eg the basic parsing of an AC3D file.
5// Conversion from AC3D scenegraph to OSG by GW Michel.
6
7#include <vector>
8#include <iostream>
9#include <stdlib.h>
10
11#include <osg/GL>
12#include <osg/GLU>
13
14#include <osg/Math>
15#include <osg/BlendFunc>
16#include <osg/CullFace>
17#include <osg/Geode>
18#include <osg/Group>
19#include <osg/Geometry>
20#include <osg/Light>
21#include <osg/LightSource>
22#include <osg/Material>
23#include <osg/Math>
24#include <osg/Texture2D>
25#include <osg/TexEnv>
26#include <osg/StateSet>
27#include <osg/ShadeModel>
28#include <osg/Math>
29#include <osg/Notify>
30
31#include <osgUtil/Tessellator>
32
33#include <osgDB/FileNameUtils>
34#include <osgDB/Registry>
35#include <osgDB/ReadFile>
36#include <osgDB/FileUtils>
37#include <osgDB/fstream>
38
39#include "Exception.h"
40#include "Geode.h"
41
42namespace ac3d {
43
44osg::Node*
45readFile(std::istream& stream, const osgDB::ReaderWriter::Options* options);
46
47}
48
49class geodeVisitor : public osg::NodeVisitor { // collects geodes from scene sub-graph attached to 'this'
50        public:
51            geodeVisitor():
52                osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
53
54            ~geodeVisitor() { _geodelist.clear();}
55
56            // one apply for each type of Node that might be a user transform
57            virtual void apply(osg::Geode& geode) {
58                _geodelist.push_back(&geode);
59            }
60            virtual void apply(osg::Group& gp){
61                traverse(gp);    // must continue subgraph traversal.
62            }
63            std::vector<const osg::Geode *> getGeodes() {return _geodelist;}
64        protected:
65
66            typedef std::vector<const osg::Geode *>    Geodelist;
67            Geodelist  _geodelist;
68};
69
70class ReaderWriterAC : public osgDB::ReaderWriter
71{
72    public:
73   
74        ReaderWriterAC()
75        {
76            supportsExtension("ac","AC3D Database format");
77        }
78       
79        virtual const char* className() const { return "AC3D Database Reader"; }
80
81        virtual ReadResult readNode(const std::string& file,const Options* options) const
82        {
83            std::string ext = osgDB::getFileExtension(file);
84            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
85
86            // GWM added Dec 2003 - get full path name (change in osgDB handling of files).
87            std::string fileName = osgDB::findDataFile( file, options );
88            osg::notify(osg::INFO) << "osgDB ac3d reader: starting reading \"" << fileName << "\"" << std::endl;
89           
90            // Anders Backmann - correct return if path not found
91            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
92
93            // allocate per file data and start reading
94            osgDB::ifstream fin;
95            fin.open(fileName.c_str(), std::ios::in);
96            if (!fin.is_open()) return ReadResult::FILE_NOT_FOUND;
97
98            // code for setting up the database path so that internally referenced file are
99            // searched for on relative paths.
100            osg::ref_ptr<Options> local_opt;
101            if (options)
102                local_opt = static_cast<Options*>(options->clone(osg::CopyOp::DEEP_COPY_ALL));
103            else
104                local_opt = new Options;
105            local_opt->getDatabasePathList().push_back(osgDB::getFilePath(fileName));
106
107            ReadResult result = readNode(fin, local_opt.get());
108            if (result.validNode())
109                result.getNode()->setName(fileName);
110            return result;
111        }
112        virtual ReadResult readNode(std::istream& fin, const Options* options) const
113        {
114            std::string header;
115            fin >> header;
116            if (header.substr(0, 4) != "AC3D")
117                return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
118
119            return ac3d::readFile(fin, options);
120        }
121        virtual WriteResult writeNode(const osg::Node& node,const std::string& fileName, const Options* /*options*/) const
122        {
123            std::string ext = osgDB::getFileExtension(fileName);
124            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
125            geodeVisitor vs; // this collects geodes.
126            std::vector<unsigned int>iNumMaterials;
127            const_cast<osg::Node&>(node).accept(vs); // this parses the tree to streamd Geodes
128            std::vector<const osg::Geode *> glist=vs.getGeodes();
129            osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
130            // Write out the file header
131            std::vector<const osg::Geode *>::iterator itr;
132            fout << "AC3Db" << std::endl;
133            // output the Materials
134            int iNumGeodesWithGeometry = 0;
135            for (itr=glist.begin();itr!= glist.end();itr++)
136            {
137                iNumMaterials.push_back(const_cast<ac3d::Geode*>(static_cast<const ac3d::Geode*>(*itr))->ProcessMaterial(fout,itr-glist.begin()));
138                unsigned int iNumDrawables = (*itr)->getNumDrawables();
139                int iNumGeometries = 0;
140                for (unsigned int i = 0; i < iNumDrawables; i++)
141                {
142                    const osg::Drawable* pDrawable = (*itr)->getDrawable(i);
143                    if (NULL != pDrawable)
144                    {
145                        const osg::Geometry *pGeometry = pDrawable->asGeometry();
146                        if (NULL != pGeometry)
147                            iNumGeometries++;
148                    }
149                }
150                if (iNumGeometries > 0)
151                    iNumGeodesWithGeometry++;
152            }
153            // output the Geometry
154            unsigned int nfirstmat=0;
155            fout << "OBJECT world" << std::endl;
156
157            fout << "kids " << iNumGeodesWithGeometry << std::endl;
158            for (itr=glist.begin();itr!= glist.end();itr++) {
159                const_cast<ac3d::Geode*>(static_cast<const ac3d::Geode*>(*itr))->ProcessGeometry(fout,nfirstmat);
160                nfirstmat+=iNumMaterials[itr-glist.begin()];
161            }
162            fout.close();
163            return WriteResult::FILE_SAVED;
164        }
165       
166        virtual WriteResult writeNode(const osg::Node& node,std::ostream& fout, const Options* opts) const
167        {
168            // write ac file.
169            if(dynamic_cast<const osg::Group*>(&node))
170            {
171                const osg::Group *gp=dynamic_cast<const osg::Group*>(&node);
172                const unsigned int nch=gp->getNumChildren();
173                for (unsigned int i=0; i<nch; i++)
174                {
175                    writeNode(*(gp->getChild(i)), fout, opts);
176                }
177            }
178            else
179                osg::notify(osg::WARN)<<"File must start with a geode "<<std::endl;
180           
181            fout.flush();
182            return WriteResult::FILE_SAVED;
183        }
184private:
185};
186
187// now register with osg::Registry to instantiate the above
188// reader/writer.
189REGISTER_OSGPLUGIN(ac, ReaderWriterAC)
190
191
192namespace ac3d {
193
194enum {
195  ObjectTypeNormal = 0,
196  ObjectTypeGroup = 1,
197  ObjectTypeLight = 2,
198
199  SurfaceTypePolygon = 0,
200  SurfaceTypeLineLoop = 1,
201  SurfaceTypeLineStrip = 2,
202
203  SurfaceShaded = 1<<4,
204  SurfaceTwoSided = 1<<5
205};
206
207/// Returns a possibly quoted string given in the end of the current line in the stream
208static
209std::string
210readString(std::istream& stream)
211{
212    std::string s;
213    stream >> std::ws;
214
215    if (stream.peek() != '\"')
216    {
217        // Not quoted, just read the string
218        stream >> s;
219    }
220    else
221    {
222        // look for quoted strings
223   
224        // throw away the quote
225        stream.get();
226   
227        // extract characters until either an error happens or a quote is found
228        while (stream.good())
229        {
230            std::istream::char_type c;
231            stream.get(c);
232            if (c == '\"')
233                break;
234            s += c;
235        }
236    }
237 
238    return s;
239}
240
241static void
242setTranslucent(osg::StateSet* stateSet)
243{
244    osg::BlendFunc* blendFunc = new osg::BlendFunc;
245    blendFunc->setDataVariance(osg::Object::STATIC);
246    blendFunc->setSource(osg::BlendFunc::SRC_ALPHA);
247    blendFunc->setDestination(osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
248    stateSet->setAttribute(blendFunc);
249    stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
250    stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
251}
252
253// Just a container to store an ac3d material
254class MaterialData
255{
256  public:
257    MaterialData() :
258        mMaterial(new osg::Material),
259        mColorArray(new osg::Vec4Array(1))
260    {
261        mMaterial->setDataVariance(osg::Object::STATIC);
262        mColorArray->setDataVariance(osg::Object::STATIC);
263    }
264
265    void readMaterial(std::istream& stream)
266    {
267        // note that this might be quoted
268        std::string name = readString(stream);
269        mMaterial->setName(name);
270        std::string tmp;
271        stream >> tmp;
272        osg::Vec4 diffuse;
273        stream >> diffuse[0] >> diffuse[1] >> diffuse[2];
274        mMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
275        stream >> tmp;
276        osg::Vec4 ambient;
277        stream >> ambient[0] >> ambient[1] >> ambient[2];
278        mMaterial->setAmbient(osg::Material::FRONT_AND_BACK, ambient);
279        stream >> tmp;
280        osg::Vec4 emmissive;
281        stream >> emmissive[0] >> emmissive[1] >> emmissive[2];
282        mMaterial->setEmission(osg::Material::FRONT_AND_BACK, emmissive);
283        stream >> tmp;
284        osg::Vec4 specular;
285        stream >> specular[0] >> specular[1] >> specular[2];
286        mMaterial->setSpecular(osg::Material::FRONT_AND_BACK, specular);
287        stream >> tmp;
288        float shininess;
289        stream >> shininess;
290        mMaterial->setShininess(osg::Material::FRONT_AND_BACK, shininess);
291        stream >> tmp;
292        float transparency;
293        stream >> transparency;
294        mMaterial->setTransparency(osg::Material::FRONT_AND_BACK, transparency);
295        mTranslucent = 0 < transparency;
296
297        // must correspond to the material we use for the color array below
298        mMaterial->setColorMode(osg::Material::DIFFUSE);
299        // this must be done past the transparency setting ...
300        (*mColorArray)[0] = mMaterial->getDiffuse(osg::Material::FRONT_AND_BACK);
301    }
302
303    void toStateSet(osg::StateSet* stateSet) const
304    {
305        stateSet->setAttribute(mMaterial.get());
306        if (mTranslucent)
307            setTranslucent(stateSet);
308    }
309
310    osg::Vec4Array* getColorArray() const
311    {
312        return mColorArray.get();
313    }
314
315private:
316    osg::ref_ptr<osg::Material> mMaterial;
317    osg::ref_ptr<osg::Vec4Array> mColorArray;
318    bool mTranslucent;
319};
320
321class TextureData
322{
323  public:
324    TextureData() :
325        mTranslucent(false),
326        mRepeat(true)
327    {
328    }
329
330    bool setTexture(const std::string& name, const osgDB::ReaderWriter::Options* options, osg::TexEnv* modulateTexEnv)
331    {
332        mTexture2DRepeat = new osg::Texture2D;
333        mTexture2DRepeat->setDataVariance(osg::Object::STATIC);
334        mTexture2DRepeat->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
335        mTexture2DRepeat->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
336
337        mTexture2DClamp = new osg::Texture2D;
338        mTexture2DClamp->setDataVariance(osg::Object::STATIC);
339        mTexture2DClamp->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE);
340        mTexture2DClamp->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE);
341
342        std::string absFileName = osgDB::findDataFile(name, options);
343        if (absFileName.empty())
344        {
345            osg::notify(osg::FATAL) << "osgDB ac3d reader: could not find texture \"" << name << "\"" << std::endl;
346            return false;
347        }
348        mImage = osgDB::readRefImageFile(absFileName, options);
349        if (!mImage.valid())
350        {
351            osg::notify(osg::FATAL) << "osgDB ac3d reader: could not read texture \"" << name << "\"" << std::endl;
352            return false;
353        }
354        mTexture2DRepeat->setImage(mImage.get());
355        mTexture2DClamp->setImage(mImage.get());
356        mTranslucent = mImage->isImageTranslucent();
357
358        // Use a shared modulate TexEnv
359        mModulateTexEnv = modulateTexEnv;
360
361        return true;
362    }
363    void setRepeat(bool repeat)
364    {
365        mRepeat = repeat;
366    }
367    bool valid() const
368    {
369        return mImage.valid();
370    }
371    std::string getFileName() const
372    {
373        if (!mImage.valid())
374            return std::string();
375        return mImage->getFileName();
376    }
377    void toTextureStateSet(osg::StateSet* stateSet) const
378    {
379        if (!valid())
380            return;
381        stateSet->setTextureAttribute(0, mModulateTexEnv.get());
382        if (mRepeat)
383           stateSet->setTextureAttribute(0, mTexture2DRepeat.get());
384        else
385           stateSet->setTextureAttribute(0, mTexture2DClamp.get());
386        stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
387        if (mTranslucent)
388            setTranslucent(stateSet);
389    }
390private:
391    osg::ref_ptr<osg::TexEnv> mModulateTexEnv;
392    osg::ref_ptr<osg::Texture2D> mTexture2DClamp;
393    osg::ref_ptr<osg::Texture2D> mTexture2DRepeat;
394    osg::ref_ptr<osg::Image> mImage;
395    bool mTranslucent;
396    bool mRepeat;
397};
398
399class FileData
400{
401  public:
402    FileData(const osgDB::ReaderWriter::Options* options) :
403        mOptions(options),
404        mLightIndex(1)
405    {
406        mModulateTexEnv = new osg::TexEnv;
407        mModulateTexEnv->setDataVariance(osg::Object::STATIC);
408        mModulateTexEnv->setMode(osg::TexEnv::MODULATE);
409    }
410
411    TextureData toTextureData(const std::string& texName)
412    {
413        // If it is already there, use this
414        TextureDataMap::iterator i = mTextureStates.find(texName);
415        if (i != mTextureStates.end())
416            return i->second;
417        // Try to load that texture.
418        TextureData textureData;
419        textureData.setTexture(texName, mOptions.get(), mModulateTexEnv.get());
420        if (textureData.valid()) {
421            mTextureStates[texName] = textureData;
422            return textureData;
423        }
424        // still no joy?, try with the stripped filename if this is different
425        // Try the pure file name if it is different
426        std::string simpleTexName = osgDB::getSimpleFileName(texName);
427        if (simpleTexName != texName)
428            return toTextureData(simpleTexName);
429
430        // Nothing that worked, return invalid data
431        return TextureData();
432    }
433
434    osg::Light* getNextLight()
435    {
436        osg::Light* light = new osg::Light;
437        light->setDataVariance(osg::Object::STATIC);
438        light->setLightNum(mLightIndex++);
439        return light;
440    }
441
442    void addMaterial(const MaterialData& material)
443    {
444        mMaterials.push_back(material);
445    }
446    unsigned getNumMaterials() const
447    {
448        return mMaterials.size();
449    }
450    const MaterialData& getMaterial(unsigned idx) const
451    {
452        return mMaterials[idx];
453    }
454
455private:
456    /// Stores the ac3d file reader options, only used for reading texture files
457    osg::ref_ptr<osgDB::ReaderWriter::Options const> mOptions;
458
459    /// The list of ac3d MATERIALS
460    std::vector<MaterialData> mMaterials;
461
462    /// Local per model texture attribute cache.
463    /// ... images are usualy cached in the registries object cache
464    typedef std::map<std::string, TextureData> TextureDataMap;
465    TextureDataMap mTextureStates;
466    /// A common shared TexEnv set to modulate
467    osg::ref_ptr<osg::TexEnv> mModulateTexEnv;
468
469    /// Hack to include light nodes from ac3d into the scenegraph
470    unsigned mLightIndex;
471};
472
473struct RefData {
474    RefData(const osg::Vec3& _weightedNormal, const osg::Vec2& _texCoord, bool _smooth) :
475        weightedFlatNormal(_weightedNormal),
476        weightedFlatNormalLength(_weightedNormal.length()),
477        texCoord(_texCoord),
478        smooth(_smooth)
479    { }
480    // weighted flat surface normal
481    osg::Vec3 weightedFlatNormal;
482    float weightedFlatNormalLength;
483    osg::Vec2 texCoord;
484    // resulting vertex normal
485    osg::Vec3 finalNormal;
486    // if zero no need to smooth
487    unsigned smooth;
488};
489
490struct VertexData {
491    VertexData(const osg::Vec3& vertex) : _vertex(vertex) {}
492    unsigned addRefData(const RefData& refData)
493    {
494        unsigned index = _refs.size();
495        _refs.push_back(refData);
496        return index;
497    }
498
499    void collect(float cosCreaseAngle, const RefData& ref)
500    {
501        unsigned size = _refs.size();
502        for (unsigned i = 0; i < size; ++i)
503        {
504            if (_refs[i].smooth == ~0u)
505            {
506                float dot = _refs[i].weightedFlatNormal*ref.weightedFlatNormal;
507                float lengths = _refs[i].weightedFlatNormalLength*ref.weightedFlatNormalLength;
508                if (cosCreaseAngle*lengths <= dot)
509                {
510                    // Ok put that into the current set
511                    _refs[i].smooth = ref.smooth;
512                    collect(cosCreaseAngle, _refs[i]);
513                }
514            }
515        }
516    }
517
518    void smoothNormals(float cosCreaseAngle)
519    {
520        // compute sets of vertices smoothed to the same normal
521        // if smooth is zero we do not need to smooth
522        // in a first pass mark all refs not yet in a set to ~0u
523        unsigned size = _refs.size();
524        for (unsigned i = 0; i < size; ++i)
525        {
526            if (_refs[i].smooth)
527            {
528                _refs[i].smooth = ~0u;
529            }
530        }
531        // Now collect the sets
532        unsigned currentSet = 1;
533        for (unsigned i = 0; i < size; ++i)
534        {
535            if (_refs[i].smooth == ~0u)
536            {
537                _refs[i].smooth = currentSet++;
538                collect(cosCreaseAngle, _refs[i]);
539            }
540        }
541        // smooth and normalize the sets
542        for (--currentSet; 0 < currentSet; --currentSet)
543        {
544            osg::Vec3 normal(0, 0, 0);
545            for (unsigned i = 0; i < size; ++i)
546            {
547                if (_refs[i].smooth == currentSet)
548                {
549                    normal += _refs[i].weightedFlatNormal;
550                }
551            }
552            normal.normalize();
553            for (unsigned i = 0; i < size; ++i)
554            {
555                if (_refs[i].smooth == currentSet)
556                {
557                  _refs[i].finalNormal = normal;
558                }
559            }
560        }
561
562        // normalize the ones which do not need smoothing
563        for (unsigned i = 0; i < size; ++i)
564        {
565            if (_refs[i].smooth == 0)
566            {
567                _refs[i].finalNormal = _refs[i].weightedFlatNormal;
568                _refs[i].finalNormal.normalize();
569            }
570        }
571    }
572    osg::Vec3 _vertex;
573    std::vector<RefData> _refs;
574};
575struct VertexIndex {
576    VertexIndex(unsigned _vertexIndex = 0, unsigned _refIndex = 0) :
577        vertexIndex(_vertexIndex), refIndex(_refIndex)
578    { }
579    unsigned vertexIndex;
580    unsigned refIndex;
581};
582
583class VertexSet : public osg::Referenced {
584public:
585    VertexSet() : _dirty(true)
586    { }
587    void reserve(unsigned n)
588    {
589        _vertices.reserve(n);
590    }
591    unsigned size() const
592    {
593        return _vertices.size();
594    }
595    void setCreaseAngle(float crease)
596    {
597        _dirty = true;
598        if (crease <= 0)
599            _cosCreaseAngle = 1;
600        else if (180 <= crease)
601            _cosCreaseAngle = -1;
602        else
603            _cosCreaseAngle = cosf(osg::DegreesToRadians(crease));
604    }
605    void addVertex(const osg::Vec3& vertex)
606    {
607        _dirty = true;
608        _vertices.push_back(vertex);
609    }
610    const osg::Vec3& getVertex(unsigned index)
611    {
612        return _vertices[index]._vertex;
613    }
614    const osg::Vec3& getVertex(const VertexIndex& vertexIndex)
615    {
616        return _vertices[vertexIndex.vertexIndex]._vertex;
617    }
618    const osg::Vec3& getNormal(const VertexIndex& vertexIndex)
619    {
620        if (_dirty)
621            smoothNormals();
622        return _vertices[vertexIndex.vertexIndex]._refs[vertexIndex.refIndex].finalNormal;
623    }
624    const osg::Vec2& getTexCoord(const VertexIndex& vertexIndex)
625    {
626        return _vertices[vertexIndex.vertexIndex]._refs[vertexIndex.refIndex].texCoord;
627    }
628
629    VertexIndex addRefData(unsigned i, const RefData& refData)
630    {
631         if (_vertices.size() <= i)
632         {
633             osg::notify(osg::FATAL) << "osgDB ac3d reader: internal error, got invalid vertex index!" << std::endl;
634             return VertexIndex(0, 0);
635         }
636        _dirty = true;
637        return VertexIndex(i, _vertices[i].addRefData(refData));
638    }
639
640private:
641    void smoothNormals()
642    {
643        std::vector<VertexData>::iterator i;
644        for (i = _vertices.begin(); i != _vertices.end(); ++i)
645        {
646            i->smoothNormals(_cosCreaseAngle);
647        }
648        _dirty = false;
649    }
650
651    std::vector<VertexData> _vertices;
652    float _cosCreaseAngle;
653    bool _dirty;
654};
655
656
657class PrimitiveBin : public osg::Referenced
658{
659  public:
660    PrimitiveBin(unsigned flags, VertexSet* vertexSet) :
661        _geode(new osg::Geode),
662        _vertexSet(vertexSet),
663        _flags(flags)
664    {
665        _geode->setDataVariance(osg::Object::STATIC);
666    }
667
668    virtual bool beginPrimitive(unsigned nRefs) = 0;
669    virtual bool vertex(unsigned vertexIndex, const osg::Vec2& texCoord) = 0;
670    virtual bool endPrimitive() = 0;
671
672    virtual osg::Geode* finalize(const MaterialData& material, const TextureData& textureData) = 0;
673
674  protected:
675    bool isLineLoop() const
676    {
677        return (_flags & SurfaceTypeLineLoop)!=0;
678    }
679    bool isLineStrip() const
680    {
681        return (_flags & SurfaceTypeLineStrip)!=0;
682    }
683    bool isTwoSided() const
684    {
685        return (_flags & SurfaceTwoSided)!=0;
686    }
687    bool isSmooth() const
688    {
689        return (_flags & SurfaceShaded)!=0;
690    }
691
692    osg::ref_ptr<osg::Geode> _geode;
693    osg::ref_ptr<VertexSet> _vertexSet;
694
695  private:
696    unsigned _flags;
697};
698
699class LineBin : public PrimitiveBin
700{
701  private:
702    osg::ref_ptr<osg::Geometry> _geometry;
703    osg::ref_ptr<osg::Vec3Array> _vertices;
704    osg::ref_ptr<osg::Vec2Array> _texCoords;
705    struct Ref {
706      osg::Vec2 texCoord;
707      unsigned index;
708    };
709    std::vector<Ref> _refs;
710
711  public:
712    LineBin(unsigned flags, VertexSet* vertexSet) :
713        PrimitiveBin(flags, vertexSet),
714        _geometry(new osg::Geometry),
715        _vertices(new osg::Vec3Array),
716        _texCoords(new osg::Vec2Array)
717    {
718        _geometry->setDataVariance(osg::Object::STATIC);
719        _vertices->setDataVariance(osg::Object::STATIC);
720        _texCoords->setDataVariance(osg::Object::STATIC);
721        _geometry->setVertexArray(_vertices.get());
722        _geometry->setTexCoordArray(0, _texCoords.get());
723        osg::StateSet* stateSet = _geode->getOrCreateStateSet();
724        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
725    }
726
727    virtual bool beginPrimitive(unsigned nRefs)
728    {
729        // Check if we have enough for a line or someting broken ...
730        if (nRefs < 2) {
731            osg::notify(osg::WARN) << "osgDB ac3d reader: detected line with less than 2 vertices!" << std::endl;
732            return false;
733        }
734
735        _refs.reserve(nRefs);
736        _refs.resize(0);
737        return true;
738    }
739    virtual bool vertex(unsigned vertexIndex, const osg::Vec2& texCoord)
740    {
741        Ref ref;
742        ref.index = vertexIndex;
743        ref.texCoord = texCoord;
744        _refs.push_back(ref);
745        return true;
746    }
747    virtual bool endPrimitive()
748    {
749        GLint type;
750        if (isLineLoop())
751            type = osg::PrimitiveSet::LINE_LOOP;
752        else if (isLineStrip())
753            type = osg::PrimitiveSet::LINE_STRIP;
754        else {
755            osg::notify(osg::FATAL) << "osgDB ac3d reader: non surface flags in surface bin!" << std::endl;
756            return false;
757        }
758        unsigned nRefs = _refs.size();
759        unsigned start = _vertices->size();
760        for (unsigned i = 0; i < nRefs; ++i) {
761            osg::Vec3 vertex = _vertexSet->getVertex(_refs[i].index);
762            _vertices->push_back(vertex);
763            _texCoords->push_back(_refs[i].texCoord);
764        }
765        _geometry->addPrimitiveSet(new osg::DrawArrays(type, start, nRefs));
766
767        return true;
768    }
769
770    virtual osg::Geode* finalize(const MaterialData& material, const TextureData& textureData)
771    {
772        _geode->addDrawable(_geometry.get());
773        material.toStateSet(_geode->getOrCreateStateSet());
774        _geometry->setColorArray(material.getColorArray());
775        _geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
776        _geometry->setNormalBinding(osg::Geometry::BIND_OFF);
777        return _geode.get();
778    }
779};
780
781
782
783class SurfaceBin : public PrimitiveBin {
784  private:
785    struct Ref {
786        osg::Vec2 texCoord;
787        unsigned index;
788    };
789    std::vector<Ref> _refs;
790 
791    struct TriangleData {
792        VertexIndex index[3];
793    };
794    std::vector<TriangleData> _triangles;
795 
796    struct QuadData {
797        VertexIndex index[4];
798    };
799    std::vector<QuadData> _quads;
800
801    struct PolygonData {
802        std::vector<VertexIndex> index;
803    };
804    std::vector<PolygonData> _polygons;
805    std::vector<PolygonData> _toTessellatePolygons;
806
807  public:
808    SurfaceBin(unsigned flags, VertexSet *vertexSet) :
809        PrimitiveBin(flags, vertexSet)
810    { }
811
812    virtual bool beginPrimitive(unsigned nRefs)
813    {
814        _refs.reserve(nRefs);
815        _refs.clear();
816
817        // Check if we have enough for a line or someting broken ...
818        if (nRefs < 3) {
819            osg::notify(osg::WARN) << "osgDB ac3d reader: detected surface with less than 3 vertices!" << std::endl;
820            return false;
821        }
822        return true;
823    }
824    virtual bool vertex(unsigned vertexIndex, const osg::Vec2& texCoord)
825    {
826        Ref ref;
827        ref.index = vertexIndex;
828        ref.texCoord = texCoord;
829        _refs.push_back(ref);
830        return true;
831    }
832    virtual bool endPrimitive()
833    {
834        unsigned nRefs = _refs.size();
835
836        // Compute the normal times the enclosed area.
837        // During that check if the surface is convex. If so, put in the surface as such.
838        bool needTessellation = false;
839        osg::Vec3 prevEdgeNormal;
840        osg::Vec3 weightedNormal(0, 0, 0);
841        osg::Vec3 v0 = _vertexSet->getVertex(_refs[0].index);
842        for (unsigned i = 2; i < nRefs; ++i) {
843            osg::Vec3 side1 = _vertexSet->getVertex(_refs[i-1].index) - v0;
844            osg::Vec3 side2 = _vertexSet->getVertex(_refs[i].index) - v0;
845            osg::Vec3 newNormal = side1^side2;
846            if (!needTessellation)
847            {
848                if (3 < nRefs && newNormal*weightedNormal < 0)
849                {
850                    needTessellation = true;
851                }
852                if (i < 3)
853                {
854                    prevEdgeNormal = newNormal;
855                }
856                else // if (3 <= i) // due to the for loop
857                {
858                    osg::Vec3 sideim1 = _vertexSet->getVertex(_refs[i-1].index) - _vertexSet->getVertex(_refs[i-2].index);
859                    osg::Vec3 sidei = _vertexSet->getVertex(_refs[i].index) - _vertexSet->getVertex(_refs[i-2].index);
860                    osg::Vec3 edgeNormal = sideim1^sidei;
861                    if (edgeNormal*prevEdgeNormal < 0)
862                    {
863                        needTessellation = true;
864                    }
865                    prevEdgeNormal = edgeNormal;
866                }
867            }
868
869            weightedNormal += newNormal;
870        }
871       
872        if (needTessellation)
873        {
874            unsigned polygonIndex = _toTessellatePolygons.size();
875            _toTessellatePolygons.resize(polygonIndex + 1);
876            for (unsigned i = 0; i < nRefs; ++i) {
877                RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
878                VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
879                _toTessellatePolygons[polygonIndex].index.push_back(vertexIndex);
880            }
881        }
882        else if (nRefs == 3)
883        {
884            unsigned triangleIndex = _triangles.size();
885            _triangles.resize(triangleIndex + 1);
886            for (unsigned i = 0; i < 3; ++i) {
887                RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
888                VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
889                _triangles[triangleIndex].index[i] = vertexIndex;
890            }
891        }
892        else if (nRefs == 4)
893        {
894            unsigned quadIndex = _quads.size();
895            _quads.resize(quadIndex + 1);
896            for (unsigned i = 0; i < 4; ++i) {
897                RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
898                VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
899                _quads[quadIndex].index[i] = vertexIndex;
900            }
901        }
902        else
903        {
904            unsigned polygonIndex = _polygons.size();
905            _polygons.resize(polygonIndex + 1);
906            for (unsigned i = 0; i < nRefs; ++i) {
907                RefData refData(weightedNormal, _refs[i].texCoord, isSmooth());
908                VertexIndex vertexIndex = _vertexSet->addRefData(_refs[i].index, refData);
909                _polygons[polygonIndex].index.push_back(vertexIndex);
910            }
911        }
912        return true;
913    }
914
915    void pushVertex(const VertexIndex& vertexIndex, osg::Vec3Array* vertexArray,
916                    osg::Vec3Array* normalArray, osg::Vec2Array* texcoordArray)
917    {
918        vertexArray->push_back(_vertexSet->getVertex(vertexIndex));
919        normalArray->push_back(_vertexSet->getNormal(vertexIndex));
920        if (texcoordArray)
921            texcoordArray->push_back(_vertexSet->getTexCoord(vertexIndex));
922    }
923
924    virtual osg::Geode* finalize(const MaterialData& material, const TextureData& textureData)
925    {
926        osg::StateSet* stateSet = _geode->getOrCreateStateSet();
927        material.toStateSet(stateSet);
928        textureData.toTextureStateSet(stateSet);
929        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
930
931        // Single- or doublesided culling
932        if (isTwoSided()) {
933            stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
934        } else {
935            osg::CullFace* cullFace = new osg::CullFace;
936            cullFace->setDataVariance(osg::Object::STATIC);
937            cullFace->setMode(osg::CullFace::BACK);
938            stateSet->setAttribute(cullFace);
939            stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
940        }
941
942        // Flat or smooth shading
943        osg::ShadeModel* shadeModel = new osg::ShadeModel;
944        shadeModel->setDataVariance(osg::Object::STATIC);
945        if (isSmooth())
946            shadeModel->setMode(osg::ShadeModel::SMOOTH);
947        else
948            shadeModel->setMode(osg::ShadeModel::FLAT);
949        stateSet->setAttribute(shadeModel);
950       
951        // Set up the arrays, allways store texture coords, may be we need them later ...
952        osg::Geometry* geometry = new osg::Geometry;
953        _geode->addDrawable(geometry);
954        geometry->setDataVariance(osg::Object::STATIC);
955        geometry->setColorArray(material.getColorArray());
956        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
957        geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
958        osg::Vec3Array* normalArray = new osg::Vec3Array;
959        normalArray->setDataVariance(osg::Object::STATIC);
960        geometry->setNormalArray(normalArray);
961        osg::Vec3Array* vertexArray = new osg::Vec3Array;
962        vertexArray->setDataVariance(osg::Object::STATIC);
963        geometry->setVertexArray(vertexArray);
964        osg::Vec2Array* texcoordArray = 0;
965        if (textureData.valid())
966        {
967            texcoordArray = new osg::Vec2Array;
968            texcoordArray->setDataVariance(osg::Object::STATIC);
969            geometry->setTexCoordArray(0, texcoordArray);
970        }
971
972        // At first handle the the polygons to tessellate, fix them and append the other polygons later
973        if (!_toTessellatePolygons.empty())
974        {
975            unsigned start = vertexArray->size();
976            osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON, start);
977            drawArrayLengths->reserve(_toTessellatePolygons.size());
978            for (unsigned i = 0; i < _toTessellatePolygons.size(); ++i)
979            {
980                for (unsigned j = 0; j < _toTessellatePolygons[i].index.size(); ++j)
981                {
982                    pushVertex(_toTessellatePolygons[i].index[j], vertexArray, normalArray, texcoordArray);
983                }
984                drawArrayLengths->push_back(_toTessellatePolygons[i].index.size());
985            }
986            geometry->addPrimitiveSet(drawArrayLengths);
987
988            osgUtil::Tessellator Tessellator;
989            Tessellator.retessellatePolygons(*geometry);
990        }
991
992        // handle triangles
993        if (!_triangles.empty())
994        {
995            unsigned start = vertexArray->size();
996            for (unsigned i = 0; i < _triangles.size(); ++i)
997            {
998                for (unsigned j = 0; j < 3; ++j)
999                {
1000                    pushVertex(_triangles[i].index[j], vertexArray, normalArray, texcoordArray);
1001                }
1002            }
1003            osg::DrawArrays* drawArray = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, start, 3*_triangles.size());
1004            geometry->addPrimitiveSet(drawArray);
1005        }
1006
1007        // handle quads
1008        if (!_quads.empty())
1009        {
1010            unsigned start = vertexArray->size();
1011            for (unsigned i = 0; i < _quads.size(); ++i)
1012            {
1013                for (unsigned j = 0; j < 4; ++j)
1014                {
1015                    pushVertex(_quads[i].index[j], vertexArray, normalArray, texcoordArray);
1016                }
1017            }
1018            osg::DrawArrays* drawArray = new osg::DrawArrays(osg::PrimitiveSet::QUADS, start, 4*_quads.size());
1019            geometry->addPrimitiveSet(drawArray);
1020        }
1021
1022        // handle polygons
1023        if (!_polygons.empty())
1024        {
1025            unsigned start = vertexArray->size();
1026            osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON, start);
1027            drawArrayLengths->reserve(_polygons.size());
1028            for (unsigned i = 0; i < _polygons.size(); ++i)
1029            {
1030                for (unsigned j = 0; j < _polygons[i].index.size(); ++j)
1031                {
1032                    pushVertex(_polygons[i].index[j], vertexArray, normalArray, texcoordArray);
1033                }
1034                drawArrayLengths->push_back(_polygons[i].index.size());
1035            }
1036            geometry->addPrimitiveSet(drawArrayLengths);
1037        }
1038
1039        return _geode.get();
1040    }
1041};
1042
1043struct Bins
1044{
1045    PrimitiveBin* getOrCreatePrimitiveBin(unsigned flags, VertexSet* vertexSet)
1046    {
1047        if ((flags & SurfaceTypeLineLoop) || (flags & SurfaceTypeLineStrip))
1048        {
1049            if (!lineBin.valid())
1050            {
1051                lineBin = new LineBin(flags, vertexSet);
1052            }
1053            return lineBin.get();
1054        }
1055        else if (flags & SurfaceShaded)
1056        {
1057            if (flags & SurfaceTwoSided)
1058            {
1059                if (!smoothDoubleSurfaceBin.valid())
1060                {
1061                    smoothDoubleSurfaceBin = new SurfaceBin(flags, vertexSet);
1062                }
1063                return smoothDoubleSurfaceBin.get();
1064            }
1065            else
1066            {
1067                if (!smoothSingleSurfaceBin.valid())
1068                {
1069                    smoothSingleSurfaceBin = new SurfaceBin(flags, vertexSet);
1070                }
1071                return smoothSingleSurfaceBin.get();
1072            }
1073        }
1074        else
1075        {
1076            if (flags & SurfaceTwoSided)
1077            {
1078                if (!flatDoubleSurfaceBin.valid())
1079                {
1080                    flatDoubleSurfaceBin = new SurfaceBin(flags, vertexSet);
1081                }
1082                return flatDoubleSurfaceBin.get();
1083            }
1084            else
1085            {
1086                if (!flatSingleSurfaceBin.valid())
1087                {
1088                    flatSingleSurfaceBin = new SurfaceBin(flags, vertexSet);
1089                }
1090                return flatSingleSurfaceBin.get();
1091            }
1092        }
1093    }
1094    void finalize(osg::Group* group, const MaterialData& material, const TextureData& textureData)
1095    {
1096        if (lineBin.valid())
1097        {
1098            group->addChild(lineBin->finalize(material, textureData));
1099        }
1100        if (smoothDoubleSurfaceBin.valid())
1101        {
1102            group->addChild(smoothDoubleSurfaceBin->finalize(material, textureData));
1103        }
1104        if (smoothSingleSurfaceBin.valid())
1105        {
1106            group->addChild(smoothSingleSurfaceBin->finalize(material, textureData));
1107        }
1108        if (flatDoubleSurfaceBin.valid())
1109        {
1110            group->addChild(flatDoubleSurfaceBin->finalize(material, textureData));
1111        }
1112        if (flatSingleSurfaceBin.valid())
1113        {
1114            group->addChild(flatSingleSurfaceBin->finalize(material, textureData));
1115        }
1116    }
1117
1118private:
1119    osg::ref_ptr<LineBin> lineBin;
1120    osg::ref_ptr<SurfaceBin> flatDoubleSurfaceBin;
1121    osg::ref_ptr<SurfaceBin> flatSingleSurfaceBin;
1122    osg::ref_ptr<SurfaceBin> smoothDoubleSurfaceBin;
1123    osg::ref_ptr<SurfaceBin> smoothSingleSurfaceBin;
1124};
1125
1126osg::Node*
1127readObject(std::istream& stream, FileData& fileData, const osg::Matrix& parentTransform, TextureData textureData)
1128{
1129    // most of this logic came from Andy Colebourne (developer of the AC3D editor) so it had better be right!
1130
1131    // The transform configured in this current object level
1132    osg::Matrix transform;
1133    // The vertex pool in this object
1134    osg::ref_ptr<VertexSet> vertexSet = new VertexSet;
1135    osg::ref_ptr<osg::Group> group = new osg::Group;
1136    group->setDataVariance(osg::Object::STATIC);
1137    osg::Vec2 textureOffset(0, 0);
1138    osg::Vec2 textureRepeat(1, 1);
1139    float creaseAngle = 61;
1140    unsigned objectType = ObjectTypeGroup;
1141   
1142    while (!stream.eof() && stream.good()) {
1143        std::string token;
1144        stream >> token;
1145     
1146        if (token == "MATERIAL") {
1147            MaterialData mat;
1148            mat.readMaterial(stream);
1149            fileData.addMaterial(mat);
1150        }
1151        else if (token == "OBJECT") {
1152            std::string type;
1153            stream >> type;
1154           
1155            if (type == "group")
1156                objectType = ObjectTypeGroup;
1157            else if (type == "light")
1158                objectType = ObjectTypeLight;
1159            else if (type == "world")
1160                objectType = ObjectTypeGroup;
1161            else
1162                objectType = ObjectTypeNormal;
1163        }
1164        else if (token == "crease") {
1165            stream >> creaseAngle;
1166        }
1167        else if (token == "data") {
1168            int len;
1169            stream >> len;
1170            std::vector<char> tmp(len);
1171            stream.read(&(tmp[0]), len);
1172        }
1173        else if (token == "name") {
1174            group->setName(readString(stream));
1175        }
1176        else if (token == "texture") {
1177            // read the texture name
1178            textureData = fileData.toTextureData(readString(stream));
1179        }
1180        else if (token == "texrep") {
1181            stream >> textureRepeat[0] >> textureRepeat[1];
1182//             if (textureRepeat[0] == 0.0f && textureRepeat[1] == 0.0f)
1183//                 textureData.setRepeat(false);
1184//             else
1185//                 textureData.setRepeat(true);
1186        }
1187        else if (token == "texoff") {
1188            stream >> textureOffset[0] >> textureOffset[1];
1189        }
1190        else if (token == "rot") {
1191            for (unsigned n = 0; n < 3; ++n)
1192                for (unsigned m = 0; m < 3; ++m)
1193                    stream >> transform(m, n);
1194        }
1195        else if (token == "loc") {
1196            for (unsigned n = 0; n < 3; ++n)
1197                stream >> transform(3, n);
1198        }
1199        else if (token == "url") {
1200            std::string url;
1201            stream >> url;
1202            group->addDescription(url);
1203        }
1204        else if (token == "numvert") {
1205            osg::Matrix currentTransform = transform*parentTransform;
1206           
1207            unsigned num;
1208            stream >> num;
1209            if (num != 0) {
1210                vertexSet->reserve(num);
1211             
1212                for (unsigned n = 0; n < num; ++n) {
1213                    osg::Vec3 p;
1214                    stream >> p[0] >> p[1] >> p[2];
1215                    vertexSet->addVertex(currentTransform.preMult(p));
1216                }
1217            }
1218        }
1219        else if (token == "numsurf") {
1220            unsigned num;
1221            stream >> num;
1222            if (0 < num) {
1223                // list of materials required- generate one geode per material
1224                std::vector<Bins> primitiveBins(fileData.getNumMaterials());
1225                vertexSet->setCreaseAngle(creaseAngle);
1226               
1227                for (unsigned n = 0; n < num; ++n) {
1228                    std::string token;
1229                    stream >> token;
1230                   
1231                    if (token != "SURF") {
1232                        osg::notify(osg::FATAL) << "osgDB ac3d reader: expected SURF line while reading object \""
1233                                                << group->getName() << "\"!" << std::endl;
1234                        return group.release();
1235                    }
1236                   
1237                    stream >> token;
1238                    unsigned flags = strtol(token.c_str(), NULL, 0);
1239                   
1240                    stream >> token;
1241                    if (token != "mat") {
1242                        osg::notify(osg::FATAL) << "osgDB ac3d reader: expected mat line while reading object \""
1243                                                << group->getName() << "\"!" << std::endl;
1244                        return group.release();
1245                    }
1246                   
1247                    // read the material index
1248                    unsigned matIdx;
1249                    stream >> matIdx;
1250                    if (primitiveBins.size() <= matIdx) {
1251                        osg::notify(osg::FATAL) << "osgDB ac3d reader: invalid material number while reading object \""
1252                                                << group->getName() << "\"" << std::endl;
1253                        return group.release();
1254                    }
1255                   
1256                    // now get the correct PrimitiveBin
1257                    PrimitiveBin* primitiveBin = 0;
1258                    primitiveBin = primitiveBins[matIdx].getOrCreatePrimitiveBin(flags, vertexSet.get());
1259                    if (!primitiveBin) {
1260                        osg::notify(osg::FATAL) << "osgDB ac3d reader: unexpected primitive flags while reading object \""
1261                                                << group->getName() << "\"" << std::endl;
1262                        return group.release();
1263                    }
1264                   
1265                    // read the refs
1266                    stream >> token;
1267                    if (token != "refs") {
1268                        osg::notify(osg::FATAL) << "osgDB ac3d reader: expected refs line while reading object \""
1269                                                << group->getName() << "\"" << std::endl;
1270                        return group.release();
1271                    }
1272                   
1273                    unsigned nRefs = 0;
1274                    stream >> nRefs;
1275                    if (!stream) {
1276                        osg::notify(osg::FATAL) << "osgDB ac3d reader: could not read number of refs while reading object \""
1277                                                << group->getName() << "\"" << std::endl;
1278                        return group.release();
1279                    }
1280                   
1281                    // in case this is an invalid refs count for this primitive
1282                    // read further, but do not store that primitive
1283                    bool acceptPrimitive = primitiveBin->beginPrimitive(nRefs);
1284                    for (unsigned i = 0; i < nRefs; ++i) {
1285                        // Read the vertex index
1286                        unsigned index;
1287                        stream >> index;
1288                        if (vertexSet->size() <= index)
1289                        {
1290                            osg::notify(osg::FATAL) << "osgDB ac3d reader: invalid ref vertex index while reading object \""
1291                                                    << group->getName() << "\"" << std::endl;
1292                            return group.release();
1293                        }
1294                       
1295                        // Read the texture corrdinates
1296                        osg::Vec2 texCoord;
1297                        stream >> texCoord[0] >> texCoord[1];
1298                        if (!stream) {
1299                            osg::notify(osg::WARN) << "osgDB ac3d reader: could not parse texture coords while reading object \""
1300                                                   << group->getName() << "\" setting to (0,0)" << std::endl;
1301                            stream.clear();
1302                            std::string dummy;
1303                            std::getline(stream, dummy);
1304                        }
1305                       
1306                        if (acceptPrimitive)
1307                        {
1308                            texCoord[0] = textureOffset[0] + texCoord[0]*textureRepeat[0];
1309                            texCoord[1] = textureOffset[1] + texCoord[1]*textureRepeat[1];
1310                       
1311                            if (!primitiveBin->vertex(index, texCoord))
1312                            {
1313                                return group.release();
1314                            }
1315                        }
1316                    }
1317                    if (acceptPrimitive)
1318                    {
1319                        if (!primitiveBin->endPrimitive())
1320                        {
1321                            return group.release();
1322                        }
1323                    }
1324                }
1325               
1326                for (unsigned i = 0; i < primitiveBins.size(); ++i)
1327                    primitiveBins[i].finalize(group.get(), fileData.getMaterial(i), textureData);
1328            }
1329        }
1330        else if (token == "kids") {
1331            unsigned num;
1332            stream >> num;
1333            if (num != 0) {
1334                for (unsigned n = 0; n < num; n++) {
1335                    osg::Node *k = readObject(stream, fileData, transform*parentTransform, textureData);
1336                    if (k == 0) {
1337                        osg::notify(osg::FATAL) << "osgDB ac3d reader: error reading child object" << std::endl;
1338                        return group.release();
1339                    }
1340                    else {
1341                        osg::LightSource *ls = dynamic_cast<osg::LightSource*>(k);
1342                        if (ls) {
1343                            osg::StateSet* lightStateSet = group->getOrCreateStateSet();
1344                            group->setStateSet(lightStateSet);
1345                            group->setCullingActive(false);
1346                            ls->setStateSetModes(*lightStateSet, osg::StateAttribute::ON);
1347                        }
1348                       
1349                        group->addChild(k);
1350                    }
1351                }
1352            }
1353            else if (objectType == ObjectTypeLight) { // add a light source to the scene 1 Nov 2003
1354                osg::Light* ac3dLight = fileData.getNextLight();
1355                osg::Matrix tt = transform*parentTransform;
1356                ac3dLight->setPosition(osg::Vec4(tt(3, 0), tt(3, 1), tt(3, 2), 1));
1357                ac3dLight->setDirection(osg::Matrix::transform3x3(osg::Vec3(0.0f, 0.0f, -1.0f), tt));
1358                ac3dLight->setAmbient(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
1359                ac3dLight->setDiffuse(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
1360                ac3dLight->setSpecular(osg::Vec4(1.0f,1.0f,0.5f,1.0f));
1361               
1362                osg::LightSource* ac3dLightSource = new osg::LightSource;
1363                ac3dLightSource->setDataVariance(osg::Object::STATIC);
1364                ac3dLightSource->setLight(ac3dLight);
1365                ac3dLightSource->setLocalStateSetModes(osg::StateAttribute::ON);
1366               
1367                // for some mad reason, you need to set this so that the light works.  WHY?
1368                return ac3dLightSource;
1369            }
1370            return group.release();
1371        }
1372    }
1373   
1374    return group.release();
1375}
1376
1377osg::Node*
1378readFile(std::istream& stream, const osgDB::ReaderWriter::Options* options)
1379{
1380    FileData fileData(options);
1381    osg::Matrix identityTransform;
1382    osg::Node* node = readObject(stream, fileData, identityTransform, TextureData());
1383    if (node)
1384      node->setName("World");
1385    return node;
1386}
1387
1388} // namespace ac3d
Note: See TracBrowser for help on using the browser.