root/OpenSceneGraph/trunk/src/osgPlugins/ac/ac3d.cpp @ 9527

Revision 9527, 48.0 kB (checked in by robert, 5 years ago)

Replaced readImageFile() usage with readRefImageFile() to prevent threading issues with caching of imagery in the osgDB::Registry cache.

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