From 3c47a87768df9c6df0cec31ec117eb0f4ffd9954 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Wed, 8 Apr 2026 20:06:40 +0300 Subject: [PATCH] Roof now works --- .../editScene/components/CellGrid.hpp | 5 + .../editScene/systems/CellGridSystem.cpp | 138 ++++++++---------- .../editScene/systems/EditorUISystem.cpp | 4 + src/features/editScene/ui/RoofEditor.cpp | 5 + 4 files changed, 71 insertions(+), 81 deletions(-) diff --git a/src/features/editScene/components/CellGrid.hpp b/src/features/editScene/components/CellGrid.hpp index 7312da0..2b35cd4 100644 --- a/src/features/editScene/components/CellGrid.hpp +++ b/src/features/editScene/components/CellGrid.hpp @@ -228,6 +228,11 @@ struct RoofComponent { // Height parameters float baseHeight = 0.5f; float maxHeight = 0.5f; + + // Dirty flag - triggers rebuild when changed + bool dirty = true; + + void markDirty() { dirty = true; } }; /** diff --git a/src/features/editScene/systems/CellGridSystem.cpp b/src/features/editScene/systems/CellGridSystem.cpp index e47f34c..0040832 100644 --- a/src/features/editScene/systems/CellGridSystem.cpp +++ b/src/features/editScene/systems/CellGridSystem.cpp @@ -53,9 +53,35 @@ void CellGridSystem::update() // Process dirty cell grids m_cellGridQuery.each( [&](flecs::entity entity, CellGridComponent &grid) { - if (grid.dirty) { + // Check if grid itself is dirty + bool needsRebuild = grid.dirty; + + // Check for dirty roofs (roof children will mark themselves dirty) + // and mark parent grid dirty to trigger rebuild + if (!needsRebuild) { + entity.children([&](flecs::entity child) { + if (child.has()) { + const auto &roof = child.get(); + if (roof.dirty) { + needsRebuild = true; + return false; // Stop iteration + } + } + return true; // Continue iteration + }); + } + + if (needsRebuild) { buildCellGrid(entity, grid); grid.dirty = false; + // Clear dirty flag on all roof children + entity.children([&](flecs::entity child) { + if (child.has()) { + auto &roof = child.get_mut(); + roof.dirty = false; + } + return true; // Continue iteration + }); } }); @@ -1708,95 +1734,45 @@ void CellGridSystem::buildWindows(const CellGridComponent &grid, } } -void CellGridSystem::buildRoofs(flecs::entity lotEntity, +void CellGridSystem::buildRoofs(flecs::entity cellGridEntity, const CellGridComponent &grid, Procedural::TriangleBuffer &roofTb) { - if (!lotEntity.has()) - return; - - // Get material for roofs (prefer ProceduralMaterial from Lot/District/Town) - std::string materialName; - flecs::entity materialEntity = flecs::entity::null(); - - // Look for ProceduralMaterial in parent hierarchy - flecs::entity parent = lotEntity.parent(); - while (parent.is_alive()) { - if (parent.has()) { - auto &lot = parent.get(); - if (lot.proceduralMaterialEntity.is_alive() && - lot.proceduralMaterialEntity - .has()) { - const auto &mat = - lot.proceduralMaterialEntity.get< - ProceduralMaterialComponent>(); - if (mat.created && !mat.materialName.empty()) { - materialName = mat.materialName; - materialEntity = - lot.proceduralMaterialEntity; - break; - } - } - } - if (parent.has()) { - auto &district = parent.get(); - if (district.proceduralMaterialEntity.is_alive() && - district.proceduralMaterialEntity - .has()) { - const auto &mat = - district.proceduralMaterialEntity.get< - ProceduralMaterialComponent>(); - if (mat.created && !mat.materialName.empty()) { - materialName = mat.materialName; - materialEntity = - district.proceduralMaterialEntity; - break; - } - } - } - if (parent.has()) { - auto &town = parent.get(); - if (town.proceduralMaterialEntity.is_alive() && - town.proceduralMaterialEntity - .has()) { - const auto &mat = - town.proceduralMaterialEntity.get< - ProceduralMaterialComponent>(); - if (mat.created && !mat.materialName.empty()) { - materialName = mat.materialName; - materialEntity = - town.proceduralMaterialEntity; - break; - } - } - // Fall back to generated material - if (!town.materialName.empty()) { - materialName = town.materialName; - break; - } - } - parent = parent.parent(); - } - - // Get roof rect name for UV mapping - std::string roofRectName = - grid.extWallRectName; // Default to exterior wall color - - // Get roof components from lot's children - lotEntity.children([&](flecs::entity child) { + // Get roof components from CellGrid's children + // Roof components are children of the CellGrid entity + cellGridEntity.children([&](flecs::entity child) { if (child.has()) { auto &roof = child.get(); - Ogre::Vector3 origin = grid.cellToWorld( - roof.posX, roof.posY, roof.posZ); - origin += Ogre::Vector3(roof.offsetX, roof.offsetY, - roof.offsetZ); + + // Skip if not dirty (no changes) + if (!roof.dirty) { + return; + } + + // Mark as clean since we're building it now + child.set(roof); + child.get_mut().dirty = false; - float width = roof.sizeX * grid.cellSize; - float depth = roof.sizeZ * grid.cellSize; + // Roof cells are twice the size of GridCell cells + // So we use full cellSize instead of halfCell for width/depth + float roofCellSize = grid.cellSize; // Full cell size for roof cells + float x = roof.posX * roofCellSize - roofCellSize / 2.0f + + roof.sizeX * roofCellSize / 2.0f; + float z = roof.posZ * roofCellSize - roofCellSize / 2.0f + + roof.sizeZ * roofCellSize / 2.0f; + // Y uses cellHeight directly + float baseY = roof.posY * grid.cellHeight; + + Ogre::Vector3 origin(x + roof.offsetX, + baseY + roof.offsetY, + z + roof.offsetZ); + + float width = roof.sizeX * roofCellSize; + float depth = roof.sizeZ * roofCellSize; float height = roof.maxHeight - roof.baseHeight; // EXTEND constant for roof edges (like old code) - const float EXTEND = 0.2f; + const float EXTEND = 0.24f; switch (roof.type) { case RoofComponent::Flat: { diff --git a/src/features/editScene/systems/EditorUISystem.cpp b/src/features/editScene/systems/EditorUISystem.cpp index fc33553..0b1c33a 100644 --- a/src/features/editScene/systems/EditorUISystem.cpp +++ b/src/features/editScene/systems/EditorUISystem.cpp @@ -397,6 +397,10 @@ void EditorUISystem::renderEntityNode(flecs::entity entity, int depth) indicators += " [Room]"; if (entity.has()) indicators += " [Furn]"; + if (entity.has()) + indicators += " [Tex]"; + if (entity.has()) + indicators += " [Mat]"; snprintf(label, sizeof(label), "%s%s##%llu", name.c_str(), indicators.c_str(), (unsigned long long)entity.id()); diff --git a/src/features/editScene/ui/RoofEditor.cpp b/src/features/editScene/ui/RoofEditor.cpp index 369bb15..540961c 100644 --- a/src/features/editScene/ui/RoofEditor.cpp +++ b/src/features/editScene/ui/RoofEditor.cpp @@ -49,5 +49,10 @@ bool RoofEditor::renderComponent(flecs::entity entity, RoofComponent& roof) ImGui::Unindent(); } + // Mark roof as dirty when modified + if (modified) { + roof.markDirty(); + } + return modified; }