Added: #1440 PolyObject triangulation and obj test exporter

--HG--
branch : build_pipeline_v3
hg/feature/build_pipeline_v3
kaetemi 12 years ago
parent 4f544bf916
commit 534d0bdca9

@ -34,7 +34,6 @@
// #include <nel/misc/debug.h> // #include <nel/misc/debug.h>
// Project includes // Project includes
#include "storage/geom_buffers.h"
// using namespace std; // using namespace std;
// using namespace NLMISC; // using namespace NLMISC;
@ -147,6 +146,110 @@ void CGeomObject::toStringLocal(std::ostream &ostream, const std::string &pad, u
} }
} }
inline uint32 rrsub(uint32 v, uint32 size)
{
if (v) return v - 1;
return size - 1;
}
inline uint32 rradd(uint32 v, uint32 size)
{
uint32 vp = v + 1;
if (vp != size) return vp;
return 0;
}
void CGeomObject::triangulatePolyFace(std::vector<STORAGE::CGeomTriIndex> &triangles, const STORAGE::CGeomPolyFaceInfo &polyFace)
{
nlassert(polyFace.Vertices.size() >= 3);
nlassert(polyFace.Triangulation.size() == polyFace.Vertices.size() - 3);
uint nbVert = polyFace.Vertices.size();
uint nbCuts = polyFace.Triangulation.size();
uint nbTriangles = 0;
// This code creates a matrix, aka a table, of all possible paths
// that can be traveled to get directly from one vertex to another
// over an egde.
// Outer edges of the polygon are one-way, backwards.
// Cut edges can be traveled both ways.
// Each edge direction can only be traveled by one triangle.
// Ingenious, if I may say so myself.
// Bad performance by std::vector, though.
std::vector<std::vector<bool> > from_to;
from_to.resize(nbVert);
for (uint i = 0; i < nbVert; ++i)
{
from_to[i].resize(nbVert);
for (uint j = 0; j < nbVert; ++j)
{
from_to[i][j] = false;
}
// Can travel backwards over the outer edge
from_to[i][rrsub(i, nbVert)] = true;
}
for (uint i = 0; i < nbCuts; ++i)
{
// Can travel both ways over cuts, but the first direction is handled directly!
// from_to[polyFace.Triangulation[i].first][polyFace.Triangulation[i].second] = true;
from_to[polyFace.Triangulation[i].second][polyFace.Triangulation[i].first] = true;
}
// Triangulate all cuts, this assumes cuts are in the direction
// of a triangle that is not already handled by another cut...
for (uint i = 0; i < nbCuts; ++i)
{
uint32 a = polyFace.Triangulation[i].first;
uint32 b = polyFace.Triangulation[i].second;
// from_to[polyFace.Triangulation[i].first][polyFace.Triangulation[i].second] = false; // handled!
// Try to find a path that works
for (uint c = 0; c < nbVert; ++c)
{
// Can we make a triangle
if (from_to[b][c] && from_to[c][a])
{
STORAGE::CGeomTriIndex tri;
tri.a = polyFace.Vertices[c];
tri.b = polyFace.Vertices[b];
tri.c = polyFace.Vertices[a];
triangles.push_back(tri);
++nbTriangles;
// nldebug("add tri from cut");
from_to[b][c] = false;
from_to[c][a] = false;
break;
}
}
}
// Find... The Last Triangle
for (uint a = 0; a < nbVert; ++a)
{
uint b = rrsub(a, nbVert);
// Can we still travel backwards over the outer edge?
if (from_to[a][b])
{
for (uint c = 0; c < nbVert; ++c)
{
// Can we make a triangle
if (from_to[b][c] && from_to[c][a])
{
STORAGE::CGeomTriIndex tri;
tri.a = polyFace.Vertices[c];
tri.b = polyFace.Vertices[b];
tri.c = polyFace.Vertices[a];
triangles.push_back(tri);
++nbTriangles;
// nldebug("add final tri");
from_to[b][c] = false;
from_to[c][a] = false;
break;
}
}
}
}
// nldebug("triangles: %i", nbTriangles);
// nldebug("cuts: %i", nbCuts);
nlassert(nbTriangles == nbCuts + 1);
}
IStorageObject *CGeomObject::createChunkById(uint16 id, bool container) IStorageObject *CGeomObject::createChunkById(uint16 id, bool container)
{ {
switch (id) switch (id)

@ -35,6 +35,7 @@
// Project includes // Project includes
#include "object.h" #include "object.h"
#include "storage/geom_buffers.h"
/// Must be passed to the parse and build functions by /// Must be passed to the parse and build functions by
/// inheriting classes to parse the actual geom object. /// inheriting classes to parse the actual geom object.
@ -43,9 +44,6 @@
namespace PIPELINE { namespace PIPELINE {
namespace MAX { namespace MAX {
namespace BUILTIN { namespace BUILTIN {
namespace STORAGE {
class CGeomBuffers;
}
/** /**
* \brief CGeomGeomObject * \brief CGeomGeomObject
@ -76,6 +74,8 @@ public:
virtual const ISceneClassDesc *classDesc() const; virtual const ISceneClassDesc *classDesc() const;
virtual void toStringLocal(std::ostream &ostream, const std::string &pad = "", uint filter = 0) const; virtual void toStringLocal(std::ostream &ostream, const std::string &pad = "", uint filter = 0) const;
static void triangulatePolyFace(std::vector<STORAGE::CGeomTriIndex> &triangles, const STORAGE::CGeomPolyFaceInfo &polyFace);
// read access // read access
inline STORAGE::CGeomBuffers *geomBuffers() const { return m_GeomBuffers; } inline STORAGE::CGeomBuffers *geomBuffers() const { return m_GeomBuffers; }

@ -107,6 +107,7 @@ void CEditablePoly::build(uint16 version, uint filter)
void CEditablePoly::disown() void CEditablePoly::disown()
{ {
m_EditablePolyUnknown.clear();
CPolyObject::disown(); CPolyObject::disown();
} }

@ -38,6 +38,8 @@
#include "../max/builtin/storage/geom_buffers.h" #include "../max/builtin/storage/geom_buffers.h"
#include "../max/builtin/scene_impl.h" #include "../max/builtin/scene_impl.h"
#include "../max/builtin/i_node.h" #include "../max/builtin/i_node.h"
#include "../max/update1/editable_mesh.h"
#include "../max/epoly/editable_poly.h"
using namespace PIPELINE::MAX; using namespace PIPELINE::MAX;
using namespace PIPELINE::MAX::BUILTIN; using namespace PIPELINE::MAX::BUILTIN;
@ -46,15 +48,28 @@ using namespace PIPELINE::MAX::UPDATE1;
using namespace PIPELINE::MAX::EPOLY; using namespace PIPELINE::MAX::EPOLY;
//static const char *filename = "/srv/work/database/interfaces/anims_max/cp_fy_hof_species.max"; //static const char *filename = "/srv/work/database/interfaces/anims_max/cp_fy_hof_species.max";
//static const char *filename = "/home/kaetemi/source/minimax/GE_Acc_MikotoBaniere.max"; static const char *filename = "/home/kaetemi/source/minimax/GE_Acc_MikotoBaniere.max";
//static const char *filename = "/home/kaetemi/3dsMax/scenes/test2008.max"; //static const char *filename = "/home/kaetemi/3dsMax/scenes/test2008.max";
//static const char *filename = "/home/kaetemi/3dsMax/scenes/teapot_test_scene.max"; //static const char *filename = "/home/kaetemi/3dsMax/scenes/teapot_test_scene.max";
//static const char *filename = "/home/kaetemi/3dsMax/scenes/testplane.max"; //static const char *filename = "/home/kaetemi/3dsMax/scenes/testplane.max";
static const char *filename = "/home/kaetemi/3dsMax/scenes/geomobjects.max"; //static const char *filename = "/home/kaetemi/3dsMax/scenes/geomobjects.max";
static const char *streamname = "Scene"; static const char *streamname = "Scene";
void exportObj(const std::string &fileName, const CReferenceMaker *triObject) #define PBMS_GEOM_BUFFERS_POLY_A_VERTEX_CHUNK_ID 0x0100
#define PBMS_GEOM_BUFFERS_POLY_A_EDGE_CHUNK_ID 0x010a
#define PBMS_GEOM_BUFFERS_POLY_A_FACE_CHUNK_ID 0x011a
// CStorageArraySizePre<CGeomPolyVertexInfo>
// CStorageArraySizePre<CGeomPolyEdgeInfo>
// CStorageArrayDynSize<CGeomPolyFaceInfo>
void exportObj(const std::string &fileName, const CReferenceMaker *geomObject)
{ {
nlassert(dynamic_cast<const CGeomObject *>(geomObject));
const CEditableMesh *mesh = dynamic_cast<const CEditableMesh *>(geomObject);
if (mesh)
{
nlerror("Not implemented!");
/*
IStorageObject *bufferBlock = triObject->findStorageObject(0x08fe); IStorageObject *bufferBlock = triObject->findStorageObject(0x08fe);
nlassert(bufferBlock->isContainer()); nlassert(bufferBlock->isContainer());
CStorageContainer *buffers = static_cast<CStorageContainer *>(bufferBlock); CStorageContainer *buffers = static_cast<CStorageContainer *>(bufferBlock);
@ -66,6 +81,35 @@ void exportObj(const std::string &fileName, const CReferenceMaker *triObject)
ofs << "v " << vertexBuffer->Value[i].x << " " << vertexBuffer->Value[i].y << " " << vertexBuffer->Value[i].z << "\n"; ofs << "v " << vertexBuffer->Value[i].x << " " << vertexBuffer->Value[i].y << " " << vertexBuffer->Value[i].z << "\n";
for (uint i = 0; i < indexBuffer->Value.size(); ++i) for (uint i = 0; i < indexBuffer->Value.size(); ++i)
ofs << "f " << (indexBuffer->Value[i].a + 1) << " " << (indexBuffer->Value[i].b + 1) << " " << (indexBuffer->Value[i].c + 1) << "\n"; // + 1 as .obj indexes at 1... ofs << "f " << (indexBuffer->Value[i].a + 1) << " " << (indexBuffer->Value[i].b + 1) << " " << (indexBuffer->Value[i].c + 1) << "\n"; // + 1 as .obj indexes at 1...
*/
return;
}
const CEditablePoly *poly = dynamic_cast<const CEditablePoly *>(geomObject);
if (poly)
{
CGeomBuffers *geomBuffers = poly->geomBuffers();
CStorageArraySizePre<CGeomPolyVertexInfo> *vertexBuffer = static_cast<CStorageArraySizePre<CGeomPolyVertexInfo> *>(geomBuffers->findStorageObject(PBMS_GEOM_BUFFERS_POLY_A_VERTEX_CHUNK_ID));
CStorageArraySizePre<CGeomPolyEdgeInfo> *edgeBuffer = static_cast<CStorageArraySizePre<CGeomPolyEdgeInfo> *>(geomBuffers->findStorageObject(PBMS_GEOM_BUFFERS_POLY_A_EDGE_CHUNK_ID));
CStorageArrayDynSize<CGeomPolyFaceInfo> *faceBuffer = static_cast<CStorageArrayDynSize<CGeomPolyFaceInfo> *>(geomBuffers->findStorageObject(PBMS_GEOM_BUFFERS_POLY_A_FACE_CHUNK_ID));
nlassert(vertexBuffer);
nlassert(edgeBuffer);
nlassert(faceBuffer);
std::ofstream ofs(fileName.c_str());
for (uint i = 0; i < vertexBuffer->Value.size(); ++i)
ofs << "v " << vertexBuffer->Value[i].v.x << " " << vertexBuffer->Value[i].v.y << " " << vertexBuffer->Value[i].v.z << "\n";
std::vector<CGeomTriIndex> triangles;
for (uint i = 0; i < faceBuffer->Value.size(); ++i)
{
CGeomObject::triangulatePolyFace(triangles, faceBuffer->Value[i]);
for (uint j = 0; j < triangles.size(); ++j)
{
ofs << "f " << (triangles[j].a + 1) << " " << (triangles[j].b + 1) << " " << (triangles[j].c + 1) << "\n"; // + 1 as .obj indexes at 1...
}
triangles.clear();
}
return;
}
nlerror("Not handled!");
} }
// int __stdcall WinMain(void *, void *, void *, int) // int __stdcall WinMain(void *, void *, void *, int)
@ -197,9 +241,9 @@ int main(int argc, char **argv)
nldebug("PARSE"); nldebug("PARSE");
scene.parse(PIPELINE::MAX::VersionUnknown); // parse the structure to readable data scene.parse(PIPELINE::MAX::VersionUnknown); // parse the structure to readable data
nldebug("CLEAN"); nldebug("CLEAN");
//## scene.clean(); // cleanup unused file structure, don't clean up if we want direct access to chunks as well scene.clean(); // cleanup unused file structure, don't clean up if we want direct access to chunks as well
// <- TEST // <- TEST
scene.toString(std::cout);//## //scene.toString(std::cout);//##
std::cout << "\n"; std::cout << "\n";
//classDirectory3.build(PIPELINE::MAX::VersionUnknown); //classDirectory3.build(PIPELINE::MAX::VersionUnknown);
//classDirectory3.disown(); //classDirectory3.disown();
@ -214,10 +258,11 @@ int main(int argc, char **argv)
//node->toString(std::cout); //node->toString(std::cout);
//exportObj("tr_hof_civil01_gilet.obj", node->getReference(1)->getReference(1)); // => CDerivedObject::getBase(node->object()) //exportObj("tr_hof_civil01_gilet.obj", node->getReference(1)->getReference(1)); // => CDerivedObject::getBase(node->object())
//INode *node = scene.container()->scene()->rootNode()->find(ucstring("GE_Acc_MikotoBaniere")); nlassert(node); INode *node = scene.container()->scene()->rootNode()->find(ucstring("GE_Acc_MikotoBaniere")); nlassert(node);
//INode *node = scene.container()->scene()->rootNode()->find(ucstring("testplane")); nlassert(node); //INode *node = scene.container()->scene()->rootNode()->find(ucstring("testplane")); nlassert(node);
//CReferenceMaker *object = node->getReference(1); CReferenceMaker *object = node->getReference(1);
//object->toString(std::cout); object->toString(std::cout);
exportObj("ge_acc_mikotobaniere.obj", object);
//GE_Acc_MikotoBaniere //GE_Acc_MikotoBaniere

Loading…
Cancel
Save