|
|
|
|
@@ -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: {
|
|
|
|
|
|