root/OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp @ 9637

Revision 9637, 32.1 kB (checked in by robert, 5 years ago)

Warning fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[8]1#include <osg/Notify>
2#include <osg/Group>
3#include <osg/Geode>
[799]4#include <osg/Geometry>
[1078]5#include <osg/Texture2D>
[8]6#include <osg/Material>
7#include <osg/TexEnv>
8#include <osg/ref_ptr>
[868]9#include <osg/MatrixTransform>
[8]10
11#include <osgDB/Registry>
12#include <osgDB/FileUtils>
13#include <osgDB/FileNameUtils>
14#include <osgDB/ReadFile>
15
[2535]16#include <osgUtil/TriStripVisitor>
17
[445]18//MIKEC debug only for PrintVisitor
19#include <osg/NodeVisitor>
20
21
[1563]22#include "file.h"
23#include "mesh.h"
24#include "material.h"
25#include "vector.h"
26#include "matrix.h"
27#include "node.h"
28#include "quat.h"
[5453]29#include "readwrite.h"
[8]30
31#include <stdlib.h>
32#include <string.h>
33
34#include <set>
35#include <map>
[2772]36#include <iostream>
[8]37
[445]38using namespace std;
39using namespace osg;
40
41class PrintVisitor : public NodeVisitor
42{
43
44   public:
45   
[2772]46        PrintVisitor(std::ostream& out):
47            NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
48            _out(out)
[445]49        {
50            _indent = 0;
51            _step = 4;
52        }
53       
54        inline void moveIn() { _indent += _step; }
55        inline void moveOut() { _indent -= _step; }
56        inline void writeIndent()
57        {
[2772]58            for(int i=0;i<_indent;++i) _out << " ";
[445]59        }
60               
61        virtual void apply(Node& node)
62        {
63            moveIn();
[2772]64            writeIndent(); _out << node.className() <<std::endl;
[445]65            traverse(node);
66            moveOut();
67        }
68
69        virtual void apply(Geode& node)         { apply((Node&)node); }
70        virtual void apply(Billboard& node)     { apply((Geode&)node); }
[2772]71        virtual void apply(LightSource& node)   { apply((Group&)node); }
72        virtual void apply(ClipNode& node)      { apply((Group&)node); }
[445]73       
74        virtual void apply(Group& node)         { apply((Node&)node); }
75        virtual void apply(Transform& node)     { apply((Group&)node); }
[2772]76        virtual void apply(Projection& node)    { apply((Group&)node); }
[445]77        virtual void apply(Switch& node)        { apply((Group&)node); }
78        virtual void apply(LOD& node)           { apply((Group&)node); }
79
80   protected:
[9637]81
82        PrintVisitor& operator = (const PrintVisitor&) { return *this; }
83
[2772]84        std::ostream& _out;
[445]85        int _indent;
86        int _step;
87};
88
[8]89class ReaderWriter3DS : public osgDB::ReaderWriter
90{
91    public:
92
93        ReaderWriter3DS();
94
[3539]95        virtual const char* className() const { return "3DS Auto Studio Reader"; }
[8]96
[3694]97        virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const;
[8]98
99    protected:
100
101
[3691]102        class ReaderObject
103        {
104        public:
105            ReaderObject();
106       
107            typedef std::map<std::string,osg::StateSet*> StateSetMap;
108            typedef std::vector<int> FaceList;
109            typedef std::map<std::string,osg::StateSet*> GeoStateMap;
[445]110
[3691]111            osg::Texture2D* createTexture(Lib3dsTextureMap *texture,const char* label,bool& transparancy, const osgDB::ReaderWriter::Options* options);
112            osg::StateSet* createStateSet(Lib3dsMaterial *materials, const osgDB::ReaderWriter::Options* options);
113            osg::Drawable* createDrawable(Lib3dsMesh *meshes,FaceList& faceList, Lib3dsMatrix* matrix);
[445]114
[3691]115            std::string _directory;
116            bool _useSmoothingGroups;
117            bool _usePerVertexNormals;
118
119            // MIKEC
120            osg::Node* processMesh(StateSetMap& drawStateMap,osg::Group* parent,Lib3dsMesh* mesh, Lib3dsMatrix* matrix);
121            osg::Node* processNode(StateSetMap drawStateMap,Lib3dsFile *f,Lib3dsNode *node);
122        };
[8]123};
124
125// now register with Registry to instantiate the above
126// reader/writer.
[7076]127REGISTER_OSGPLUGIN(3ds, ReaderWriter3DS)
[8]128
129ReaderWriter3DS::ReaderWriter3DS()
130{
[8578]131    supportsExtension("3ds","3D Studio model format");
132
[5453]133    setByteOrder();
134
135#if 0
136    osg::notify(osg::NOTICE)<<"3DS reader sizes:"<<std::endl;
137    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsBool)="<<sizeof(Lib3dsBool)<<std::endl;
138    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsByte)="<<sizeof(Lib3dsByte)<<std::endl;
139    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsWord)="<<sizeof(Lib3dsWord)<<std::endl;
140    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsDword)="<<sizeof(Lib3dsDword)<<std::endl;
141    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsIntb)="<<sizeof(Lib3dsIntb)<<std::endl;
142    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsIntw)="<<sizeof(Lib3dsIntw)<<std::endl;
143    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsIntd)="<<sizeof(Lib3dsIntd)<<std::endl;
144    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsFloat)="<<sizeof(Lib3dsFloat)<<std::endl;
145    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsDouble)="<<sizeof(Lib3dsDouble)<<std::endl;
146    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsVector)="<<sizeof(Lib3dsVector)<<std::endl;
147    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsTexel)="<<sizeof(Lib3dsTexel)<<std::endl;
148    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsQuat)="<<sizeof(Lib3dsQuat)<<std::endl;
149    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsMatrix)="<<sizeof(Lib3dsMatrix)<<std::endl;
150    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsRgb)="<<sizeof(Lib3dsRgb)<<std::endl;
151    osg::notify(osg::NOTICE)<<"  sizeof(Lib3dsRgba)="<<sizeof(Lib3dsRgba)<<std::endl;
152#endif
153
[3691]154}
155
156ReaderWriter3DS::ReaderObject::ReaderObject()
157{
[8]158    _useSmoothingGroups = true;
159    _usePerVertexNormals = true;
160}
161
162
[445]163/**
164    These print methods for 3ds hacking
165*/
166void pad(int level) {
[2772]167    for(int i=0;i<level;i++) std::cout<<"  ";
[445]168}
169void print(Lib3dsMesh *mesh,int level);
170void print(Lib3dsUserData *user,int level);
171void print(Lib3dsNodeData *user,int level);
172void print(Lib3dsObjectData *object,int level);
173void print(Lib3dsNode *node, int level);
[8]174
[445]175void print(Lib3dsMatrix matrix,int level) {
176    pad(level); cout << matrix[0][0] <<" "<< matrix[0][1] <<" "<< matrix[0][2] <<" "<< matrix[0][3] << endl;
177    pad(level); cout << matrix[1][0] <<" "<< matrix[1][1] <<" "<< matrix[1][2] <<" "<< matrix[1][3] << endl;
178    pad(level); cout << matrix[2][0] <<" "<< matrix[2][1] <<" "<< matrix[2][2] <<" "<< matrix[2][3] << endl;
179    pad(level); cout << matrix[3][0] <<" "<< matrix[3][1] <<" "<< matrix[3][2] <<" "<< matrix[3][3] << endl;
180}
181void print(Lib3dsMesh *mesh,int level) {
182    if (mesh) {
183        pad(level); cout << "mesh name " << mesh->name  << endl;
184        print(mesh->matrix,level);
185    } else {
186        pad(level); cout << "no mesh " << endl;
187    }
188}
189void print(Lib3dsUserData *user,int level) {
190    if (user) {
191        pad(level); cout << "user data" << endl;
192        //print(user->mesh,level+1);
193    } else {
194        pad(level); cout << "no user data" << endl;
195    }
196}
197void print(Lib3dsNodeData *node,int level) {
198    if (node) {
199        pad(level); cout << "node data:" << endl;
200        // nodedata->object is a union of many types
201        print((Lib3dsObjectData *)&node->object,level+1);
202    } else {
203        pad(level); cout << "no user data" << endl;
204    }
205}
206void print(Lib3dsObjectData *object,int level) {
207    if (object) {
208        pad(level); cout << "objectdata instance [" << object->instance << "]" << endl;
209        pad(level); cout << "pivot     " << object->pivot[0] <<" "<< object->pivot[1] <<" "<< object->pivot[2] << endl;
210        pad(level); cout << "pos       " << object->pos[0] <<" "<< object->pos[1] <<" "<< object->pos[2] << endl;
211        pad(level); cout << "scl       " << object->scl[0] <<" "<< object->scl[1] <<" "<< object->scl[2] << endl;
212        pad(level); cout << "rot       " << object->rot[0] <<" "<< object->rot[1] <<" "<< object->rot[2] <<" "<< object->rot[3] << endl;
213    } else {
214        pad(level); cout << "no object data" << endl;
215    }
216}
[8]217
[445]218void print(Lib3dsNode *node, int level) {
219   
220    pad(level); cout << "node name [" << node->name << "]" << endl;
221    pad(level); cout << "node id    " << node->node_id << endl;
222    pad(level); cout << "node parent id " << node->parent_id << endl;
223    pad(level); cout << "node matrix:" << endl;
224    print(node->matrix,level+1);
225    print(&node->data,level);
226    print(&node->user,level);
227   
[8]228
[445]229    for(Lib3dsNode *child=node->childs; child; child=child->next) {
230        print(child,level+1);
231    }
[8]232
[445]233}
[8]234
[6518]235void copyLib3dsMatrixToOsgMatrix(osg::Matrix& osg_matrix, const Lib3dsMatrix lib3ds_matrix)
236{
237    osg_matrix.set(
238        lib3ds_matrix[0][0],lib3ds_matrix[0][1],lib3ds_matrix[0][2],lib3ds_matrix[0][3],
239        lib3ds_matrix[1][0],lib3ds_matrix[1][1],lib3ds_matrix[1][2],lib3ds_matrix[1][3],
240        lib3ds_matrix[2][0],lib3ds_matrix[2][1],lib3ds_matrix[2][2],lib3ds_matrix[2][3],
241        lib3ds_matrix[3][0],lib3ds_matrix[3][1],lib3ds_matrix[3][2],lib3ds_matrix[3][3]);
242}
243
[445]244// Transforms points by matrix if 'matrix' is not NULL
[799]245// Creates a Geode and Geometry (as parent,child) and adds the Geode to 'parent' parameter iff 'parent' is non-NULL
[528]246// Returns ptr to the Geode
[3691]247osg::Node* ReaderWriter3DS::ReaderObject::processMesh(StateSetMap& drawStateMap,osg::Group* parent,Lib3dsMesh* mesh, Lib3dsMatrix* matrix) {
[445]248    typedef std::vector<int> FaceList;
249    typedef std::map<std::string,FaceList> MaterialFaceMap;
250    MaterialFaceMap materialFaceMap;
251    for (unsigned int i=0; i<mesh->faces; ++i)
[8]252    {
[445]253        materialFaceMap[mesh->faceL[i].material].push_back(i);
[8]254    }
255
[445]256    if (materialFaceMap.empty())
[8]257    {
[445]258        osg::notify(osg::NOTICE)<<"Warning : no triangles assigned to mesh '"<<mesh->name<<"'"<< std::endl;
[528]259        return NULL;
[445]260    }
261    else
262    {
[8]263
[445]264        osg::Geode* geode = new osg::Geode;
265        geode->setName(mesh->name);
[8]266
[445]267        for(MaterialFaceMap::iterator itr=materialFaceMap.begin();
268            itr!=materialFaceMap.end();
269            ++itr)
[8]270        {
[445]271            FaceList& faceList = itr->second;
272           
273            if (_useSmoothingGroups)
274            {
[8]275
[445]276                typedef std::map<int,FaceList> SmoothingFaceMap;
277                SmoothingFaceMap smoothingFaceMap;
278                for (FaceList::iterator flitr=faceList.begin();
279                     flitr!=faceList.end();
280                     ++flitr)
281                {
282                    smoothingFaceMap[mesh->faceL[*flitr].smoothing].push_back(*flitr);
283                }
[8]284
[445]285                for(SmoothingFaceMap::iterator sitr=smoothingFaceMap.begin();
286                    sitr!=smoothingFaceMap.end();
287                    ++sitr)
[8]288                {
[799]289                    // each smoothing group to have its own geom
[445]290                    // to ensure the vertices on adjacent groups
291                    // don't get shared.
292                    FaceList& smoothFaceMap = sitr->second;
[8]293
[799]294                    osg::Drawable* drawable = createDrawable(mesh,smoothFaceMap,matrix);
295                    if (drawable)
[8]296                    {
[799]297                        drawable->setStateSet(drawStateMap[itr->first]);
298                        geode->addDrawable(drawable);
[8]299                    }
300                }
301            }
[445]302            else // ignore smoothing groups.
303            {
[799]304                osg::Drawable* drawable = createDrawable(mesh,faceList,matrix);
305                if (drawable)
[445]306                {
[799]307                    drawable->setStateSet(drawStateMap[itr->first]);
308                    geode->addDrawable(drawable);
[445]309                }
310            }
311        }
[8]312
[528]313        if (parent) parent->addChild(geode);
314        return geode;
[8]315    }
316}
317
318
[445]319/**
320How to cope with pivot points in 3ds (short version)
[8]321
[528]322  All object coordinates in 3ds are stored in world space, this is why you can just rip out the meshes and use/draw them without meddeling further
323  Unfortunately, this gets a bit wonky with objects with pivot points (conjecture: PP support is retro fitted into the .3ds format and so doesn't fit perfectly?)
[8]324
[445]325  Objects with pivot points have a position relative to their PP, so they have to undergo this transform:
[8]326
[445]327    invert the mesh matrix, apply this matrix to the object. This puts the object back at the origin
[7648]328    Transform the object by the nodes (negative) pivot point coords, this puts the PP at the origin
329    Transform the node by the node matrix, which does the orientation about the pivot point, (and currently) transforms the object back by a translation to the PP.
[8]330
[445]331  */
[3691]332osg::Node* ReaderWriter3DS::ReaderObject::processNode(StateSetMap drawStateMap,Lib3dsFile *f,Lib3dsNode *node) {
[445]333   
[528]334    osg::Group* group=NULL;// created on demand if we find we have children to group together
335   
[8]336
[445]337    // Handle all children of this node for hierarchical assemblies
338    Lib3dsNode *p;
339    for (p=node->childs; p!=0; p=p->next) {
[528]340        if (!group) {
341            group =new osg::Group;
[4801]342            if (strcmp(node->name, "$$$DUMMY") == 0) {
343                group->setName(node->data.object.instance);
344            } else {
345                group->setName(node->name);
346            }
[528]347        }
348        group->addChild(processNode(drawStateMap,f,p));
[445]349    }
350   
351    // MIKEC: possible BUG - 3ds files APPEAR to enforce unqiue names, so this is OK, but I am not 100% sure
352    // failed to find any alternative way to do it in lib3ds though, and lib3ds player.c application uses this method
353    Lib3dsMesh *mesh=lib3ds_file_mesh_by_name(f,node->name);
354    if (mesh) {
355        Lib3dsObjectData* object=&node->data.object;
356        Lib3dsMatrix mesh_inverse;
357        osg::Matrix osgmatrix;
358       
359        lib3ds_matrix_copy(mesh_inverse,mesh->matrix);
360        lib3ds_matrix_inv(mesh_inverse);
361       
362        Lib3dsMatrix M,N;
363        lib3ds_matrix_identity(M);
364        lib3ds_matrix_identity(N);
365        lib3ds_matrix_copy(M,node->matrix);
366        N[3][0]=-object->pivot[0];
367        N[3][1]=-object->pivot[1];
368        N[3][2]=-object->pivot[2];
[8]369
[528]370        bool pivoted=false;
371        if ( (object->pivot[0]!=0.0) || (object->pivot[1]!=0.0) || (object->pivot[2]!=0.0) ) {
372            pivoted=true; // there is a pivot point, so we must use it
373        }
[445]374
[528]375        /*cout<<"M"<<node->name<<endl;
376        print(M,0);
377        cout<<"N"<<endl;
378        print(N,0);*/
[445]379
[528]380        if (pivoted) {
381            // Transform object's pivot point to the world origin
[868]382            osg::MatrixTransform* T=new osg::MatrixTransform;
[6518]383            copyLib3dsMatrixToOsgMatrix(osgmatrix, N);
[528]384            T->setMatrix(osgmatrix);
385            T->setName("3DSPIVOTPOINT: Translate pivotpoint to (world) origin");
386            //cout<<"Translation for "<<node->name<<" is "<<osgmatrix<<endl;
[445]387
[528]388            // rotate about "origin" (after the transform this is the world origin)
389            // BUG this matrix also contains the translation to the pivot point - we should plit that out (maybe)
[868]390            osg::MatrixTransform* R=new osg::MatrixTransform;
[6518]391            copyLib3dsMatrixToOsgMatrix(osgmatrix, M);
[528]392            R->setMatrix(osgmatrix);
393            R->setName("3DSPIVOTPOINT: Rotate");
394               
395            /*
396            cout<<"Rotation for "<<node->name<<" is "<<osgmatrix<<endl;
397            osg::Quat quat;
398            quat.set(osgmatrix);
399            osg::Vec3 axis;
400            float angle;
401            quat.getRotate(angle,axis);
402            cout<<"which is "<<osg::RadiansToDegrees(angle)<<" degrees around "<<axis<<endl;
403            */
404            /*
405            printf("%s---------------\n",node->name);
406            printf("mesh matrix :\n");         print(mesh->matrix,1);
407            printf("mesh inverse:\n");         print(mesh_inverse,1);
408            printf("node matrix :\n");         print(matrix,1);
409            printf("pivot=%f,%f,%f pos=%f,%f,%f\n",object->pivot[0],object->pivot[1],object->pivot[2],object->pos[0],object->pos[1],object->pos[2]);
410            */
411
412            if (group) {
413                // Always in reverse order...
414                group->addChild(R);
415                R->addChild(T);
416                processMesh(drawStateMap,T,mesh,&mesh_inverse); // creates geometry under modifier node
417                return group;
418            } else {
419                // We are a pivoted node with no children
420                R->addChild(T);
421                processMesh(drawStateMap,T,mesh,&mesh_inverse); // creates geometry under modifier node
422                return R;
423            }
424        } else {
425            if(group) {
426                // add our geometry to group (where our children already are)
427                processMesh(drawStateMap,group,mesh,NULL); // creates geometry under modifier node
428                return group;
429            } else {
430                // didnt use group for children
431                // return a ptr directly to the Geode for this mesh
432                return processMesh(drawStateMap,NULL,mesh,NULL);
433            }   
434        }
435
[445]436    } else {
437        // no mesh for this node - probably a camera or something of that persuasion
438        //cout << "no mesh for object " << node->name << endl;
[528]439        return group; // we have no mesh, but we might have children
[8]440    }
441}
442
443
[3694]444osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const
[8]445{
[5453]446
[2501]447    std::string ext = osgDB::getLowerCaseFileExtension(file);
448    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
449
[3691]450    std::string fileName = osgDB::findDataFile( file, options );
[2501]451    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
452
[445]453    Lib3dsFile *f = lib3ds_file_load(fileName.c_str());
454    if (f==NULL) return ReadResult::FILE_NOT_HANDLED;
[8]455
[445]456    // MIKEC
457    // This appears to build the matrix structures for the 3ds structure
458    // It wasn't previously necessary because all the meshes are stored in world coordinates
459    // but is VERY necessary if you want to use pivot points...
460    lib3ds_file_eval(f,0.0f); // second param is time 't' for animated files
[8]461
[3691]462    ReaderObject reader;
[8]463
[3691]464    reader._directory = osgDB::getFilePath(fileName);
465
[445]466    osg::Group* group = new osg::Group;
467    group->setName(fileName);
[8]468
[3691]469    ReaderObject::StateSetMap drawStateMap;
[8]470
[445]471    for (Lib3dsMaterial *mat=f->materials; mat; mat=mat->next)
[8]472    {
[3691]473        drawStateMap[mat->name] = reader.createStateSet(mat, options);
[445]474    }
475   
[5453]476    if (osg::getNotifyLevel()>=osg::INFO)
477    {
[445]478        int level=0;
[5453]479        std::cout << "NODE TRAVERSAL of 3ds file "<<f->name<<std::endl;
[445]480        for(Lib3dsNode *node=f->nodes; node; node=node->next) {
481            print(node,level+1);
[8]482        }
[5453]483        std::cout << "MESH TRAVERSAL of 3ds file "<<f->name<<std::endl;
[445]484        for(Lib3dsMesh *mesh=f->meshes; mesh; mesh=mesh->next) {
485            print(mesh,level+1);
[8]486        }
[5453]487    }
[8]488
[445]489    // We can traverse by meshes (old method, broken for pivot points, but otherwise works), or by nodes (new method, not so well tested yet)
490    // if your model is broken, especially wrt object positions try setting this flag. If that fixes it,
491    // send me the model
492    bool traverse_nodes=false;
493   
494    // MIKEC: have found 3ds files with NO node structure - only meshes, for this case we fall back to the old traverse-by-meshes code
495    // Loading and re-exporting these files from 3DS produces a file with correct node structure, so perhaps these are not 100% conformant?
496    if (f->nodes == NULL) {
497        osg::notify(osg::WARN)<<"Warning: in 3ds loader: file has no nodes, traversing by meshes instead"<< std::endl;
498        traverse_nodes=true;
[8]499    }
500
[445]501    if (traverse_nodes) { // old method
502        for (Lib3dsMesh *mesh=f->meshes; mesh; mesh=mesh->next) {
[3691]503            reader.processMesh(drawStateMap,group,mesh,NULL);
[445]504        }
505    } else { // new method
506        for(Lib3dsNode *node=f->nodes; node; node=node->next) {
[3691]507            group->addChild(reader.processNode(drawStateMap,f,node));
[445]508        }
509    }
510
[6518]511    if (osg::getNotifyLevel()>=osg::INFO)
[5453]512    {
513        osg::notify(osg::NOTICE) << "Final OSG node structure looks like this:"<< endl;
514        PrintVisitor pv(osg::notify(osg::NOTICE));
515        group->accept(pv);
516    }   
[528]517   
[445]518    lib3ds_file_free(f);
519
520    return group;
[8]521}
522
[445]523/**
524use matrix to pretransform geometry, or NULL to do nothing
525*/
[3691]526osg::Drawable*   ReaderWriter3DS::ReaderObject::createDrawable(Lib3dsMesh *m,FaceList& faceList,Lib3dsMatrix *matrix)
[8]527{
528
[799]529    osg::Geometry* geom = new osg::Geometry;
[8]530
531    unsigned int i;
[270]532   
[8]533    std::vector<int> orig2NewMapping;
534    for(i=0;i<m->points;++i) orig2NewMapping.push_back(-1);
535
536    unsigned int noVertex=0;
537    FaceList::iterator fitr;
538    for (fitr=faceList.begin();
539        fitr!=faceList.end();
540        ++fitr)
541    {
542
543        Lib3dsFace& face = m->faceL[*fitr];
544
545        if (orig2NewMapping[face.points[0]]<0)
546            orig2NewMapping[face.points[0]] = noVertex++;
547
548        if (orig2NewMapping[face.points[1]]<0)
549            orig2NewMapping[face.points[1]] = noVertex++;
550
551        if (orig2NewMapping[face.points[2]]<0)
552            orig2NewMapping[face.points[2]] = noVertex++;
553
554    }
555
[814]556    // create vertices.
[2339]557   
[799]558    osg::Vec3Array* osg_coords = new osg::Vec3Array(noVertex);
[814]559    geom->setVertexArray(osg_coords);
560
[270]561    Lib3dsVector c;
[445]562       
[8]563    for (i=0; i<m->points; ++i)
564    {
[814]565        if (orig2NewMapping[i]>=0)
566        {
[445]567            if (matrix)
[270]568            {
[445]569                lib3ds_vector_transform(c,*matrix, m->pointL[i].pos);
[799]570                (*osg_coords)[orig2NewMapping[i]].set(c[0],c[1],c[2]);
[270]571            }
572            else
573            {
574                // original no transform code.
[799]575                (*osg_coords)[orig2NewMapping[i]].set(m->pointL[i].pos[0],m->pointL[i].pos[1],m->pointL[i].pos[2]);
[270]576            }
577        }
[8]578    }
579
[814]580    // create texture coords if needed.
[8]581    if (m->texels>0)
582    {
583        if (m->texels==m->points)
584        {
[814]585            osg::Vec2Array* osg_tcoords = new osg::Vec2Array(noVertex);
586            geom->setTexCoordArray(0,osg_tcoords);
[8]587            for (i=0; i<m->texels; ++i)
588            {
[799]589                if (orig2NewMapping[i]>=0) (*osg_tcoords)[orig2NewMapping[i]].set(m->texelL[i][0],m->texelL[i][1]);
[8]590            }
591        }
592        else
593        {
[211]594            osg::notify(osg::WARN)<<"Warning: in 3ds loader m->texels ("<<m->texels<<") != m->points ("<<m->points<<")"<< std::endl;
[8]595        }
596    }
597
[814]598    // create normals.
[8]599    if (_usePerVertexNormals)
600    {
[4461]601        osg::Vec3Array* osg_normals = new osg::Vec3Array(noVertex);
[8]602       
603        // initialize normal list to zero's.
604        for (i=0; i<noVertex; ++i)
605        {
[799]606            (*osg_normals)[i].set(0.0f,0.0f,0.0f);
[8]607        }
608
[814]609        for (fitr=faceList.begin();
610            fitr!=faceList.end();
611            ++fitr)
[8]612        {
[814]613            Lib3dsFace& face = m->faceL[*fitr];
614
[799]615            (*osg_normals)[orig2NewMapping[face.points[0]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);;
616            (*osg_normals)[orig2NewMapping[face.points[1]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);;
617            (*osg_normals)[orig2NewMapping[face.points[2]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);;
[814]618
[8]619        }
620
[6518]621        if (matrix)
622        {
623            osg::Matrix osg_matrix;
624            copyLib3dsMatrixToOsgMatrix(osg_matrix, *matrix);
625            for (i=0; i<noVertex; ++i)
626            {
627                (*osg_normals)[i] = osg::Matrix::transform3x3((*osg_normals)[i], osg_matrix);
628            }
629        }
630
[8]631        // normalize the normal list to unit length normals.
632        for (i=0; i<noVertex; ++i)
633        {
[799]634            (*osg_normals)[i].normalize();
[8]635        }
636
[799]637        geom->setNormalArray(osg_normals);
638        geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
[8]639
640    }
[814]641    else 
[8]642    {
[814]643        osg::Vec3Array* osg_normals = new osg::Vec3Array(faceList.size());
644        osg::Vec3Array::iterator normal_itr = osg_normals->begin();
645        for (fitr=faceList.begin();
646            fitr!=faceList.end();
647            ++fitr)
648        {
649            Lib3dsFace& face = m->faceL[*fitr];
650            *(normal_itr++) =  osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);
651        }
[799]652        geom->setNormalArray(osg_normals);
653        geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
[8]654    }
[814]655   
[4390]656    osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
[2339]657    (*osg_colors)[0].set(255,255,255,255);
658    geom->setColorArray(osg_colors);
659    geom->setColorBinding(osg::Geometry::BIND_OVERALL);
[814]660   
[2339]661
[814]662    // create primitives
663    int numIndices = faceList.size()*3;
[1166]664    DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,numIndices);
665    DrawElementsUShort::iterator index_itr = elements->begin();
[8]666
[814]667    for (fitr=faceList.begin();
668        fitr!=faceList.end();
669        ++fitr)
670    {
671        Lib3dsFace& face = m->faceL[*fitr];
[8]672
[814]673        *(index_itr++) = orig2NewMapping[face.points[0]];
674        *(index_itr++) = orig2NewMapping[face.points[1]];
675        *(index_itr++) = orig2NewMapping[face.points[2]];
676    }
677   
[1186]678    geom->addPrimitiveSet(elements);
[8]679
[5453]680#if 0
[2535]681    osgUtil::TriStripVisitor tsv;
682    tsv.stripify(*geom);
[5453]683#endif
[2535]684
[799]685    return geom;
[8]686}
[445]687
688
[3691]689osg::Texture2D*  ReaderWriter3DS::ReaderObject::createTexture(Lib3dsTextureMap *texture,const char* label,bool& transparancy, const osgDB::ReaderWriter::Options* options)
[445]690{
691    if (texture && *(texture->name))
692    {
[2449]693        std::string fileName = osgDB::findFileInDirectory(texture->name,_directory,osgDB::CASE_INSENSITIVE);
694        if (fileName.empty())
695        {
696            // file not found in .3ds file's directory, so we'll look in the datafile path list.
[3691]697            fileName = osgDB::findDataFile(texture->name,options, osgDB::CASE_INSENSITIVE);
[2449]698        }
699       
[445]700        if (fileName.empty())
701        {
702            osg::notify(osg::WARN) << "texture '"<<texture->name<<"' not found"<< std::endl;
703            return NULL;
704        }
705
706        if (label) osg::notify(osg::DEBUG_INFO) << label;
707        else osg::notify(osg::DEBUG_INFO) << "texture name";
708        osg::notify(osg::DEBUG_INFO) << " '"<<texture->name<<"'"<< std::endl;
709        osg::notify(osg::DEBUG_INFO) << "    texture flag        "<<texture->flags<< std::endl;
710        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_DECALE       "<<((texture->flags)&LIB3DS_DECALE)<< std::endl;
711        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_MIRROR       "<<((texture->flags)&LIB3DS_MIRROR)<< std::endl;
712        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_NEGATE       "<<((texture->flags)&LIB3DS_NEGATE)<< std::endl;
713        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_NO_TILE      "<<((texture->flags)&LIB3DS_NO_TILE)<< std::endl;
714        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_SUMMED_AREA  "<<((texture->flags)&LIB3DS_SUMMED_AREA)<< std::endl;
715        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_ALPHA_SOURCE "<<((texture->flags)&LIB3DS_ALPHA_SOURCE)<< std::endl;
716        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_TINT         "<<((texture->flags)&LIB3DS_TINT)<< std::endl;
717        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_IGNORE_ALPHA "<<((texture->flags)&LIB3DS_IGNORE_ALPHA)<< std::endl;
718        osg::notify(osg::DEBUG_INFO) << "    LIB3DS_RGB_TINT     "<<((texture->flags)&LIB3DS_RGB_TINT)<< std::endl;
719
[9527]720        osg::ref_ptr<osg::Image> osg_image = osgDB::readRefImageFile(fileName.c_str());
721        if (!osg_image)
[445]722        {
723            osg::notify(osg::NOTICE) << "Warning: Cannot create texture "<<texture->name<< std::endl;
724            return NULL;
725        }
726
[1078]727        osg::Texture2D* osg_texture = new osg::Texture2D;
[9527]728        osg_texture->setImage(osg_image.get());
[445]729
730        // does the texture support transparancy?
731        transparancy = ((texture->flags)&LIB3DS_ALPHA_SOURCE)!=0;
732
733        // what is the wrap mode of the texture.
[1078]734        osg::Texture2D::WrapMode wm = ((texture->flags)&LIB3DS_NO_TILE) ?
[4461]735                osg::Texture2D::CLAMP :
736                osg::Texture2D::REPEAT;
[1078]737        osg_texture->setWrap(osg::Texture2D::WRAP_S,wm);
738        osg_texture->setWrap(osg::Texture2D::WRAP_T,wm);
739        osg_texture->setWrap(osg::Texture2D::WRAP_R,wm);
[445]740                                 // bilinear.
[1078]741        osg_texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR_MIPMAP_NEAREST);
[445]742
743        return osg_texture;
744    }
745    else
746        return NULL;
747}
748
749
[3691]750osg::StateSet* ReaderWriter3DS::ReaderObject::createStateSet(Lib3dsMaterial *mat, const osgDB::ReaderWriter::Options* options)
[445]751{
752    if (mat==NULL) return NULL;
753
754    osg::StateSet* stateset = new osg::StateSet;
755
756    osg::Material* material = new osg::Material;
757
758    float transparency = mat->transparency;
759    float alpha = 1.0f-transparency;
760
761    osg::Vec4 ambient(mat->ambient[0],mat->ambient[1],mat->ambient[2],alpha);
762    osg::Vec4 diffuse(mat->diffuse[0],mat->diffuse[1],mat->diffuse[2],alpha);
763    osg::Vec4 specular(mat->specular[0],mat->specular[1],mat->specular[2],alpha);
[2421]764    specular *= mat->shin_strength;
[445]765
766    float shininess = mat->shininess;
[7623]767    material->setName(mat->name);
[445]768    material->setAmbient(osg::Material::FRONT_AND_BACK,ambient);
769    material->setDiffuse(osg::Material::FRONT_AND_BACK,diffuse);
770    material->setSpecular(osg::Material::FRONT_AND_BACK,specular);
[1020]771    material->setShininess(osg::Material::FRONT_AND_BACK,shininess*128.0f);
[445]772
773    stateset->setAttribute(material);
774
775    bool textureTransparancy=false;
[3691]776    osg::Texture2D* texture1_map = createTexture(&(mat->texture1_map),"texture1_map",textureTransparancy, options);
[445]777    if (texture1_map)
778    {
[845]779        stateset->setTextureAttributeAndModes(0,texture1_map,osg::StateAttribute::ON);
[445]780       
[2339]781        if (!textureTransparancy)
782        {       
783            // from an email from Eric Hamil, September 30, 2003.
784            // According to the 3DS spec, and other
785            // software (like Max, Lightwave, and Deep Exploration) a 3DS material that has
786            // a non-white diffuse base color and a 100% opaque bitmap texture, will show the
787            // texture with no influence from the base color.
788           
789            // so we'll override material back to white.
790            // and no longer require the decal hack below...
[2872]791#if 0
[7648]792            // Eric original fallback
[2339]793            osg::Vec4 white(1.0f,1.0f,1.0f,alpha);
794            material->setAmbient(osg::Material::FRONT_AND_BACK,white);
795            material->setDiffuse(osg::Material::FRONT_AND_BACK,white);
796            material->setSpecular(osg::Material::FRONT_AND_BACK,white);
[2872]797#else
[7648]798            // try alternative to avoid saturating with white
[2872]799            // setting white as per OpenGL defaults.
800            material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(0.2f,0.2f,0.2f,alpha));
801            material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(0.8f,0.8f,0.8f,alpha));
802            material->setSpecular(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,alpha));
803#endif           
[445]804        }
[2339]805       
806// no longer required...       
807//         bool decal = false;
808//         
809//         // not sure exactly how to interpret what is best for .3ds
810//         // but the default text env MODULATE doesn't work well, and
811//         // DECAL seems to work better.
812//         osg::TexEnv* texenv = new osg::TexEnv;
813//         if (decal)
814//         {
815//             texenv->setMode(osg::TexEnv::DECAL);
816//         }
817//         else
818//         {
819//             texenv->setMode(osg::TexEnv::MODULATE);
820//         }
821//        stateset->setTextureAttribute(0,texenv);
[445]822    }
823
824    if (transparency>0.0f || textureTransparancy)
825    {
826        stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
827        stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
828    }
829
830/*
831    osg::ref_ptr<osg::Texture> texture1_mask = createTexture(&(mat->texture1_mask),"texture1_mask",textureTransparancy);
832    osg::ref_ptr<osg::Texture> texture2_map = createTexture(&(mat->texture2_map),"texture2_map",textureTransparancy);
833    osg::ref_ptr<osg::Texture> texture2_mask = createTexture(&(mat->texture2_mask),"texture2_mask",textureTransparancy);
834    osg::ref_ptr<osg::Texture> opacity_map = createTexture(&(mat->opacity_map),"opacity_map",textureTransparancy);
835    osg::ref_ptr<osg::Texture> opacity_mask = createTexture(&(mat->opacity_mask),"opacity_mask",textureTransparancy);
836    osg::ref_ptr<osg::Texture> bump_map = createTexture(&(mat->bump_map),"bump_map",textureTransparancy);
837    osg::ref_ptr<osg::Texture> bump_mask = createTexture(&(mat->bump_mask),"bump_mask",textureTransparancy);
838    osg::ref_ptr<osg::Texture> specular_map = createTexture(&(mat->specular_map),"specular_map",textureTransparancy);
839    osg::ref_ptr<osg::Texture> specular_mask = createTexture(&(mat->specular_mask),"specular_mask",textureTransparancy);
840    osg::ref_ptr<osg::Texture> shininess_map = createTexture(&(mat->shininess_map),"shininess_map",textureTransparancy);
841    osg::ref_ptr<osg::Texture> shininess_mask = createTexture(&(mat->shininess_mask),"shininess_mask",textureTransparancy);
842    osg::ref_ptr<osg::Texture> self_illum_map = createTexture(&(mat->self_illum_map),"self_illum_map",textureTransparancy);
843    osg::ref_ptr<osg::Texture> self_illum_mask = createTexture(&(mat->self_illum_mask),"self_illum_mask",textureTransparancy);
844    osg::ref_ptr<osg::Texture> reflection_map = createTexture(&(mat->reflection_map),"reflection_map",textureTransparancy);
845    osg::ref_ptr<osg::Texture> reflection_mask = createTexture(&(mat->reflection_mask),"reflection_mask",textureTransparancy);
846*/
847    return stateset;
848}
Note: See TracBrowser for help on using the browser.