diff --git a/src/planet-a/chunk_generate.cpp b/src/planet-a/chunk_generate.cpp index 3910d9fa..d2d9ad64 100644 --- a/src/planet-a/chunk_generate.cpp +++ b/src/planet-a/chunk_generate.cpp @@ -42,11 +42,11 @@ void ChunkScratchpad::resize(ChunkSkeleton const& rChSk) { auto const maxSharedVrtx = rChSk.m_sharedIds.capacity(); - edgeVertices.resize((rChSk.m_chunkEdgeVrtxCount - 1) * 3); - stitchCmds .resize(rChSk.m_chunkIds.capacity(), {}); - osp::bitvector_resize(sharedAdded, maxSharedVrtx); - osp::bitvector_resize(sharedRemoved, maxSharedVrtx); - osp::bitvector_resize(sharedNormalsDirty, maxSharedVrtx); + edgeVertices .resize((rChSk.m_chunkEdgeVrtxCount - 1) * 3); + stitchCmds .resize(rChSk.m_chunkIds.capacity(), {}); + sharedAdded .resize(maxSharedVrtx); + sharedRemoved .resize(maxSharedVrtx); + sharedNormalsDirty .resize(maxSharedVrtx); } void restitch_check( @@ -329,11 +329,11 @@ void subtract_normal_contrib( break; } - if (rSkCh.m_sharedIds.exists(rContrib.shared) && ! rChSP.sharedRemoved.test(rContrib.shared.value)) + if (rSkCh.m_sharedIds.exists(rContrib.shared) && ! rChSP.sharedRemoved.contains(rContrib.shared)) { osp::Vector3 &rNormal = rGeom.sharedNormalSum[rContrib.shared]; rNormal -= rContrib.sum; - rChSP.sharedNormalsDirty.set(rContrib.shared.value); + rChSP.sharedNormalsDirty.insert(rContrib.shared); } rContrib.sum *= 0.0f; } @@ -354,12 +354,12 @@ void subtract_normal_contrib( break; } - if (rSkCh.m_sharedIds.exists(shared) && ! rChSP.sharedRemoved.test(shared.value)) + if (rSkCh.m_sharedIds.exists(shared) && ! rChSP.sharedRemoved.contains(shared)) { Vector3 const &contrib = fillNormalContrib[i]; Vector3 &rNormal = rGeom.sharedNormalSum[shared]; rNormal -= contrib; - rChSP.sharedNormalsDirty.set(shared.value); + rChSP.sharedNormalsDirty.insert(shared); } fillNormalContrib[i] *= 0.0f; } diff --git a/src/planet-a/chunk_generate.h b/src/planet-a/chunk_generate.h index 61d231ee..ae0ad221 100644 --- a/src/planet-a/chunk_generate.h +++ b/src/planet-a/chunk_generate.h @@ -51,13 +51,13 @@ struct ChunkScratchpad std::vector chunksAdded; /// Recently added shared vertices, position needs to be copied from skeleton - osp::BitVector_t sharedAdded; + lgrn::IdSetStl sharedAdded; /// Recently added shared vertices - osp::BitVector_t sharedRemoved; + lgrn::IdSetStl sharedRemoved; /// Shared vertices that need to recalculate normals - osp::BitVector_t sharedNormalsDirty; + lgrn::IdSetStl sharedNormalsDirty; }; /** diff --git a/src/planet-a/geometry.h b/src/planet-a/geometry.h index 3265dcad..21e63583 100644 --- a/src/planet-a/geometry.h +++ b/src/planet-a/geometry.h @@ -125,7 +125,7 @@ struct TerrainFaceWriter fillNormalContrib[local.value] += selectedFaceNormal; sharedNormalSum [shared.value] += selectedFaceNormal; - rSharedNormalsDirty.set(shared.value); + rSharedNormalsDirty.insert(shared); } void fill_add_normal_filled(VertexIdx const vertex) @@ -187,7 +187,7 @@ struct TerrainFaceWriter { rContrib.shared = shared; rContrib.sum = osp::Vector3{osp::ZeroInit}; - rSharedNormalsDirty.set(shared.value); + rSharedNormalsDirty.insert(shared); std::advance(contribLast, 1); LGRN_ASSERT(contribLast != fanNormalContrib.end()); } @@ -212,7 +212,7 @@ struct TerrainFaceWriter osp::Vector3u selectedFaceIndx; IndxIt_t currentFace; ContribIt_t contribLast; - osp::BitVector_t &rSharedNormalsDirty; + lgrn::IdSetStl &rSharedNormalsDirty; }; static_assert(CFaceWriter, "TerrainFaceWriter must satisfy concept CFaceWriter"); diff --git a/src/planet-a/skeleton.cpp b/src/planet-a/skeleton.cpp index 8aa10439..4e33badf 100644 --- a/src/planet-a/skeleton.cpp +++ b/src/planet-a/skeleton.cpp @@ -82,8 +82,8 @@ void SubdivTriangleSkeleton::tri_group_resize_fit_ids() for (int lvl = 0; lvl < this->levelMax+1; ++lvl) { - osp::bitvector_resize(levels[lvl].hasSubdivedNeighbor, triCapacity); - osp::bitvector_resize(levels[lvl].hasNonSubdivedNeighbor, triCapacity); + levels[lvl].hasSubdivedNeighbor .resize(triCapacity); + levels[lvl].hasNonSubdivedNeighbor.resize(triCapacity); } } @@ -322,24 +322,24 @@ void SubdivTriangleSkeleton::debug_check_invariants() if (sktri.children.has_value()) { - LGRN_ASSERTMV(rLvl.hasNonSubdivedNeighbor.test(sktriId.value) == (nonSubdivedNeighbors != 0), + LGRN_ASSERTMV(rLvl.hasNonSubdivedNeighbor.contains(sktriId) == (nonSubdivedNeighbors != 0), "Incorrectly set hasNonSubdivedNeighbor", sktriId.value, int(group.depth), - rLvl.hasNonSubdivedNeighbor.test(sktriId.value), + rLvl.hasNonSubdivedNeighbor.contains(sktriId), nonSubdivedNeighbors); - LGRN_ASSERTM(rLvl.hasSubdivedNeighbor.test(sktriId.value) == false, + LGRN_ASSERTM(rLvl.hasSubdivedNeighbor.contains(sktriId) == false, "hasSubdivedNeighbor is only for non-subdivided tris"); } else { - LGRN_ASSERTMV(rLvl.hasSubdivedNeighbor.test(sktriId.value) == (subdivedNeighbors != 0), + LGRN_ASSERTMV(rLvl.hasSubdivedNeighbor.contains(sktriId) == (subdivedNeighbors != 0), "Incorrectly set hasSubdivedNeighbor", sktriId.value, int(group.depth), - rLvl.hasSubdivedNeighbor.test(sktriId.value), + rLvl.hasSubdivedNeighbor.contains(sktriId), subdivedNeighbors); - LGRN_ASSERTM(rLvl.hasNonSubdivedNeighbor.test(sktriId.value) == false, + LGRN_ASSERTM(rLvl.hasNonSubdivedNeighbor.contains(sktriId) == false, "hasNonSubdivedNeighbor is only for subdivided tris"); } } @@ -369,7 +369,7 @@ void SubdivTriangleSkeleton::debug_check_invariants() ChunkId ChunkSkeleton::chunk_create( SkTriId const sktriId, SubdivTriangleSkeleton &rSkel, - osp::BitVector_t &rSharedAdded, + lgrn::IdSetStl &rSharedAdded, osp::ArrayView> const edgeLft, osp::ArrayView> const edgeBtm, osp::ArrayView> const edgeRte) @@ -383,7 +383,7 @@ ChunkId ChunkSkeleton::chunk_create( MaybeNewId const shared = shared_get_or_create(vrtx, rSkel); if (shared.isNew) { - rSharedAdded.set(shared.id.value); + rSharedAdded.insert(shared.id); } return shared_store(shared.id); }; @@ -422,7 +422,7 @@ ChunkId ChunkSkeleton::chunk_create( void ChunkSkeleton::chunk_remove( ChunkId const chunkId, SkTriId const sktriId, - osp::BitVector_t &rSharedRemoved, + lgrn::IdSetStl &rSharedRemoved, SubdivTriangleSkeleton &rSkel) noexcept { for (SharedVrtxOwner_t& rOwner : shared_vertices_used(chunkId)) @@ -431,7 +431,7 @@ void ChunkSkeleton::chunk_remove( auto const status = shared_release(std::exchange(rOwner, {}), rSkel); if (status.refCount == 0) { - rSharedRemoved.set(shared.value); + rSharedRemoved.insert(shared); } } m_triToChunk[sktriId] = {}; diff --git a/src/planet-a/skeleton.h b/src/planet-a/skeleton.h index cdfc7f19..c037f165 100644 --- a/src/planet-a/skeleton.h +++ b/src/planet-a/skeleton.h @@ -34,11 +34,12 @@ #include "planeta_types.h" #include -#include #include #include #include +#include + #include #include @@ -394,10 +395,10 @@ class SubdivTriangleSkeleton struct Level { /// Subdivided triangles that neighbor a non-subdivided one - osp::BitVector_t hasNonSubdivedNeighbor; + lgrn::IdSetStl hasNonSubdivedNeighbor; /// Non-subdivided triangles that neighbor a subdivided one - osp::BitVector_t hasSubdivedNeighbor; + lgrn::IdSetStl hasSubdivedNeighbor; }; std::array levels; @@ -482,12 +483,12 @@ class ChunkSkeleton ChunkId chunk_create( SkTriId sktriId, SubdivTriangleSkeleton &rSkel, - osp::BitVector_t &rSharedAdded, + lgrn::IdSetStl &rSharedAdded, osp::ArrayView< osp::MaybeNewId > edgeLft, osp::ArrayView< osp::MaybeNewId > edgeBtm, osp::ArrayView< osp::MaybeNewId > edgeRte); - void chunk_remove(ChunkId chunkId, SkTriId sktriId, osp::BitVector_t &rSharedRemoved, SubdivTriangleSkeleton& rSkel) noexcept; + void chunk_remove(ChunkId chunkId, SkTriId sktriId, lgrn::IdSetStl &rSharedRemoved, SubdivTriangleSkeleton& rSkel) noexcept; /** * @brief Get shared vertices used by a chunk diff --git a/src/planet-a/skeleton_subdiv.cpp b/src/planet-a/skeleton_subdiv.cpp index e29e91fe..309db949 100644 --- a/src/planet-a/skeleton_subdiv.cpp +++ b/src/planet-a/skeleton_subdiv.cpp @@ -24,7 +24,6 @@ */ #include "skeleton_subdiv.h" -using osp::bitvector_resize; using osp::Vector3; using osp::Vector3l; @@ -35,11 +34,11 @@ void SkeletonSubdivScratchpad::resize(SubdivTriangleSkeleton &rSkel) { auto const triCapacity = rSkel.tri_group_ids().capacity() * 4; - bitvector_resize(this-> distanceTestDone, triCapacity); - bitvector_resize(this-> tryUnsubdiv, triCapacity); - bitvector_resize(this-> cantUnsubdiv, triCapacity); - bitvector_resize(this-> surfaceAdded, triCapacity); - bitvector_resize(this-> surfaceRemoved, triCapacity); + distanceTestDone.resize(triCapacity); + tryUnsubdiv .resize(triCapacity); + cantUnsubdiv .resize(triCapacity); + surfaceAdded .resize(triCapacity); + surfaceRemoved .resize(triCapacity); } void unsubdivide_select_by_distance( @@ -54,7 +53,7 @@ void unsubdivide_select_by_distance( auto const maybe_distance_check = [&rSkel, &rSP, &rLvl, &rLvlSP] (SkTriId const sktriId) { - if (rSP.distanceTestDone.test(sktriId.value)) + if (rSP.distanceTestDone.contains(sktriId)) { return; // Already checked } @@ -75,15 +74,15 @@ void unsubdivide_select_by_distance( } rLvlSP.distanceTestNext.push_back(sktriId); - rSP.distanceTestDone.set(sktriId.value); + rSP.distanceTestDone.insert(sktriId); }; // Use a floodfill-style algorithm to avoid needing to check every triangle // Initial seed for floodfill are all subdivided triangles that neighbor a non-subdivided one - for (std::size_t const sktriInt : rLvl.hasNonSubdivedNeighbor.ones()) + for (SkTriId const sktriId : rLvl.hasNonSubdivedNeighbor) { - maybe_distance_check(SkTriId(sktriInt)); + maybe_distance_check(sktriId); } while (rLvlSP.distanceTestNext.size() != 0) @@ -102,7 +101,7 @@ void unsubdivide_select_by_distance( if (tooFar) { // All checks passed - rSP.tryUnsubdiv.set(sktriId.value); + rSP.tryUnsubdiv.insert(sktriId); // Floodfill by checking neighbors next SkeletonTriangle const& sktri = rSkel.tri_at(sktriId); @@ -135,8 +134,8 @@ void unsubdivide_deselect_invariant_violations( // Pretend neighbor is unsubdivided when it's in tryUnsubdiv, overrided // by cantUnsubdiv if (rNeighbor.children.has_value() - && ( ! rSP.tryUnsubdiv .test(neighbor.value) - || rSP.cantUnsubdiv.test(neighbor.value) ) ) + && ( ! rSP.tryUnsubdiv .contains(neighbor) + || rSP.cantUnsubdiv.contains(neighbor) ) ) { // Neighbor is subdivided ++subdivedNeighbors; @@ -178,22 +177,22 @@ void unsubdivide_deselect_invariant_violations( if (violates_invariants(sktriId, sktri)) { - rSP.cantUnsubdiv.set(sktriId.value); + rSP.cantUnsubdiv.insert(sktriId); // Recurse into neighbors if they're also tryUnsubdiv for (SkTriId const neighbor : sktri.neighbors) - if (rSP.tryUnsubdiv.test(neighbor.value) && ! rSP.cantUnsubdiv.test(neighbor.value)) + if (rSP.tryUnsubdiv.contains(neighbor) && ! rSP.cantUnsubdiv.contains(neighbor)) { self(self, neighbor); } } }; - for (std::size_t const sktriInt : rSP.tryUnsubdiv.ones()) + for (SkTriId const sktriId : rSP.tryUnsubdiv) { - if ( ! rSP.cantUnsubdiv.test(sktriInt) ) + if ( ! rSP.cantUnsubdiv.contains(sktriId) ) { - check_recurse(check_recurse, SkTriId::from_index(sktriInt)); + check_recurse(check_recurse, sktriId); } } } @@ -206,29 +205,27 @@ void unsubdivide_level( { auto const wont_unsubdivide = [&rSP] (SkTriId const sktriId) -> bool { - return ( ! rSP.tryUnsubdiv.test(sktriId.value) || rSP.cantUnsubdiv.test(sktriId.value) ); + return ( ! rSP.tryUnsubdiv.contains(sktriId) || rSP.cantUnsubdiv.contains(sktriId) ); }; SubdivTriangleSkeleton::Level &rLvl = rSkel.levels[lvl]; SubdivScratchpadLevel &rLvlSP = rSP .levels[lvl]; - for (std::size_t const sktriInt : rSP.tryUnsubdiv.ones()) - if ( ! rSP.cantUnsubdiv.test(sktriInt) ) + for (SkTriId const sktriId : rSP.tryUnsubdiv) + if ( ! rSP.cantUnsubdiv.contains(sktriId) ) { // All checks passed, 100% confirmed sktri will be unsubdivided - - SkTriId const sktriId = SkTriId::from_index(sktriInt); SkeletonTriangle &rTri = rSkel.tri_at(sktriId); - LGRN_ASSERT(!rLvl.hasSubdivedNeighbor.test(sktriInt)); + LGRN_ASSERT(!rLvl.hasSubdivedNeighbor.contains(sktriId)); for (SkTriId const neighborId : rTri.neighbors) if ( neighborId.has_value() && wont_unsubdivide(neighborId) ) { SkeletonTriangle const& rNeighborTri = rSkel.tri_at(neighborId); if ( rNeighborTri.children.has_value() ) { - rLvl.hasNonSubdivedNeighbor.set(neighborId.value); - rLvl.hasSubdivedNeighbor.set(sktriInt); + rLvl.hasNonSubdivedNeighbor.insert(neighborId); + rLvl.hasSubdivedNeighbor.insert(sktriId); } else { @@ -245,37 +242,37 @@ void unsubdivide_level( if (neighborHasSubdivedNeighbor) { - rLvl.hasSubdivedNeighbor.set(neighborId.value); + rLvl.hasSubdivedNeighbor.insert(neighborId); } else { - rLvl.hasSubdivedNeighbor.reset(neighborId.value); + rLvl.hasSubdivedNeighbor.erase(neighborId); } } } - rLvl.hasNonSubdivedNeighbor.reset(sktriInt); + rLvl.hasNonSubdivedNeighbor.erase(sktriId); - LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.test(tri_id(rTri.children, 0).value) ); - LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.test(tri_id(rTri.children, 1).value) ); - LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.test(tri_id(rTri.children, 2).value) ); - LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.test(tri_id(rTri.children, 3).value) ); + LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.contains(tri_id(rTri.children, 0)) ); + LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.contains(tri_id(rTri.children, 1)) ); + LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.contains(tri_id(rTri.children, 2)) ); + LGRN_ASSERT( ! rLvl.hasSubdivedNeighbor.contains(tri_id(rTri.children, 3)) ); - LGRN_ASSERT(!rSP.surfaceAdded.test(sktriInt)); - rSP.surfaceAdded.set(sktriInt); + LGRN_ASSERT(!rSP.surfaceAdded.contains(sktriId)); + rSP.surfaceAdded.insert(sktriId); // If child is in surfaceAdded. This means it was just recently unsubdivided. // It will be removed right away and is an intermediate step, so don't include it in // surfaceAdded or surfaceRemoved. auto const check_surface = [&rSP] (SkTriId const child) { - if (rSP.surfaceAdded.test(child.value)) + if (rSP.surfaceAdded.contains(child)) { - rSP.surfaceAdded.reset(child.value); + rSP.surfaceAdded.erase(child); } else { - rSP.surfaceRemoved.set(child.value); + rSP.surfaceRemoved.insert(child); } }; check_surface(tri_id(rTri.children, 0)); @@ -285,11 +282,11 @@ void unsubdivide_level( rSP.onUnsubdiv(sktriId, rTri, rSkel, rSkData, rSP.onUnsubdivUserData); - rSkel.tri_unsubdiv(SkTriId(sktriInt), rTri); + rSkel.tri_unsubdiv(sktriId, rTri); } - rSP.tryUnsubdiv.reset(); - rSP.cantUnsubdiv.reset(); + rSP.tryUnsubdiv.clear(); + rSP.cantUnsubdiv.clear(); } SkTriGroupId subdivide( @@ -336,30 +333,30 @@ SkTriGroupId subdivide( tri_id(groupId, 2), tri_id(groupId, 3), }); - rSP.distanceTestDone.set(tri_id(groupId, 0).value); - rSP.distanceTestDone.set(tri_id(groupId, 1).value); - rSP.distanceTestDone.set(tri_id(groupId, 2).value); - rSP.distanceTestDone.set(tri_id(groupId, 3).value); + rSP.distanceTestDone.insert(tri_id(groupId, 0)); + rSP.distanceTestDone.insert(tri_id(groupId, 1)); + rSP.distanceTestDone.insert(tri_id(groupId, 2)); + rSP.distanceTestDone.insert(tri_id(groupId, 3)); } // sktri is recently unsubdivided or newly added // It will be removed right away and is an intermediate step, so don't include it // in surfaceAdded or surfaceRemoved. - if (rSP.surfaceAdded.test(sktriId.value)) + if (rSP.surfaceAdded.contains(sktriId)) { - rSP.surfaceAdded.reset(sktriId.value); + rSP.surfaceAdded.erase(sktriId); } else { - rSP.surfaceRemoved.set(sktriId.value); + rSP.surfaceRemoved.insert(sktriId); } - rSP.surfaceAdded.set(tri_id(groupId, 0).value); - rSP.surfaceAdded.set(tri_id(groupId, 1).value); - rSP.surfaceAdded.set(tri_id(groupId, 2).value); - rSP.surfaceAdded.set(tri_id(groupId, 3).value); + rSP.surfaceAdded.insert(tri_id(groupId, 0)); + rSP.surfaceAdded.insert(tri_id(groupId, 1)); + rSP.surfaceAdded.insert(tri_id(groupId, 2)); + rSP.surfaceAdded.insert(tri_id(groupId, 3)); // hasSubdivedNeighbor is only for Non-subdivided triangles - rLvl.hasSubdivedNeighbor.reset(sktriId.value); + rLvl.hasSubdivedNeighbor.erase(sktriId); bool hasNonSubdivNeighbor = false; @@ -386,14 +383,14 @@ SkTriGroupId subdivide( SubdivTriangleSkeleton::Level &rNextLvl = rSkel.levels[lvl+1]; if (rSkel.tri_at(neighborEdge.childB).children.has_value()) { - rNextLvl.hasSubdivedNeighbor.set(selfEdge.childA.value); - rNextLvl.hasNonSubdivedNeighbor.set(neighborEdge.childB.value); + rNextLvl.hasSubdivedNeighbor.insert(selfEdge.childA); + rNextLvl.hasNonSubdivedNeighbor.insert(neighborEdge.childB); } if (rSkel.tri_at(neighborEdge.childA).children.has_value()) { - rNextLvl.hasSubdivedNeighbor.set(selfEdge.childB.value); - rNextLvl.hasNonSubdivedNeighbor.set(neighborEdge.childA.value); + rNextLvl.hasSubdivedNeighbor.insert(selfEdge.childB); + rNextLvl.hasNonSubdivedNeighbor.insert(neighborEdge.childA); } } @@ -409,28 +406,28 @@ SkTriGroupId subdivide( if (neighborHasNonSubdivedNeighbor) { - rLvl.hasNonSubdivedNeighbor.set(neighborId.value); + rLvl.hasNonSubdivedNeighbor.insert(neighborId); } else { - rLvl.hasNonSubdivedNeighbor.reset(neighborId.value); + rLvl.hasNonSubdivedNeighbor.erase(neighborId); } } else { // Neighbor is not subdivided hasNonSubdivNeighbor = true; - rLvl.hasSubdivedNeighbor.set(neighborId.value); + rLvl.hasSubdivedNeighbor.insert(neighborId); } } if (hasNonSubdivNeighbor) { - rLvl.hasNonSubdivedNeighbor.set(sktriId.value); + rLvl.hasNonSubdivedNeighbor.insert(sktriId); } else { - rLvl.hasNonSubdivedNeighbor.reset(sktriId.value); + rLvl.hasNonSubdivedNeighbor.erase(sktriId); } // Check and immediately fix Invariant A and B violations. @@ -462,13 +459,13 @@ SkTriGroupId subdivide( { // Invariant A violation, more than 2 neighbors subdivided subdivide(neighborId, rSkel.tri_at(neighborId), lvl, hasNextLevel, rSkel, rSkData, rSP); - rSP.distanceTestDone.set(neighborId.value); + rSP.distanceTestDone.insert(neighborId); } - else if (!rSP.distanceTestDone.test(neighborId.value)) + else if (!rSP.distanceTestDone.contains(neighborId)) { // No Invariant A violation, but floodfill distance-test instead rSP.levels[lvl].distanceTestNext.push_back(neighborId); - rSP.distanceTestDone.set(neighborId.value); + rSP.distanceTestDone.insert(neighborId); } } @@ -491,7 +488,7 @@ SkTriGroupId subdivide( // Adds to ctx.rTerrain.levels[level-1].distanceTestNext subdivide(neighborParent, rSkel.tri_at(neighborParent), lvl-1, true, rSkel, rSkData, rSP); - rSP.distanceTestDone.set(neighborParent.value); + rSP.distanceTestDone.insert(neighborParent); rSP.levelNeedProcess = std::min(rSP.levelNeedProcess, lvl-1); } @@ -524,7 +521,7 @@ void subdivide_level_by_distance( { Vector3l const center = rSkData.centers[sktriId]; - LGRN_ASSERT(rSP.distanceTestDone.test(sktriId.value)); + LGRN_ASSERT(rSP.distanceTestDone.contains(sktriId)); bool const distanceNear = osp::is_distance_near(pos, center, rSP.distanceThresholdSubdiv[lvl]); ++rSP.distanceCheckCount; @@ -542,10 +539,10 @@ void subdivide_level_by_distance( tri_id(children, 2), tri_id(children, 3), }); - rSP.distanceTestDone.set(tri_id(children, 0).value); - rSP.distanceTestDone.set(tri_id(children, 1).value); - rSP.distanceTestDone.set(tri_id(children, 2).value); - rSP.distanceTestDone.set(tri_id(children, 3).value); + rSP.distanceTestDone.insert(tri_id(children, 0)); + rSP.distanceTestDone.insert(tri_id(children, 1)); + rSP.distanceTestDone.insert(tri_id(children, 2)); + rSP.distanceTestDone.insert(tri_id(children, 3)); } } else diff --git a/src/planet-a/skeleton_subdiv.h b/src/planet-a/skeleton_subdiv.h index 97f983e2..3f16bba1 100644 --- a/src/planet-a/skeleton_subdiv.h +++ b/src/planet-a/skeleton_subdiv.h @@ -62,17 +62,17 @@ struct SkeletonSubdivScratchpad /// Used to record which Skeleton triangles have already been distance-checked. Used for both /// subdividing and unsubdividing - osp::BitVector_t distanceTestDone; + lgrn::IdSetStl distanceTestDone; - osp::BitVector_t tryUnsubdiv; - osp::BitVector_t cantUnsubdiv; + lgrn::IdSetStl tryUnsubdiv; + lgrn::IdSetStl cantUnsubdiv; /// Non-subdivided triangles recently added, excluding intermediate triangles removed /// directly after creation. - osp::BitVector_t surfaceAdded; + lgrn::IdSetStl surfaceAdded; /// Non-subdivided triangles recently removed, excluding intermediate triangles removed /// directly after creation. - osp::BitVector_t surfaceRemoved; + lgrn::IdSetStl surfaceRemoved; std::uint8_t levelNeedProcess {}; diff --git a/src/testapp/sessions/terrain.cpp b/src/testapp/sessions/terrain.cpp index ce712010..12b45cf0 100644 --- a/src/testapp/sessions/terrain.cpp +++ b/src/testapp/sessions/terrain.cpp @@ -75,8 +75,8 @@ Session setup_terrain( .args({ idTerrain }) .func([] (ACtxTerrain &rTerrain) noexcept { - rTerrain.scratchpad.surfaceAdded .reset(); - rTerrain.scratchpad.surfaceRemoved.reset(); + rTerrain.scratchpad.surfaceAdded .clear(); + rTerrain.scratchpad.surfaceRemoved.clear(); }); rBuilder.task() @@ -158,7 +158,7 @@ Session setup_terrain_subdiv_dist( // Perform changes on skeleton, delete selected triangles unsubdivide_level(level, rSkel, rSkData, rSkSP); } - rSkSP.distanceTestDone.reset(); + rSkSP.distanceTestDone.clear(); // ## Subdivide nearby triangles @@ -170,7 +170,7 @@ Session setup_terrain_subdiv_dist( for (SkTriId const sktriId : rTerrainIco.icoTri) { rSkSP.levels[0].distanceTestNext.push_back(sktriId); - rSkSP.distanceTestDone.set(sktriId.value); + rSkSP.distanceTestDone.insert(sktriId); } rSkSP.levelNeedProcess = 0; } @@ -180,7 +180,10 @@ Session setup_terrain_subdiv_dist( { subdivide_level_by_distance(rTerrainFrame.position, level, rSkel, rSkData, rSkSP); } - rSkSP.distanceTestDone.reset(); + rSkSP.distanceTestDone.clear(); + + // Uncomment these if some new change breaks something + //rSkel.debug_check_invariants(); }); rBuilder.task() @@ -205,14 +208,13 @@ Session setup_terrain_subdiv_dist( SkeletonSubdivScratchpad &rSkSP = rTerrain.scratchpad; rChSP.chunksAdded .clear(); - rChSP.sharedNormalsDirty.reset(); - rChSP.sharedAdded .reset(); - rChSP.sharedRemoved .reset(); + rChSP.sharedNormalsDirty.clear(); + rChSP.sharedAdded .clear(); + rChSP.sharedRemoved .clear(); // Delete chunks of now-deleted Skeleton Triangles - for (std::size_t const sktriInt : rSkSP.surfaceRemoved.ones()) + for (SkTriId const sktriId : rSkSP.surfaceRemoved) { - auto const sktriId = SkTriId(sktriInt); ChunkId const chunkId = rSkCh.m_triToChunk[sktriId]; subtract_normal_contrib(chunkId, false, rChGeo, rChInfo, rChSP, rSkCh); @@ -225,10 +227,9 @@ Session setup_terrain_subdiv_dist( // Create new chunks for each new surface Skeleton Triangle added rSkCh.m_triToChunk.resize(rSkel.tri_group_ids().capacity() * 4); - for (std::size_t const sktriInt : rSkSP.surfaceAdded.ones()) + for (SkTriId const sktriId : rSkSP.surfaceAdded) { - auto const sktriId = SkTriId::from_index(sktriInt); - auto const &corners = rSkel.tri_at(SkTriId(sktriInt)).vertices; + auto const &corners = rSkel.tri_at(sktriId).vertices; ArrayView< MaybeNewId > const edgeVrtxView = rChSP.edgeVertices; ArrayView< MaybeNewId > const edgeLft = edgeVrtxView.sliceSize(edgeSize * 0, edgeSize); @@ -252,18 +253,16 @@ Session setup_terrain_subdiv_dist( ico_calc_chunk_edge(rTerrainIco.radius, chLevel, corners[2], corners[0], edgeRte, rSkData); } - for (std::size_t const sktriInt : rSkSP.surfaceAdded.ones()) + for (SkTriId const sktriId : rSkSP.surfaceAdded) { - auto const sktriId = SkTriId::from_index(sktriInt); - auto const chunkId = rSkCh.m_triToChunk[SkTriId::from_index(sktriInt)]; + auto const chunkId = rSkCh.m_triToChunk[sktriId]; restitch_check(chunkId, sktriId, rSkCh, rSkel, rSkData, rChSP); } // Calculate positions for newly added shared vertex float const scalepow = std::pow(2.0f, -rSkData.precision); - for (std::size_t const sharedVrtxInt : rChSP.sharedAdded.ones()) + for (SharedVrtxId const sharedVrtxId : rChSP.sharedAdded) { - auto const sharedVrtxId = SharedVrtxId::from_index(sharedVrtxInt); SkVrtxId const skelVrtx = rSkCh.m_sharedToSkVrtx[sharedVrtxId]; // Normal is not cleaned up by the previous user. Normal is initially set to zero, and @@ -272,16 +271,16 @@ Session setup_terrain_subdiv_dist( //Vector3l const translated = positions[size_t(skelId)] + translaton; Vector3d const scaled = Vector3d(rSkData.positions[skelVrtx]) * scalepow; - VertexIdx const vertex = rChInfo.vbufSharedOffset + sharedVrtxInt; + VertexIdx const vertex = rChInfo.vbufSharedOffset + sharedVrtxId.value; // Heightmap goes here (1) rChGeo.chunkVbufPos[vertex] = Vector3(scaled); } // Calculate fill vertex positions - for (std::size_t const sktriInt : rSkSP.surfaceAdded.ones()) + for (SkTriId const sktriId : rSkSP.surfaceAdded) { - auto const chunk = rSkCh.m_triToChunk[SkTriId::from_index(sktriInt)]; + auto const chunk = rSkCh.m_triToChunk[sktriId]; auto const chunkIdInt = std::size_t(chunk); std::size_t const fillOffset = rChInfo.vbufFillOffset + chunkIdInt*rChInfo.fillVrtxCount; @@ -304,26 +303,26 @@ Session setup_terrain_subdiv_dist( } } - // Update index buffer and calculate normals - for (std::size_t const chunkInt : rSkCh.m_chunkIds.bitview().zeros()) + // Add or remove faces according to chunk changes. This also calculates normals. + // Vertex normals are calculated from a weighted sum of face normals of connected faces. + // For shared vertices, we add or subtract face normals from rChGeo.sharedNormalSum. + for (ChunkId const chunkId : rSkCh.m_chunkIds) { - auto const chunkId = ChunkId::from_index(chunkInt); SkTriId const sktriId = rSkCh.m_chunkToTri[chunkId]; - bool const newlyAdded = rSkSP.surfaceAdded.test(sktriId.value); + bool const newlyAdded = rSkSP.surfaceAdded.contains(sktriId); update_faces(chunkId, sktriId, newlyAdded, rSkel, rSkData, rChGeo, rChInfo, rChSP, rSkCh); } std::fill(rChSP.stitchCmds.begin(), rChSP.stitchCmds.end(), ChunkStitch{}); - - for (std::size_t sharedIdx = 0; sharedIdx < rChSP.sharedNormalsDirty.size(); ++sharedIdx) - if (rSkCh.m_sharedIds.exists(SharedVrtxId(sharedIdx))) + // Update vertex buffer normals of shared vertices, as rChGeo.sharedNormalSum was modified. + for (SharedVrtxId const sharedId : rChSP.sharedNormalsDirty) { - SharedVrtxId const shared = SharedVrtxId(sharedIdx); - Vector3 const normalSum = rChGeo.sharedNormalSum[shared]; - rChGeo.chunkVbufNrm[rChInfo.vbufSharedOffset + sharedIdx] = normalSum.normalized(); + Vector3 const normalSum = rChGeo.sharedNormalSum[sharedId]; + rChGeo.chunkVbufNrm[rChInfo.vbufSharedOffset + sharedId.value] = normalSum.normalized(); } + // Uncomment these if some new change breaks something //debug_check_invariants(rChGeo, rChInfo, rSkCh); // TODO: temporary, write debug obj file every ~10 seconds @@ -401,10 +400,10 @@ void initialize_ico_terrain( for (SkTriGroupId const groupId : rTerrainIco.icoGroups) { // Notify subsequent functions of the newly added initial icosahedron faces - rSP.surfaceAdded.set(tri_id(groupId, 0).value); - rSP.surfaceAdded.set(tri_id(groupId, 1).value); - rSP.surfaceAdded.set(tri_id(groupId, 2).value); - rSP.surfaceAdded.set(tri_id(groupId, 3).value); + rSP.surfaceAdded.insert(tri_id(groupId, 0)); + rSP.surfaceAdded.insert(tri_id(groupId, 1)); + rSP.surfaceAdded.insert(tri_id(groupId, 2)); + rSP.surfaceAdded.insert(tri_id(groupId, 3)); } // Set function pointer to apply spherical curvature to the skeleton on subdivision. @@ -459,7 +458,7 @@ void initialize_ico_terrain( rTerrain.skChunks = make_skeleton_chunks(chunkSubdivLevels); // Approximate max number of chunks. Determined experimentally with margin. Surprisingly linear. - std::uint32_t const maxChunksApprox = 36 * specs.skelMaxSubdivLevels + 30; + std::uint32_t const maxChunksApprox = 42 * specs.skelMaxSubdivLevels + 30; // Approximate max number of shared vertices. Determined experimentally, roughly 60% of all // vertices end up being shared. Margin is inherited from maxChunksApprox.