/** * \file geom_object.cpp * \brief CGeomGeomObject * \date 2012-08-22 08:58GMT * \author Jan Boon (Kaetemi) * CGeomGeomObject */ /* * Copyright (C) 2012 by authors * * This file is part of RYZOM CORE PIPELINE. * RYZOM CORE PIPELINE 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. * * RYZOM CORE PIPELINE 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 RYZOM CORE PIPELINE. If not, see * . */ #include #include "geom_object.h" // STL includes // NeL includes // #include // Project includes // using namespace std; // using namespace NLMISC; namespace PIPELINE { namespace MAX { namespace BUILTIN { #define PMB_GEOM_UNKNOWN0900_CHUNK_ID 0x0900 #define PMB_GEOM_BUFFERS_CHUNK_ID 0x08fe CGeomObject::CGeomObject(CScene *scene) : CObject(scene), m_Unknown0900(NULL), m_GeomBuffers(NULL) { } CGeomObject::~CGeomObject() { if (!m_ChunksOwnsPointers) { m_Unknown0900 = NULL; m_GeomBuffers = NULL; } } const ucstring CGeomObject::DisplayName = ucstring("GeomObject"); const char *CGeomObject::InternalName = "GeomObject"; const char *CGeomObject::InternalNameUnknown = "GeomObjectUnknown"; const NLMISC::CClassId CGeomObject::ClassId = NLMISC::CClassId(0x37097c44, 0x38aa3f24); /* Not official, please correct */ const TSClassId CGeomObject::SuperClassId = 0x00000010; const CGeomObjectClassDesc GeomObjectClassDesc(&DllPluginDescBuiltin); const CGeomObjectSuperClassDesc GeomObjectSuperClassDesc(&GeomObjectClassDesc); void CGeomObject::parse(uint16 version, uint filter) { if (filter == 0) { CObject::parse(version); } else if (filter == PMB_GEOM_OBJECT_PARSE_FILTER) { if (!m_ChunksOwnsPointers) { m_Unknown0900 = getChunk(PMB_GEOM_UNKNOWN0900_CHUNK_ID); m_GeomBuffers = static_cast(getChunk(PMB_GEOM_BUFFERS_CHUNK_ID)); } } } void CGeomObject::clean() { CObject::clean(); } void CGeomObject::build(uint16 version, uint filter) { if (filter == 0) { CObject::build(version); } else if (filter == PMB_GEOM_OBJECT_PARSE_FILTER) { if (m_Unknown0900) putChunk(PMB_GEOM_UNKNOWN0900_CHUNK_ID, m_Unknown0900); if (m_GeomBuffers) putChunk(PMB_GEOM_BUFFERS_CHUNK_ID, m_GeomBuffers); } } void CGeomObject::disown() { m_Unknown0900 = NULL; m_GeomBuffers = NULL; CObject::disown(); } void CGeomObject::init() { CObject::init(); } bool CGeomObject::inherits(const NLMISC::CClassId classId) const { if (classId == classDesc()->classId()) return true; return CObject::inherits(classId); } const ISceneClassDesc *CGeomObject::classDesc() const { return &GeomObjectClassDesc; } void CGeomObject::toStringLocal(std::ostream &ostream, const std::string &pad, uint filter) const { if (filter == 0) { CObject::toStringLocal(ostream, pad); } else if (filter == PMB_GEOM_OBJECT_PARSE_FILTER) { std::string padpad = pad + "\t"; if (m_Unknown0900) { ostream << "\n" << pad << "GeomObject Unknown 0x0900: "; m_Unknown0900->toString(ostream, padpad); } if (m_GeomBuffers) { ostream << "\n" << pad << "GeomBuffers: "; m_GeomBuffers->toString(ostream, padpad); } } } 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) { case PMB_GEOM_UNKNOWN0900_CHUNK_ID: return new CStorageArray(); case PMB_GEOM_BUFFERS_CHUNK_ID: return new STORAGE::CGeomBuffers(); } return CObject::createChunkById(id, container); } } /* namespace BUILTIN */ } /* namespace MAX */ } /* namespace PIPELINE */ /* end of file */