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

Revision 10758, 47.8 kB (checked in by robert, 5 years ago)

Removed catch

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