/* Copyright (C) 2005-2007 Feeling Software Inc. Portions of the code are: Copyright (C) 2005-2007 Sony Computer Entertainment America MIT License: http://www.opensource.org/licenses/mit-license.php */ /* Based on the FS Import classes: Copyright (C) 2005-2006 Feeling Software Inc Copyright (C) 2005-2006 Autodesk Media Entertainment MIT License: http://www.opensource.org/licenses/mit-license.php */ #include "StdAfx.h" #include "FCDocument/FCDocument.h" #include "FCDocument/FCDExtra.h" #include "FCDocument/FCDGeometryMesh.h" #include "FCDocument/FCDGeometryPolygons.h" #include "FCDocument/FCDGeometryPolygonsInput.h" #include "FCDocument/FCDGeometrySource.h" // // FCDGeometryPolygons // ImplementObjectType(FCDGeometryPolygons); ImplementParameterObject(FCDGeometryPolygons, FCDGeometryPolygonsInput, inputs, new FCDGeometryPolygonsInput(parent->GetDocument(), parent)); ImplementParameterObject(FCDGeometryPolygons, FCDExtra, extra, new FCDExtra(parent->GetDocument(), parent)); FCDGeometryPolygons::FCDGeometryPolygons(FCDocument* document, FCDGeometryMesh* _parent) : FCDObject(document) , parent(_parent) , InitializeParameterNoArg(inputs) , InitializeParameterNoArg(faceVertexCounts) , InitializeParameterNoArg(holeFaces) , InitializeParameter(primitiveType, POLYGONS) , faceVertexCount(0), faceOffset(0), faceVertexOffset(0), holeOffset(0) , InitializeParameterNoArg(materialSemantic) , InitializeParameterNoArg(extra) { // Pre-buffer the face-vertex counts so that AddFaceVertexCount won't be extremely costly. faceVertexCounts.reserve(32); } FCDGeometryPolygons::~FCDGeometryPolygons() { holeFaces.clear(); parent = NULL; } FCDExtra* FCDGeometryPolygons::GetExtra() { return (extra != NULL) ? extra : (extra = new FCDExtra(GetDocument(), this)); } // Creates a new face. void FCDGeometryPolygons::AddFace(uint32 degree) { bool newPolygonSet = faceVertexCounts.empty(); faceVertexCounts.push_back(degree); // Inserts empty indices size_t inputCount = inputs.size(); for (size_t i = 0; i < inputCount; ++i) { FCDGeometryPolygonsInput* input = inputs[i]; if (!newPolygonSet && input->OwnsIndices()) input->SetIndexCount(input->GetIndexCount() + degree); else if (newPolygonSet && input->GetIndexCount() == 0) { // Declare this input as the owner! input->SetIndexCount(degree); } } parent->Recalculate(); SetDirtyFlag(); } // Removes a face void FCDGeometryPolygons::RemoveFace(size_t index) { FUAssert(index < GetFaceCount(), return); // Remove the associated indices, if they exist. size_t offset = GetFaceVertexOffset(index); size_t indexCount = GetFaceVertexCount(index); size_t inputCount = inputs.size(); for (size_t i = 0; i < inputCount; ++i) { FCDGeometryPolygonsInput* input = inputs[i]; if (!input->OwnsIndices()) continue; size_t inputIndexCount = input->GetIndexCount(); if (offset < inputIndexCount) { // Move the indices backwards. uint32* indices = input->GetIndices(); for (size_t o = offset; o < inputIndexCount - indexCount; ++o) { indices[o] = indices[o + indexCount]; } input->SetIndexCount(max(offset, inputIndexCount - indexCount)); } } // Remove the face and its holes size_t holeBefore = GetHoleCountBefore(index); size_t holeCount = GetHoleCount(index); faceVertexCounts.erase(index + holeBefore, holeCount + 1); // +1 in order to remove the polygon as well as the holes. parent->Recalculate(); SetDirtyFlag(); } // Calculates the offset of face-vertex pairs before the given face index within the polygon set. size_t FCDGeometryPolygons::GetFaceVertexOffset(size_t index) const { size_t offset = 0; // We'll need to skip over the holes size_t holeCount = GetHoleCountBefore(index); if (index + holeCount < faceVertexCounts.size()) { // Sum up the wanted offset UInt32List::const_iterator end = faceVertexCounts.begin() + index + holeCount; for (UInt32List::const_iterator it = faceVertexCounts.begin(); it != end; ++it) { offset += (*it); } } return offset; } // Calculates the number of holes within the polygon set that appear before the given face index. size_t FCDGeometryPolygons::GetHoleCountBefore(size_t index) const { size_t holeCount = 0; for (UInt32List::const_iterator it = holeFaces.begin(); it != holeFaces.end(); ++it) { if ((*it) <= index) { ++holeCount; ++index; } } return holeCount; } // Retrieves the number of holes within a given face. size_t FCDGeometryPolygons::GetHoleCount(size_t index) const { size_t holeCount = 0; for (size_t i = index + GetHoleCountBefore(index) + 1; i < faceVertexCounts.size(); ++i) { bool isHoled = holeFaces.find((uint32) i) != holeFaces.end(); if (!isHoled) break; else ++holeCount; } return holeCount; } // The number of face-vertex pairs for a given face. size_t FCDGeometryPolygons::GetFaceVertexCount(size_t index) const { size_t count = 0; if (index < GetFaceCount()) { size_t holeCount = GetHoleCount(index); UInt32List::const_iterator it = faceVertexCounts.begin() + index + GetHoleCountBefore(index); UInt32List::const_iterator end = it + holeCount + 1; // +1 in order to sum the face-vertex pairs of the polygon as its holes. for (; it != end; ++it) count += (*it); } return count; } FCDGeometryPolygonsInput* FCDGeometryPolygons::AddInput(FCDGeometrySource* source, uint32 offset) { FCDGeometryPolygonsInput* input = new FCDGeometryPolygonsInput(GetDocument(), this); inputs.push_back(input); input->SetOffset(offset); input->SetSource(source); SetNewChildFlag(); return input; } void FCDGeometryPolygons::SetHoleFaceCount(size_t count) { holeFaces.resize(count); SetDirtyFlag(); } bool FCDGeometryPolygons::IsHoleFaceHole(size_t index) { return holeFaces.find((uint32) index) != holeFaces.end(); } void FCDGeometryPolygons::AddHole(uint32 index) { FUAssert(!IsHoleFaceHole(index), return); // Ordered insert const uint32* it = holeFaces.begin(); for (; it != holeFaces.end(); ++it) { if (index < (*it)) break; } holeFaces.insert(it - holeFaces.begin(), index); } void FCDGeometryPolygons::AddFaceVertexCount(uint32 count) { faceVertexCounts.push_back(count); } void FCDGeometryPolygons::SetFaceVertexCountCount(size_t count) { faceVertexCounts.resize(count); } const FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(FUDaeGeometryInput::Semantic semantic) const { for (const FCDGeometryPolygonsInput** it = inputs.begin(); it != inputs.end(); ++it) { if ((*it)->GetSemantic() == semantic) return (*it); } return NULL; } const FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(const FCDGeometrySource* source) const { for (const FCDGeometryPolygonsInput** it = inputs.begin(); it != inputs.end(); ++it) { if ((*it)->GetSource() == source) return (*it); } return NULL; } FCDGeometryPolygonsInput* FCDGeometryPolygons::FindInput(const fm::string& sourceId) { const char* s = sourceId.c_str(); if (*s == '#') ++s; size_t inputCount = inputs.size(); for (size_t i = 0; i < inputCount; ++i) { FCDGeometryPolygonsInput* input = inputs[i]; if (input->GetSource()->GetDaeId() == s) return input; } return NULL; } void FCDGeometryPolygons::FindInputs(FUDaeGeometryInput::Semantic semantic, FCDGeometryPolygonsInputConstList& _inputs) const { for (const FCDGeometryPolygonsInput** it = inputs.begin(); it != inputs.end(); ++it) { if ((*it)->GetSemantic() == semantic) _inputs.push_back(*it); } } // Recalculates the face-vertex count within the polygons void FCDGeometryPolygons::Recalculate() { faceVertexCount = 0; for (const uint32* itC = faceVertexCounts.begin(); itC != faceVertexCounts.end(); ++itC) { faceVertexCount += (*itC); } SetDirtyFlag(); } // [DEPRECATED] bool FCDGeometryPolygons::IsTriangles() const { UInt32List::const_iterator itC; for (itC = faceVertexCounts.begin(); itC != faceVertexCounts.end() && (*itC) == 3; ++itC) {} return (itC == faceVertexCounts.end()); } int32 FCDGeometryPolygons::TestPolyType() const { UInt32List::const_iterator itC = faceVertexCounts.begin(); if (!faceVertexCounts.empty()) { uint32 fCount = *itC; for (; itC != faceVertexCounts.end() && *itC == fCount; ++itC) {} if (itC == faceVertexCounts.end()) return fCount; } return -1; } // Clone this list of polygons FCDGeometryPolygons* FCDGeometryPolygons::Clone(FCDGeometryPolygons* clone, const FCDGeometrySourceCloneMap& cloneMap) const { if (clone == NULL) return NULL; // Clone the miscellaneous information. clone->materialSemantic = materialSemantic; clone->faceVertexCounts = faceVertexCounts; clone->faceOffset = faceOffset; clone->faceVertexCount = faceVertexCount; clone->faceVertexOffset = faceVertexOffset; clone->holeOffset = holeOffset; clone->holeFaces = holeFaces; // Clone the geometry inputs // Note that the vertex source inputs are usually created by default. size_t inputCount = inputs.size(); clone->inputs.reserve(inputCount); for (size_t i = 0; i < inputCount; ++i) { // Find the cloned source that correspond to the original input. FCDGeometrySource* cloneSource = NULL; FCDGeometrySourceCloneMap::const_iterator it = cloneMap.find(inputs[i]->GetSource()); if (it == cloneMap.end()) { // Attempt to match by ID instead. const fm::string& id = inputs[i]->GetSource()->GetDaeId(); cloneSource = clone->GetParent()->FindSourceById(id); } else { cloneSource = (*it).second; } // Retrieve or create the input to clone. FCDGeometryPolygonsInput* input = clone->FindInput(cloneSource); if (input == NULL) { input = clone->AddInput(cloneSource, inputs[i]->GetOffset()); } // Clone the input information. if (inputs[i]->OwnsIndices()) { input->SetIndices(inputs[i]->GetIndices(), inputs[i]->GetIndexCount()); } input->SetSet(inputs[i]->GetSet()); } return clone; }