diff --git a/code/nel/tools/pipeline/max/builtin/geom_object.cpp b/code/nel/tools/pipeline/max/builtin/geom_object.cpp index 0b869b459..76bb5a4aa 100644 --- a/code/nel/tools/pipeline/max/builtin/geom_object.cpp +++ b/code/nel/tools/pipeline/max/builtin/geom_object.cpp @@ -34,7 +34,6 @@ // #include // Project includes -#include "storage/geom_buffers.h" // using namespace std; // 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 &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 > 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) { switch (id) diff --git a/code/nel/tools/pipeline/max/builtin/geom_object.h b/code/nel/tools/pipeline/max/builtin/geom_object.h index 59512bb57..5415ddca3 100644 --- a/code/nel/tools/pipeline/max/builtin/geom_object.h +++ b/code/nel/tools/pipeline/max/builtin/geom_object.h @@ -35,6 +35,7 @@ // Project includes #include "object.h" +#include "storage/geom_buffers.h" /// Must be passed to the parse and build functions by /// inheriting classes to parse the actual geom object. @@ -43,9 +44,6 @@ namespace PIPELINE { namespace MAX { namespace BUILTIN { -namespace STORAGE { - class CGeomBuffers; -} /** * \brief CGeomGeomObject @@ -76,6 +74,8 @@ public: virtual const ISceneClassDesc *classDesc() const; virtual void toStringLocal(std::ostream &ostream, const std::string &pad = "", uint filter = 0) const; + static void triangulatePolyFace(std::vector &triangles, const STORAGE::CGeomPolyFaceInfo &polyFace); + // read access inline STORAGE::CGeomBuffers *geomBuffers() const { return m_GeomBuffers; } diff --git a/code/nel/tools/pipeline/max/epoly/editable_poly.cpp b/code/nel/tools/pipeline/max/epoly/editable_poly.cpp index 25a0e0c1f..0d8f92f69 100644 --- a/code/nel/tools/pipeline/max/epoly/editable_poly.cpp +++ b/code/nel/tools/pipeline/max/epoly/editable_poly.cpp @@ -107,6 +107,7 @@ void CEditablePoly::build(uint16 version, uint filter) void CEditablePoly::disown() { + m_EditablePolyUnknown.clear(); CPolyObject::disown(); } diff --git a/code/nel/tools/pipeline/max_dump/main.cpp b/code/nel/tools/pipeline/max_dump/main.cpp index afd736c9f..0ba0026f7 100644 --- a/code/nel/tools/pipeline/max_dump/main.cpp +++ b/code/nel/tools/pipeline/max_dump/main.cpp @@ -38,6 +38,8 @@ #include "../max/builtin/storage/geom_buffers.h" #include "../max/builtin/scene_impl.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::BUILTIN; @@ -46,26 +48,68 @@ using namespace PIPELINE::MAX::UPDATE1; using namespace PIPELINE::MAX::EPOLY; //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/teapot_test_scene.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"; -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 +// CStorageArraySizePre +// CStorageArrayDynSize + +void exportObj(const std::string &fileName, const CReferenceMaker *geomObject) { - IStorageObject *bufferBlock = triObject->findStorageObject(0x08fe); - nlassert(bufferBlock->isContainer()); - CStorageContainer *buffers = static_cast(bufferBlock); - CStorageArraySizePre *vertexBuffer = static_cast *>(buffers->findStorageObject(0x0914)); - CStorageArraySizePre *indexBuffer = static_cast *>(buffers->findStorageObject(0x0912)); - - std::ofstream ofs(fileName.c_str()); - for (uint i = 0; i < vertexBuffer->Value.size(); ++i) - ofs << "v " << vertexBuffer->Value[i].x << " " << vertexBuffer->Value[i].y << " " << vertexBuffer->Value[i].z << "\n"; - 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... + nlassert(dynamic_cast(geomObject)); + const CEditableMesh *mesh = dynamic_cast(geomObject); + if (mesh) + { + nlerror("Not implemented!"); + /* + IStorageObject *bufferBlock = triObject->findStorageObject(0x08fe); + nlassert(bufferBlock->isContainer()); + CStorageContainer *buffers = static_cast(bufferBlock); + CStorageArraySizePre *vertexBuffer = static_cast *>(buffers->findStorageObject(0x0914)); + CStorageArraySizePre *indexBuffer = static_cast *>(buffers->findStorageObject(0x0912)); + + std::ofstream ofs(fileName.c_str()); + for (uint i = 0; i < vertexBuffer->Value.size(); ++i) + ofs << "v " << vertexBuffer->Value[i].x << " " << vertexBuffer->Value[i].y << " " << vertexBuffer->Value[i].z << "\n"; + 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... + */ + return; + } + const CEditablePoly *poly = dynamic_cast(geomObject); + if (poly) + { + CGeomBuffers *geomBuffers = poly->geomBuffers(); + CStorageArraySizePre *vertexBuffer = static_cast *>(geomBuffers->findStorageObject(PBMS_GEOM_BUFFERS_POLY_A_VERTEX_CHUNK_ID)); + CStorageArraySizePre *edgeBuffer = static_cast *>(geomBuffers->findStorageObject(PBMS_GEOM_BUFFERS_POLY_A_EDGE_CHUNK_ID)); + CStorageArrayDynSize *faceBuffer = static_cast *>(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 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) @@ -197,9 +241,9 @@ int main(int argc, char **argv) nldebug("PARSE"); scene.parse(PIPELINE::MAX::VersionUnknown); // parse the structure to readable data 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 - scene.toString(std::cout);//## + //scene.toString(std::cout);//## std::cout << "\n"; //classDirectory3.build(PIPELINE::MAX::VersionUnknown); //classDirectory3.disown(); @@ -214,10 +258,11 @@ int main(int argc, char **argv) //node->toString(std::cout); //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); - //CReferenceMaker *object = node->getReference(1); - //object->toString(std::cout); + CReferenceMaker *object = node->getReference(1); + object->toString(std::cout); + exportObj("ge_acc_mikotobaniere.obj", object); //GE_Acc_MikotoBaniere