Support added for pivot points, submission from Mike Connel.

This commit is contained in:
Robert Osfield
2002-03-09 10:54:56 +00:00
parent 8a8015c41c
commit bc30edb9e6

View File

@@ -6,17 +6,24 @@
#include <osg/Material>
#include <osg/TexEnv>
#include <osg/ref_ptr>
#include <osg/Transform>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
//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 <stdlib.h>
#include <string.h>
@@ -24,6 +31,52 @@
#include <set>
#include <map>
using namespace std;
using namespace osg;
class PrintVisitor : public NodeVisitor
{
public:
PrintVisitor():NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
_indent = 0;
_step = 4;
}
inline void moveIn() { _indent += _step; }
inline void moveOut() { _indent -= _step; }
inline void writeIndent()
{
for(int i=0;i<_indent;++i) std::cout << " ";
}
virtual void apply(Node& node)
{
moveIn();
writeIndent(); std::cout << node.className() << " name=" << node.getName() << 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((Node&)node); }
virtual void apply(Group& node) { apply((Node&)node); }
virtual void apply(Transform& node) { apply((Group&)node); }
virtual void apply(Switch& node) { apply((Group&)node); }
virtual void apply(LOD& node) { apply((Group&)node); }
virtual void apply(Impostor& node) { apply((LOD&)node); }
protected:
int _indent;
int _step;
};
typedef std::map<std::string,osg::StateSet*> StateSetMap;
class ReaderWriter3DS : public osgDB::ReaderWriter
{
public:
@@ -42,11 +95,16 @@ class ReaderWriter3DS : public osgDB::ReaderWriter
osg::Texture* createTexture(Lib3dsTextureMap *texture,const char* label,bool& transparancy);
osg::StateSet* createStateSet(Lib3dsMaterial *materials);
osg::GeoSet* createGeoSet(Lib3dsMesh *meshes,FaceList& faceList);
osg::GeoSet* createGeoSet(Lib3dsMesh *meshes,FaceList& faceList, Lib3dsMatrix* matrix);
std::string _directory;
bool _useSmoothingGroups;
bool _usePerVertexNormals;
// MIKEC
void 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
@@ -60,84 +118,127 @@ ReaderWriter3DS::ReaderWriter3DS()
}
osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*)
{
/**
These print methods for 3ds hacking
*/
void pad(int level) {
for(int i=0;i<level;i++) 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);
Lib3dsFile *f = lib3ds_file_load(fileName.c_str());
if (f==NULL) return ReadResult::FILE_NOT_HANDLED;
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;
}
}
_directory = osgDB::getFilePath(fileName);
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);
osg::Group* group = new osg::Group;
group->setName(fileName);
typedef std::map<std::string,osg::StateSet*> StateSetMap;
StateSetMap drawStateMap;
for (Lib3dsMaterial *mat=f->materials; mat; mat=mat->next)
{
drawStateMap[mat->name] = createStateSet(mat);
for(Lib3dsNode *child=node->childs; child; child=child->next) {
print(child,level+1);
}
for (Lib3dsMesh *mesh=f->meshes; mesh; mesh=mesh->next)
}
// Transforms points by matrix if 'matrix' is not NULL
// Creates a Geode and GeoSet (as parent,child) and adds the Geode to 'parent' parameter
void ReaderWriter3DS::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;
}
else
{
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);
}
osg::Geode* geode = new osg::Geode;
geode->setName(mesh->name);
if (materialFaceMap.empty())
for(MaterialFaceMap::iterator itr=materialFaceMap.begin();
itr!=materialFaceMap.end();
++itr)
{
osg::notify(osg::NOTICE)<<"Warning : no triangles assigned to mesh '"<<mesh->name<<"'"<< std::endl;
}
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)
{
FaceList& faceList = itr->second;
if (_useSmoothingGroups)
typedef std::map<int,FaceList> SmoothingFaceMap;
SmoothingFaceMap smoothingFaceMap;
for (FaceList::iterator flitr=faceList.begin();
flitr!=faceList.end();
++flitr)
{
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 geoset
// to ensure the vertices on adjacent groups
// don't get shared.
FaceList& smoothFaceMap = sitr->second;
osg::GeoSet* geoset = createGeoSet(mesh,smoothFaceMap);
if (geoset)
{
geoset->setStateSet(drawStateMap[itr->first]);
geode->addDrawable(geoset);
}
}
smoothingFaceMap[mesh->faceL[*flitr].smoothing].push_back(*flitr);
}
else // ignore smoothing groups.
for(SmoothingFaceMap::iterator sitr=smoothingFaceMap.begin();
sitr!=smoothingFaceMap.end();
++sitr)
{
osg::GeoSet* geoset = createGeoSet(mesh,faceList);
// each smoothing group to have its own geoset
// to ensure the vertices on adjacent groups
// don't get shared.
FaceList& smoothFaceMap = sitr->second;
osg::GeoSet* geoset = createGeoSet(mesh,smoothFaceMap,matrix);
if (geoset)
{
geoset->setStateSet(drawStateMap[itr->first]);
@@ -145,18 +246,340 @@ osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& fil
}
}
}
group->addChild(geode);
else // ignore smoothing groups.
{
osg::GeoSet* geoset = createGeoSet(mesh,faceList,matrix);
if (geoset)
{
geoset->setStateSet(drawStateMap[itr->first]);
geode->addDrawable(geoset);
}
}
}
parent->addChild(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 devling further
Unfortunately, this gets a bit wonky with objects with pivot points (conjucture: 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 (nnegative) pivot point coords, this puts the PP at the origin
Tranform 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::processNode(StateSetMap drawStateMap,Lib3dsFile *f,Lib3dsNode *node) {
osg::Group* group=new osg::Group;
group->setName(node->name);
// Handle all children of this node for hierarchical assemblies
Lib3dsNode *p;
for (p=node->childs; p!=0; p=p->next) {
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];
// Transform object's pivot point to the world origin
osg::Transform* T=new osg::Transform;
osgmatrix.set(
N[0][0],N[0][1],N[0][2],N[0][3],
N[1][0],N[1][1],N[1][2],N[1][3],
N[2][0],N[2][1],N[2][2],N[2][3],
N[3][0],N[3][1],N[3][2],N[3][3]);
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::Transform* R=new osg::Transform;
osgmatrix.set(
M[0][0],M[0][1],M[0][2],M[0][3],
M[1][0],M[1][1],M[1][2],M[1][3],
M[2][0],M[2][1],M[2][2],M[2][3],
M[3][0],M[3][1],M[3][2],M[3][3]);
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]);
*/
// Always in reverse order...
group->addChild(R);
R->addChild(T);
processMesh(drawStateMap,T,mesh,&mesh_inverse); // creates geometry under modifier node
} else {
// no mesh for this node - probably a camera or something of that persuasion
//cout << "no mesh for object " << node->name << endl;
}
return group;
}
osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*)
{
Lib3dsFile *f = lib3ds_file_load(fileName.c_str());
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
_directory = osgDB::getFilePath(fileName);
osg::Group* group = new osg::Group;
group->setName(fileName);
StateSetMap drawStateMap;
for (Lib3dsMaterial *mat=f->materials; mat; mat=mat->next)
{
drawStateMap[mat->name] = createStateSet(mat);
}
/*{
int level=0;
std::cout << "NODE TRAVERSAL of file "<<f->name<<std::endl;
for(Lib3dsNode *node=f->nodes; node; node=node->next) {
print(node,level+1);
}
std::cout << "MESH TRAVERSAL of 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) {
processMesh(drawStateMap,group,mesh,NULL);
}
} else { // new method
for(Lib3dsNode *node=f->nodes; node; node=node->next) {
group->addChild(processNode(drawStateMap,f,node));
}
}
/*
cout << "Final OSG node structure looks like this:"<< endl;
PrintVisitor pv;
group->accept(pv);
*/
lib3ds_file_free(f);
return group;
}
/**
use matrix to pretransform geometry, or NULL to do nothing
*/
osg::GeoSet* ReaderWriter3DS::createGeoSet(Lib3dsMesh *m,FaceList& faceList,Lib3dsMatrix *matrix)
{
osg::GeoSet* geoset = new osg::GeoSet;
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++;
}
osg::Vec3* osg_coords = new osg::Vec3[noVertex];
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]);
}
}
}
osg::Vec2* osg_tcoords = NULL;
if (m->texels>0)
{
if (m->texels==m->points)
{
osg_tcoords = new osg::Vec2[noVertex];
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;
}
}
// handle normals.
osg::Vec3* osg_normals;
if (_usePerVertexNormals)
{
osg_normals = new osg::Vec3[noVertex];
// initialize normal list to zero's.
for (i=0; i<noVertex; ++i)
{
osg_normals[i].set(0.0f,0.0f,0.0f);
}
}
else
{
osg_normals = new osg::Vec3[faceList.size()];
}
osg::Vec3* normal_ptr = osg_normals;
int numIndices = faceList.size()*3;
osg::ushort* osg_indices = new osg::ushort[numIndices];
osg::ushort* index_ptr = osg_indices;
for (fitr=faceList.begin();
fitr!=faceList.end();
++fitr)
{
Lib3dsFace& face = m->faceL[*fitr];
*(index_ptr++) = orig2NewMapping[face.points[0]];
*(index_ptr++) = orig2NewMapping[face.points[1]];
*(index_ptr++) = orig2NewMapping[face.points[2]];
if (_usePerVertexNormals)
{
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]);;
}
else
{
*(normal_ptr++) = osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);
}
}
if (_usePerVertexNormals)
{
// normalize the normal list to unit length normals.
for (i=0; i<noVertex; ++i)
{
// osg_normals[i].normalize();
float len = osg_normals[i].length();
if (len) osg_normals[i]/=len;
}
geoset->setNormals(osg_normals,osg_indices);
geoset->setNormalBinding(osg::GeoSet::BIND_PERVERTEX);
}
else
{
geoset->setNormals(osg_normals);
geoset->setNormalBinding(osg::GeoSet::BIND_PERPRIM);
}
geoset->setCoords(osg_coords,osg_indices);
if (osg_tcoords)
{
geoset->setTextureBinding(osg::GeoSet::BIND_PERVERTEX);
geoset->setTextureCoords(osg_tcoords,osg_indices);
}
geoset->setPrimType(osg::GeoSet::TRIANGLES);
geoset->setNumPrims(faceList.size());
return geoset;
}
osg::Texture* ReaderWriter3DS::createTexture(Lib3dsTextureMap *texture,const char* label,bool& transparancy)
{
@@ -285,164 +708,3 @@ osg::StateSet* ReaderWriter3DS::createStateSet(Lib3dsMaterial *mat)
return stateset;
}
osg::GeoSet* ReaderWriter3DS::createGeoSet(Lib3dsMesh *m,FaceList& faceList)
{
osg::GeoSet* geoset = new osg::GeoSet;
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++;
}
osg::Vec3* osg_coords = new osg::Vec3[noVertex];
Lib3dsVector c;
// Note for Ben, 1st Jan 2002 from Robert.
// added code to use the matrix attached with each lib3dsMesh to
// multiply each coord on the mesh before passing to the OSG.
// however, this caused plenty of problems as applying the matrices
// moved the objects away from the original positions.
bool useMatrix = false;
if (useMatrix)
{
lib3ds_matrix_dump(m->matrix);
}
for (i=0; i<m->points; ++i)
{
// lib3ds_vector_transform(pos, m->matrix, m->pointL[i].pos);
if (orig2NewMapping[i]>=0) {
if (useMatrix)
{
lib3ds_vector_transform(c,m->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]);
}
}
}
osg::Vec2* osg_tcoords = NULL;
if (m->texels>0)
{
if (m->texels==m->points)
{
osg_tcoords = new osg::Vec2[noVertex];
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;
}
}
// handle normals.
osg::Vec3* osg_normals;
if (_usePerVertexNormals)
{
osg_normals = new osg::Vec3[noVertex];
// initialize normal list to zero's.
for (i=0; i<noVertex; ++i)
{
osg_normals[i].set(0.0f,0.0f,0.0f);
}
}
else
{
osg_normals = new osg::Vec3[faceList.size()];
}
osg::Vec3* normal_ptr = osg_normals;
int numIndices = faceList.size()*3;
osg::ushort* osg_indices = new osg::ushort[numIndices];
osg::ushort* index_ptr = osg_indices;
for (fitr=faceList.begin();
fitr!=faceList.end();
++fitr)
{
Lib3dsFace& face = m->faceL[*fitr];
*(index_ptr++) = orig2NewMapping[face.points[0]];
*(index_ptr++) = orig2NewMapping[face.points[1]];
*(index_ptr++) = orig2NewMapping[face.points[2]];
if (_usePerVertexNormals)
{
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]);;
}
else
{
*(normal_ptr++) = osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);
}
}
if (_usePerVertexNormals)
{
// normalize the normal list to unit length normals.
for (i=0; i<noVertex; ++i)
{
// osg_normals[i].normalize();
float len = osg_normals[i].length();
if (len) osg_normals[i]/=len;
}
geoset->setNormals(osg_normals,osg_indices);
geoset->setNormalBinding(osg::GeoSet::BIND_PERVERTEX);
}
else
{
geoset->setNormals(osg_normals);
geoset->setNormalBinding(osg::GeoSet::BIND_PERPRIM);
}
geoset->setCoords(osg_coords,osg_indices);
if (osg_tcoords)
{
geoset->setTextureBinding(osg::GeoSet::BIND_PERVERTEX);
geoset->setTextureCoords(osg_tcoords,osg_indices);
}
geoset->setPrimType(osg::GeoSet::TRIANGLES);
geoset->setNumPrims(faceList.size());
return geoset;
}