Material editing fixes
This commit is contained in:
@@ -26,6 +26,9 @@ struct ProceduralMaterialComponent {
|
||||
// Pointer to the created Ogre material
|
||||
Ogre::MaterialPtr ogreMaterial;
|
||||
|
||||
// Track texture version for automatic rebuild when texture changes
|
||||
unsigned int textureVersion = 0;
|
||||
|
||||
// Material properties
|
||||
float ambient[3] = {0.2f, 0.2f, 0.2f}; // Ambient color (RGB 0-1)
|
||||
float diffuse[3] = {1.0f, 1.0f, 1.0f}; // Diffuse color multiplier (RGB 0-1)
|
||||
|
||||
@@ -49,6 +49,10 @@ struct ProceduralTextureComponent {
|
||||
// Whether the texture has been generated
|
||||
bool generated = false;
|
||||
|
||||
// Version counter - increments each time texture is regenerated
|
||||
// Used by dependent systems to detect texture changes
|
||||
unsigned int version = 0;
|
||||
|
||||
// Pointer to the generated Ogre texture
|
||||
Ogre::TexturePtr ogreTexture;
|
||||
|
||||
@@ -107,6 +111,7 @@ struct ProceduralTextureComponent {
|
||||
getRectUVs(rectIndex, u1, v1, u2, v2);
|
||||
|
||||
namedRects[name] = TextureRectInfo(name, u1, v1, u2, v2);
|
||||
dirty = true; // Mark texture as dirty since rect atlas changed
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -115,6 +120,7 @@ struct ProceduralTextureComponent {
|
||||
auto it = namedRects.find(name);
|
||||
if (it != namedRects.end()) {
|
||||
namedRects.erase(it);
|
||||
dirty = true; // Mark texture as dirty since rect atlas changed
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -71,6 +71,69 @@ void CellGridSystem::update()
|
||||
});
|
||||
}
|
||||
|
||||
// Check if texture has changed (new color rects, etc.)
|
||||
// We check this even if needsRebuild is already true, to ensure we capture
|
||||
// the latest texture version for tracking
|
||||
flecs::entity currentTextureEntity = flecs::entity::null();
|
||||
unsigned int currentTextureVersion = 0;
|
||||
|
||||
// First check stored texture entity
|
||||
auto it = m_entityMeshes.find(entity.id());
|
||||
if (it != m_entityMeshes.end() &&
|
||||
it->second.textureEntity.is_alive() &&
|
||||
it->second.textureEntity.has<ProceduralTextureComponent>()) {
|
||||
currentTextureEntity = it->second.textureEntity;
|
||||
currentTextureVersion = it->second.textureVersion;
|
||||
}
|
||||
|
||||
// If no stored texture, try to find from parent material
|
||||
if (!currentTextureEntity.is_alive()) {
|
||||
flecs::entity parent = entity.parent();
|
||||
while (parent.is_alive()) {
|
||||
flecs::entity matEntity = flecs::entity::null();
|
||||
if (parent.has<LotComponent>()) {
|
||||
matEntity = parent.get<LotComponent>().proceduralMaterialEntity;
|
||||
} else if (parent.has<DistrictComponent>()) {
|
||||
matEntity = parent.get<DistrictComponent>().proceduralMaterialEntity;
|
||||
} else if (parent.has<TownComponent>()) {
|
||||
matEntity = parent.get<TownComponent>().proceduralMaterialEntity;
|
||||
}
|
||||
|
||||
if (matEntity.is_alive() && matEntity.has<ProceduralMaterialComponent>()) {
|
||||
const auto &mat = matEntity.get<ProceduralMaterialComponent>();
|
||||
if (mat.diffuseTextureEntity.is_alive() &&
|
||||
mat.diffuseTextureEntity.has<ProceduralTextureComponent>()) {
|
||||
currentTextureEntity = mat.diffuseTextureEntity;
|
||||
const auto &tex = mat.diffuseTextureEntity.get<ProceduralTextureComponent>();
|
||||
currentTextureVersion = tex.version;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parent = parent.parent();
|
||||
}
|
||||
}
|
||||
|
||||
bool textureChanged = false;
|
||||
if (currentTextureEntity.is_alive()) {
|
||||
const auto &tex = currentTextureEntity.get<ProceduralTextureComponent>();
|
||||
if (tex.version != currentTextureVersion) {
|
||||
textureChanged = true;
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we need to rebuild, mark all roof children as dirty
|
||||
// This is needed because buildRoofs() only builds dirty roofs,
|
||||
// and the rebuild will destroy existing roof meshes
|
||||
if (needsRebuild) {
|
||||
entity.children([&](flecs::entity child) {
|
||||
if (child.has<RoofComponent>()) {
|
||||
child.get_mut<RoofComponent>().markDirty();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (needsRebuild) {
|
||||
buildCellGrid(entity, grid);
|
||||
grid.dirty = false;
|
||||
@@ -99,7 +162,22 @@ void CellGridSystem::update()
|
||||
m_districtQuery.each([&](flecs::entity entity,
|
||||
DistrictComponent &district) {
|
||||
districtCount++;
|
||||
if (district.dirty) {
|
||||
bool needsRebuild = district.dirty;
|
||||
|
||||
// Check if texture has changed
|
||||
if (!needsRebuild) {
|
||||
auto it = m_plazaMeshes.find(entity.id());
|
||||
if (it != m_plazaMeshes.end() &&
|
||||
it->second.textureEntity.is_alive() &&
|
||||
it->second.textureEntity.has<ProceduralTextureComponent>()) {
|
||||
const auto &tex = it->second.textureEntity.get<ProceduralTextureComponent>();
|
||||
if (tex.version != it->second.textureVersion) {
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsRebuild) {
|
||||
dirtyDistrictCount++;
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"CellGrid: Processing dirty district " +
|
||||
@@ -120,7 +198,22 @@ void CellGridSystem::update()
|
||||
|
||||
// Process dirty lots (for base geometry)
|
||||
m_lotQuery.each([&](flecs::entity entity, LotComponent &lot) {
|
||||
if (lot.dirty) {
|
||||
bool needsRebuild = lot.dirty;
|
||||
|
||||
// Check if texture has changed
|
||||
if (!needsRebuild) {
|
||||
auto it = m_lotBaseMeshes.find(entity.id());
|
||||
if (it != m_lotBaseMeshes.end() &&
|
||||
it->second.textureEntity.is_alive() &&
|
||||
it->second.textureEntity.has<ProceduralTextureComponent>()) {
|
||||
const auto &tex = it->second.textureEntity.get<ProceduralTextureComponent>();
|
||||
if (tex.version != it->second.textureVersion) {
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsRebuild) {
|
||||
buildLotBase(entity, lot);
|
||||
lot.dirty = false;
|
||||
}
|
||||
@@ -403,6 +496,20 @@ void CellGridSystem::buildCellGrid(flecs::entity entity,
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"CellGrid: Unknown error building frames");
|
||||
}
|
||||
|
||||
// Store texture dependency for automatic rebuild when texture changes
|
||||
// Get texture entity from material entity
|
||||
if (materialEntity.is_alive() &&
|
||||
materialEntity.has<ProceduralMaterialComponent>()) {
|
||||
const auto &mat = materialEntity.get<ProceduralMaterialComponent>();
|
||||
if (mat.diffuseTextureEntity.is_alive() &&
|
||||
mat.diffuseTextureEntity.has<ProceduralTextureComponent>()) {
|
||||
auto &meshData = m_entityMeshes[entity.id()];
|
||||
meshData.textureEntity = mat.diffuseTextureEntity;
|
||||
const auto &tex = mat.diffuseTextureEntity.get<ProceduralTextureComponent>();
|
||||
meshData.textureVersion = tex.version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BitSet structure matching original town.cpp
|
||||
@@ -2440,6 +2547,17 @@ void CellGridSystem::buildDistrictPlaza(flecs::entity entity,
|
||||
PlazaData data;
|
||||
data.meshName = meshName;
|
||||
data.entity = plazzaEntity;
|
||||
// Store texture dependency for automatic rebuild when texture changes
|
||||
if (district.proceduralMaterialEntity.is_alive() &&
|
||||
district.proceduralMaterialEntity.has<ProceduralMaterialComponent>()) {
|
||||
const auto &mat = district.proceduralMaterialEntity.get<ProceduralMaterialComponent>();
|
||||
if (mat.diffuseTextureEntity.is_alive() &&
|
||||
mat.diffuseTextureEntity.has<ProceduralTextureComponent>()) {
|
||||
data.textureEntity = mat.diffuseTextureEntity;
|
||||
const auto &tex = mat.diffuseTextureEntity.get<ProceduralTextureComponent>();
|
||||
data.textureVersion = tex.version;
|
||||
}
|
||||
}
|
||||
m_plazaMeshes[entity.id()] = data;
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
@@ -2667,10 +2785,11 @@ void CellGridSystem::buildLotBase(flecs::entity entity, LotComponent &lot)
|
||||
}
|
||||
}
|
||||
|
||||
// Find texture entity from the material that was selected
|
||||
flecs::entity textureEntity = flecs::entity::null();
|
||||
|
||||
// Apply UV mapping
|
||||
if (!textureRectToUse.empty()) {
|
||||
// Find texture entity from the material that was selected
|
||||
flecs::entity textureEntity = flecs::entity::null();
|
||||
if (materialEntityToUse.is_alive() &&
|
||||
materialEntityToUse.has<ProceduralMaterialComponent>()) {
|
||||
const auto &mat =
|
||||
@@ -2823,6 +2942,14 @@ void CellGridSystem::buildLotBase(flecs::entity entity, LotComponent &lot)
|
||||
LotBaseData data;
|
||||
data.meshName = meshName;
|
||||
data.entity = lotBaseEntity;
|
||||
// Store texture dependency for automatic rebuild when texture changes
|
||||
// textureEntity was determined earlier in the function
|
||||
if (textureEntity.is_alive() &&
|
||||
textureEntity.has<ProceduralTextureComponent>()) {
|
||||
data.textureEntity = textureEntity;
|
||||
const auto &tex = textureEntity.get<ProceduralTextureComponent>();
|
||||
data.textureVersion = tex.version;
|
||||
}
|
||||
m_lotBaseMeshes[entity.id()] = data;
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
|
||||
@@ -94,6 +94,10 @@ private:
|
||||
std::string roofSideMesh;
|
||||
std::vector<Ogre::Entity*> entities;
|
||||
|
||||
// Track texture dependency for automatic rebuild when texture changes
|
||||
flecs::entity textureEntity = flecs::entity::null();
|
||||
unsigned int textureVersion = 0;
|
||||
|
||||
// Frame meshes (unique per CellGrid for cellSize/cellHeight adaptation)
|
||||
std::string externalWindowFrameMesh;
|
||||
std::string internalWindowFrameMesh;
|
||||
@@ -109,6 +113,9 @@ private:
|
||||
struct PlazaData {
|
||||
std::string meshName;
|
||||
Ogre::Entity* entity = nullptr;
|
||||
// Track texture dependency for automatic rebuild when texture changes
|
||||
flecs::entity textureEntity = flecs::entity::null();
|
||||
unsigned int textureVersion = 0;
|
||||
};
|
||||
std::unordered_map<uint64_t, PlazaData> m_plazaMeshes;
|
||||
|
||||
@@ -116,6 +123,9 @@ private:
|
||||
struct LotBaseData {
|
||||
std::string meshName;
|
||||
Ogre::Entity* entity = nullptr;
|
||||
// Track texture dependency for automatic rebuild when texture changes
|
||||
flecs::entity textureEntity = flecs::entity::null();
|
||||
unsigned int textureVersion = 0;
|
||||
};
|
||||
std::unordered_map<uint64_t, LotBaseData> m_lotBaseMeshes;
|
||||
};
|
||||
|
||||
@@ -29,8 +29,18 @@ void ProceduralMaterialSystem::update()
|
||||
if (!m_initialized) return;
|
||||
|
||||
m_query.each([&](flecs::entity entity, ProceduralMaterialComponent& component) {
|
||||
// Check if we need to recreate (dirty or not created yet)
|
||||
if (component.dirty || !component.created) {
|
||||
bool needsRecreate = component.dirty || !component.created;
|
||||
|
||||
// Check if texture has changed (new version)
|
||||
if (!needsRecreate && component.diffuseTextureEntity.is_alive() &&
|
||||
component.diffuseTextureEntity.has<ProceduralTextureComponent>()) {
|
||||
const auto& tex = component.diffuseTextureEntity.get<ProceduralTextureComponent>();
|
||||
if (tex.version != component.textureVersion) {
|
||||
needsRecreate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsRecreate) {
|
||||
createMaterial(entity, component);
|
||||
}
|
||||
});
|
||||
@@ -65,10 +75,12 @@ void ProceduralMaterialSystem::createMaterial(flecs::entity entity, ProceduralMa
|
||||
pass->setShininess(component.shininess);
|
||||
|
||||
// Add diffuse texture if we have a reference to a ProceduralTexture entity
|
||||
unsigned int currentTexVersion = 0;
|
||||
if (component.diffuseTextureEntity.is_alive() &&
|
||||
component.diffuseTextureEntity.has<ProceduralTextureComponent>()) {
|
||||
|
||||
const auto& textureComp = component.diffuseTextureEntity.get<ProceduralTextureComponent>();
|
||||
currentTexVersion = textureComp.version;
|
||||
if (textureComp.generated && !textureComp.textureName.empty()) {
|
||||
Ogre::TextureUnitState* texUnit = pass->createTextureUnitState();
|
||||
texUnit->setTextureName(textureComp.textureName);
|
||||
@@ -78,6 +90,7 @@ void ProceduralMaterialSystem::createMaterial(flecs::entity entity, ProceduralMa
|
||||
|
||||
component.created = true;
|
||||
component.dirty = false;
|
||||
component.textureVersion = currentTexVersion;
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"ProceduralMaterial: Created '" + component.materialName + "'");
|
||||
|
||||
@@ -105,6 +105,7 @@ void ProceduralTextureSystem::generateTexture(flecs::entity entity, ProceduralTe
|
||||
|
||||
component.generated = true;
|
||||
component.dirty = false;
|
||||
component.version++;
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"ProceduralTexture: Generated '" + component.textureName +
|
||||
|
||||
Reference in New Issue
Block a user