// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace NLMISC;
using namespace NL3D;
using namespace std;
struct CVertex
{
CVector vertex;
CVector normal;
CUV uv;
};
bool operator == (const CVertex &v1, const CVertex &v2)
{
return (v1.vertex == v2.vertex) && (v1.normal == v2.normal) && (v1.uv == v2.uv);
}
bool operator < (const CVertex &v1, const CVertex &v2)
{
return (v1.vertex < v2.vertex);
}
const CIndexBuffer *getRdrPassPrimitiveBlock(const CMeshMRMGeom *mesh, uint lodId, uint renderPass)
{
return &(mesh->getRdrPassPrimitiveBlock(lodId, renderPass));
}
// ***************************************************************************
const CIndexBuffer *getRdrPassPrimitiveBlock(const CMeshMRMSkinnedGeom *mesh, uint lodId, uint renderPass)
{
static CIndexBuffer block;
mesh->getRdrPassPrimitiveBlock(lodId, renderPass, block);
return █
}
// ***************************************************************************
bool ProcessMeshMRMSkinned(const std::string &filename, IShape *shapeMesh);
bool ProcessMeshMRM(const std::string &filename, IShape *shapeMesh);
//bool ProcessMesh(const std::string &filename, IShape *shapeMesh);
int main(int argc, char* argv[])
{
if (argc < 2)
{
cout << "Syntax : shape2obj " << endl;
return 1;
}
if (!NLMISC::INelContext::isContextInitialised()) new NLMISC::CApplicationContext();
registerSerial3d();
CScene::registerBasics();
IShape *shapeMesh = NULL;
CIFile ifile;
// Sream a shape
CShapeStream streamShape;
string filename = argv[1];
if (!ifile.open(filename)) return 1;
try
{
// Stream it
streamShape.serial(ifile);
// Add the shape
shapeMesh = streamShape.getShapePointer();
}
catch (Exception& e)
{
cout << "Error : " << e.what() << endl;
return 1;
}
if (ProcessMeshMRMSkinned(filename, shapeMesh)) return 0;
if (ProcessMeshMRM(filename, shapeMesh)) return 0;
// if (ProcessMesh(filename, shapeMesh)) return 0;
return 0;
}
bool ProcessMeshMRMSkinned(const std::string &filename, IShape *shapeMesh)
{
CMeshMRMSkinned *mesh = dynamic_cast(shapeMesh);
if (!mesh) return false;
COFile ofile;
CMeshMRMSkinnedGeom* meshIn = (CMeshMRMSkinnedGeom*)&mesh->getMeshGeom();
std::vector skinWeights;
meshIn->getSkinWeights(skinWeights);
CVertexBuffer vertexBuffer;
meshIn->getVertexBuffer(vertexBuffer);
CVertexBufferRead vba;
vertexBuffer.lock (vba);
uint i, j;
// **** Select the Lod.
uint numLods= meshIn->getNbLod();
// get the max tris displayed
float numMeshFacesMin= (float)meshIn->getLevelDetail().MinFaceUsed;
float numMeshFacesMax= (float)meshIn->getLevelDetail().MaxFaceUsed;
// find the lod
sint lodId = numLods-1;
// **** First, for the best lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
vector vertexUsed;
// -1 means "not used"
vertexUsed.resize(skinWeights.size(), -1);
// Parse all triangles.
for(i=0;igetNbRdrPass(lodId); ++i)
{
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
CIndexBufferRead iba;
pb->lock (iba);
if (iba.getFormat() == CIndexBuffer::Indices32)
{
const uint32 *triPtr= (const uint32 *) iba.getPtr();
for(j=0;jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Flag the vertex with its own index => used.
vertexUsed[idx]= idx;
triPtr++;
}
}
else
{
const uint16 *triPtr= (const uint16 *) iba.getPtr();
for(j=0;jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Flag the vertex with its own index => used.
vertexUsed[idx]= idx;
triPtr++;
}
}
}
// Special for Geomorphs: must take The End target vertex.
const std::vector &geomorphs= meshIn->getGeomorphs(lodId);
for(i=0;i shadowVertices;
vector vertexToVSkin;
vertexToVSkin.resize(vertexUsed.size());
shadowVertices.reserve(vertexUsed.size());
// use a map to remove duplicates (because of UV/normal discontinuities before!!)
map shadowVertexMap;
uint numMerged= 0;
// Skip Geomorphs.
for(i=geomorphs.size();imaxW)
{
matId= sw.MatrixId[j];
maxW= sw.Weights[j];
}
}
// shadowVert.MatrixId= matId;
*/
// If dont find the shadowVertex in the map.
map::iterator it= shadowVertexMap.find(shadowVert);
if(it==shadowVertexMap.end())
{
// Append
uint index= shadowVertices.size();
vertexToVSkin[i]= index;
shadowVertices.push_back(shadowVert);
shadowVertexMap.insert(make_pair(shadowVert, index));
}
else
{
// Ok, map.
vertexToVSkin[i]= it->second;
numMerged++;
}
}
}
ofstream ofs(string(filename + ".obj").c_str());
for(size_t y = 0; y < shadowVertices.size(); ++y)
{
CVector v = shadowVertices[y].vertex;
CVector vn = shadowVertices[y].normal;
CUV vt = shadowVertices[y].uv;
ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
ofs << "vt " << vt.U << " " << vt.V << endl;
}
// **** Get All Faces
// Final List Of Triangles that match the bone.
vector shadowTriangles;
shadowTriangles.reserve(1000);
// Parse all input tri of the mesh.
for(i=0; igetNbRdrPass(lodId); ++i)
{
ofs << "g pass" << i << endl;
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
CIndexBufferRead iba;
pb->lock (iba);
if (iba.getFormat() == CIndexBuffer::Indices32)
{
const uint32 *triPtr= (const uint32 *) iba.getPtr();
for(j=0; jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Get the real Vertex (ie not the geomporhed one).
idx= vertexUsed[idx];
// Get the ShadowVertex associated
idx= vertexToVSkin[idx];
shadowTriangles.push_back(idx);
triPtr++;
}
}
else
{
const uint16 *triPtr= (const uint16 *) iba.getPtr();
for(j=0; jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Get the real Vertex (ie not the geomporhed one).
idx= vertexUsed[idx];
// Get the ShadowVertex associated
idx= vertexToVSkin[idx];
shadowTriangles.push_back(idx);
triPtr++;
}
}
for(size_t pass = 0; pass(shapeMesh);
if (!mesh) return false;
COFile ofile;
CMeshMRMGeom* meshIn = (CMeshMRMGeom*)&mesh->getMeshGeom();
std::vector skinWeights = meshIn->getSkinWeights();
CVertexBuffer vertexBuffer = meshIn->getVertexBuffer();
CVertexBufferRead vba;
vertexBuffer.lock (vba);
uint i, j;
// **** Select the Lod.
uint numLods= meshIn->getNbLod();
// get the max tris displayed
float numMeshFacesMin= (float)meshIn->getLevelDetail().MinFaceUsed;
float numMeshFacesMax= (float)meshIn->getLevelDetail().MaxFaceUsed;
// find the lod
sint lodId = numLods-1;
// **** First, for the best lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
vector vertexUsed;
// -1 means "not used"
vertexUsed.resize(skinWeights.size(), -1);
// Parse all triangles.
for(i=0;igetNbRdrPass(lodId); ++i)
{
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
CIndexBufferRead iba;
pb->lock (iba);
if (iba.getFormat() == CIndexBuffer::Indices32)
{
const uint32 *triPtr= (const uint32 *) iba.getPtr();
for(j=0;jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Flag the vertex with its own index => used.
vertexUsed[idx]= idx;
triPtr++;
}
}
else
{
const uint16 *triPtr= (const uint16 *) iba.getPtr();
for(j=0;jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Flag the vertex with its own index => used.
vertexUsed[idx]= idx;
triPtr++;
}
}
}
// Special for Geomorphs: must take The End target vertex.
const std::vector &geomorphs= meshIn->getGeomorphs(lodId);
for(i=0;i shadowVertices;
vector vertexToVSkin;
vertexToVSkin.resize(vertexUsed.size());
shadowVertices.reserve(vertexUsed.size());
// use a map to remove duplicates (because of UV/normal discontinuities before!!)
map shadowVertexMap;
uint numMerged= 0;
// Skip Geomorphs.
for(i=geomorphs.size();imaxW)
{
matId= sw.MatrixId[j];
maxW= sw.Weights[j];
}
}
// shadowVert.MatrixId= matId;
*/
// If dont find the shadowVertex in the map.
map::iterator it= shadowVertexMap.find(shadowVert);
if(it==shadowVertexMap.end())
{
// Append
uint index= shadowVertices.size();
vertexToVSkin[i]= index;
shadowVertices.push_back(shadowVert);
shadowVertexMap.insert(make_pair(shadowVert, index));
}
else
{
// Ok, map.
vertexToVSkin[i]= it->second;
numMerged++;
}
}
}
ofstream ofs(string(filename + ".obj").c_str());
for(size_t y = 0; y < shadowVertices.size(); ++y)
{
CVector v = shadowVertices[y].vertex;
CVector vn = shadowVertices[y].normal;
CUV vt = shadowVertices[y].uv;
ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
ofs << "vt " << vt.U << " " << vt.V << endl;
}
// **** Get All Faces
// Final List Of Triangles that match the bone.
vector shadowTriangles;
shadowTriangles.reserve(1000);
// Parse all input tri of the mesh.
for(i=0; igetNbRdrPass(lodId); ++i)
{
ofs << "g pass" << i << endl;
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
CIndexBufferRead iba;
pb->lock (iba);
if (iba.getFormat() == CIndexBuffer::Indices32)
{
const uint32 *triPtr= (const uint32 *) iba.getPtr();
for(j=0; jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Get the real Vertex (ie not the geomporhed one).
idx= vertexUsed[idx];
// Get the ShadowVertex associated
idx= vertexToVSkin[idx];
shadowTriangles.push_back(idx);
triPtr++;
}
}
else
{
const uint16 *triPtr= (const uint16 *) iba.getPtr();
for(j=0; jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Get the real Vertex (ie not the geomporhed one).
idx= vertexUsed[idx];
// Get the ShadowVertex associated
idx= vertexToVSkin[idx];
shadowTriangles.push_back(idx);
triPtr++;
}
}
for(size_t pass = 0; pass(shapeMesh);
if (!mesh) return false;
COFile ofile;
CMeshGeom* meshIn = (CMeshGeom*)&mesh->getMeshGeom();
CVertexBuffer vertexBuffer = meshIn->getVertexBuffer();
// CVertexBufferRead vba;
// vertexBuffer.lock (vba);
uint i = vertexBuffer.getNumVertices();
std::vector vertices;
meshIn->retrieveVertices(vertices);
std::vector indices;
meshIn->retrieveTriangles(indices);
// **** For all vertices used (not geomorphs), compute vertex Skins.
vector shadowVertices;
vector vertexToVSkin;
vertexToVSkin.resize(indices.size());
shadowVertices.reserve(indices.size());
// use a map to remove duplicates (because of UV/normal discontinuities before!!)
map shadowVertexMap;
uint numMerged= 0;
// Skip Geomorphs.
for(i=0;imaxW)
{
matId= sw.MatrixId[j];
maxW= sw.Weights[j];
}
}
// If dont find the shadowVertex in the map.
map::iterator it= shadowVertexMap.find(shadowVert);
if(it==shadowVertexMap.end())
{
// Append
uint index= shadowVertices.size();
vertexToVSkin[i]= index;
shadowVertices.push_back(shadowVert);
shadowVertexMap.insert(make_pair(shadowVert, index));
}
else
{
// Ok, map.
vertexToVSkin[i]= it->second;
numMerged++;
}
}
ofstream ofs(string(filename + ".obj").c_str());
for(size_t y = 0; y < shadowVertices.size(); ++y)
{
CVector v = shadowVertices[y].vertex;
CVector vn = shadowVertices[y].normal;
CUV vt = shadowVertices[y].uv;
ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
ofs << "vt " << vt.U << " " << vt.V << endl;
}
// **** Get All Faces
// Final List Of Triangles that match the bone.
vector shadowTriangles;
shadowTriangles.reserve(1000);
// Parse all input tri of the mesh.
for(i=0; igetNbRdrPass(lodId); ++i)
{
ofs << "g pass" << i << endl;
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
CIndexBufferRead iba;
pb->lock (iba);
if (iba.getFormat() == CIndexBuffer::Indices32)
{
const uint32 *triPtr= (const uint32 *) iba.getPtr();
for(j=0; jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Get the real Vertex (ie not the geomporhed one).
idx= vertexUsed[idx];
// Get the ShadowVertex associated
idx= vertexToVSkin[idx];
shadowTriangles.push_back(idx);
triPtr++;
}
}
else
{
const uint16 *triPtr= (const uint16 *) iba.getPtr();
for(j=0; jgetNumIndexes(); ++j)
{
uint idx= *triPtr;
// Get the real Vertex (ie not the geomporhed one).
idx= vertexUsed[idx];
// Get the ShadowVertex associated
idx= vertexToVSkin[idx];
shadowTriangles.push_back(idx);
triPtr++;
}
}
for(size_t pass = 0; pass