The function 'ReaderWriter3DS::ReaderObject::createTexture' does not pass through the options object when loading textures. I have attached a corrected version of ReaderWriter3DS.cpp based on version 2.9.5 revision 10374. The only change is the addition of the 'options' parameter when calling 'readRefImage'. "osg::ref_ptr<osg::Image> osg_image = osgDB::readRefImageFile(fileName.c_str(), options);"

Chris Denham.
#include <osg/Notify>
#include <osg/Group>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/Material>
#include <osg/TexEnv>
#include <osg/ref_ptr>
#include <osg/MatrixTransform>

#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>

#include <osgUtil/TriStripVisitor>

//MIKEC debug only for PrintVisitor
#include <osg/NodeVisitor>


#include "file.h"
#include "mesh.h"
#include "material.h"
#include "vector.h"
#include "matrix.h"
#include "node.h"
#include "quat.h"
#include "readwrite.h"

#include <stdlib.h>
#include <string.h>

#include <set>
#include <map>
#include <iostream>
#include <sstream>

using namespace std;
using namespace osg;

class PrintVisitor : public NodeVisitor
{

  public:
PrintVisitor(std::ostream& out):
           NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
           _out(out)
       {
           _indent = 0;
           _step = 4;
       }
inline void moveIn() { _indent += _step; }
       inline void moveOut() { _indent -= _step; }
inline void writeIndent() {
           for(int i=0;i<_indent;++i) _out << " ";
       }
virtual void apply(Node& node)
       {
           moveIn();
           writeIndent(); _out << node.className() <<std::endl;
           traverse(node);
           moveOut();
       }

       virtual void apply(Geode& node)         { apply((Node&)node); }
       virtual void apply(Billboard& node)     { apply((Geode&)node); }
       virtual void apply(LightSource& node)   { apply((Group&)node); }
       virtual void apply(ClipNode& node)      { apply((Group&)node); }
virtual void apply(Group& node) { apply((Node&)node); }
       virtual void apply(Transform& node)     { apply((Group&)node); }
       virtual void apply(Projection& node)    { apply((Group&)node); }
       virtual void apply(Switch& node)        { apply((Group&)node); }
       virtual void apply(LOD& node)           { apply((Group&)node); }

  protected:

       PrintVisitor& operator = (const PrintVisitor&) { return *this; }

       std::ostream& _out;
       int _indent;
       int _step;
};

class ReaderWriter3DS : public osgDB::ReaderWriter
{
   public:

       ReaderWriter3DS();

       virtual const char* className() const { return "3DS Auto Studio Reader"; 
}

       virtual ReadResult readNode(const std::string& file, const 
osgDB::ReaderWriter::Options* options) const;
       virtual ReadResult readNode(std::istream& fin, const Options* options) 
const;

   protected:
       ReadResult constructFrom3dsFile(Lib3dsFile *f,const std::string& 
filename, const Options* options) const;


       class ReaderObject
       {
       public:
           ReaderObject();
typedef std::map<std::string,osg::StateSet*> StateSetMap;
           typedef std::vector<int> FaceList;
           typedef std::map<std::string,osg::StateSet*> GeoStateMap;

           osg::Texture2D* createTexture(Lib3dsTextureMap *texture,const char* 
label,bool& transparancy, const osgDB::ReaderWriter::Options* options);
           osg::StateSet* createStateSet(Lib3dsMaterial *materials, const 
osgDB::ReaderWriter::Options* options);
           osg::Drawable* createDrawable(Lib3dsMesh *meshes,FaceList& faceList, 
Lib3dsMatrix* matrix);

           std::string _directory;
           bool _useSmoothingGroups;
           bool _usePerVertexNormals;

           // MIKEC
           osg::Node* processMesh(StateSetMap& drawStateMap,osg::Group* 
parent,Lib3dsMesh* mesh, Lib3dsMatrix* matrix);
           osg::Node* processNode(StateSetMap drawStateMap,Lib3dsFile 
*f,Lib3dsNode *node);
       };
};

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(3ds, ReaderWriter3DS)

ReaderWriter3DS::ReaderWriter3DS()
{
   supportsExtension("3ds","3D Studio model format");

   setByteOrder();

#if 0
   osg::notify(osg::NOTICE)<<"3DS reader sizes:"<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsBool)="<<sizeof(Lib3dsBool)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsByte)="<<sizeof(Lib3dsByte)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsWord)="<<sizeof(Lib3dsWord)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsDword)="<<sizeof(Lib3dsDword)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsIntb)="<<sizeof(Lib3dsIntb)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsIntw)="<<sizeof(Lib3dsIntw)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsIntd)="<<sizeof(Lib3dsIntd)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsFloat)="<<sizeof(Lib3dsFloat)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsDouble)="<<sizeof(Lib3dsDouble)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsVector)="<<sizeof(Lib3dsVector)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsTexel)="<<sizeof(Lib3dsTexel)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsQuat)="<<sizeof(Lib3dsQuat)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsMatrix)="<<sizeof(Lib3dsMatrix)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsRgb)="<<sizeof(Lib3dsRgb)<<std::endl;
   osg::notify(osg::NOTICE)<<"  
sizeof(Lib3dsRgba)="<<sizeof(Lib3dsRgba)<<std::endl;
#endif

}

ReaderWriter3DS::ReaderObject::ReaderObject()
{
   _useSmoothingGroups = true;
   _usePerVertexNormals = true;
}


/**
   These print methods for 3ds hacking
*/
void pad(int level) {
   for(int i=0;i<level;i++) std::cout<<"  ";
}
void print(Lib3dsMesh *mesh,int level);
void print(Lib3dsUserData *user,int level);
void print(Lib3dsNodeData *user,int level);
void print(Lib3dsObjectData *object,int level);
void print(Lib3dsNode *node, int level);

void print(Lib3dsMatrix matrix,int level) {
   pad(level); cout << matrix[0][0] <<" "<< matrix[0][1] <<" "<< matrix[0][2] <<" "<< 
matrix[0][3] << endl;
   pad(level); cout << matrix[1][0] <<" "<< matrix[1][1] <<" "<< matrix[1][2] <<" "<< 
matrix[1][3] << endl;
   pad(level); cout << matrix[2][0] <<" "<< matrix[2][1] <<" "<< matrix[2][2] <<" "<< 
matrix[2][3] << endl;
   pad(level); cout << matrix[3][0] <<" "<< matrix[3][1] <<" "<< matrix[3][2] <<" "<< 
matrix[3][3] << endl;
}
void print(Lib3dsMesh *mesh,int level) {
   if (mesh) {
       pad(level); cout << "mesh name " << mesh->name  << endl;
       print(mesh->matrix,level);
   } else {
       pad(level); cout << "no mesh " << endl;
   }
}
void print(Lib3dsUserData *user,int level) {
   if (user) {
       pad(level); cout << "user data" << endl;
       //print(user->mesh,level+1);
   } else {
       pad(level); cout << "no user data" << endl;
   }
}
void print(Lib3dsNodeData *node,int level) {
   if (node) {
       pad(level); cout << "node data:" << endl;
       // nodedata->object is a union of many types
       print((Lib3dsObjectData *)&node->object,level+1);
   } else {
       pad(level); cout << "no user data" << endl;
   }
}
void print(Lib3dsObjectData *object,int level) {
   if (object) {
       pad(level); cout << "objectdata instance [" << object->instance << "]" 
<< endl;
       pad(level); cout << "pivot     " << object->pivot[0] <<" "<< object->pivot[1] <<" 
"<< object->pivot[2] << endl;
       pad(level); cout << "pos       " << object->pos[0] <<" "<< object->pos[1] <<" "<< 
object->pos[2] << endl;
       pad(level); cout << "scl       " << object->scl[0] <<" "<< object->scl[1] <<" "<< 
object->scl[2] << endl;
       pad(level); cout << "rot       " << object->rot[0] <<" "<< object->rot[1] <<" "<< object->rot[2] 
<<" "<< object->rot[3] << endl;
   } else {
       pad(level); cout << "no object data" << endl;
   }
}

void print(Lib3dsNode *node, int level) {
pad(level); cout << "node name [" << node->name << "]" << endl;
   pad(level); cout << "node id    " << node->node_id << endl;
   pad(level); cout << "node parent id " << node->parent_id << endl;
   pad(level); cout << "node matrix:" << endl;
   print(node->matrix,level+1);
   print(&node->data,level);
   print(&node->user,level);
   for(Lib3dsNode *child=node->childs; child; child=child->next) {
       print(child,level+1);
   }

}

void copyLib3dsMatrixToOsgMatrix(osg::Matrix& osg_matrix, const Lib3dsMatrix 
lib3ds_matrix)
{
   osg_matrix.set(
       
lib3ds_matrix[0][0],lib3ds_matrix[0][1],lib3ds_matrix[0][2],lib3ds_matrix[0][3],
       
lib3ds_matrix[1][0],lib3ds_matrix[1][1],lib3ds_matrix[1][2],lib3ds_matrix[1][3],
       
lib3ds_matrix[2][0],lib3ds_matrix[2][1],lib3ds_matrix[2][2],lib3ds_matrix[2][3],
lib3ds_matrix[3][0],lib3ds_matrix[3][1],lib3ds_matrix[3][2],lib3ds_matrix[3][3]); }

// Transforms points by matrix if 'matrix' is not NULL
// Creates a Geode and Geometry (as parent,child) and adds the Geode to 
'parent' parameter iff 'parent' is non-NULL
// Returns ptr to the Geode
osg::Node* ReaderWriter3DS::ReaderObject::processMesh(StateSetMap& 
drawStateMap,osg::Group* parent,Lib3dsMesh* mesh, Lib3dsMatrix* matrix) {
   typedef std::vector<int> FaceList;
   typedef std::map<std::string,FaceList> MaterialFaceMap;
   MaterialFaceMap materialFaceMap;
   for (unsigned int i=0; i<mesh->faces; ++i)
   {
       materialFaceMap[mesh->faceL[i].material].push_back(i);
   }

   if (materialFaceMap.empty())
   {
       osg::notify(osg::NOTICE)<<"Warning : no triangles assigned to mesh 
'"<<mesh->name<<"'"<< std::endl;
       return NULL;
   }
   else
   {

       osg::Geode* geode = new osg::Geode;
       geode->setName(mesh->name);

       for(MaterialFaceMap::iterator itr=materialFaceMap.begin();
           itr!=materialFaceMap.end();
           ++itr)
       {
           FaceList& faceList = itr->second;
if (_useSmoothingGroups)
           {

               typedef std::map<int,FaceList> SmoothingFaceMap;
               SmoothingFaceMap smoothingFaceMap;
               for (FaceList::iterator flitr=faceList.begin();
                    flitr!=faceList.end();
                    ++flitr)
               {
                   
smoothingFaceMap[mesh->faceL[*flitr].smoothing].push_back(*flitr);
               }

               for(SmoothingFaceMap::iterator sitr=smoothingFaceMap.begin();
                   sitr!=smoothingFaceMap.end();
                   ++sitr)
               {
// each smoothing group to have its own geom // to ensure the vertices on adjacent groups
                   // don't get shared.
                   FaceList& smoothFaceMap = sitr->second;

                   osg::Drawable* drawable = 
createDrawable(mesh,smoothFaceMap,matrix);
                   if (drawable)
                   {
                       drawable->setStateSet(drawStateMap[itr->first]);
                       geode->addDrawable(drawable);
                   }
               }
           }
           else // ignore smoothing groups.
           {
               osg::Drawable* drawable = createDrawable(mesh,faceList,matrix);
               if (drawable)
               {
                   drawable->setStateSet(drawStateMap[itr->first]);
                   geode->addDrawable(drawable);
               }
           }
       }

       if (parent) parent->addChild(geode);
       return geode;
   }
}


/**
How to cope with pivot points in 3ds (short version)

 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
 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?)

 Objects with pivot points have a position relative to their PP, so they have 
to undergo this transform:

   invert the mesh matrix, apply this matrix to the object. This puts the 
object back at the origin
   Transform the object by the nodes (negative) pivot point coords, this puts 
the PP at the origin
   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.

 */
osg::Node* ReaderWriter3DS::ReaderObject::processNode(StateSetMap 
drawStateMap,Lib3dsFile *f,Lib3dsNode *node) {
osg::Group* group=NULL;// created on demand if we find we have children to group together
   // Handle all children of this node for hierarchical assemblies
   Lib3dsNode *p;
   for (p=node->childs; p!=0; p=p->next) {
       if (!group) {
           group =new osg::Group;
           if (strcmp(node->name, "$$$DUMMY") == 0) {
               group->setName(node->data.object.instance);
           } else {
               group->setName(node->name);
           }
       }
       group->addChild(processNode(drawStateMap,f,p));
   }
// MIKEC: possible BUG - 3ds files APPEAR to enforce unqiue names, so this is OK, but I am not 100% sure
   // failed to find any alternative way to do it in lib3ds though, and lib3ds 
player.c application uses this method
   Lib3dsMesh *mesh=lib3ds_file_mesh_by_name(f,node->name);
   if (mesh) {
       Lib3dsObjectData* object=&node->data.object;
       Lib3dsMatrix mesh_inverse;
       osg::Matrix osgmatrix;
lib3ds_matrix_copy(mesh_inverse,mesh->matrix); lib3ds_matrix_inv(mesh_inverse); Lib3dsMatrix M,N;
       lib3ds_matrix_identity(M);
       lib3ds_matrix_identity(N);
       lib3ds_matrix_copy(M,node->matrix);
       N[3][0]=-object->pivot[0];
       N[3][1]=-object->pivot[1];
       N[3][2]=-object->pivot[2];

       bool pivoted=false;
       if ( (object->pivot[0]!=0.0) || (object->pivot[1]!=0.0) || 
(object->pivot[2]!=0.0) ) {
           pivoted=true; // there is a pivot point, so we must use it
       }

       /*cout<<"M"<<node->name<<endl;
       print(M,0);
       cout<<"N"<<endl;
       print(N,0);*/

       if (pivoted) {
           // Transform object's pivot point to the world origin
           osg::MatrixTransform* T=new osg::MatrixTransform;
           copyLib3dsMatrixToOsgMatrix(osgmatrix, N);
           T->setMatrix(osgmatrix);
           T->setName("3DSPIVOTPOINT: Translate pivotpoint to (world) origin");
           //cout<<"Translation for "<<node->name<<" is "<<osgmatrix<<endl;

           // rotate about "origin" (after the transform this is the world 
origin)
           // BUG this matrix also contains the translation to the pivot point 
- we should plit that out (maybe)
           osg::MatrixTransform* R=new osg::MatrixTransform;
           copyLib3dsMatrixToOsgMatrix(osgmatrix, M);
           R->setMatrix(osgmatrix);
           R->setName("3DSPIVOTPOINT: Rotate");
/*
           cout<<"Rotation for "<<node->name<<" is "<<osgmatrix<<endl;
           osg::Quat quat;
           quat.set(osgmatrix);
           osg::Vec3 axis;
           float angle;
           quat.getRotate(angle,axis);
           cout<<"which is "<<osg::RadiansToDegrees(angle)<<" degrees around 
"<<axis<<endl;
           */
           /*
           printf("%s---------------\n",node->name);
           printf("mesh matrix :\n");         print(mesh->matrix,1);
           printf("mesh inverse:\n");         print(mesh_inverse,1);
           printf("node matrix :\n");         print(matrix,1);
           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]);
           */

           if (group) {
               // Always in reverse order...
group->addChild(R); R->addChild(T);
               processMesh(drawStateMap,T,mesh,&mesh_inverse); // creates 
geometry under modifier node
               return group;
           } else {
               // We are a pivoted node with no children
               R->addChild(T);
               processMesh(drawStateMap,T,mesh,&mesh_inverse); // creates 
geometry under modifier node
               return R;
           }
       } else {
           if(group) {
               // add our geometry to group (where our children already are)
               processMesh(drawStateMap,group,mesh,NULL); // creates geometry 
under modifier node
               return group;
           } else {
               // didnt use group for children
               // return a ptr directly to the Geode for this mesh
return processMesh(drawStateMap,NULL,mesh,NULL); } }

   } else {
       // no mesh for this node - probably a camera or something of that 
persuasion
       //cout << "no mesh for object " << node->name << endl;
       return group; // we have no mesh, but we might have children
   }
}

osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(std::istream& fin,  
const osgDB::ReaderWriter::Options* options) const
{
   osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;

   std::string optFileName = "";
   if (options)
   {
       optFileName = options->getPluginStringData("STREAM_FILENAME");
   }

   Lib3dsFile *f = lib3ds_stream_load((iostream *) &fin);
   if (f)
   {
       result = constructFrom3dsFile(f,optFileName,options);
       lib3ds_file_free(f);
   }

   return(result);
}

osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& 
file, const osgDB::ReaderWriter::Options* options) const
{
   osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;

   std::string ext = osgDB::getLowerCaseFileExtension(file);
   if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

   std::string fileName = osgDB::findDataFile( file, options );
   if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

   Lib3dsFile *f = lib3ds_file_load(fileName.c_str(),options);

   if (f)
   {
       osg::ref_ptr<Options> local_opt = options ? 
static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
       
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));

       result = constructFrom3dsFile(f,file,local_opt.get());
       lib3ds_file_free(f);
   }

   return result;
}

osgDB::ReaderWriter::ReadResult ReaderWriter3DS::constructFrom3dsFile(Lib3dsFile 
*f,const std::string& fileName, const osgDB::ReaderWriter::Options* options) 
const
{
   if (f==NULL) return ReadResult::FILE_NOT_HANDLED;

   // MIKEC
   // This appears to build the matrix structures for the 3ds structure
   // It wasn't previously necessary because all the meshes are stored in world 
coordinates
   // but is VERY necessary if you want to use pivot points...
   lib3ds_file_eval(f,0.0f); // second param is time 't' for animated files

   ReaderObject reader;

   reader._directory = options->getDatabasePathList().empty() ? 
osgDB::getFilePath(fileName) : options->getDatabasePathList().front();

   osg::Group* group = new osg::Group;
   group->setName(fileName);

   ReaderObject::StateSetMap drawStateMap;

   for (Lib3dsMaterial *mat=f->materials; mat; mat=mat->next)
   {
       drawStateMap[mat->name] = reader.createStateSet(mat, options);
   }
if (osg::getNotifyLevel()>=osg::INFO)
   {
       int level=0;
       std::cout << "NODE TRAVERSAL of 3ds file "<<f->name<<std::endl;
       for(Lib3dsNode *node=f->nodes; node; node=node->next) {
           print(node,level+1);
       }
       std::cout << "MESH TRAVERSAL of 3ds file "<<f->name<<std::endl;
       for(Lib3dsMesh *mesh=f->meshes; mesh; mesh=mesh->next) {
           print(mesh,level+1);
       }
   }

   // We can traverse by meshes (old method, broken for pivot points, but 
otherwise works), or by nodes (new method, not so well tested yet)
   // if your model is broken, especially wrt object positions try setting this 
flag. If that fixes it,
   // send me the model
   bool traverse_nodes=false;
// MIKEC: have found 3ds files with NO node structure - only meshes, for this case we fall back to the old traverse-by-meshes code
   // Loading and re-exporting these files from 3DS produces a file with 
correct node structure, so perhaps these are not 100% conformant?
   if (f->nodes == NULL) {
       osg::notify(osg::WARN)<<"Warning: in 3ds loader: file has no nodes, traversing by 
meshes instead"<< std::endl;
       traverse_nodes=true;
   }

   if (traverse_nodes) { // old method
       for (Lib3dsMesh *mesh=f->meshes; mesh; mesh=mesh->next) {
           reader.processMesh(drawStateMap,group,mesh,NULL);
       }
   } else { // new method
       for(Lib3dsNode *node=f->nodes; node; node=node->next) {
           group->addChild(reader.processNode(drawStateMap,f,node));
       }
}
   if (osg::getNotifyLevel()>=osg::INFO)
   {
       osg::notify(osg::NOTICE) << "Final OSG node structure looks like 
this:"<< endl;
       PrintVisitor pv(osg::notify(osg::NOTICE));
       group->accept(pv);
} return group;
}

/**
use matrix to pretransform geometry, or NULL to do nothing
*/
osg::Drawable*   ReaderWriter3DS::ReaderObject::createDrawable(Lib3dsMesh 
*m,FaceList& faceList,Lib3dsMatrix *matrix)
{

   osg::Geometry* geom = new osg::Geometry;

   unsigned int i;
std::vector<int> orig2NewMapping;
   for(i=0;i<m->points;++i) orig2NewMapping.push_back(-1);

   unsigned int noVertex=0;
   FaceList::iterator fitr;
   for (fitr=faceList.begin();
       fitr!=faceList.end();
       ++fitr)
   {

       Lib3dsFace& face = m->faceL[*fitr];

       if (orig2NewMapping[face.points[0]]<0)
           orig2NewMapping[face.points[0]] = noVertex++;

       if (orig2NewMapping[face.points[1]]<0)
           orig2NewMapping[face.points[1]] = noVertex++;

       if (orig2NewMapping[face.points[2]]<0)
           orig2NewMapping[face.points[2]] = noVertex++;

   }

   // create vertices.
osg::Vec3Array* osg_coords = new osg::Vec3Array(noVertex);
   geom->setVertexArray(osg_coords);

   Lib3dsVector c;
for (i=0; i<m->points; ++i)
   {
       if (orig2NewMapping[i]>=0)
       {
           if (matrix)
           {
               lib3ds_vector_transform(c,*matrix, m->pointL[i].pos);
               (*osg_coords)[orig2NewMapping[i]].set(c[0],c[1],c[2]);
           }
           else
           {
               // original no transform code.
               
(*osg_coords)[orig2NewMapping[i]].set(m->pointL[i].pos[0],m->pointL[i].pos[1],m->pointL[i].pos[2]);
           }
       }
   }

   // create texture coords if needed.
   if (m->texels>0)
   {
       if (m->texels==m->points)
       {
           osg::Vec2Array* osg_tcoords = new osg::Vec2Array(noVertex);
           geom->setTexCoordArray(0,osg_tcoords);
           for (i=0; i<m->texels; ++i)
           {
               if (orig2NewMapping[i]>=0) 
(*osg_tcoords)[orig2NewMapping[i]].set(m->texelL[i][0],m->texelL[i][1]);
           }
       }
       else
       {
           osg::notify(osg::WARN)<<"Warning: in 3ds loader m->texels ("<<m->texels<<") != m->points 
("<<m->points<<")"<< std::endl;
       }
   }

   // create normals.
   if (_usePerVertexNormals)
   {
       osg::Vec3Array* osg_normals = new osg::Vec3Array(noVertex);
// initialize normal list to zero's.
       for (i=0; i<noVertex; ++i)
       {
           (*osg_normals)[i].set(0.0f,0.0f,0.0f);
       }

       for (fitr=faceList.begin();
           fitr!=faceList.end();
           ++fitr)
       {
           Lib3dsFace& face = m->faceL[*fitr];

           (*osg_normals)[orig2NewMapping[face.points[0]]] += 
osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);;
           (*osg_normals)[orig2NewMapping[face.points[1]]] += 
osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);;
           (*osg_normals)[orig2NewMapping[face.points[2]]] += 
osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);;

       }

       if (matrix)
       {
           osg::Matrix osg_matrix;
           copyLib3dsMatrixToOsgMatrix(osg_matrix, *matrix);
           for (i=0; i<noVertex; ++i)
           {
               (*osg_normals)[i] = osg::Matrix::transform3x3((*osg_normals)[i], 
osg_matrix);
           }
       }

       // normalize the normal list to unit length normals.
       for (i=0; i<noVertex; ++i)
       {
           (*osg_normals)[i].normalize();
       }

       geom->setNormalArray(osg_normals);
       geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);

   }
else {
       osg::Vec3Array* osg_normals = new osg::Vec3Array(faceList.size());
       osg::Vec3Array::iterator normal_itr = osg_normals->begin();
       for (fitr=faceList.begin();
           fitr!=faceList.end();
           ++fitr)
       {
           Lib3dsFace& face = m->faceL[*fitr];
           *(normal_itr++) =  
osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);
       }
       geom->setNormalArray(osg_normals);
       geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
   }
osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
   (*osg_colors)[0].set(255,255,255,255);
   geom->setColorArray(osg_colors);
   geom->setColorBinding(osg::Geometry::BIND_OVERALL);
   // create primitives
   int numIndices = faceList.size()*3;
   DrawElementsUShort* elements = new 
osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,numIndices);
   DrawElementsUShort::iterator index_itr = elements->begin();

   for (fitr=faceList.begin();
       fitr!=faceList.end();
       ++fitr)
   {
       Lib3dsFace& face = m->faceL[*fitr];

       *(index_itr++) = orig2NewMapping[face.points[0]];
       *(index_itr++) = orig2NewMapping[face.points[1]];
       *(index_itr++) = orig2NewMapping[face.points[2]];
   }
geom->addPrimitiveSet(elements);

#if 0
   osgUtil::TriStripVisitor tsv;
   tsv.stripify(*geom);
#endif

   return geom;
}


osg::Texture2D*  ReaderWriter3DS::ReaderObject::createTexture(Lib3dsTextureMap 
*texture,const char* label,bool& transparancy, const 
osgDB::ReaderWriter::Options* options)
{
   if (texture && *(texture->name))
   {
       osg::notify(osg::NOTICE)<<"texture->name="<<texture->name<<", 
_directory="<<_directory<<std::endl;


       std::string fileName = 
osgDB::findFileInDirectory(texture->name,_directory,osgDB::CASE_INSENSITIVE);
if (fileName.empty()) {
           // file not found in .3ds file's directory, so we'll look in the 
datafile path list.
           fileName = osgDB::findDataFile(texture->name,options, 
osgDB::CASE_INSENSITIVE);
       }

       if (fileName.empty())
       {
           if (osgDB::containsServerAddress(_directory))
           {
               // if 3DS file is loaded from http, just attempt to load texture 
from same location.
               fileName = _directory + "/" + texture->name;
           } else {
               osg::notify(osg::WARN) << "texture '"<<texture->name<<"' not 
found"<< std::endl;
               return NULL;
           }
       }

       if (label) osg::notify(osg::DEBUG_INFO) << label;
       else osg::notify(osg::DEBUG_INFO) << "texture name";
       osg::notify(osg::DEBUG_INFO) << " '"<<texture->name<<"'"<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    texture flag        
"<<texture->flags<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_DECALE       
"<<((texture->flags)&LIB3DS_DECALE)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_MIRROR       
"<<((texture->flags)&LIB3DS_MIRROR)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_NEGATE       
"<<((texture->flags)&LIB3DS_NEGATE)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_NO_TILE      
"<<((texture->flags)&LIB3DS_NO_TILE)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_SUMMED_AREA  
"<<((texture->flags)&LIB3DS_SUMMED_AREA)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_ALPHA_SOURCE 
"<<((texture->flags)&LIB3DS_ALPHA_SOURCE)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_TINT         
"<<((texture->flags)&LIB3DS_TINT)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_IGNORE_ALPHA 
"<<((texture->flags)&LIB3DS_IGNORE_ALPHA)<< std::endl;
       osg::notify(osg::DEBUG_INFO) << "    LIB3DS_RGB_TINT     
"<<((texture->flags)&LIB3DS_RGB_TINT)<< std::endl;

       osg::ref_ptr<osg::Image> osg_image = 
osgDB::readRefImageFile(fileName.c_str(), options);
       if (!osg_image)
       {
           osg::notify(osg::NOTICE) << "Warning: Cannot create texture 
"<<texture->name<< std::endl;
           return NULL;
       }

       osg::Texture2D* osg_texture = new osg::Texture2D;
       osg_texture->setImage(osg_image.get());

       // does the texture support transparancy?
       transparancy = ((texture->flags)&LIB3DS_ALPHA_SOURCE)!=0;

       // what is the wrap mode of the texture.
       osg::Texture2D::WrapMode wm = ((texture->flags)&LIB3DS_NO_TILE) ?
               osg::Texture2D::CLAMP :
               osg::Texture2D::REPEAT;
       osg_texture->setWrap(osg::Texture2D::WRAP_S,wm);
       osg_texture->setWrap(osg::Texture2D::WRAP_T,wm);
       osg_texture->setWrap(osg::Texture2D::WRAP_R,wm);
                                // bilinear.
       
osg_texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR_MIPMAP_NEAREST);

       return osg_texture;
   }
   else
       return NULL;
}


osg::StateSet* ReaderWriter3DS::ReaderObject::createStateSet(Lib3dsMaterial 
*mat, const osgDB::ReaderWriter::Options* options)
{
   if (mat==NULL) return NULL;

   osg::StateSet* stateset = new osg::StateSet;

   osg::Material* material = new osg::Material;

   float transparency = mat->transparency;
   float alpha = 1.0f-transparency;

   osg::Vec4 ambient(mat->ambient[0],mat->ambient[1],mat->ambient[2],alpha);
   osg::Vec4 diffuse(mat->diffuse[0],mat->diffuse[1],mat->diffuse[2],alpha);
   osg::Vec4 specular(mat->specular[0],mat->specular[1],mat->specular[2],alpha);
   specular *= mat->shin_strength;

   float shininess = mat->shininess;
   material->setName(mat->name);
   material->setAmbient(osg::Material::FRONT_AND_BACK,ambient);
   material->setDiffuse(osg::Material::FRONT_AND_BACK,diffuse);
   material->setSpecular(osg::Material::FRONT_AND_BACK,specular);
   material->setShininess(osg::Material::FRONT_AND_BACK,shininess*128.0f);

   stateset->setAttribute(material);

   bool textureTransparancy=false;
   osg::Texture2D* texture1_map = 
createTexture(&(mat->texture1_map),"texture1_map",textureTransparancy, options);
   if (texture1_map)
   {
       
stateset->setTextureAttributeAndModes(0,texture1_map,osg::StateAttribute::ON);
if (!textureTransparancy) { // from an email from Eric Hamil, September 30, 2003.
           // According to the 3DS spec, and other
           // software (like Max, Lightwave, and Deep Exploration) a 3DS 
material that has
           // a non-white diffuse base color and a 100% opaque bitmap texture, 
will show the
           // texture with no influence from the base color.
// so we'll override material back to white.
           // and no longer require the decal hack below...
#if 0
           // Eric original fallback
           osg::Vec4 white(1.0f,1.0f,1.0f,alpha);
           material->setAmbient(osg::Material::FRONT_AND_BACK,white);
           material->setDiffuse(osg::Material::FRONT_AND_BACK,white);
           material->setSpecular(osg::Material::FRONT_AND_BACK,white);
#else
           // try alternative to avoid saturating with white
           // setting white as per OpenGL defaults.
           
material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(0.2f,0.2f,0.2f,alpha));
           
material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(0.8f,0.8f,0.8f,alpha));
           
material->setSpecular(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,alpha));
#endif } // no longer required... // bool decal = false; // // // not sure exactly how to interpret what is best for .3ds
//         // but the default text env MODULATE doesn't work well, and
//         // DECAL seems to work better.
//         osg::TexEnv* texenv = new osg::TexEnv;
//         if (decal)
//         {
//             texenv->setMode(osg::TexEnv::DECAL);
//         }
//         else
//         {
//             texenv->setMode(osg::TexEnv::MODULATE);
//         }
//        stateset->setTextureAttribute(0,texenv);
   }

   if (transparency>0.0f || textureTransparancy)
   {
       stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
       stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
   }

/*
   osg::ref_ptr<osg::Texture> texture1_mask = 
createTexture(&(mat->texture1_mask),"texture1_mask",textureTransparancy);
   osg::ref_ptr<osg::Texture> texture2_map = 
createTexture(&(mat->texture2_map),"texture2_map",textureTransparancy);
   osg::ref_ptr<osg::Texture> texture2_mask = 
createTexture(&(mat->texture2_mask),"texture2_mask",textureTransparancy);
   osg::ref_ptr<osg::Texture> opacity_map = 
createTexture(&(mat->opacity_map),"opacity_map",textureTransparancy);
   osg::ref_ptr<osg::Texture> opacity_mask = 
createTexture(&(mat->opacity_mask),"opacity_mask",textureTransparancy);
   osg::ref_ptr<osg::Texture> bump_map = 
createTexture(&(mat->bump_map),"bump_map",textureTransparancy);
   osg::ref_ptr<osg::Texture> bump_mask = 
createTexture(&(mat->bump_mask),"bump_mask",textureTransparancy);
   osg::ref_ptr<osg::Texture> specular_map = 
createTexture(&(mat->specular_map),"specular_map",textureTransparancy);
   osg::ref_ptr<osg::Texture> specular_mask = 
createTexture(&(mat->specular_mask),"specular_mask",textureTransparancy);
   osg::ref_ptr<osg::Texture> shininess_map = 
createTexture(&(mat->shininess_map),"shininess_map",textureTransparancy);
   osg::ref_ptr<osg::Texture> shininess_mask = 
createTexture(&(mat->shininess_mask),"shininess_mask",textureTransparancy);
   osg::ref_ptr<osg::Texture> self_illum_map = 
createTexture(&(mat->self_illum_map),"self_illum_map",textureTransparancy);
   osg::ref_ptr<osg::Texture> self_illum_mask = 
createTexture(&(mat->self_illum_mask),"self_illum_mask",textureTransparancy);
   osg::ref_ptr<osg::Texture> reflection_map = 
createTexture(&(mat->reflection_map),"reflection_map",textureTransparancy);
   osg::ref_ptr<osg::Texture> reflection_mask = 
createTexture(&(mat->reflection_mask),"reflection_mask",textureTransparancy);
*/
   return stateset;
}

_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to