Roof now works

This commit is contained in:
2026-04-08 20:06:40 +03:00
parent 4ba28fe512
commit 3c47a87768
4 changed files with 71 additions and 81 deletions

View File

@@ -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; }
};
/**

View File

@@ -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<RoofComponent>()) {
const auto &roof = child.get<RoofComponent>();
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<RoofComponent>()) {
auto &roof = child.get_mut<RoofComponent>();
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<LotComponent>())
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<LotComponent>()) {
auto &lot = parent.get<LotComponent>();
if (lot.proceduralMaterialEntity.is_alive() &&
lot.proceduralMaterialEntity
.has<ProceduralMaterialComponent>()) {
const auto &mat =
lot.proceduralMaterialEntity.get<
ProceduralMaterialComponent>();
if (mat.created && !mat.materialName.empty()) {
materialName = mat.materialName;
materialEntity =
lot.proceduralMaterialEntity;
break;
}
}
}
if (parent.has<DistrictComponent>()) {
auto &district = parent.get<DistrictComponent>();
if (district.proceduralMaterialEntity.is_alive() &&
district.proceduralMaterialEntity
.has<ProceduralMaterialComponent>()) {
const auto &mat =
district.proceduralMaterialEntity.get<
ProceduralMaterialComponent>();
if (mat.created && !mat.materialName.empty()) {
materialName = mat.materialName;
materialEntity =
district.proceduralMaterialEntity;
break;
}
}
}
if (parent.has<TownComponent>()) {
auto &town = parent.get<TownComponent>();
if (town.proceduralMaterialEntity.is_alive() &&
town.proceduralMaterialEntity
.has<ProceduralMaterialComponent>()) {
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<RoofComponent>()) {
auto &roof = child.get<RoofComponent>();
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<RoofComponent>(roof);
child.get_mut<RoofComponent>().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: {

View File

@@ -397,6 +397,10 @@ void EditorUISystem::renderEntityNode(flecs::entity entity, int depth)
indicators += " [Room]";
if (entity.has<FurnitureTemplateComponent>())
indicators += " [Furn]";
if (entity.has<ProceduralTextureComponent>())
indicators += " [Tex]";
if (entity.has<ProceduralMaterialComponent>())
indicators += " [Mat]";
snprintf(label, sizeof(label), "%s%s##%llu", name.c_str(),
indicators.c_str(), (unsigned long long)entity.id());

View File

@@ -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;
}