Skip to content

Commit

Permalink
MeshLOD: range loop refactoring (OGRECave#3016)
Browse files Browse the repository at this point in the history
  • Loading branch information
Joilnen authored Jan 28, 2024
1 parent 497aacf commit 67a4575
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 124 deletions.
43 changes: 20 additions & 23 deletions Components/MeshLodGenerator/src/OgreLodCollapseCostProfiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,35 +35,34 @@ namespace Ogre
{
OgreAssert(0, "Only computeVertexCollapseCost should call this function.");
return 0;
}
}

void LodCollapseCostProfiler::computeVertexCollapseCost( LodData* data, LodData::Vertex* vertex, Real& collapseCost, LodData::Vertex*& collapseTo )
{
LodData::VEdges::iterator it = vertex->edges.begin();
if(!mHasProfile[LodData::getVectorIDFromPointer(data->mVertexList, vertex)]){
for (; it != vertex->edges.end(); ++it) {
it->collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &*it);
if (collapseCost > it->collapseCost) {
collapseCost = it->collapseCost;
collapseTo = it->dst;
for (auto& e : vertex->edges) {
e.collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &e);
if (collapseCost > e.collapseCost) {
collapseCost = e.collapseCost;
collapseTo = e.dst;
}
}
} else {
std::pair<ProfileLookup::iterator, ProfileLookup::iterator> ret = mProfileLookup.equal_range(vertex);
for (; it != vertex->edges.end(); ++it) {
it->collapseCost = LodData::UNINITIALIZED_COLLAPSE_COST;
for(ProfileLookup::iterator it2 = ret.first; it2 != ret.second; ++it2){
if(it2->second.dst == it->dst ){
it->collapseCost = it2->second.cost;
for (auto& e : vertex->edges) {
e.collapseCost = LodData::UNINITIALIZED_COLLAPSE_COST;
for(ProfileLookup::iterator it = ret.first; it != ret.second; ++it){
if(it->second.dst == e.dst ){
e.collapseCost = it->second.cost;
break;
}
}
if(it->collapseCost == LodData::UNINITIALIZED_COLLAPSE_COST){
it->collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &*it);
if(e.collapseCost == LodData::UNINITIALIZED_COLLAPSE_COST){
e.collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &e);
}
if (collapseCost > it->collapseCost) {
collapseCost = it->collapseCost;
collapseTo = it->dst;
if (collapseCost > e.collapseCost) {
collapseCost = e.collapseCost;
collapseTo = e.dst;
}
}
}
Expand All @@ -73,20 +72,18 @@ namespace Ogre
{
mHasProfile.clear();
mHasProfile.resize(data->mVertexList.size(), false);
LodProfile::iterator it = mProfile.begin();
LodProfile::iterator itEnd = mProfile.end();
for(;it != itEnd;it++){
for(auto& p : mProfile){
LodData::Vertex v;
v.position = it->src;
v.position = p.src;
LodData::UniqueVertexSet::iterator src = data->mUniqueVertexSet.find(&v);
OgreAssert(src != data->mUniqueVertexSet.end(), "Invalid vertex position in Lod profile");
mHasProfile[LodData::getVectorIDFromPointer(data->mVertexList, *src)] = true;
v.position = it->dst;
v.position = p.dst;
LodData::UniqueVertexSet::iterator dst = data->mUniqueVertexSet.find(&v);
OgreAssert(dst != data->mUniqueVertexSet.end(), "Invalid vertex position in Lod profile");
ProfiledEdge e;
e.dst = *dst;
e.cost = it->cost;
e.cost = p.cost;
OgreAssert(e.cost >= 0 && e.cost != LodData::UNINITIALIZED_COLLAPSE_COST, "Invalid collapse cost");
mProfileLookup.emplace(*src, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,15 @@ namespace Ogre

return cost;

}
}

void LodCollapseCostQuadric::computeVertexQuadric( LodData* data, size_t vertexID )
{
Matrix4& quadric = mVertexQuadricList[vertexID];
quadric = Matrix4::ZERO;
LodData::Vertex& vertex = data->mVertexList[vertexID];
LodData::VTriangles::iterator tri, triEnd;
tri = vertex.triangles.begin();
triEnd = vertex.triangles.end();
for (;tri != triEnd; ++tri) {
size_t id = LodData::getVectorIDFromPointer(data->mTriangleList, *tri);
for (const auto& t : vertex.triangles) {
size_t id = LodData::getVectorIDFromPointer(data->mTriangleList, t);
quadric = quadric + mTrianglePlaneQuadricList[id];
}
}
Expand Down
158 changes: 63 additions & 95 deletions Components/MeshLodGenerator/src/OgreLodCollapser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,14 @@ namespace Ogre
// Allows to find bugs in collapsing.
// size_t s1 = mUniqueVertexSet.size();
// size_t s2 = mCollapseCostHeap.size();
LodData::CollapseCostHeap::iterator it = data->mCollapseCostHeap.begin();
LodData::CollapseCostHeap::iterator itEnd = data->mCollapseCostHeap.end();
while (it != itEnd) {
assertValidVertex(data, it->second);
it++;
}
for (const auto& c : data->mCollapseCostHeap)
assertValidVertex(data, c.second);
}

void LodCollapser::assertValidVertex(LodData* data, LodData::Vertex* v)
{
// Allows to find bugs in collapsing.
LodData::VTriangles::iterator it = v->triangles.begin();
LodData::VTriangles::iterator itEnd = v->triangles.end();
for (; it != itEnd; it++) {
LodData::Triangle* t = *it;
for (const auto& t : v->triangles) {
for (int i = 0; i < 3; i++) {
OgreAssert(t->vertex[i]->costHeapPosition != data->mCollapseCostHeap.end(), "");
t->vertex[i]->edges.findExists(LodData::Edge(t->vertex[i]->collapseTo));
Expand All @@ -85,15 +78,11 @@ namespace Ogre
{
// Validates that collapsing has updated all edges needed by computeEdgeCollapseCost.
// This will OgreAssert if the dependencies inside computeEdgeCollapseCost changes.
LodData::VEdges::iterator it = vertex->edges.begin();
LodData::VEdges::iterator itEnd = vertex->edges.end();
for (; it != itEnd; it++) {
OgreAssert(it->collapseCost == cost->computeEdgeCollapseCost(data, vertex, &*it), "");
LodData::Vertex* neighbor = it->dst;
LodData::VEdges::iterator it2 = neighbor->edges.begin();
LodData::VEdges::iterator it2End = neighbor->edges.end();
for (; it2 != it2End; it2++) {
OgreAssert(it2->collapseCost == cost->computeEdgeCollapseCost(data, neighbor, &*it2), "");
for (auto& e : vertex->edges) {
OgreAssert(e.collapseCost == cost->computeEdgeCollapseCost(data, vertex, &e), "");
LodData::Vertex* neighbor = e.dst;
for (auto& e1 : vertex->edges) {
OgreAssert(e1.collapseCost == cost->computeEdgeCollapseCost(data, neighbor, &e1), "");
}
}
}
Expand All @@ -113,7 +102,7 @@ namespace Ogre
{
triangle->isRemoved = true;
// skip is needed if we are iterating on the vertex's edges or triangles.
for (auto & i : triangle->vertex) {
for (auto& i : triangle->vertex) {
if (i != skip) {
i->triangles.removeExists(triangle);
}
Expand All @@ -130,7 +119,7 @@ namespace Ogre
{
line->isRemoved = true;

for (auto & i : line->vertex) {
for (auto& i : line->vertex) {
if (i != skip) {
i->lines.removeExists(line);
}
Expand Down Expand Up @@ -212,43 +201,36 @@ namespace Ogre
// so we need to connect them correctly based on deleted triangle's edge.
// mCollapsedEdgeIDs will be used, when looking up the connections for replacement.
tmpCollapsedEdges.clear();
LodData::VTriangles::iterator it = src->triangles.begin();
LodData::VTriangles::iterator itEnd = src->triangles.end();
for (; it != itEnd; ++it) {
LodData::Triangle* triangle = *it;
if (triangle->hasVertex(dst)) {
for (const auto& t : src->triangles) {
if (t->hasVertex(dst)) {
// Remove a triangle
// Tasks:
// 1. Add it to the collapsed edges list.
// 2. Reduce index count for the Lods, which will not have this triangle.
// 3. Remove references/pointers to this triangle and mark as removed.

// 1. task
unsigned int srcID = triangle->getVertexID(src);
if (!hasSrcID(srcID, triangle->submeshID)) {
unsigned int srcID = t->getVertexID(src);
if (!hasSrcID(srcID, t->submeshID)) {
tmpCollapsedEdges.push_back(CollapsedEdge());
tmpCollapsedEdges.back().srcID = srcID;
tmpCollapsedEdges.back().dstID = triangle->getVertexID(dst);
tmpCollapsedEdges.back().submeshID = triangle->submeshID;
tmpCollapsedEdges.back().dstID = t->getVertexID(dst);
tmpCollapsedEdges.back().submeshID = t->submeshID;
}

// 2. task
data->mIndexBufferInfoList[triangle->submeshID].indexCount -= 3;
output->triangleRemoved(data, triangle);
data->mIndexBufferInfoList[t->submeshID].indexCount -= 3;
output->triangleRemoved(data, t);
// 3. task
removeTriangleFromEdges(triangle, src);
removeTriangleFromEdges(t, src);

}
}
OgreAssert(tmpCollapsedEdges.size(), "");
OgreAssert(dst->edges.find(LodData::Edge(src)) == dst->edges.end(), "");

LodData::VLines::iterator lineIt = src->lines.begin();
LodData::VLines::iterator lineItEnd = src->lines.end();
for (; lineIt != lineItEnd; ++lineIt)
for (const auto& l : src->lines)
{
LodData::Line* line = *lineIt;
if (line->hasVertex(dst))
if (l->hasVertex(dst))
{
// Remove a line
// Tasks:
Expand All @@ -257,129 +239,115 @@ namespace Ogre
// 3. Remove references/pointers to this line and mark as removed.

// 1. task
unsigned int srcID = line->getVertexID(src);
if (!hasSrcID(srcID, line->submeshID)) {
unsigned int srcID = l->getVertexID(src);
if (!hasSrcID(srcID, l->submeshID)) {
tmpCollapsedEdges.push_back(CollapsedEdge());
tmpCollapsedEdges.back().srcID = srcID;
tmpCollapsedEdges.back().dstID = line->getVertexID(dst);
tmpCollapsedEdges.back().submeshID = line->submeshID;
tmpCollapsedEdges.back().dstID = l->getVertexID(dst);
tmpCollapsedEdges.back().submeshID = l->submeshID;
}

// 2. task
data->mIndexBufferInfoList[line->submeshID].indexCount -= 2;
output->lineRemoved(data, line);
data->mIndexBufferInfoList[l->submeshID].indexCount -= 2;
output->lineRemoved(data, l);
// 3. task
removeLine(line, src);
removeLine(l, src);
}
}

it = src->triangles.begin();
for (; it != itEnd; ++it) {
LodData::Triangle* triangle = *it;
if (!triangle->hasVertex(dst)) {
for (const auto& t : src->triangles) {
if (!t->hasVertex(dst)) {
// Replace a triangle
// Tasks:
// 1. Determine the edge which we will move along. (we need to modify single vertex only)
// 2. Move along the selected edge.

// 1. task
unsigned int srcID = triangle->getVertexID(src);
size_t id = findDstID(srcID, triangle->submeshID);
unsigned int srcID = t->getVertexID(src);
size_t id = findDstID(srcID, t->submeshID);
if (id == std::numeric_limits<size_t>::max()) {
// Not found any edge to move along.
// Destroy the triangle.
data->mIndexBufferInfoList[triangle->submeshID].indexCount -= 3;
output->triangleRemoved(data, triangle);
removeTriangleFromEdges(triangle, src);
data->mIndexBufferInfoList[t->submeshID].indexCount -= 3;
output->triangleRemoved(data, t);
removeTriangleFromEdges(t, src);
continue;
}
unsigned int dstID = tmpCollapsedEdges[id].dstID;

// 2. task
replaceVertexID(triangle, srcID, dstID, dst);
replaceVertexID(t, srcID, dstID, dst);

output->triangleChanged(data, triangle);
output->triangleChanged(data, t);

#if MESHLOD_QUALITY >= 3
triangle->computeNormal();
t->computeNormal();
#endif
}
}

lineIt = src->lines.begin();
for (; lineIt != lineItEnd; ++lineIt)
for (const auto& l : src->lines)
{
LodData::Line* line = *lineIt;
if (!line->hasVertex(dst))
if (!l->hasVertex(dst))
{
// Replace a line
// Tasks:
// 1. Determine the edge which we will move along. (we need to modify single vertex only)
// 2. Move along the selected edge.

// 1. task
unsigned int srcID = line->getVertexID(src);
size_t id = findDstID(srcID, line->submeshID);
unsigned int srcID = l->getVertexID(src);
size_t id = findDstID(srcID, l->submeshID);
if (id == std::numeric_limits<size_t>::max()) {
// Not found any edge to move along.
// Destroy the triangle.
data->mIndexBufferInfoList[line->submeshID].indexCount -= 2;
output->lineRemoved(data, line);
removeLine(line, src);
data->mIndexBufferInfoList[l->submeshID].indexCount -= 2;
output->lineRemoved(data, l);
removeLine(l, src);
continue;
}
unsigned int dstID = tmpCollapsedEdges[id].dstID;

// 2. task
replaceVertexID(line, srcID, dstID, dst);
replaceVertexID(l, srcID, dstID, dst);

output->lineChanged(data, line);
output->lineChanged(data, l);
}
}

dst->seam |= src->seam; // Inherit seam property

#if MESHLOD_QUALITY <= 2
LodData::VEdges::iterator it3 = src->edges.begin();
LodData::VEdges::iterator it3End = src->edges.end();
for (; it3 != it3End; ++it3) {
cost->updateVertexCollapseCost(data, it3->dst);
for (const auto& e : src->edges) {
cost->updateVertexCollapseCost(data, e.dst);
}
#else
// TODO: Find out why is this needed. assertOutdatedCollapseCost() fails on some
// rare situations without this. For example goblin.mesh fails.
typedef SmallVector<LodData::Vertex*, 64> UpdatableList;
UpdatableList updatable;
LodData::VEdges::iterator it3 = src->edges.begin();
LodData::VEdges::iterator it3End = src->edges.end();
for (; it3 != it3End; it3++) {
updatable.push_back(it3->dst);
LodData::VEdges::iterator it4End = it3->dst->edges.end();
LodData::VEdges::iterator it4 = it3->dst->edges.begin();
for (; it4 != it4End; it4++) {
updatable.push_back(it4->dst);
for (const auto& e : src->edges) {
updatable.push_back(e.dst);
for (const auto& e1 : src->edges) {
updatable.push_back(e1.dst);
}
}

// Remove duplicates.
UpdatableList::iterator it5 = updatable.begin();
UpdatableList::iterator it5End = updatable.end();
std::sort(it5, it5End);
it5End = std::unique(it5, it5End);
UpdatableList::iterator it = updatable.begin();
UpdatableList::iterator itEnd = updatable.end();
std::sort(it, itEnd);
itEnd = std::unique(it, itEnd);

for (; it5 != it5End; it5++) {
cost->updateVertexCollapseCost(data, *it5);
for (const auto& u : updatable) {
cost->updateVertexCollapseCost(data, u);
}
#if OGRE_DEBUG_MODE
it3 = src->edges.begin();
it3End = src->edges.end();
for (; it3 != it3End; it3++) {
assertOutdatedCollapseCost(data, cost, it3->dst);
for (const auto& e : src->edges) {
assertOutdatedCollapseCost(data, cost, e.dst);
}
it3 = dst->edges.begin();
it3End = dst->edges.end();
for (; it3 != it3End; it3++) {
assertOutdatedCollapseCost(data, cost, it3->dst);
for (const auto& e : src->edges) {
assertOutdatedCollapseCost(data, cost, e.dst);
}
assertOutdatedCollapseCost(data, cost, dst);
#endif // ifndef OGRE_DEBUG_MODE
Expand Down

0 comments on commit 67a4575

Please sign in to comment.