From 3798f227a712eca38fc941938d00ac1fe02d7bde Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 6 Apr 2026 23:00:20 +0300 Subject: [PATCH] Fixed external door geometry --- .../editScene/systems/CellGridSystem.cpp | 2285 ++-- .../editScene/systems/CellGridSystem.hpp | 12 +- src/gamedata/items/town.cpp | 11126 ++++++++-------- 3 files changed, 7068 insertions(+), 6355 deletions(-) diff --git a/src/features/editScene/systems/CellGridSystem.cpp b/src/features/editScene/systems/CellGridSystem.cpp index 7517101..1fe3675 100644 --- a/src/features/editScene/systems/CellGridSystem.cpp +++ b/src/features/editScene/systems/CellGridSystem.cpp @@ -190,15 +190,14 @@ void CellGridSystem::buildCellGrid(flecs::entity entity, // Build geometry parts Procedural::TriangleBuffer floorTb, ceilingTb, extWallTb, intWallTb, - intWindowsTb, roofTb; - std::vector doorTbs, windowTbs; + extWindowsTb, intWindowsTb, extDoorsTb, intDoorsTb, roofTb; buildFloorsAndCeilings(grid, floorTb, ceilingTb); buildWalls(grid, extWallTb, intWallTb, intWindowsTb); buildCorners(grid, extWallTb); buildInternalCorners(grid, intWallTb); - buildDoors(grid, doorTbs); - buildWindows(grid, windowTbs); + buildDoors(grid, extDoorsTb, intDoorsTb); + buildWindows(grid, extWindowsTb, intWindowsTb); buildRoofs(entity, grid, roofTb); // Apply UV mapping for each part (use rect if specified, otherwise default) @@ -210,14 +209,14 @@ void CellGridSystem::buildCellGrid(flecs::entity entity, applyUVMappingToBuffer(ceilingTb, grid.ceilingRectName, materialEntity); applyUVMappingToBuffer(extWallTb, grid.extWallRectName, materialEntity); applyUVMappingToBuffer(intWallTb, grid.intWallRectName, materialEntity); + applyUVMappingToBuffer(extWindowsTb, grid.extWallRectName, + materialEntity); applyUVMappingToBuffer(intWindowsTb, grid.intWallRectName, materialEntity); - for (auto &tb : doorTbs) { - applyUVMappingToBuffer(tb, grid.doorRectName, materialEntity); - } - for (auto &tb : windowTbs) { - applyUVMappingToBuffer(tb, grid.windowRectName, materialEntity); - } + applyUVMappingToBuffer(extDoorsTb, grid.extWallRectName, + materialEntity); + applyUVMappingToBuffer(intDoorsTb, grid.intWallRectName, + materialEntity); applyUVMappingToBuffer(roofTb, grid.roofRectName, materialEntity); // Generate unique base name @@ -296,32 +295,48 @@ void CellGridSystem::buildCellGrid(flecs::entity entity, meshData.entities.push_back(entity3d); } - // Doors - int doorIdx = 0; - for (auto &tb : doorTbs) { - if (tb.getVertices().size() >= 3) { - std::string meshName = - baseName + "_door" + std::to_string(doorIdx++); - meshData.doorMeshes.push_back(meshName); - auto mesh = convertToMesh(meshName, tb, materialName); - auto entity3d = m_sceneMgr->createEntity(meshName); - transform.node->attachObject(entity3d); - meshData.entities.push_back(entity3d); - } + // External doors + if (extDoorsTb.getVertices().size() >= 3) { + meshData.doorMeshes.push_back(baseName + "_extDoors"); + auto mesh = convertToMesh(baseName + "_extDoors", extDoorsTb, + materialName); + auto entity3d = + m_sceneMgr->createEntity(baseName + "_extDoors"); + transform.node->attachObject(entity3d); + meshData.entities.push_back(entity3d); } - // Windows - int windowIdx = 0; - for (auto &tb : windowTbs) { - if (tb.getVertices().size() >= 3) { - std::string meshName = baseName + "_window" + - std::to_string(windowIdx++); - meshData.windowMeshes.push_back(meshName); - auto mesh = convertToMesh(meshName, tb, materialName); - auto entity3d = m_sceneMgr->createEntity(meshName); - transform.node->attachObject(entity3d); - meshData.entities.push_back(entity3d); - } + // Internal doors + if (intDoorsTb.getVertices().size() >= 3) { + meshData.doorMeshes.push_back(baseName + "_intDoors"); + auto mesh = convertToMesh(baseName + "_intDoors", intDoorsTb, + materialName); + auto entity3d = + m_sceneMgr->createEntity(baseName + "_intDoors"); + transform.node->attachObject(entity3d); + meshData.entities.push_back(entity3d); + } + + // External windows + if (extWindowsTb.getVertices().size() >= 3) { + meshData.windowMeshes.push_back(baseName + "_extWindows"); + auto mesh = convertToMesh(baseName + "_extWindows", + extWindowsTb, materialName); + auto entity3d = + m_sceneMgr->createEntity(baseName + "_extWindows"); + transform.node->attachObject(entity3d); + meshData.entities.push_back(entity3d); + } + + // Internal windows + if (intWindowsTb.getVertices().size() >= 3) { + meshData.intWindowsMesh = baseName + "_intWindows"; + auto mesh = convertToMesh(meshData.intWindowsMesh, intWindowsTb, + materialName); + auto entity3d = + m_sceneMgr->createEntity(meshData.intWindowsMesh); + transform.node->attachObject(entity3d); + meshData.entities.push_back(entity3d); } Ogre::LogManager::getSingleton().logMessage( @@ -333,16 +348,19 @@ void CellGridSystem::buildCellGrid(flecs::entity entity, " intWall=" + std::to_string(intWallTb.getVertices().size()) + " intWindows=" + std::to_string(intWindowsTb.getVertices().size()) + - " doors=" + std::to_string(doorTbs.size()) + - " windows=" + std::to_string(windowTbs.size()) + + " extWindows=" + + std::to_string(extWindowsTb.getVertices().size()) + + " extDoors=" + std::to_string(extDoorsTb.getVertices().size()) + + " intDoors=" + std::to_string(intDoorsTb.getVertices().size()) + " roof=" + std::to_string(roofTb.getVertices().size())); // Build window and door frames try { buildFrames(entity, grid, materialName); - } catch (const std::exception& e) { + } catch (const std::exception &e) { Ogre::LogManager::getSingleton().logMessage( - "CellGrid: Error building frames: " + std::string(e.what())); + "CellGrid: Error building frames: " + + std::string(e.what())); } catch (...) { Ogre::LogManager::getSingleton().logMessage( "CellGrid: Unknown error building frames"); @@ -609,15 +627,20 @@ void CellGridSystem::buildCorners(const CellGridComponent &grid, for (const auto &bit : bits_ext_corners) { // Check for corner based on which features are present - bool hasXNeg = (bit.bit & CellFlags::AllXNeg) && xNegFlags; - bool hasXPos = (bit.bit & CellFlags::AllXPos) && xPosFlags; - bool hasZNeg = (bit.bit & CellFlags::AllZNeg) && zNegFlags; - bool hasZPos = (bit.bit & CellFlags::AllZPos) && zPosFlags; - + bool hasXNeg = (bit.bit & CellFlags::AllXNeg) && + xNegFlags; + bool hasXPos = (bit.bit & CellFlags::AllXPos) && + xPosFlags; + bool hasZNeg = (bit.bit & CellFlags::AllZNeg) && + zNegFlags; + bool hasZPos = (bit.bit & CellFlags::AllZPos) && + zPosFlags; + // Corner exists if both adjacent sides have features - bool hasCorner = (hasXNeg && hasZPos) || (hasXNeg && hasZNeg) || - (hasXPos && hasZPos) || (hasXPos && hasZNeg); - + bool hasCorner = + (hasXNeg && hasZPos) || (hasXNeg && hasZNeg) || + (hasXPos && hasZPos) || (hasXPos && hasZNeg); + if (hasCorner) { genPlane(bit.sizeX, bit.sizeY, bit.normal, bit.offset, *bit.tb, origin); @@ -734,21 +757,29 @@ void CellGridSystem::buildInternalCorners(const CellGridComponent &grid, for (const auto &bit : bits_int_corners1) { // Check if the corresponding direction has any feature (wall/door/window) bool hasFeature = false; - if ((bit.bit & CellFlags::AllIntXNeg) && intXNegFlags) hasFeature = true; - if ((bit.bit & CellFlags::AllIntXPos) && intXPosFlags) hasFeature = true; - if ((bit.bit & CellFlags::AllIntZPos) && intZPosFlags) hasFeature = true; - if ((bit.bit & CellFlags::AllIntZNeg) && intZNegFlags) hasFeature = true; - + if ((bit.bit & CellFlags::AllIntXNeg) && intXNegFlags) + hasFeature = true; + if ((bit.bit & CellFlags::AllIntXPos) && intXPosFlags) + hasFeature = true; + if ((bit.bit & CellFlags::AllIntZPos) && intZPosFlags) + hasFeature = true; + if ((bit.bit & CellFlags::AllIntZNeg) && intZNegFlags) + hasFeature = true; + if (hasFeature) { // Conflict resolution - skip if adjacent wall would overlap bool skip = false; - if ((bit.bit & CellFlags::AllIntXNeg) && intZPosFlags) + if ((bit.bit & CellFlags::AllIntXNeg) && + intZPosFlags) skip = true; - if ((bit.bit & CellFlags::AllIntXPos) && intZPosFlags) + if ((bit.bit & CellFlags::AllIntXPos) && + intZPosFlags) skip = true; - if ((bit.bit & CellFlags::AllIntZPos) && intXPosFlags) + if ((bit.bit & CellFlags::AllIntZPos) && + intXPosFlags) skip = true; - if ((bit.bit & CellFlags::AllIntZNeg) && intXPosFlags) + if ((bit.bit & CellFlags::AllIntZNeg) && + intXPosFlags) skip = true; if (!skip) { @@ -762,21 +793,29 @@ void CellGridSystem::buildInternalCorners(const CellGridComponent &grid, // Process bits_int_corners2 with conflict resolution for (const auto &bit : bits_int_corners2) { bool hasFeature = false; - if ((bit.bit & CellFlags::AllIntXNeg) && intXNegFlags) hasFeature = true; - if ((bit.bit & CellFlags::AllIntXPos) && intXPosFlags) hasFeature = true; - if ((bit.bit & CellFlags::AllIntZPos) && intZPosFlags) hasFeature = true; - if ((bit.bit & CellFlags::AllIntZNeg) && intZNegFlags) hasFeature = true; - + if ((bit.bit & CellFlags::AllIntXNeg) && intXNegFlags) + hasFeature = true; + if ((bit.bit & CellFlags::AllIntXPos) && intXPosFlags) + hasFeature = true; + if ((bit.bit & CellFlags::AllIntZPos) && intZPosFlags) + hasFeature = true; + if ((bit.bit & CellFlags::AllIntZNeg) && intZNegFlags) + hasFeature = true; + if (hasFeature) { // Conflict resolution bool skip = false; - if ((bit.bit & CellFlags::AllIntXNeg) && intZNegFlags) + if ((bit.bit & CellFlags::AllIntXNeg) && + intZNegFlags) skip = true; - if ((bit.bit & CellFlags::AllIntXPos) && intZNegFlags) + if ((bit.bit & CellFlags::AllIntXPos) && + intZNegFlags) skip = true; - if ((bit.bit & CellFlags::AllIntZPos) && intXNegFlags) + if ((bit.bit & CellFlags::AllIntZPos) && + intXNegFlags) skip = true; - if ((bit.bit & CellFlags::AllIntZNeg) && intXNegFlags) + if ((bit.bit & CellFlags::AllIntZNeg) && + intXNegFlags) skip = true; if (!skip) { @@ -790,7 +829,8 @@ void CellGridSystem::buildInternalCorners(const CellGridComponent &grid, } void CellGridSystem::buildDoors(const CellGridComponent &grid, - std::vector &doorTbs) + Procedural::TriangleBuffer &extDoorsTb, + Procedural::TriangleBuffer &intDoorsTb) { // Based on original town.cpp door construction // Uses plane-based door frames around the opening @@ -809,13 +849,11 @@ void CellGridSystem::buildDoors(const CellGridComponent &grid, for (const auto &cell : grid.cells) { Ogre::Vector3 origin = grid.cellToWorld(cell.x, cell.y, cell.z); - // External doors + // External doors - append directly to extDoorsTb if (cell.hasFlag(CellFlags::DoorXNeg) || cell.hasFlag(CellFlags::DoorXPos) || cell.hasFlag(CellFlags::DoorZNeg) || cell.hasFlag(CellFlags::DoorZPos)) { - Procedural::TriangleBuffer tb; - float sideWidth = (2.0f * hScale - doorWidth) / 2.0f; float moffset = (2.0f * hScale - sideWidth) / 2.0f; float doorHeight = doorHeightBase - solidExtOffset; @@ -824,101 +862,237 @@ void CellGridSystem::buildDoors(const CellGridComponent &grid, if (cell.hasFlag(CellFlags::DoorXNeg)) { // Left side frame - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, baseOffsetY + doorHeight / 2.0f, -moffset), tb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(-halfCell - cornerWidth, + baseOffsetY + + doorHeight / 2.0f, + -moffset), + extDoorsTb, origin); // Right side frame - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, baseOffsetY + doorHeight / 2.0f, moffset), tb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(-halfCell - cornerWidth, + baseOffsetY + + doorHeight / 2.0f, + moffset), + extDoorsTb, origin); // Top frame - genPlane(doorTopHeight, 2.0f * hScale, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, baseOffsetY + doorHeight + doorTopHeight / 2.0f, 0), tb, origin); + genPlane(doorTopHeight, 2.0f * hScale, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + -halfCell - cornerWidth, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + 0), + extDoorsTb, origin); } if (cell.hasFlag(CellFlags::DoorXPos)) { - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, baseOffsetY + doorHeight / 2.0f, -moffset), tb, origin); - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, baseOffsetY + doorHeight / 2.0f, moffset), tb, origin); - genPlane(doorTopHeight, 2.0f * hScale, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, baseOffsetY + doorHeight + doorTopHeight / 2.0f, 0), tb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(halfCell + cornerWidth, + baseOffsetY + + doorHeight / 2.0f, + -moffset), + extDoorsTb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(halfCell + cornerWidth, + baseOffsetY + + doorHeight / 2.0f, + moffset), + extDoorsTb, origin); + genPlane(doorTopHeight, 2.0f * hScale, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + halfCell + cornerWidth, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + 0), + extDoorsTb, origin); } if (cell.hasFlag(CellFlags::DoorZNeg)) { - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-moffset, baseOffsetY + doorHeight / 2.0f, -halfCell - cornerWidth), tb, origin); - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(moffset, baseOffsetY + doorHeight / 2.0f, -halfCell - cornerWidth), tb, origin); - genPlane(doorTopHeight, 2.0f * hScale, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(0, baseOffsetY + doorHeight + doorTopHeight / 2.0f, -halfCell - cornerWidth), tb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(-moffset, + baseOffsetY + + doorHeight / 2.0f, + -halfCell - cornerWidth), + extDoorsTb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(moffset, + baseOffsetY + + doorHeight / 2.0f, + -halfCell - cornerWidth), + extDoorsTb, origin); + genPlane(doorTopHeight, 2.0f * hScale, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + 0, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + -halfCell - cornerWidth), + extDoorsTb, origin); } if (cell.hasFlag(CellFlags::DoorZPos)) { - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-moffset, baseOffsetY + doorHeight / 2.0f, halfCell + cornerWidth), tb, origin); - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(moffset, baseOffsetY + doorHeight / 2.0f, halfCell + cornerWidth), tb, origin); - genPlane(doorTopHeight, 2.0f * hScale, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(0, baseOffsetY + doorHeight + doorTopHeight / 2.0f, halfCell + cornerWidth), tb, origin); - } - - if (tb.getVertices().size() > 0) { - doorTbs.push_back(std::move(tb)); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(-moffset, + baseOffsetY + + doorHeight / 2.0f, + halfCell + cornerWidth), + extDoorsTb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(moffset, + baseOffsetY + + doorHeight / 2.0f, + halfCell + cornerWidth), + extDoorsTb, origin); + genPlane(doorTopHeight, 2.0f * hScale, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + 0, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + halfCell + cornerWidth), + extDoorsTb, origin); } } - // Internal doors + // Internal doors - append directly to intDoorsTb if (cell.hasFlag(CellFlags::IntDoorXNeg) || cell.hasFlag(CellFlags::IntDoorXPos) || cell.hasFlag(CellFlags::IntDoorZNeg) || cell.hasFlag(CellFlags::IntDoorZPos)) { - Procedural::TriangleBuffer tb; - - float sideWidth = (2.0f * hScale - 0.2f - doorWidth) / 2.0f; - float moffset = (2.0f * hScale - 0.2f - sideWidth) / 2.0f; + float sideWidth = + (2.0f * hScale - 0.2f - doorWidth) / 2.0f; + float moffset = + (2.0f * hScale - 0.2f - sideWidth) / 2.0f; float doorHeight = doorHeightBase - solidIntOffset; float doorTopHeight = solidIntHeight - doorHeight; float baseOffsetY = solidIntOffset; if (cell.hasFlag(CellFlags::IntDoorXNeg)) { - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + 0.1f, baseOffsetY + doorHeight / 2.0f, -moffset), tb, origin); - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + 0.1f, baseOffsetY + doorHeight / 2.0f, moffset), tb, origin); - genPlane(doorTopHeight, 2.0f * hScale - 0.2f, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + 0.1f, baseOffsetY + doorHeight + doorTopHeight / 2.0f, 0), tb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(-halfCell + 0.1f, + baseOffsetY + + doorHeight / 2.0f, + -moffset), + intDoorsTb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(-halfCell + 0.1f, + baseOffsetY + + doorHeight / 2.0f, + moffset), + intDoorsTb, origin); + genPlane(doorTopHeight, 2.0f * hScale - 0.2f, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + -halfCell + 0.1f, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + 0), + intDoorsTb, origin); } if (cell.hasFlag(CellFlags::IntDoorXPos)) { - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - 0.1f, baseOffsetY + doorHeight / 2.0f, -moffset), tb, origin); - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - 0.1f, baseOffsetY + doorHeight / 2.0f, moffset), tb, origin); - genPlane(doorTopHeight, 2.0f * hScale - 0.2f, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - 0.1f, baseOffsetY + doorHeight + doorTopHeight / 2.0f, 0), tb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(halfCell - 0.1f, + baseOffsetY + + doorHeight / 2.0f, + -moffset), + intDoorsTb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(halfCell - 0.1f, + baseOffsetY + + doorHeight / 2.0f, + moffset), + intDoorsTb, origin); + genPlane(doorTopHeight, 2.0f * hScale - 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + halfCell - 0.1f, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + 0), + intDoorsTb, origin); } if (cell.hasFlag(CellFlags::IntDoorZNeg)) { - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-moffset, baseOffsetY + doorHeight / 2.0f, -halfCell + 0.1f), tb, origin); - genPlane(doorHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(moffset, baseOffsetY + doorHeight / 2.0f, -halfCell + 0.1f), tb, origin); - genPlane(doorTopHeight, 2.0f * hScale - 0.2f, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(0, baseOffsetY + doorHeight + doorTopHeight / 2.0f, -halfCell + 0.1f), tb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(-moffset, + baseOffsetY + + doorHeight / 2.0f, + -halfCell + 0.1f), + intDoorsTb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(moffset, + baseOffsetY + + doorHeight / 2.0f, + -halfCell + 0.1f), + intDoorsTb, origin); + genPlane(doorTopHeight, 2.0f * hScale - 0.2f, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + 0, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + -halfCell + 0.1f), + intDoorsTb, origin); } if (cell.hasFlag(CellFlags::IntDoorZPos)) { - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-moffset, baseOffsetY + doorHeight / 2.0f, halfCell - 0.1f), tb, origin); - genPlane(doorHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(moffset, baseOffsetY + doorHeight / 2.0f, halfCell - 0.1f), tb, origin); - genPlane(doorTopHeight, 2.0f * hScale - 0.2f, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(0, baseOffsetY + doorHeight + doorTopHeight / 2.0f, halfCell - 0.1f), tb, origin); - } - - if (tb.getVertices().size() > 0) { - doorTbs.push_back(std::move(tb)); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(-moffset, + baseOffsetY + + doorHeight / 2.0f, + halfCell - 0.1f), + intDoorsTb, origin); + genPlane( + doorHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(moffset, + baseOffsetY + + doorHeight / 2.0f, + halfCell - 0.1f), + intDoorsTb, origin); + genPlane(doorTopHeight, 2.0f * hScale - 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + 0, + baseOffsetY + doorHeight + + doorTopHeight / 2.0f, + halfCell - 0.1f), + intDoorsTb, origin); } } } } -void CellGridSystem::buildWindows( - const CellGridComponent &grid, - std::vector &windowTbs) +void CellGridSystem::buildWindows(const CellGridComponent &grid, + Procedural::TriangleBuffer &extWindowsTb, + Procedural::TriangleBuffer &intWindowsTb) { // Based on original town.cpp window construction // Uses plane-based window frames around the opening @@ -927,7 +1101,7 @@ void CellGridSystem::buildWindows( const float cornerWidth = 0.2f; const float solidExtOffset = 0.0f; const float solidIntOffset = 0.1f; - + // Window dimensions (original values scaled) // Original: windowBottomOffset = 0.8f, windowHeight = 2.0f // Window Y center = 0.8f + 2.0f/2 = 1.8f for cellHeight=4.0f @@ -935,210 +1109,600 @@ void CellGridSystem::buildWindows( const float windowHeight = 2.0f * (grid.cellHeight / 4.0f); const float windowBottomOffset = 0.8f * (grid.cellHeight / 4.0f); const float windowY = windowBottomOffset + windowHeight / 2.0f; - + for (const auto &cell : grid.cells) { Ogre::Vector3 origin = grid.cellToWorld(cell.x, cell.y, cell.z); - // External windows + // External windows - append directly to extWindowsTb if (cell.hasFlag(CellFlags::WindowXNeg) || cell.hasFlag(CellFlags::WindowXPos) || cell.hasFlag(CellFlags::WindowZNeg) || cell.hasFlag(CellFlags::WindowZPos)) { - Procedural::TriangleBuffer tb; - // External cell width = 2.0 * hScale (full cell size) float externalCellWidth = 2.0f * hScale; - float sideWidth = (externalCellWidth - windowWidth) / 2.0f; + float sideWidth = + (externalCellWidth - windowWidth) / 2.0f; // Window frame pieces to match full wall height // Bottom piece: from solidExtOffset to window bottom float bottomSize = windowBottomOffset - solidExtOffset; // Mid piece (window opening height): windowHeight // Top piece: remaining height to ceiling (external walls go to full cellHeight) - float topSize = grid.cellHeight - windowBottomOffset - windowHeight; + float topSize = grid.cellHeight - windowBottomOffset - + windowHeight; // Side pieces span full height: bottom + window + top = cellHeight float sideHeight = bottomSize + windowHeight + topSize; float offsetY = solidExtOffset; if (cell.hasFlag(CellFlags::WindowXNeg)) { // Left side - spans full height (bottom + window + top) - genPlane(sideHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, offsetY + sideHeight/2.0f, -windowWidth/2 - sideWidth/2), tb, origin); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(-halfCell - cornerWidth, + offsetY + sideHeight / + 2.0f, + -windowWidth / 2 - + sideWidth / 2), + extWindowsTb, origin); // Right side - spans full height (bottom + window + top) - genPlane(sideHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, offsetY + sideHeight/2.0f, windowWidth/2 + sideWidth/2), tb, origin); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(-halfCell - cornerWidth, + offsetY + sideHeight / + 2.0f, + windowWidth / 2 + + sideWidth / 2), + extWindowsTb, origin); // Top - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, windowY + windowHeight/2 + topSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, windowY + windowHeight/2 + topSize/2, windowWidth/2 + sideWidth/2), tb, origin); - // Bottom - Y position includes solidExtOffset to match internal window's lower edge - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, solidExtOffset + bottomSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, solidExtOffset + bottomSize/2, windowWidth/2 + sideWidth/2), tb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + -halfCell - cornerWidth, + windowY + windowHeight / 2 + + topSize / 2, + -windowWidth / 2 - + sideWidth / 2), + extWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + -halfCell - cornerWidth, + windowY + windowHeight / 2 + + topSize / 2, + windowWidth / 2 + + sideWidth / 2), + extWindowsTb, origin); + // Bottom - Y position includes solidExtOffset + genPlane(bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(-halfCell - cornerWidth, + solidExtOffset + + bottomSize / 2, + -windowWidth / 2 - + sideWidth / 2), + extWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(-halfCell - cornerWidth, + solidExtOffset + + bottomSize / 2, + windowWidth / 2 + + sideWidth / 2), + extWindowsTb, origin); // Top center - genPlane(topSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, windowY + windowHeight/2 + topSize/2, 0), tb, origin); - // Bottom center - Y position includes solidExtOffset to match internal window's lower edge - genPlane(bottomSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(-halfCell - cornerWidth, solidExtOffset + bottomSize/2, 0), tb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + -halfCell - cornerWidth, + windowY + windowHeight / 2 + + topSize / 2, + 0), + extWindowsTb, origin); + // Bottom center - Y position includes solidExtOffset + genPlane(bottomSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(-halfCell - cornerWidth, + solidExtOffset + + bottomSize / 2, + 0), + extWindowsTb, origin); } if (cell.hasFlag(CellFlags::WindowXPos)) { // Left side - spans full height - genPlane(sideHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, offsetY + sideHeight/2.0f, -windowWidth/2 - sideWidth/2), tb, origin); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(halfCell + cornerWidth, + offsetY + sideHeight / + 2.0f, + -windowWidth / 2 - + sideWidth / 2), + extWindowsTb, origin); // Right side - spans full height - genPlane(sideHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, offsetY + sideHeight/2.0f, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, windowY + windowHeight/2 + topSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, windowY + windowHeight/2 + topSize/2, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, solidExtOffset + bottomSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, solidExtOffset + bottomSize/2, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(topSize, windowWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, windowY + windowHeight/2 + topSize/2, 0), tb, origin); - genPlane(bottomSize, windowWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(halfCell + cornerWidth, solidExtOffset + bottomSize/2, 0), tb, origin); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(halfCell + cornerWidth, + offsetY + sideHeight / + 2.0f, + windowWidth / 2 + + sideWidth / 2), + extWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + halfCell + cornerWidth, + windowY + windowHeight / 2 + + topSize / 2, + -windowWidth / 2 - + sideWidth / 2), + extWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + halfCell + cornerWidth, + windowY + windowHeight / 2 + + topSize / 2, + windowWidth / 2 + + sideWidth / 2), + extWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(halfCell + cornerWidth, + solidExtOffset + + bottomSize / 2, + -windowWidth / 2 - + sideWidth / 2), + extWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(halfCell + cornerWidth, + solidExtOffset + + bottomSize / 2, + windowWidth / 2 + + sideWidth / 2), + extWindowsTb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + halfCell + cornerWidth, + windowY + windowHeight / 2 + + topSize / 2, + 0), + extWindowsTb, origin); + genPlane(bottomSize, windowWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(halfCell + cornerWidth, + solidExtOffset + + bottomSize / 2, + 0), + extWindowsTb, origin); } if (cell.hasFlag(CellFlags::WindowZNeg)) { // Left side - spans full height - genPlane(sideHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, offsetY + sideHeight/2.0f, -halfCell - cornerWidth), tb, origin); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + offsetY + sideHeight / + 2.0f, + -halfCell - cornerWidth), + extWindowsTb, origin); // Right side - spans full height - genPlane(sideHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, offsetY + sideHeight/2.0f, -halfCell - cornerWidth), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, windowY + windowHeight/2 + topSize/2, -halfCell - cornerWidth), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, windowY + windowHeight/2 + topSize/2, -halfCell - cornerWidth), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, solidExtOffset + bottomSize/2, -halfCell - cornerWidth), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, solidExtOffset + bottomSize/2, -halfCell - cornerWidth), tb, origin); - genPlane(topSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(0, windowY + windowHeight/2 + topSize/2, -halfCell - cornerWidth), tb, origin); - genPlane(bottomSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(0, solidExtOffset + bottomSize/2, -halfCell - cornerWidth), tb, origin); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(windowWidth / 2 + + sideWidth / 2, + offsetY + sideHeight / + 2.0f, + -halfCell - cornerWidth), + extWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + -windowWidth / 2 - + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + -halfCell - cornerWidth), + extWindowsTb, origin); + genPlane( + topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + windowWidth / 2 + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + -halfCell - cornerWidth), + extWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + solidExtOffset + + bottomSize / 2, + -halfCell - cornerWidth), + extWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(windowWidth / 2 + + sideWidth / 2, + solidExtOffset + + bottomSize / 2, + -halfCell - cornerWidth), + extWindowsTb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + 0, + windowY + windowHeight / 2 + + topSize / 2, + -halfCell - cornerWidth), + extWindowsTb, origin); + genPlane(bottomSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(0, + solidExtOffset + + bottomSize / 2, + -halfCell - cornerWidth), + extWindowsTb, origin); } if (cell.hasFlag(CellFlags::WindowZPos)) { // Left side - spans full height - genPlane(sideHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, offsetY + sideHeight/2.0f, halfCell + cornerWidth), tb, origin); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + offsetY + sideHeight / + 2.0f, + halfCell + cornerWidth), + extWindowsTb, origin); // Right side - spans full height - genPlane(sideHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, offsetY + sideHeight/2.0f, halfCell + cornerWidth), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, windowY + windowHeight/2 + topSize/2, halfCell + cornerWidth), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, windowY + windowHeight/2 + topSize/2, halfCell + cornerWidth), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, solidExtOffset + bottomSize/2, halfCell + cornerWidth), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, solidExtOffset + bottomSize/2, halfCell + cornerWidth), tb, origin); - genPlane(topSize, windowWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(0, windowY + windowHeight/2 + topSize/2, halfCell + cornerWidth), tb, origin); - genPlane(bottomSize, windowWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(0, solidExtOffset + bottomSize/2, halfCell + cornerWidth), tb, origin); - } - - if (tb.getVertices().size() > 0) { - windowTbs.push_back(std::move(tb)); + genPlane(sideHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(windowWidth / 2 + + sideWidth / 2, + offsetY + sideHeight / + 2.0f, + halfCell + cornerWidth), + extWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + -windowWidth / 2 - + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + halfCell + cornerWidth), + extWindowsTb, origin); + genPlane( + topSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + windowWidth / 2 + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + halfCell + cornerWidth), + extWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + solidExtOffset + + bottomSize / 2, + halfCell + cornerWidth), + extWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(windowWidth / 2 + + sideWidth / 2, + solidExtOffset + + bottomSize / 2, + halfCell + cornerWidth), + extWindowsTb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + 0, + windowY + windowHeight / 2 + + topSize / 2, + halfCell + cornerWidth), + extWindowsTb, origin); + genPlane(bottomSize, windowWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(0, + solidExtOffset + + bottomSize / 2, + halfCell + cornerWidth), + extWindowsTb, origin); } } - // Internal windows + // Internal windows - append directly to intWindowsTb if (cell.hasFlag(CellFlags::IntWindowXNeg) || cell.hasFlag(CellFlags::IntWindowXPos) || cell.hasFlag(CellFlags::IntWindowZNeg) || cell.hasFlag(CellFlags::IntWindowZPos)) { - Procedural::TriangleBuffer tb; - float intWallOffset = 0.1f; // Internal cell width = 2.0 * hScale - 2 * intWallOffset (1.8f for cellSize=4.0) - float internalCellWidth = 2.0f * hScale - 2.0f * intWallOffset; - float sideWidth = (internalCellWidth - windowWidth) / 2.0f; + float internalCellWidth = + 2.0f * hScale - 2.0f * intWallOffset; + float sideWidth = + (internalCellWidth - windowWidth) / 2.0f; // Internal windows start at solidIntOffset, so bottom piece is shorter float bottomSize = windowBottomOffset - solidIntOffset; - float topSize = grid.cellHeight - windowY - windowHeight / 2.0f - 0.3f; + float topSize = grid.cellHeight - windowY - + windowHeight / 2.0f - 0.3f; if (cell.hasFlag(CellFlags::IntWindowXNeg)) { - genPlane(windowHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, windowY, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(windowHeight, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, windowY, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, windowY + windowHeight/2 + topSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, windowY + windowHeight/2 + topSize/2, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, solidIntOffset + bottomSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, solidIntOffset + bottomSize/2, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(topSize, windowWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, windowY + windowHeight/2 + topSize/2, 0), tb, origin); - genPlane(bottomSize, windowWidth, Ogre::Vector3::UNIT_X, - Ogre::Vector3(-halfCell + intWallOffset, solidIntOffset + bottomSize/2, 0), tb, origin); + genPlane( + windowHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(-halfCell + intWallOffset, + windowY, + -windowWidth / 2 - + sideWidth / 2), + intWindowsTb, origin); + genPlane( + windowHeight, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(-halfCell + intWallOffset, + windowY, + windowWidth / 2 + + sideWidth / 2), + intWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + -halfCell + intWallOffset, + windowY + windowHeight / 2 + + topSize / 2, + -windowWidth / 2 - + sideWidth / 2), + intWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + -halfCell + intWallOffset, + windowY + windowHeight / 2 + + topSize / 2, + windowWidth / 2 + + sideWidth / 2), + intWindowsTb, origin); + genPlane( + bottomSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(-halfCell + intWallOffset, + solidIntOffset + + bottomSize / 2, + -windowWidth / 2 - + sideWidth / 2), + intWindowsTb, origin); + genPlane( + bottomSize, sideWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(-halfCell + intWallOffset, + solidIntOffset + + bottomSize / 2, + windowWidth / 2 + + sideWidth / 2), + intWindowsTb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3( + -halfCell + intWallOffset, + windowY + windowHeight / 2 + + topSize / 2, + 0), + intWindowsTb, origin); + genPlane( + bottomSize, windowWidth, + Ogre::Vector3::UNIT_X, + Ogre::Vector3(-halfCell + intWallOffset, + solidIntOffset + + bottomSize / 2, + 0), + intWindowsTb, origin); } if (cell.hasFlag(CellFlags::IntWindowXPos)) { - genPlane(windowHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, windowY, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(windowHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, windowY, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, windowY + windowHeight/2 + topSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, windowY + windowHeight/2 + topSize/2, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, solidIntOffset + bottomSize/2, -windowWidth/2 - sideWidth/2), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, solidIntOffset + bottomSize/2, windowWidth/2 + sideWidth/2), tb, origin); - genPlane(topSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, windowY + windowHeight/2 + topSize/2, 0), tb, origin); - genPlane(bottomSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_X, - Ogre::Vector3(halfCell - intWallOffset, solidIntOffset + bottomSize/2, 0), tb, origin); + genPlane(windowHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(halfCell - intWallOffset, + windowY, + -windowWidth / 2 - + sideWidth / 2), + intWindowsTb, origin); + genPlane(windowHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(halfCell - intWallOffset, + windowY, + windowWidth / 2 + + sideWidth / 2), + intWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + halfCell - intWallOffset, + windowY + windowHeight / 2 + + topSize / 2, + -windowWidth / 2 - + sideWidth / 2), + intWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + halfCell - intWallOffset, + windowY + windowHeight / 2 + + topSize / 2, + windowWidth / 2 + + sideWidth / 2), + intWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(halfCell - intWallOffset, + solidIntOffset + + bottomSize / 2, + -windowWidth / 2 - + sideWidth / 2), + intWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(halfCell - intWallOffset, + solidIntOffset + + bottomSize / 2, + windowWidth / 2 + + sideWidth / 2), + intWindowsTb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3( + halfCell - intWallOffset, + windowY + windowHeight / 2 + + topSize / 2, + 0), + intWindowsTb, origin); + genPlane(bottomSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_X, + Ogre::Vector3(halfCell - intWallOffset, + solidIntOffset + + bottomSize / 2, + 0), + intWindowsTb, origin); } if (cell.hasFlag(CellFlags::IntWindowZNeg)) { - genPlane(windowHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, windowY, -halfCell + intWallOffset), tb, origin); - genPlane(windowHeight, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, windowY, -halfCell + intWallOffset), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, windowY + windowHeight/2 + topSize/2, -halfCell + intWallOffset), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, windowY + windowHeight/2 + topSize/2, -halfCell + intWallOffset), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, solidIntOffset + bottomSize/2, -halfCell + intWallOffset), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, solidIntOffset + bottomSize/2, -halfCell + intWallOffset), tb, origin); - genPlane(topSize, windowWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(0, windowY + windowHeight/2 + topSize/2, -halfCell + intWallOffset), tb, origin); - genPlane(bottomSize, windowWidth, Ogre::Vector3::UNIT_Z, - Ogre::Vector3(0, solidIntOffset + bottomSize/2, -halfCell + intWallOffset), tb, origin); + genPlane(windowHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + windowY, + -halfCell + + intWallOffset), + intWindowsTb, origin); + genPlane(windowHeight, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(windowWidth / 2 + + sideWidth / 2, + windowY, + -halfCell + + intWallOffset), + intWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + -windowWidth / 2 - + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + -halfCell + intWallOffset), + intWindowsTb, origin); + genPlane( + topSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + windowWidth / 2 + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + -halfCell + intWallOffset), + intWindowsTb, origin); + genPlane(bottomSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + solidIntOffset + + bottomSize / 2, + -halfCell + + intWallOffset), + intWindowsTb, origin); + genPlane( + bottomSize, sideWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + windowWidth / 2 + sideWidth / 2, + solidIntOffset + bottomSize / 2, + -halfCell + intWallOffset), + intWindowsTb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3( + 0, + windowY + windowHeight / 2 + + topSize / 2, + -halfCell + intWallOffset), + intWindowsTb, origin); + genPlane(bottomSize, windowWidth, + Ogre::Vector3::UNIT_Z, + Ogre::Vector3(0, + solidIntOffset + + bottomSize / 2, + -halfCell + + intWallOffset), + intWindowsTb, origin); } if (cell.hasFlag(CellFlags::IntWindowZPos)) { - genPlane(windowHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, windowY, halfCell - intWallOffset), tb, origin); - genPlane(windowHeight, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, windowY, halfCell - intWallOffset), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, windowY + windowHeight/2 + topSize/2, halfCell - intWallOffset), tb, origin); - genPlane(topSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, windowY + windowHeight/2 + topSize/2, halfCell - intWallOffset), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(-windowWidth/2 - sideWidth/2, solidIntOffset + bottomSize/2, halfCell - intWallOffset), tb, origin); - genPlane(bottomSize, sideWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(windowWidth/2 + sideWidth/2, solidIntOffset + bottomSize/2, halfCell - intWallOffset), tb, origin); - genPlane(topSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(0, windowY + windowHeight/2 + topSize/2, halfCell - intWallOffset), tb, origin); - genPlane(bottomSize, windowWidth, Ogre::Vector3::NEGATIVE_UNIT_Z, - Ogre::Vector3(0, solidIntOffset + bottomSize/2, halfCell - intWallOffset), tb, origin); - } - - if (tb.getVertices().size() > 0) { - windowTbs.push_back(std::move(tb)); + genPlane( + windowHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + windowY, + halfCell - intWallOffset), + intWindowsTb, origin); + genPlane( + windowHeight, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(windowWidth / 2 + + sideWidth / 2, + windowY, + halfCell - intWallOffset), + intWindowsTb, origin); + genPlane(topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + -windowWidth / 2 - + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + halfCell - intWallOffset), + intWindowsTb, origin); + genPlane( + topSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + windowWidth / 2 + sideWidth / 2, + windowY + windowHeight / 2 + + topSize / 2, + halfCell - intWallOffset), + intWindowsTb, origin); + genPlane( + bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(-windowWidth / 2 - + sideWidth / 2, + solidIntOffset + + bottomSize / 2, + halfCell - intWallOffset), + intWindowsTb, origin); + genPlane( + bottomSize, sideWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + windowWidth / 2 + sideWidth / 2, + solidIntOffset + bottomSize / 2, + halfCell - intWallOffset), + intWindowsTb, origin); + genPlane(topSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3( + 0, + windowY + windowHeight / 2 + + topSize / 2, + halfCell - intWallOffset), + intWindowsTb, origin); + genPlane( + bottomSize, windowWidth, + Ogre::Vector3::NEGATIVE_UNIT_Z, + Ogre::Vector3(0, + solidIntOffset + + bottomSize / 2, + halfCell - intWallOffset), + intWindowsTb, origin); } } } @@ -2035,528 +2599,677 @@ void CellGridSystem::applyUVMappingToBuffer(Procedural::TriangleBuffer &tb, } } - // ============================================================================ // Window and Door Frame Methods // ============================================================================ -void CellGridSystem::buildFrames(flecs::entity entity, const CellGridComponent& grid, const std::string& materialName) +void CellGridSystem::buildFrames(flecs::entity entity, + const CellGridComponent &grid, + const std::string &materialName) { - // Destroy old frames first - destroyFrames(entity); - - // Get material entity for UV mapping - flecs::entity materialEntity = flecs::entity::null(); - flecs::entity parent = entity.parent(); - while (parent.is_alive()) { - if (parent.has()) { - auto& lot = parent.get(); - if (lot.proceduralMaterialEntity.is_alive()) { - materialEntity = lot.proceduralMaterialEntity; - break; - } - } - if (parent.has()) { - auto& district = parent.get(); - if (district.proceduralMaterialEntity.is_alive()) { - materialEntity = district.proceduralMaterialEntity; - break; - } - } - if (parent.has()) { - auto& town = parent.get(); - if (town.proceduralMaterialEntity.is_alive()) { - materialEntity = town.proceduralMaterialEntity; - break; - } - } - parent = parent.parent(); - } - - // Create frame meshes with unique names per entity - std::string meshPrefix = "CellGrid_" + std::to_string(entity.id()) + "_"; - createWindowFrameMeshes(grid, materialName, meshPrefix, materialEntity); - createDoorFrameMeshes(grid, materialName, meshPrefix, materialEntity); - - // Create StaticGeometry for frames - std::string geoName = "CellGridFrames_" + std::to_string(entity.id()); - Ogre::LogManager::getSingleton().logMessage( - "CellGrid: Creating StaticGeometry: " + geoName); - Ogre::StaticGeometry* geo = m_sceneMgr->createStaticGeometry(geoName); - if (!geo) { - Ogre::LogManager::getSingleton().logMessage( - "CellGrid: Failed to create StaticGeometry!"); - return; - } - geo->setCastShadows(true); - - // Set region to cover a large area to ensure all frames are included - geo->setRegionDimensions(Ogre::Vector3(1000, 1000, 1000)); - geo->setOrigin(Ogre::Vector3::ZERO); - - // Place frames - std::vector frameEntities; - placeWindowFrames(entity, grid, geo, frameEntities); - placeDoorFrames(entity, grid, geo, frameEntities); - - // Build the static geometry - Ogre::LogManager::getSingleton().logMessage( - "CellGrid: Building StaticGeometry..."); - geo->build(); - Ogre::LogManager::getSingleton().logMessage( - "CellGrid: StaticGeometry built successfully"); - - // Destroy temporary frame entities after build - for (auto* ent : frameEntities) { - m_sceneMgr->destroyEntity(ent); - } - - // Store reference - auto it = m_entityMeshes.find(entity.id()); - if (it != m_entityMeshes.end()) { - it->second.framesStaticGeo = geo; - } + // Destroy old frames first + destroyFrames(entity); + + // Get material entity for UV mapping + flecs::entity materialEntity = flecs::entity::null(); + flecs::entity parent = entity.parent(); + while (parent.is_alive()) { + if (parent.has()) { + auto &lot = parent.get(); + if (lot.proceduralMaterialEntity.is_alive()) { + materialEntity = lot.proceduralMaterialEntity; + break; + } + } + if (parent.has()) { + auto &district = parent.get(); + if (district.proceduralMaterialEntity.is_alive()) { + materialEntity = + district.proceduralMaterialEntity; + break; + } + } + if (parent.has()) { + auto &town = parent.get(); + if (town.proceduralMaterialEntity.is_alive()) { + materialEntity = town.proceduralMaterialEntity; + break; + } + } + parent = parent.parent(); + } + + // Get the transform node to attach frames to + Ogre::SceneNode *transformNode = nullptr; + if (entity.has()) { + auto &transform = entity.get(); + transformNode = transform.node; + } + if (!transformNode) { + Ogre::LogManager::getSingleton().logMessage( + "CellGrid: No transform node for frames!"); + return; + } + + // Create frame meshes with unique names per entity + std::string meshPrefix = + "CellGrid_" + std::to_string(entity.id()) + "_"; + createWindowFrameMeshes(grid, materialName, meshPrefix, materialEntity); + createDoorFrameMeshes(grid, materialName, meshPrefix, materialEntity); + + // Place frames as child entities of the transform node + // This way they move automatically when the parent transform changes + std::vector frameEntities; + placeWindowFrames(entity, grid, transformNode, frameEntities); + placeDoorFrames(entity, grid, transformNode, frameEntities); + + Ogre::LogManager::getSingleton().logMessage( + "CellGrid: Placed " + std::to_string(frameEntities.size()) + + " frame entities"); + + // Store reference + auto it = m_entityMeshes.find(entity.id()); + if (it != m_entityMeshes.end()) { + it->second.frameEntities = std::move(frameEntities); + } else { + // Clean up if we can't store them + for (auto *ent : frameEntities) { + m_sceneMgr->destroyEntity(ent); + } + } } -void CellGridSystem::createWindowFrameMeshes(const CellGridComponent& grid, const std::string& materialName, - const std::string& meshPrefix, flecs::entity materialEntity) +void CellGridSystem::createWindowFrameMeshes(const CellGridComponent &grid, + const std::string &materialName, + const std::string &meshPrefix, + flecs::entity materialEntity) { - // Create unique mesh names per CellGrid entity - std::string extFrameMeshName = meshPrefix + "window_external"; - std::string intFrameMeshName = meshPrefix + "window_internal"; - - // Destroy old meshes if they exist - auto& meshMgr = Ogre::MeshManager::getSingleton(); - if (meshMgr.resourceExists(extFrameMeshName)) { - meshMgr.remove(extFrameMeshName); - } - if (meshMgr.resourceExists(intFrameMeshName)) { - meshMgr.remove(intFrameMeshName); - } - - // Window dimensions (scaled by cellSize/cellHeight) - float windowWidth = 1.6f * (grid.cellSize / 4.0f); - float windowHeight = 2.0f * (grid.cellHeight / 4.0f); - float frameDepth = 0.34f * (grid.cellSize / 4.0f); - float frameThickness = 0.1f * (grid.cellSize / 4.0f); - - // Create external window frame mesh - Procedural::TriangleBuffer extFrameTb; - - // Left frame - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(windowHeight) - .setSizeZ(frameDepth) - .setNumSegX(1) - .setNumSegY(2) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(-windowWidth/2 + frameThickness/2, windowHeight/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - // Right frame - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(windowHeight) - .setSizeZ(frameDepth) - .setNumSegX(1) - .setNumSegY(2) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(windowWidth/2 - frameThickness/2, windowHeight/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - // Top frame - Procedural::BoxGenerator() - .setSizeX(windowWidth) - .setSizeY(frameThickness) - .setSizeZ(frameDepth) - .setNumSegX(2) - .setNumSegY(1) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(0, windowHeight - frameThickness/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - // Windowsill (extends outward) - float sillDepth = frameDepth * 1.5f; - Procedural::BoxGenerator() - .setSizeX(windowWidth + frameThickness * 2) - .setSizeY(frameThickness * 1.5f) - .setSizeZ(sillDepth) - .setNumSegX(2) - .setNumSegY(1) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(0, frameThickness * 0.75f, -(sillDepth - frameDepth)/2)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - // Apply UV mapping and create mesh - applyUVMappingToBuffer(extFrameTb, grid.windowFrameRectName, materialEntity); - Ogre::MeshPtr extMesh = extFrameTb.transformToMesh(extFrameMeshName); - if (!materialName.empty() && extMesh->getNumSubMeshes() > 0) { - extMesh->getSubMesh(0)->setMaterialName(materialName); - } - - // Create internal window frame mesh (simpler, no sill) - Procedural::TriangleBuffer intFrameTb; - float intFrameDepth = frameDepth * 0.5f; - - // Left frame - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(windowHeight) - .setSizeZ(intFrameDepth) - .setNumSegX(1) - .setNumSegY(2) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(-windowWidth/2 + frameThickness/2, windowHeight/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(intFrameTb); - - // Right frame - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(windowHeight) - .setSizeZ(intFrameDepth) - .setNumSegX(1) - .setNumSegY(2) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(windowWidth/2 - frameThickness/2, windowHeight/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(intFrameTb); - - // Top frame - Procedural::BoxGenerator() - .setSizeX(windowWidth) - .setSizeY(frameThickness) - .setSizeZ(intFrameDepth) - .setNumSegX(2) - .setNumSegY(1) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(0, windowHeight - frameThickness/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(intFrameTb); - - applyUVMappingToBuffer(intFrameTb, grid.windowFrameRectName, materialEntity); - Ogre::MeshPtr intMesh = intFrameTb.transformToMesh(intFrameMeshName); - if (!materialName.empty() && intMesh->getNumSubMeshes() > 0) { - intMesh->getSubMesh(0)->setMaterialName(materialName); - } + // Create unique mesh names per CellGrid entity + std::string extFrameMeshName = meshPrefix + "window_external"; + std::string intFrameMeshName = meshPrefix + "window_internal"; + + // Destroy old meshes if they exist + auto &meshMgr = Ogre::MeshManager::getSingleton(); + if (meshMgr.resourceExists(extFrameMeshName)) { + meshMgr.remove(extFrameMeshName); + } + if (meshMgr.resourceExists(intFrameMeshName)) { + meshMgr.remove(intFrameMeshName); + } + + // Window dimensions (scaled by cellSize/cellHeight) + float windowWidth = 1.6f * (grid.cellSize / 4.0f); + float windowHeight = 2.0f * (grid.cellHeight / 4.0f); + float frameDepth = 0.34f * (grid.cellSize / 4.0f); + float frameThickness = 0.1f * (grid.cellSize / 4.0f); + + // Create external window frame mesh + Procedural::TriangleBuffer extFrameTb; + + // Left frame + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(windowHeight) + .setSizeZ(frameDepth) + .setNumSegX(1) + .setNumSegY(2) + .setNumSegZ(1) + .setPosition( + Ogre::Vector3(-windowWidth / 2 + frameThickness / 2, + windowHeight / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + // Right frame + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(windowHeight) + .setSizeZ(frameDepth) + .setNumSegX(1) + .setNumSegY(2) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(windowWidth / 2 - frameThickness / 2, + windowHeight / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + // Top frame + Procedural::BoxGenerator() + .setSizeX(windowWidth) + .setSizeY(frameThickness) + .setSizeZ(frameDepth) + .setNumSegX(2) + .setNumSegY(1) + .setNumSegZ(1) + .setPosition( + Ogre::Vector3(0, windowHeight - frameThickness / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + // Windowsill (extends outward) + float sillDepth = frameDepth * 1.5f; + Procedural::BoxGenerator() + .setSizeX(windowWidth + frameThickness * 2) + .setSizeY(frameThickness * 1.5f) + .setSizeZ(sillDepth) + .setNumSegX(2) + .setNumSegY(1) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(0, frameThickness * 0.75f, + -(sillDepth - frameDepth) / 2)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + // Apply UV mapping and create mesh + applyUVMappingToBuffer(extFrameTb, grid.windowFrameRectName, + materialEntity); + Ogre::MeshPtr extMesh = extFrameTb.transformToMesh(extFrameMeshName); + if (!materialName.empty() && extMesh->getNumSubMeshes() > 0) { + extMesh->getSubMesh(0)->setMaterialName(materialName); + } + + // Create internal window frame mesh (simpler, no sill) + Procedural::TriangleBuffer intFrameTb; + float intFrameDepth = frameDepth * 0.5f; + + // Left frame + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(windowHeight) + .setSizeZ(intFrameDepth) + .setNumSegX(1) + .setNumSegY(2) + .setNumSegZ(1) + .setPosition( + Ogre::Vector3(-windowWidth / 2 + frameThickness / 2, + windowHeight / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(intFrameTb); + + // Right frame + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(windowHeight) + .setSizeZ(intFrameDepth) + .setNumSegX(1) + .setNumSegY(2) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(windowWidth / 2 - frameThickness / 2, + windowHeight / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(intFrameTb); + + // Top frame + Procedural::BoxGenerator() + .setSizeX(windowWidth) + .setSizeY(frameThickness) + .setSizeZ(intFrameDepth) + .setNumSegX(2) + .setNumSegY(1) + .setNumSegZ(1) + .setPosition( + Ogre::Vector3(0, windowHeight - frameThickness / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(intFrameTb); + + applyUVMappingToBuffer(intFrameTb, grid.windowFrameRectName, + materialEntity); + Ogre::MeshPtr intMesh = intFrameTb.transformToMesh(intFrameMeshName); + if (!materialName.empty() && intMesh->getNumSubMeshes() > 0) { + intMesh->getSubMesh(0)->setMaterialName(materialName); + } } -void CellGridSystem::createDoorFrameMeshes(const CellGridComponent& grid, const std::string& materialName, - const std::string& meshPrefix, flecs::entity materialEntity) +void CellGridSystem::createDoorFrameMeshes(const CellGridComponent &grid, + const std::string &materialName, + const std::string &meshPrefix, + flecs::entity materialEntity) { - // Create unique mesh names per CellGrid entity - std::string extFrameMeshName = meshPrefix + "door_external"; - std::string intFrameMeshName = meshPrefix + "door_internal"; - - // Destroy old meshes if they exist - auto& meshMgr = Ogre::MeshManager::getSingleton(); - if (meshMgr.resourceExists(extFrameMeshName)) { - meshMgr.remove(extFrameMeshName); - } - if (meshMgr.resourceExists(intFrameMeshName)) { - meshMgr.remove(intFrameMeshName); - } - - // Door dimensions - float doorWidth = 1.4f * (grid.cellSize / 4.0f); - float doorHeight = 3.0f * (grid.cellHeight / 4.0f); - float frameDepth = 0.34f * (grid.cellSize / 4.0f); - float frameThickness = 0.1f * (grid.cellSize / 4.0f); - - // Create external door frame mesh - Procedural::TriangleBuffer extFrameTb; - float stepDepth = frameDepth * 2.0f; - - // Left frame with step - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(doorHeight) - .setSizeZ(stepDepth) - .setNumSegX(1) - .setNumSegY(3) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(-doorWidth/2 + frameThickness/2, doorHeight/2, (stepDepth - frameDepth)/2)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - // Right frame with step - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(doorHeight) - .setSizeZ(stepDepth) - .setNumSegX(1) - .setNumSegY(3) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(doorWidth/2 - frameThickness/2, doorHeight/2, (stepDepth - frameDepth)/2)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - // Top frame - Procedural::BoxGenerator() - .setSizeX(doorWidth + frameThickness * 2) - .setSizeY(frameThickness) - .setSizeZ(frameDepth) - .setNumSegX(2) - .setNumSegY(1) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(0, doorHeight - frameThickness/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - // Step - float stepWidth = doorWidth + frameThickness * 4; - Procedural::BoxGenerator() - .setSizeX(stepWidth) - .setSizeY(frameThickness) - .setSizeZ(stepDepth) - .setNumSegX(2) - .setNumSegY(1) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(0, frameThickness/2, -(stepDepth - frameDepth)/2)) - .setEnableNormals(true) - .addToTriangleBuffer(extFrameTb); - - applyUVMappingToBuffer(extFrameTb, grid.doorFrameRectName, materialEntity); - Ogre::MeshPtr extMesh = extFrameTb.transformToMesh(extFrameMeshName); - if (!materialName.empty() && extMesh->getNumSubMeshes() > 0) { - extMesh->getSubMesh(0)->setMaterialName(materialName); - } - - // Create internal door frame (simpler) - Procedural::TriangleBuffer intFrameTb; - float intFrameDepth = frameDepth * 0.5f; - - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(doorHeight) - .setSizeZ(intFrameDepth) - .setNumSegX(1) - .setNumSegY(2) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(-doorWidth/2 + frameThickness/2, doorHeight/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(intFrameTb); - - Procedural::BoxGenerator() - .setSizeX(frameThickness) - .setSizeY(doorHeight) - .setSizeZ(intFrameDepth) - .setNumSegX(1) - .setNumSegY(2) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(doorWidth/2 - frameThickness/2, doorHeight/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(intFrameTb); - - Procedural::BoxGenerator() - .setSizeX(doorWidth) - .setSizeY(frameThickness) - .setSizeZ(intFrameDepth) - .setNumSegX(2) - .setNumSegY(1) - .setNumSegZ(1) - .setPosition(Ogre::Vector3(0, doorHeight - frameThickness/2, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(intFrameTb); - - applyUVMappingToBuffer(intFrameTb, grid.doorFrameRectName, materialEntity); - Ogre::MeshPtr intMesh = intFrameTb.transformToMesh(intFrameMeshName); - if (!materialName.empty() && intMesh->getNumSubMeshes() > 0) { - intMesh->getSubMesh(0)->setMaterialName(materialName); - } + // Create unique mesh names per CellGrid entity + std::string extFrameMeshName = meshPrefix + "door_external"; + std::string intFrameMeshName = meshPrefix + "door_internal"; + + // Destroy old meshes if they exist + auto &meshMgr = Ogre::MeshManager::getSingleton(); + if (meshMgr.resourceExists(extFrameMeshName)) { + meshMgr.remove(extFrameMeshName); + } + if (meshMgr.resourceExists(intFrameMeshName)) { + meshMgr.remove(intFrameMeshName); + } + + // Door dimensions + float doorWidth = 2.8f * (grid.cellSize / 4.0f); + float doorHeight = 3.0f * (grid.cellHeight / 4.0f); + float frameDepth = 0.34f /* * (grid.cellSize / 4.0f) */; + float frameThickness = 0.1f /* * (grid.cellSize / 4.0f) */; + + // Create external door frame mesh + Procedural::TriangleBuffer extFrameTb; + float stepDepth = frameDepth * 2.0f; + + // Left frame with step + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(doorHeight) + .setSizeZ(stepDepth) + .setNumSegX(1) + .setNumSegY(3) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(-doorWidth / 2 + frameThickness / 2, + doorHeight / 2, + (stepDepth - frameDepth) / 2)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + // Right frame with step + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(doorHeight) + .setSizeZ(stepDepth) + .setNumSegX(1) + .setNumSegY(3) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(doorWidth / 2 - frameThickness / 2, + doorHeight / 2, + (stepDepth - frameDepth) / 2)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + // Top frame + Procedural::BoxGenerator() + .setSizeX(doorWidth) + .setSizeY(frameThickness) + .setSizeZ(stepDepth) + .setNumSegX(2) + .setNumSegY(1) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(0, doorHeight + frameThickness / 2, + (stepDepth - frameDepth) / 2)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + // Step + float stepWidth = doorWidth + frameThickness * 4; + Procedural::BoxGenerator() + .setSizeX(stepWidth) + .setSizeY(frameThickness) + .setSizeZ(stepDepth) + .setNumSegX(2) + .setNumSegY(1) + .setNumSegZ(1) + .setPosition( + Ogre::Vector3(0, frameThickness / 2 + 0.1f, + (stepDepth - frameDepth) / 2 + 0.05f)) + .setEnableNormals(true) + .addToTriangleBuffer(extFrameTb); + + applyUVMappingToBuffer(extFrameTb, grid.doorFrameRectName, + materialEntity); + Ogre::MeshPtr extMesh = extFrameTb.transformToMesh(extFrameMeshName); + if (!materialName.empty() && extMesh->getNumSubMeshes() > 0) { + extMesh->getSubMesh(0)->setMaterialName(materialName); + } + + // Create internal door frame (simpler) + Procedural::TriangleBuffer intFrameTb; + float intFrameDepth = frameDepth * 0.5f; + + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(doorHeight) + .setSizeZ(intFrameDepth) + .setNumSegX(1) + .setNumSegY(2) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(-doorWidth / 2 + frameThickness / 2, + doorHeight / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(intFrameTb); + + Procedural::BoxGenerator() + .setSizeX(frameThickness) + .setSizeY(doorHeight) + .setSizeZ(intFrameDepth) + .setNumSegX(1) + .setNumSegY(2) + .setNumSegZ(1) + .setPosition(Ogre::Vector3(doorWidth / 2 - frameThickness / 2, + doorHeight / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(intFrameTb); + + Procedural::BoxGenerator() + .setSizeX(doorWidth) + .setSizeY(frameThickness) + .setSizeZ(intFrameDepth) + .setNumSegX(2) + .setNumSegY(1) + .setNumSegZ(1) + .setPosition( + Ogre::Vector3(0, doorHeight - frameThickness / 2, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(intFrameTb); + + applyUVMappingToBuffer(intFrameTb, grid.doorFrameRectName, + materialEntity); + Ogre::MeshPtr intMesh = intFrameTb.transformToMesh(intFrameMeshName); + if (!materialName.empty() && intMesh->getNumSubMeshes() > 0) { + intMesh->getSubMesh(0)->setMaterialName(materialName); + } } -void CellGridSystem::placeWindowFrames(flecs::entity entity, const CellGridComponent& grid, Ogre::StaticGeometry* geo, std::vector& frameEntities) +void CellGridSystem::placeWindowFrames( + flecs::entity entity, const CellGridComponent &grid, + Ogre::SceneNode *parentNode, std::vector &frameEntities) { - std::string meshPrefix = "CellGrid_" + std::to_string(entity.id()) + "_"; - Ogre::MeshPtr extMesh = Ogre::MeshManager::getSingleton().getByName(meshPrefix + "window_external"); - Ogre::MeshPtr intMesh = Ogre::MeshManager::getSingleton().getByName(meshPrefix + "window_internal"); - - if (!extMesh && !intMesh) return; - - // Get the CellGrid entity's world position (Lot position) - Ogre::Vector3 lotWorldPos(0, 0, 0); - if (entity.has()) { - auto& transform = entity.get(); - if (transform.node) { - lotWorldPos = transform.node->_getDerivedPosition(); - } - } - - float halfCell = grid.cellSize / 2.0f; - float frameOffset = 0.2f * (grid.cellSize / 4.0f); - float windowY = 1.5f * (grid.cellHeight / 4.0f); - - for (const auto& cell : grid.cells) { - Ogre::Vector3 origin = grid.cellToWorld(cell.x, cell.y, cell.z); - - auto addFrame = [&](Ogre::MeshPtr mesh, const Ogre::Vector3& pos, const Ogre::Quaternion& rot, const char* name) { - if (!mesh) return; - // Add lot world position to get actual world coordinates - Ogre::Vector3 worldPos = lotWorldPos + pos; - Ogre::LogManager::getSingleton().logMessage( - "CellGrid: Placing " + Ogre::String(name) + " frame at world pos=" + - std::to_string(worldPos.x) + "," + std::to_string(worldPos.y) + "," + std::to_string(worldPos.z)); - Ogre::Entity* ent = m_sceneMgr->createEntity(mesh->getName()); - geo->addEntity(ent, worldPos, rot); - frameEntities.push_back(ent); - }; - - if (extMesh) { - if (cell.hasFlag(CellFlags::WindowXNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(-halfCell - frameOffset, windowY, 0); - Ogre::Quaternion rot(Ogre::Degree(-90), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extWindowXNeg"); - } - if (cell.hasFlag(CellFlags::WindowXPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(halfCell + frameOffset, windowY, 0); - Ogre::Quaternion rot(Ogre::Degree(90), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extWindowXPos"); - } - if (cell.hasFlag(CellFlags::WindowZNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, windowY, -halfCell - frameOffset); - Ogre::Quaternion rot(Ogre::Degree(180), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extWindowZNeg"); - } - if (cell.hasFlag(CellFlags::WindowZPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, windowY, halfCell + frameOffset); - Ogre::Quaternion rot(Ogre::Degree(0), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extWindowZPos"); - } - } - - if (intMesh) { - if (cell.hasFlag(CellFlags::IntWindowXNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(-halfCell + frameOffset, windowY, 0); - Ogre::Quaternion rot(Ogre::Degree(-90), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intWindowXNeg"); - } - if (cell.hasFlag(CellFlags::IntWindowXPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(halfCell - frameOffset, windowY, 0); - Ogre::Quaternion rot(Ogre::Degree(90), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intWindowXPos"); - } - if (cell.hasFlag(CellFlags::IntWindowZNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, windowY, -halfCell + frameOffset); - Ogre::Quaternion rot(Ogre::Degree(180), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intWindowZNeg"); - } - if (cell.hasFlag(CellFlags::IntWindowZPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, windowY, halfCell - frameOffset); - Ogre::Quaternion rot(Ogre::Degree(0), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intWindowZPos"); - } - } - } + std::string meshPrefix = + "CellGrid_" + std::to_string(entity.id()) + "_"; + Ogre::MeshPtr extMesh = Ogre::MeshManager::getSingleton().getByName( + meshPrefix + "window_external"); + Ogre::MeshPtr intMesh = Ogre::MeshManager::getSingleton().getByName( + meshPrefix + "window_internal"); + + if (!extMesh && !intMesh) + return; + + float halfCell = grid.cellSize / 2.0f; + float frameOffset = 0.2f * (grid.cellSize / 4.0f); + // Window frame should match window geometry positioning + // Window center Y = windowBottomOffset + windowHeight/2 + float windowHeight = 2.0f * (grid.cellHeight / 4.0f); + float windowBottomOffset = 0.8f * (grid.cellHeight / 4.0f); + float windowY = windowBottomOffset + windowHeight / 2.0f; + + for (const auto &cell : grid.cells) { + Ogre::Vector3 origin = grid.cellToWorld(cell.x, cell.y, cell.z); + + auto addFrame = [&](Ogre::MeshPtr mesh, + const Ogre::Vector3 &pos, + const Ogre::Quaternion &rot, + const char *name) { + if (!mesh) + return; + // Position is relative to parent node (local coordinates) + Ogre::LogManager::getSingleton().logMessage( + "CellGrid: Placing " + Ogre::String(name) + + " frame at local pos=" + std::to_string(pos.x) + + "," + std::to_string(pos.y) + "," + + std::to_string(pos.z)); + + // Create entity + Ogre::Entity *ent = + m_sceneMgr->createEntity(mesh->getName()); + + // Create child node attached to parent + Ogre::SceneNode *frameNode = + parentNode->createChildSceneNode(); + frameNode->setPosition(pos); + frameNode->setOrientation(rot); + frameNode->attachObject(ent); + + frameEntities.push_back(ent); + }; + + if (extMesh) { + if (cell.hasFlag(CellFlags::WindowXNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(-halfCell - frameOffset, + windowY, 0); + Ogre::Quaternion rot(Ogre::Degree(-90), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extWindowXNeg"); + } + if (cell.hasFlag(CellFlags::WindowXPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(halfCell + frameOffset, + windowY, 0); + Ogre::Quaternion rot(Ogre::Degree(90), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extWindowXPos"); + } + if (cell.hasFlag(CellFlags::WindowZNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, windowY, + -halfCell - frameOffset); + Ogre::Quaternion rot(Ogre::Degree(180), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extWindowZNeg"); + } + if (cell.hasFlag(CellFlags::WindowZPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, windowY, + halfCell + frameOffset); + Ogre::Quaternion rot(Ogre::Degree(0), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extWindowZPos"); + } + } + + if (intMesh) { + if (cell.hasFlag(CellFlags::IntWindowXNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(-halfCell + frameOffset, + windowY, 0); + Ogre::Quaternion rot(Ogre::Degree(-90), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intWindowXNeg"); + } + if (cell.hasFlag(CellFlags::IntWindowXPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(halfCell - frameOffset, + windowY, 0); + Ogre::Quaternion rot(Ogre::Degree(90), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intWindowXPos"); + } + if (cell.hasFlag(CellFlags::IntWindowZNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, windowY, + -halfCell + frameOffset); + Ogre::Quaternion rot(Ogre::Degree(180), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intWindowZNeg"); + } + if (cell.hasFlag(CellFlags::IntWindowZPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, windowY, + halfCell - frameOffset); + Ogre::Quaternion rot(Ogre::Degree(0), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intWindowZPos"); + } + } + } } -void CellGridSystem::placeDoorFrames(flecs::entity entity, const CellGridComponent& grid, Ogre::StaticGeometry* geo, std::vector& frameEntities) +void CellGridSystem::placeDoorFrames(flecs::entity entity, + const CellGridComponent &grid, + Ogre::SceneNode *parentNode, + std::vector &frameEntities) { - std::string meshPrefix = "CellGrid_" + std::to_string(entity.id()) + "_"; - Ogre::MeshPtr extMesh = Ogre::MeshManager::getSingleton().getByName(meshPrefix + "door_external"); - Ogre::MeshPtr intMesh = Ogre::MeshManager::getSingleton().getByName(meshPrefix + "door_internal"); - - if (!extMesh && !intMesh) return; - - // Get the CellGrid entity's world position (Lot position) - Ogre::Vector3 lotWorldPos(0, 0, 0); - if (entity.has()) { - auto& transform = entity.get(); - if (transform.node) { - lotWorldPos = transform.node->_getDerivedPosition(); - } - } - - float halfCell = grid.cellSize / 2.0f; - float frameOffset = 0.2f * (grid.cellSize / 4.0f); - float doorHeight = 3.0f * (grid.cellHeight / 4.0f); - float doorY = doorHeight / 2.0f; - - auto addFrame = [&](Ogre::MeshPtr mesh, const Ogre::Vector3& pos, const Ogre::Quaternion& rot, const char* name) { - if (!mesh) return; - // Add lot world position to get actual world coordinates - Ogre::Vector3 worldPos = lotWorldPos + pos; - Ogre::LogManager::getSingleton().logMessage( - "CellGrid: Placing " + Ogre::String(name) + " frame at world pos=" + - std::to_string(worldPos.x) + "," + std::to_string(worldPos.y) + "," + std::to_string(worldPos.z)); - Ogre::Entity* ent = m_sceneMgr->createEntity(mesh->getName()); - geo->addEntity(ent, worldPos, rot); - frameEntities.push_back(ent); - }; - - for (const auto& cell : grid.cells) { - Ogre::Vector3 origin = grid.cellToWorld(cell.x, cell.y, cell.z); - - if (extMesh) { - if (cell.hasFlag(CellFlags::DoorXNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(-halfCell - frameOffset, doorY, 0); - Ogre::Quaternion rot(Ogre::Degree(-90), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extDoorXNeg"); - } - if (cell.hasFlag(CellFlags::DoorXPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(halfCell + frameOffset, doorY, 0); - Ogre::Quaternion rot(Ogre::Degree(90), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extDoorXPos"); - } - if (cell.hasFlag(CellFlags::DoorZNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, doorY, -halfCell - frameOffset); - Ogre::Quaternion rot(Ogre::Degree(180), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extDoorZNeg"); - } - if (cell.hasFlag(CellFlags::DoorZPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, doorY, halfCell + frameOffset); - Ogre::Quaternion rot(Ogre::Degree(0), Ogre::Vector3::UNIT_Y); - addFrame(extMesh, pos, rot, "extDoorZPos"); - } - } - - if (intMesh) { - if (cell.hasFlag(CellFlags::IntDoorXNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(-halfCell + frameOffset, doorY, 0); - Ogre::Quaternion rot(Ogre::Degree(-90), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intDoorXNeg"); - } - if (cell.hasFlag(CellFlags::IntDoorXPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(halfCell - frameOffset, doorY, 0); - Ogre::Quaternion rot(Ogre::Degree(90), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intDoorXPos"); - } - if (cell.hasFlag(CellFlags::IntDoorZNeg)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, doorY, -halfCell + frameOffset); - Ogre::Quaternion rot(Ogre::Degree(180), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intDoorZNeg"); - } - if (cell.hasFlag(CellFlags::IntDoorZPos)) { - Ogre::Vector3 pos = origin + Ogre::Vector3(0, doorY, halfCell - frameOffset); - Ogre::Quaternion rot(Ogre::Degree(0), Ogre::Vector3::UNIT_Y); - addFrame(intMesh, pos, rot, "intDoorZPos"); - } - } - } + std::string meshPrefix = + "CellGrid_" + std::to_string(entity.id()) + "_"; + Ogre::MeshPtr extMesh = Ogre::MeshManager::getSingleton().getByName( + meshPrefix + "door_external"); + Ogre::MeshPtr intMesh = Ogre::MeshManager::getSingleton().getByName( + meshPrefix + "door_internal"); + + if (!extMesh && !intMesh) + return; + + float halfCell = grid.cellSize / 2.0f; + float frameOffset = 0.1f /* * (grid.cellSize / 4.0f) */; + // Door frame should match door geometry positioning + // External doors start at solidExtOffset=0, internal at solidIntOffset=0.1f + float solidExtOffset = 0.0f; + float solidIntOffset = 0.1f; + float doorHeightBase = 3.0f * (grid.cellHeight / 4.0f); + float extDoorHeight = doorHeightBase - solidExtOffset; + float intDoorHeight = doorHeightBase - solidIntOffset; + // Frame center Y = baseOffset + doorHeight/2 + float extDoorFrameY = solidExtOffset; /*+ extDoorHeight / 2.0f */ + ; + float intDoorFrameY = solidIntOffset /*+ intDoorHeight / 2.0f */; + + auto addFrame = [&](Ogre::MeshPtr mesh, const Ogre::Vector3 &pos, + const Ogre::Quaternion &rot, const char *name) { + if (!mesh) + return; + // Position is relative to parent node (local coordinates) + Ogre::LogManager::getSingleton().logMessage( + "CellGrid: Placing " + Ogre::String(name) + + " frame at local pos=" + std::to_string(pos.x) + "," + + std::to_string(pos.y) + "," + std::to_string(pos.z)); + + // Create entity + Ogre::Entity *ent = m_sceneMgr->createEntity(mesh->getName()); + + // Create child node attached to parent + Ogre::SceneNode *frameNode = parentNode->createChildSceneNode(); + frameNode->setPosition(pos); + frameNode->setOrientation(rot); + frameNode->attachObject(ent); + + frameEntities.push_back(ent); + }; + + for (const auto &cell : grid.cells) { + Ogre::Vector3 origin = grid.cellToWorld(cell.x, cell.y, cell.z); + + if (extMesh) { + if (cell.hasFlag(CellFlags::DoorXNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(-halfCell - frameOffset, + extDoorFrameY, 0); + Ogre::Quaternion rot(Ogre::Degree(-90), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extDoorXNeg"); + } + if (cell.hasFlag(CellFlags::DoorXPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(halfCell + frameOffset, + extDoorFrameY, 0); + Ogre::Quaternion rot(Ogre::Degree(90), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extDoorXPos"); + } + if (cell.hasFlag(CellFlags::DoorZNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, extDoorFrameY, + -halfCell - frameOffset); + Ogre::Quaternion rot(Ogre::Degree(180), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extDoorZNeg"); + } + if (cell.hasFlag(CellFlags::DoorZPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, extDoorFrameY, + halfCell + frameOffset); + Ogre::Quaternion rot(Ogre::Degree(0), + Ogre::Vector3::UNIT_Y); + addFrame(extMesh, pos, rot, "extDoorZPos"); + } + } + + if (intMesh) { + if (cell.hasFlag(CellFlags::IntDoorXNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(-halfCell + frameOffset, + intDoorFrameY, 0); + Ogre::Quaternion rot(Ogre::Degree(-90), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intDoorXNeg"); + } + if (cell.hasFlag(CellFlags::IntDoorXPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(halfCell - frameOffset, + intDoorFrameY, 0); + Ogre::Quaternion rot(Ogre::Degree(90), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intDoorXPos"); + } + if (cell.hasFlag(CellFlags::IntDoorZNeg)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, intDoorFrameY, + -halfCell + frameOffset); + Ogre::Quaternion rot(Ogre::Degree(180), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intDoorZNeg"); + } + if (cell.hasFlag(CellFlags::IntDoorZPos)) { + Ogre::Vector3 pos = + origin + + Ogre::Vector3(0, intDoorFrameY, + halfCell - frameOffset); + Ogre::Quaternion rot(Ogre::Degree(0), + Ogre::Vector3::UNIT_Y); + addFrame(intMesh, pos, rot, "intDoorZPos"); + } + } + } } void CellGridSystem::destroyFrames(flecs::entity entity) { - auto it = m_entityMeshes.find(entity.id()); - if (it != m_entityMeshes.end()) { - if (it->second.framesStaticGeo) { - try { - m_sceneMgr->destroyStaticGeometry(it->second.framesStaticGeo); - } catch (...) {} - it->second.framesStaticGeo = nullptr; - } - - auto& meshMgr = Ogre::MeshManager::getSingleton(); - std::string meshPrefix = "CellGrid_" + std::to_string(entity.id()) + "_"; - - try { meshMgr.remove(meshPrefix + "window_external"); } catch (...) {} - try { meshMgr.remove(meshPrefix + "window_internal"); } catch (...) {} - try { meshMgr.remove(meshPrefix + "door_external"); } catch (...) {} - try { meshMgr.remove(meshPrefix + "door_internal"); } catch (...) {} - } + auto it = m_entityMeshes.find(entity.id()); + if (it != m_entityMeshes.end()) { + // Destroy frame entities (and their child nodes) + for (auto *ent : it->second.frameEntities) { + if (ent) { + // Get the node that owns this entity + Ogre::SceneNode *node = + ent->getParentSceneNode(); + if (node) { + // Detach and destroy the node (this also detaches the entity) + node->getParentSceneNode()->removeChild( + node); + m_sceneMgr->destroySceneNode(node); + } + // Destroy the entity + try { + m_sceneMgr->destroyEntity(ent); + } catch (...) { + } + } + } + it->second.frameEntities.clear(); + + // Destroy frame meshes + auto &meshMgr = Ogre::MeshManager::getSingleton(); + std::string meshPrefix = + "CellGrid_" + std::to_string(entity.id()) + "_"; + + try { + meshMgr.remove(meshPrefix + "window_external"); + } catch (...) { + } + try { + meshMgr.remove(meshPrefix + "window_internal"); + } catch (...) { + } + try { + meshMgr.remove(meshPrefix + "door_external"); + } catch (...) { + } + try { + meshMgr.remove(meshPrefix + "door_internal"); + } catch (...) { + } + } } diff --git a/src/features/editScene/systems/CellGridSystem.hpp b/src/features/editScene/systems/CellGridSystem.hpp index 2f95642..44e39bc 100644 --- a/src/features/editScene/systems/CellGridSystem.hpp +++ b/src/features/editScene/systems/CellGridSystem.hpp @@ -43,8 +43,8 @@ private: Procedural::TriangleBuffer& extWallTb, Procedural::TriangleBuffer& intWallTb, Procedural::TriangleBuffer& intWindowsTb); - void buildDoors(const struct CellGridComponent& grid, std::vector& doorTbs); - void buildWindows(const struct CellGridComponent& grid, std::vector& windowTbs); + void buildDoors(const struct CellGridComponent& grid, Procedural::TriangleBuffer& extDoorsTb, Procedural::TriangleBuffer& intDoorsTb); + void buildWindows(const struct CellGridComponent& grid, Procedural::TriangleBuffer& extWindowsTb, Procedural::TriangleBuffer& intWindowsTb); void buildCorners(const struct CellGridComponent& grid, Procedural::TriangleBuffer& extWallTb); void buildInternalCorners(const struct CellGridComponent& grid, Procedural::TriangleBuffer& intWallTb); @@ -63,8 +63,8 @@ private: const std::string& meshPrefix, flecs::entity materialEntity); void createDoorFrameMeshes(const struct CellGridComponent& grid, const std::string& materialName, const std::string& meshPrefix, flecs::entity materialEntity); - void placeWindowFrames(flecs::entity entity, const struct CellGridComponent& grid, Ogre::StaticGeometry* geo, std::vector& frameEntities); - void placeDoorFrames(flecs::entity entity, const struct CellGridComponent& grid, Ogre::StaticGeometry* geo, std::vector& frameEntities); + void placeWindowFrames(flecs::entity entity, const struct CellGridComponent& grid, Ogre::SceneNode* parentNode, std::vector& frameEntities); + void placeDoorFrames(flecs::entity entity, const struct CellGridComponent& grid, Ogre::SceneNode* parentNode, std::vector& frameEntities); void destroyFrames(flecs::entity entity); // Convert triangle buffer to mesh @@ -98,8 +98,8 @@ private: std::string externalDoorFrameMesh; std::string internalDoorFrameMesh; - // StaticGeometry for frames (per CellGrid) - Ogre::StaticGeometry* framesStaticGeo = nullptr; + // Frame entities attached to the SceneNode (so they move with transform) + std::vector frameEntities; }; std::unordered_map m_entityMeshes; diff --git a/src/gamedata/items/town.cpp b/src/gamedata/items/town.cpp index d7df460..a6d134c 100644 --- a/src/gamedata/items/town.cpp +++ b/src/gamedata/items/town.cpp @@ -34,11 +34,11 @@ void serializeMesh(Ogre::MeshPtr mesh, const Ogre::String &meshName) { - ZoneScoped; - Ogre::MeshSerializer meshSerializer; + ZoneScoped; + Ogre::MeshSerializer meshSerializer; - meshSerializer.exportMesh(mesh, meshName, - Ogre::Serializer::ENDIAN_NATIVE); + meshSerializer.exportMesh(mesh, meshName, + Ogre::Serializer::ENDIAN_NATIVE); } namespace ECS { @@ -46,67 +46,67 @@ namespace Items { int64_t makeCellKey(int kx, int ky, int kz) { - ZoneScoped; - int64_t key = - (int64_t)kx + 1024 * (int64_t)ky + 1024 * 1024 * (int64_t)kz; - return key; + ZoneScoped; + int64_t key = + (int64_t)kx + 1024 * (int64_t)ky + 1024 * 1024 * (int64_t)kz; + return key; } int64_t makeCellKey(const nlohmann::json &cell) { - ZoneScoped; - int64_t kx = cell["x"].get(); - int64_t ky = cell["y"].get(); - int64_t kz = cell["z"].get(); - int64_t key = makeCellKey(kx, ky, kz); - return key; + ZoneScoped; + int64_t kx = cell["x"].get(); + int64_t ky = cell["y"].get(); + int64_t kz = cell["z"].get(); + int64_t key = makeCellKey(kx, ky, kz); + return key; }; void displayGrid(flecs::entity e, nlohmann::json &lot, int index, - Ogre::SceneNode *sceneNode, const Ogre::Vector3 &localPosition, - const Ogre::Quaternion &localRotation) + Ogre::SceneNode *sceneNode, const Ogre::Vector3 &localPosition, + const Ogre::Quaternion &localRotation) { - ZoneScoped; - if (lot.find("edited") == lot.end()) { - lot["edited"] = true; - int width = lot["width"].get(); - int height = lot["height"].get(); - Ogre::Vector3 worldPosition = - sceneNode->_getDerivedPosition() + localPosition; - Ogre::Quaternion worldRotation = - sceneNode->_getDerivedOrientation() * localRotation; - Ogre::Vector3 origin = worldPosition + - worldRotation * Ogre::Vector3::UNIT_X * - 4.0f * (-width / 2) + - worldRotation * Ogre::Vector3::UNIT_Z * - 4.0f * (-height / 2); - Ogre::ManualObject *mobj = - ECS::get().mScnMgr->createManualObject( - "lot" + - Ogre::StringConverter::toString(e.id()) + "_" + - Ogre::StringConverter::toString(index)); - mobj->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY); - mobj->begin(ECS::get().material, - Ogre::RenderOperation::OT_LINE_LIST); - mobj->setBufferUsage(Ogre::HardwareBufferUsage::HBU_GPU_ONLY); - int i, j; - for (j = 0; j < width; j++) { - Ogre::Vector3 d1 = worldRotation * - Ogre::Vector3::UNIT_X * 4.0f * j; - Ogre::Vector3 d2 = worldRotation * - Ogre::Vector3::UNIT_Z * 4.0f * - height; - mobj->position(origin + d1); - mobj->colour(Ogre::ColourValue(0, 1, 1, 1)); - mobj->position(origin + d1 + d2); - mobj->colour(Ogre::ColourValue(0, 1, 1, 1)); - } - mobj->end(); - sceneNode->attachObject(mobj); - } + ZoneScoped; + if (lot.find("edited") == lot.end()) { + lot["edited"] = true; + int width = lot["width"].get(); + int height = lot["height"].get(); + Ogre::Vector3 worldPosition = + sceneNode->_getDerivedPosition() + localPosition; + Ogre::Quaternion worldRotation = + sceneNode->_getDerivedOrientation() * localRotation; + Ogre::Vector3 origin = worldPosition + + worldRotation * Ogre::Vector3::UNIT_X * + 4.0f * (-width / 2) + + worldRotation * Ogre::Vector3::UNIT_Z * + 4.0f * (-height / 2); + Ogre::ManualObject *mobj = + ECS::get().mScnMgr->createManualObject( + "lot" + + Ogre::StringConverter::toString(e.id()) + "_" + + Ogre::StringConverter::toString(index)); + mobj->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY); + mobj->begin(ECS::get().material, + Ogre::RenderOperation::OT_LINE_LIST); + mobj->setBufferUsage(Ogre::HardwareBufferUsage::HBU_GPU_ONLY); + int i, j; + for (j = 0; j < width; j++) { + Ogre::Vector3 d1 = worldRotation * + Ogre::Vector3::UNIT_X * 4.0f * j; + Ogre::Vector3 d2 = worldRotation * + Ogre::Vector3::UNIT_Z * 4.0f * + height; + mobj->position(origin + d1); + mobj->colour(Ogre::ColourValue(0, 1, 1, 1)); + mobj->position(origin + d1 + d2); + mobj->colour(Ogre::ColourValue(0, 1, 1, 1)); + } + mobj->end(); + sceneNode->attachObject(mobj); + } } void createTownItem() { - ZoneScoped; - Ogre::Vector3 itemPosition = + ZoneScoped; + Ogre::Vector3 itemPosition = ECS::get().sceneNode->_getDerivedPosition(); Ogre::Quaternion itemOrientation = ECS::get().sceneNode->_getDerivedOrientation(); @@ -120,1374 +120,1374 @@ void createTownItem() } void createTownMenu() { - ZoneScoped; - if (ImGui::MenuItem("Create")) + ZoneScoped; + if (ImGui::MenuItem("Create")) createTownItem(); } bool editCell(const Ogre::String &cellLabel, nlohmann::json &cell) { - ZoneScoped; - bool changed = false; - auto checkboxBit = [cellLabel, &changed](Ogre::String label, - nlohmann::json &cell, - uint64_t bit) { - uint64_t flags = cell["flags"].get(); - bool status = (flags & bit) == bit; - if (ImGui::Checkbox((label + "##" + cellLabel).c_str(), - &status)) { - if (status) - flags |= bit; - else - flags &= ~bit; - cell["flags"] = flags; - changed = true; - } - }; - checkboxBit("Floor", cell, (1ULL << 0)); - checkboxBit("Ceiling", cell, (1ULL << 1)); - checkboxBit("Ext Wall X-", cell, (1ULL << 2)); - checkboxBit("Ext Wall X+", cell, (1ULL << 3)); - checkboxBit("Ext Wall Z+", cell, (1ULL << 4)); - checkboxBit("Ext Wall Z-", cell, (1ULL << 5)); - checkboxBit("Ext Door X-", cell, (1ULL << 6)); - checkboxBit("Ext Door X+", cell, (1ULL << 7)); - checkboxBit("Ext Door Z+", cell, (1ULL << 8)); - checkboxBit("Ext Door Z-", cell, (1ULL << 9)); - checkboxBit("Ext Window X-", cell, (1ULL << 10)); - checkboxBit("Ext Window X+", cell, (1ULL << 11)); - checkboxBit("Ext Window Z+", cell, (1ULL << 12)); - checkboxBit("Ext Window Z-", cell, (1ULL << 13)); - checkboxBit("Int Wall X-", cell, (1ULL << 14)); - checkboxBit("Int Wall X+", cell, (1ULL << 15)); - checkboxBit("Int Wall Z+", cell, (1ULL << 16)); - checkboxBit("Int Wall Z-", cell, (1ULL << 17)); - checkboxBit("Int Door X-", cell, (1ULL << 18)); - checkboxBit("Int Door X+", cell, (1ULL << 19)); - checkboxBit("Int Door Z+", cell, (1ULL << 20)); - checkboxBit("Int Door Z-", cell, (1ULL << 21)); - checkboxBit("Int Window X-", cell, (1ULL << 22)); - checkboxBit("Int Window X+", cell, (1ULL << 23)); - checkboxBit("Int Window Z+", cell, (1ULL << 24)); - checkboxBit("Int Window Z-", cell, (1ULL << 25)); - return changed; + ZoneScoped; + bool changed = false; + auto checkboxBit = [cellLabel, &changed](Ogre::String label, + nlohmann::json &cell, + uint64_t bit) { + uint64_t flags = cell["flags"].get(); + bool status = (flags & bit) == bit; + if (ImGui::Checkbox((label + "##" + cellLabel).c_str(), + &status)) { + if (status) + flags |= bit; + else + flags &= ~bit; + cell["flags"] = flags; + changed = true; + } + }; + checkboxBit("Floor", cell, (1ULL << 0)); + checkboxBit("Ceiling", cell, (1ULL << 1)); + checkboxBit("Ext Wall X-", cell, (1ULL << 2)); + checkboxBit("Ext Wall X+", cell, (1ULL << 3)); + checkboxBit("Ext Wall Z+", cell, (1ULL << 4)); + checkboxBit("Ext Wall Z-", cell, (1ULL << 5)); + checkboxBit("Ext Door X-", cell, (1ULL << 6)); + checkboxBit("Ext Door X+", cell, (1ULL << 7)); + checkboxBit("Ext Door Z+", cell, (1ULL << 8)); + checkboxBit("Ext Door Z-", cell, (1ULL << 9)); + checkboxBit("Ext Window X-", cell, (1ULL << 10)); + checkboxBit("Ext Window X+", cell, (1ULL << 11)); + checkboxBit("Ext Window Z+", cell, (1ULL << 12)); + checkboxBit("Ext Window Z-", cell, (1ULL << 13)); + checkboxBit("Int Wall X-", cell, (1ULL << 14)); + checkboxBit("Int Wall X+", cell, (1ULL << 15)); + checkboxBit("Int Wall Z+", cell, (1ULL << 16)); + checkboxBit("Int Wall Z-", cell, (1ULL << 17)); + checkboxBit("Int Door X-", cell, (1ULL << 18)); + checkboxBit("Int Door X+", cell, (1ULL << 19)); + checkboxBit("Int Door Z+", cell, (1ULL << 20)); + checkboxBit("Int Door Z-", cell, (1ULL << 21)); + checkboxBit("Int Window X-", cell, (1ULL << 22)); + checkboxBit("Int Window X+", cell, (1ULL << 23)); + checkboxBit("Int Window Z+", cell, (1ULL << 24)); + checkboxBit("Int Window Z-", cell, (1ULL << 25)); + return changed; } struct CellsScript { - struct room { - int minX; - int minZ; - int sizeX; - int sizeZ; - }; - std::vector rooms; - lua_State *L; - int currentX; - int currentY; - int currentZ; - Ogre::String cellScript; - nlohmann::json &lot; - nlohmann::json &cells; - nlohmann::json &fucells; - FastNoiseLite noise; - CellsScript(const Ogre::String &cellScript, nlohmann::json &lot) - : L(luaL_newstate()) - , currentX(0) - , currentY(0) - , currentZ(0) - , cellScript(cellScript) - , lot(lot) - , cells(lot["cells"]) - , fucells(lot["furniture_cells"]) - { - ZoneScoped; - noise.SetNoiseType(FastNoiseLite::NoiseType_OpenSimplex2); - noise.SetSeed(310); - noise.SetFrequency(0.01f); - noise.SetFractalType(FastNoiseLite::FractalType_FBm); - noise.SetFractalOctaves(4); - noise.SetFractalLacunarity(2.0f); - noise.SetFractalGain(0.5f); - luaL_requiref(L, "table", luaopen_table, 1); - lua_pop(L, 1); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int seed = lua_tointeger(L, 1); - _this->noise.SetSeed(seed); - return 0; - }, - 1); - lua_setglobal(L, "seed"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int pX = lua_tointeger(L, 1); - int pY = lua_tointeger(L, 2); - int pZ = lua_tointeger(L, 3); - _this->currentX = pX; - _this->currentY = pY; - _this->currentZ = pZ; - return 0; - }, - 1); - lua_setglobal(L, "pos"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int pX = lua_tointeger(L, 1); - int pY = lua_tointeger(L, 2); - int pZ = lua_tointeger(L, 3); - _this->currentX += pX; - _this->currentY += pY; - _this->currentZ += pZ; - return 0; - }, - 1); - lua_setglobal(L, "go"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - _this->cell(0); - return 0; - }, - 1); - lua_setglobal(L, "cell"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - Ogre::String cmd = lua_tostring(L, 1); - Ogre::String bit = lua_tostring(L, 2); - _this->bitCmd(cmd, bit); - return 0; - }, - 1); - lua_setglobal(L, "bit"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int minX = lua_tointeger(L, 1); - int minZ = lua_tointeger(L, 2); - int sizeX = lua_tointeger(L, 3); - int sizeZ = lua_tointeger(L, 4); - int r = _this->room(minX, minZ, sizeX, sizeZ); - std::cout << "room: " << r << std::endl; - lua_pushinteger(L, r); - return 1; - }, - 1); - lua_setglobal(L, "room"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int minX = lua_tointeger(L, 1); - int minZ = lua_tointeger(L, 2); - int sizeX = lua_tointeger(L, 3); - int sizeZ = lua_tointeger(L, 4); - float height = lua_tonumber(L, 5); - int type = lua_tointeger(L, 6); - int r = _this->roof(minX, minZ, sizeX, sizeZ, - height, type); - std::cout << "roof: " << r << std::endl; - lua_pushinteger(L, r); - return 1; - }, - 1); - lua_setglobal(L, "roof"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int room = lua_tointeger(L, 1); - Ogre::String tags = lua_tostring(L, 2); - _this->place_furniture(room, tags); - return 0; - }, - 1); - lua_setglobal(L, "place_furniture"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int minX = lua_tointeger(L, 1); - int minZ = lua_tointeger(L, 2); - int sizeX = lua_tointeger(L, 3); - int sizeZ = lua_tointeger(L, 4); - _this->clear_area(minX, minZ, sizeX, sizeZ); - return 0; - }, - 1); - lua_setglobal(L, "clear_area"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int minX = lua_tointeger(L, 1); - int minZ = lua_tointeger(L, 2); - int sizeX = lua_tointeger(L, 3); - int sizeZ = lua_tointeger(L, 4); - _this->clear_furniture_area(minX, minZ, sizeX, - sizeZ); - return 0; - }, - 1); - lua_setglobal(L, "clear_furniture_area"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - _this->clear_roofs(); - return 0; - }, - 1); - lua_setglobal(L, "clear_roofs"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int r1 = lua_tointeger(L, 1); - int r2 = lua_tointeger(L, 2); - _this->connectRooms(r1, r2); - std::cout << "connect rooms: " << r1 << " " - << r2 << std::endl; - return 0; - }, - 1); - lua_setglobal(L, "connect_rooms"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int room = lua_tointeger(L, 1); - _this->createExit0(room); - return 0; - }, - 1); - lua_setglobal(L, "create_exit0"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int room = lua_tointeger(L, 1); - _this->createExit1(room); - return 0; - }, - 1); - lua_setglobal(L, "create_exit1"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int room = lua_tointeger(L, 1); - _this->createExit2(room); - return 0; - }, - 1); - lua_setglobal(L, "create_exit2"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int room = lua_tointeger(L, 1); - _this->createExit3(room); - return 0; - }, - 1); - lua_setglobal(L, "create_exit3"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - int room = lua_tointeger(L, 1); - _this->createWindows(room); - return 0; - }, - 1); - lua_setglobal(L, "create_windows"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - _this->createExterior(); - return 0; - }, - 1); - lua_setglobal(L, "create_exterior"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - float angle = lua_tonumber(L, 1); - _this->lot["angle"] = angle; - return 0; - }, - 1); - lua_setglobal(L, "set_lot_angle_degrees"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - float width = lua_tonumber(L, 1); - _this->lot["width"] = width; - return 0; - }, - 1); - lua_setglobal(L, "set_lot_width"); - lua_pushlightuserdata(L, this); - lua_pushcclosure( - L, - [](lua_State *L) -> int { - CellsScript *_this = static_cast( - lua_touserdata(L, lua_upvalueindex(1))); - float depth = lua_tonumber(L, 1); - _this->lot["depth"] = depth; - return 0; - }, - 1); - lua_setglobal(L, "set_lot_depth"); - } - static std::string trim(const std::string &str) - { - ZoneScoped; - // Find the first character that is not a whitespace character - const std::string ws = - " \t\n\r\f\v"; // Common whitespace characters - size_t first = str.find_first_not_of(ws); + struct room { + int minX; + int minZ; + int sizeX; + int sizeZ; + }; + std::vector rooms; + lua_State *L; + int currentX; + int currentY; + int currentZ; + Ogre::String cellScript; + nlohmann::json &lot; + nlohmann::json &cells; + nlohmann::json &fucells; + FastNoiseLite noise; + CellsScript(const Ogre::String &cellScript, nlohmann::json &lot) + : L(luaL_newstate()) + , currentX(0) + , currentY(0) + , currentZ(0) + , cellScript(cellScript) + , lot(lot) + , cells(lot["cells"]) + , fucells(lot["furniture_cells"]) + { + ZoneScoped; + noise.SetNoiseType(FastNoiseLite::NoiseType_OpenSimplex2); + noise.SetSeed(310); + noise.SetFrequency(0.01f); + noise.SetFractalType(FastNoiseLite::FractalType_FBm); + noise.SetFractalOctaves(4); + noise.SetFractalLacunarity(2.0f); + noise.SetFractalGain(0.5f); + luaL_requiref(L, "table", luaopen_table, 1); + lua_pop(L, 1); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int seed = lua_tointeger(L, 1); + _this->noise.SetSeed(seed); + return 0; + }, + 1); + lua_setglobal(L, "seed"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int pX = lua_tointeger(L, 1); + int pY = lua_tointeger(L, 2); + int pZ = lua_tointeger(L, 3); + _this->currentX = pX; + _this->currentY = pY; + _this->currentZ = pZ; + return 0; + }, + 1); + lua_setglobal(L, "pos"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int pX = lua_tointeger(L, 1); + int pY = lua_tointeger(L, 2); + int pZ = lua_tointeger(L, 3); + _this->currentX += pX; + _this->currentY += pY; + _this->currentZ += pZ; + return 0; + }, + 1); + lua_setglobal(L, "go"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + _this->cell(0); + return 0; + }, + 1); + lua_setglobal(L, "cell"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + Ogre::String cmd = lua_tostring(L, 1); + Ogre::String bit = lua_tostring(L, 2); + _this->bitCmd(cmd, bit); + return 0; + }, + 1); + lua_setglobal(L, "bit"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int minX = lua_tointeger(L, 1); + int minZ = lua_tointeger(L, 2); + int sizeX = lua_tointeger(L, 3); + int sizeZ = lua_tointeger(L, 4); + int r = _this->room(minX, minZ, sizeX, sizeZ); + std::cout << "room: " << r << std::endl; + lua_pushinteger(L, r); + return 1; + }, + 1); + lua_setglobal(L, "room"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int minX = lua_tointeger(L, 1); + int minZ = lua_tointeger(L, 2); + int sizeX = lua_tointeger(L, 3); + int sizeZ = lua_tointeger(L, 4); + float height = lua_tonumber(L, 5); + int type = lua_tointeger(L, 6); + int r = _this->roof(minX, minZ, sizeX, sizeZ, + height, type); + std::cout << "roof: " << r << std::endl; + lua_pushinteger(L, r); + return 1; + }, + 1); + lua_setglobal(L, "roof"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int room = lua_tointeger(L, 1); + Ogre::String tags = lua_tostring(L, 2); + _this->place_furniture(room, tags); + return 0; + }, + 1); + lua_setglobal(L, "place_furniture"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int minX = lua_tointeger(L, 1); + int minZ = lua_tointeger(L, 2); + int sizeX = lua_tointeger(L, 3); + int sizeZ = lua_tointeger(L, 4); + _this->clear_area(minX, minZ, sizeX, sizeZ); + return 0; + }, + 1); + lua_setglobal(L, "clear_area"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int minX = lua_tointeger(L, 1); + int minZ = lua_tointeger(L, 2); + int sizeX = lua_tointeger(L, 3); + int sizeZ = lua_tointeger(L, 4); + _this->clear_furniture_area(minX, minZ, sizeX, + sizeZ); + return 0; + }, + 1); + lua_setglobal(L, "clear_furniture_area"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + _this->clear_roofs(); + return 0; + }, + 1); + lua_setglobal(L, "clear_roofs"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int r1 = lua_tointeger(L, 1); + int r2 = lua_tointeger(L, 2); + _this->connectRooms(r1, r2); + std::cout << "connect rooms: " << r1 << " " + << r2 << std::endl; + return 0; + }, + 1); + lua_setglobal(L, "connect_rooms"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int room = lua_tointeger(L, 1); + _this->createExit0(room); + return 0; + }, + 1); + lua_setglobal(L, "create_exit0"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int room = lua_tointeger(L, 1); + _this->createExit1(room); + return 0; + }, + 1); + lua_setglobal(L, "create_exit1"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int room = lua_tointeger(L, 1); + _this->createExit2(room); + return 0; + }, + 1); + lua_setglobal(L, "create_exit2"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int room = lua_tointeger(L, 1); + _this->createExit3(room); + return 0; + }, + 1); + lua_setglobal(L, "create_exit3"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + int room = lua_tointeger(L, 1); + _this->createWindows(room); + return 0; + }, + 1); + lua_setglobal(L, "create_windows"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + _this->createExterior(); + return 0; + }, + 1); + lua_setglobal(L, "create_exterior"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + float angle = lua_tonumber(L, 1); + _this->lot["angle"] = angle; + return 0; + }, + 1); + lua_setglobal(L, "set_lot_angle_degrees"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + float width = lua_tonumber(L, 1); + _this->lot["width"] = width; + return 0; + }, + 1); + lua_setglobal(L, "set_lot_width"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) -> int { + CellsScript *_this = static_cast( + lua_touserdata(L, lua_upvalueindex(1))); + float depth = lua_tonumber(L, 1); + _this->lot["depth"] = depth; + return 0; + }, + 1); + lua_setglobal(L, "set_lot_depth"); + } + static std::string trim(const std::string &str) + { + ZoneScoped; + // Find the first character that is not a whitespace character + const std::string ws = + " \t\n\r\f\v"; // Common whitespace characters + size_t first = str.find_first_not_of(ws); - // If all characters are whitespace (or string is empty), return an empty string - if (std::string::npos == first) { - return ""; - } + // If all characters are whitespace (or string is empty), return an empty string + if (std::string::npos == first) { + return ""; + } - // Find the last character that is not a whitespace character - size_t last = str.find_last_not_of(ws); + // Find the last character that is not a whitespace character + size_t last = str.find_last_not_of(ws); - // Extract the substring between the first and last non-whitespace characters - return str.substr(first, (last - first + 1)); - } - static std::vector split_and_trim(const std::string &s, - char delimiter) - { - ZoneScoped; - std::vector tokens; - std::string token; - std::stringstream ss(s); // Use stringstream to parse the string + // Extract the substring between the first and last non-whitespace characters + return str.substr(first, (last - first + 1)); + } + static std::vector split_and_trim(const std::string &s, + char delimiter) + { + ZoneScoped; + std::vector tokens; + std::string token; + std::stringstream ss(s); // Use stringstream to parse the string - // Use getline to extract each token based on the delimiter - while (std::getline(ss, token, delimiter)) { - // Trim whitespace from the extracted token - std::string trimmed_token = trim(token); - // Add the trimmed token to the vector (optional: skip empty strings) - if (!trimmed_token.empty()) { - tokens.push_back(trimmed_token); - } - } - return tokens; - } - void buildCellIndex() - { - ZoneScoped; - for (auto &cell : cells) - cell["id"] = makeCellKey(cell); - } - void buildFCellIndex() - { - ZoneScoped; - for (auto &fucell : fucells) - fucell["id"] = makeCellKey(fucell); - } - int findCell(int X, int Y, int Z) - { - ZoneScoped; - int64_t key = makeCellKey(X, Y, Z); - int result = -1; - int i; - for (i = 0; i < cells.size(); i++) { - int64_t ckey = makeCellKey(cells[i]); - if (key == ckey) { - result = i; - break; - } - } - return result; - } - int findFCell(int X, int Y, int Z) - { - ZoneScoped; - int64_t key = makeCellKey(X, Y, Z); - int result = -1; - int i; - for (i = 0; i < fucells.size(); i++) { - int64_t ckey = makeCellKey(fucells[i]); - if (key == ckey) { - result = i; - break; - } - } - return result; - } - void bitCmd(const Ogre::String &cmd, const Ogre::String &bit) - { - ZoneScoped; - uint64_t flags = 0; - std::vector bitconv = { - "floor", "ceiling", "wallx-", "wallx+", - "wallz+", "wallz-", "doorx-", "doorx+", - "doorz+", "doorz-", "windowx-", "windowx+", - "windowz+", "windowz-", "iwallx-", "iwallx+", - "iwallz+", "iwallz-", "idoorx-", "idoorx+", - "idoorz+", "idoorz-", "iwindowx-", "iwindowx+", - "iwindowz+", "iwindowz-" - }; - std::vector bits = split_and_trim(bit, ','); - bool cmdSet = cmd == "set"; - bool cmdClear = cmd == "clear"; - int cellIndex = findCell(currentX, currentY, currentZ); - if (cellIndex >= 0) - flags = cells[cellIndex]["flags"].get(); - for (auto &sbit : bits) { - auto loc = - std::find(bitconv.begin(), bitconv.end(), sbit); - if (loc != bitconv.end()) { - int index = std::distance(bitconv.begin(), loc); - if (cmdSet) - flags |= (1 << (uint64_t)index); - if (cmdClear) - flags &= ~(1 << (uint64_t)index); - } - } - cell(flags); - } - bool isBit(const Ogre::String &bit) - { - ZoneScoped; - uint64_t flags = 0; - std::vector bitconv = { - "floor", "ceiling", "wallx-", "wallx+", - "wallz+", "wallz-", "doorx-", "doorx+", - "doorz+", "doorz-", "windowx-", "windowx+", - "windowz+", "windowz-", "iwallx-", "iwallx+", - "iwallz+", "iwallz-", "idoorx-", "idoorx+", - "idoorz+", "idoorz-", "iwindowx-", "iwindowx+", - "iwindowz+", "iwindowz-" - }; - std::vector bits = split_and_trim(bit, ','); - int cellIndex = findCell(currentX, currentY, currentZ); - if (cellIndex >= 0) - flags = cells[cellIndex]["flags"].get(); - uint64_t bitset = 0; - for (auto &sbit : bits) { - auto loc = - std::find(bitconv.begin(), bitconv.end(), sbit); - if (loc != bitconv.end()) { - int index = std::distance(bitconv.begin(), loc); - bitset |= (1ULL << (uint64_t)index); - } - } - return (flags & bitset) == bitset; - } - static bool isBit(const nlohmann::json &cell, const Ogre::String &bit) - { - ZoneScoped; - uint64_t flags = 0; - std::vector bitconv = { - "floor", "ceiling", "wallx-", "wallx+", - "wallz+", "wallz-", "doorx-", "doorx+", - "doorz+", "doorz-", "windowx-", "windowx+", - "windowz+", "windowz-", "iwallx-", "iwallx+", - "iwallz+", "iwallz-", "idoorx-", "idoorx+", - "idoorz+", "idoorz-", "iwindowx-", "iwindowx+", - "iwindowz+", "iwindowz-" - }; - std::vector bits = split_and_trim(bit, ','); - flags = cell["flags"].get(); - uint64_t bitset = 0; - for (auto &sbit : bits) { - auto loc = - std::find(bitconv.begin(), bitconv.end(), sbit); - if (loc != bitconv.end()) { - int index = std::distance(bitconv.begin(), loc); - bitset |= (1ULL << (uint64_t)index); - } - } - return (flags & bitset) == bitset; - } - void cell(uint64_t flags) - { - ZoneScoped; - if (findCell(currentX, currentY, currentZ) == -1) { - nlohmann::json cell; - buildCellIndex(); - cell["x"] = currentX; - cell["y"] = currentY; - cell["z"] = currentZ; - cell["flags"] = flags; - cell["id"] = makeCellKey(cell); - cells.push_back(cell); - } else { - int index = findCell(currentX, currentY, currentZ); - if (index >= 0) - cells[index]["flags"] = flags; - } - } - void clear() - { - ZoneScoped; - int index = findCell(currentX, currentY, currentZ); - if (index >= 0) - cells.erase(index); - } - void clear_area(int minX, int minZ, int sizeX, int sizeZ) - { - ZoneScoped; - int i, j; - for (i = 0; i < sizeZ; i++) - for (j = 0; j < sizeX; j++) { - currentX = minX + j; - currentZ = minZ + i; - clear(); - } - } - void clear_furniture() - { - ZoneScoped; - int index = findFCell(currentX, currentY, currentZ); - if (index >= 0) - fucells.erase(index); - } - void clear_furniture_area(int minX, int minZ, int sizeX, int sizeZ) - { - ZoneScoped; - int i, j; - for (i = 0; i < sizeZ; i++) - for (j = 0; j < sizeX; j++) { - currentX = minX + j; - currentZ = minZ + i; - clear_furniture(); - } - } - int room(int minX, int minZ, int sizeX, int sizeZ) - { - ZoneScoped; - int i, j, ret; - clear_area(minX, minZ, sizeX, sizeZ); - for (i = 0; i < sizeZ; i++) - for (j = 0; j < sizeX; j++) { - currentX = minX + j; - currentZ = minZ + i; - bitCmd("set", "floor,ceiling"); - } - for (i = 0; i < sizeX; i++) { - currentX = minX + i; - currentZ = minZ; - bitCmd("set", "iwallz-"); - } - for (i = 0; i < sizeX; i++) { - currentX = minX + i; - currentZ = minZ + sizeZ - 1; - bitCmd("set", "iwallz+"); - } - for (i = 0; i < sizeZ; i++) { - currentX = minX; - currentZ = minZ + i; - bitCmd("set", "iwallx-"); - } - for (i = 0; i < sizeZ; i++) { - currentX = minX + sizeX - 1; - currentZ = minZ + i; - bitCmd("set", "iwallx+"); - } - ret = rooms.size(); - rooms.push_back({ minX, minZ, sizeX, sizeZ }); - return ret; - } - int roof(int minX, int minZ, int sizeX, int sizeZ, float height, - int type) - { - ZoneScoped; - nlohmann::json roofs = nlohmann::json::array(); - if (lot.find("roofs") != lot.end()) - roofs = lot["roofs"]; - int ret = roofs.size(); - nlohmann::json roof; - roof["type"] = type; - roof["position_x"] = minX; - roof["position_y"] = currentY; - roof["position_z"] = minZ; - roof["size_x"] = sizeX; - roof["size_z"] = sizeZ; - roof["offset_x"] = 0.0f; - roof["offset_y"] = 0.0f; - roof["offset_z"] = 0.0f; - roof["base_height"] = height; - roof["max_height"] = height; - roofs.push_back(roof); - lot["roofs"] = roofs; - return ret; - } - void clear_roofs() - { - ZoneScoped; - lot["roofs"] = nlohmann::json::array(); - } - void fcell(const std::vector &tags, - nlohmann::json furniture, int rotation) - { - ZoneScoped; - nlohmann::json jtags = nlohmann::json::array(); - for (const auto &tag : tags) - jtags.push_back(tag); - if (findFCell(currentX, currentY, currentZ) == -1) { - nlohmann::json fucell; - buildFCellIndex(); - fucell["x"] = currentX; - fucell["y"] = currentY; - fucell["z"] = currentZ; - fucell["tags"] = jtags; - fucell["id"] = makeCellKey(fucell); - fucell["furniture"] = furniture; - fucell["rotation"] = rotation; - fucells.push_back(fucell); - } else { - int index = findFCell(currentX, currentY, currentZ); - if (index >= 0) { - fucells[index]["tags"] = jtags; - fucells[index]["furniture"] = furniture; - fucells[index]["rotation"] = rotation; - } - } - } - nlohmann::json select_furniture(const std::vector &tags, - const std::vector ¬ags) - { - ZoneScoped; - nlohmann::json adata = nlohmann::json::array(); - ECS::get().query_builder().build().each( - [&](flecs::entity e, const FurnitureItem &item) { - bool apply = true; - // if at least one tag not found, do not add - for (auto &t : item.tags) { - std::cout << "tag: " << t << std::endl; - for (auto ¬ag : notags) { - std::cout << "notag: " << notag - << std::endl; - } - } - for (auto &t : tags) { - if (std::find(item.tags.begin(), - item.tags.end(), - t) == item.tags.end()) { - apply = false; - break; - } - } - if (apply) - // if at least one notag found, do not add - for (auto &t : item.tags) { - if (std::find(notags.begin(), - notags.end(), - t) != - notags.end()) { - apply = false; - break; - } - } - if (apply) { - nlohmann::json jdata = - nlohmann::json::parse( - item.properties); - adata.push_back(jdata); - } - }); - if (adata.size() == 0) - return nlohmann::json(); - float nvalue = noise.GetNoise((float)currentX, (float)currentY, - (float)currentZ); - float selectionf = (nvalue + 1) / 2.0f; - int selection = Ogre::Math::Floor(selectionf * adata.size()); - return adata[selection]; - } - bool place_furniture(int room, Ogre::String tags) - { - ZoneScoped; - bool ret = true; - std::vector atags = split_and_trim(tags, ','); - int i, j; - int minX = rooms[room].minX; - int minZ = rooms[room].minZ; - int sizeX = rooms[room].sizeX; - int sizeZ = rooms[room].sizeZ; - int midX = minX + sizeX / 2; - int midZ = minZ + sizeZ / 2; - std::cout << "room: " << room << " " << minX << " " << minZ - << " " << sizeX << " " << sizeZ << std::endl; - clear_furniture_area(minX, minZ, sizeX, sizeZ); - auto nodoors = [&]() -> bool { - return !isBit("idoorz+") && !isBit("idoorz-") && - !isBit("idoorx+") && !isBit("idoorx-"); - }; - auto nowindows = [&]() -> bool { - return !isBit("windowz+") && !isBit("windowz-") && - !isBit("windowx+") && !isBit("windowx-"); - }; - auto placeOne = [&](const Ogre::String &bit, - const std::vector &tags, - const std::vector ¬ags, - int rotation) -> bool { - if (findFCell(currentX, currentY, currentZ) >= 0) - return false; - if (isBit(bit) && nodoors()) { - nlohmann::json furniture = - select_furniture(tags, notags); - if (furniture.empty()) // got nothing - return false; - std::cout << currentX << " " << currentY << " " - << currentZ << std::endl; - fcell(tags, furniture, rotation); - return true; - } - return false; - }; - std::vector etags = atags; - std::vector itags = atags; - std::vector otags = atags; - std::vector ftags = atags; - struct midpoints { - int X, Z; - int rotation; - }; - struct ranges { - int startX, endX; - int startZ, endZ; - int rotation; - }; - struct tagdata { - std::vector tags, notagswalls, - notagswindows; - bool essential; - bool filler; - }; - etags.push_back("essential"); - itags.push_back("important"); - otags.push_back("optional"); - ftags.push_back("filler"); - struct tagdata taglist[] = { - { etags, - { "nowall", "nowindow" }, - { "nowindow" }, - true, - false }, - { itags, - { "nowall", "nowindow" }, - { "nowindow" }, - false, - false }, - { otags, - { "nowall", "nowindow" }, - { "nowindow" }, - false, - false }, - { ftags, - { "nowall", "nowindow" }, - { "nowindow" }, - false, - true }, - }; - Ogre::String bits_walls[] = { "iwallz+", "iwallx+", "iwallz-", - "iwallx-" }; - Ogre::String bits_windows[] = { "windowz+", "windowx+", - "windowz-", "windowx-" }; - struct midpoints mpoints[] = { - { midX, minZ, 2 }, { midX, minZ + sizeZ - 1, 0 }, - { minX, midZ, 3 }, { minX + sizeX - 1, midZ, 1 }, - { midX, minZ, 2 }, { midX, minZ + sizeZ - 1, 0 }, - { minX, midZ, 3 }, { minX + sizeX - 1, midZ, 1 } - }; - struct ranges range_points[] = { - { minX, sizeX - 1, minZ, minZ, 2 }, - { minX, sizeX - 1, minZ + sizeZ - 1, minZ + sizeZ - 1, - 0 }, - { minX, minX, minZ, minZ + sizeZ - 1, 3 }, - { minX + sizeX - 1, minX + sizeX - 1, minZ, - minZ + sizeZ - 1, 1 }, - }; - for (const auto &mtags : taglist) { - bool placed = false; - if (!placed) - for (auto &p : mpoints) { - currentX = p.X; - currentZ = p.Z; - if (!placed && nodoors()) { - const Ogre::String &bit = - bits_walls[p.rotation]; - placed = placeOne( - bit, mtags.tags, - mtags.notagswalls, - p.rotation); - if (placed && !mtags.filler) - break; - } - if (mtags.filler) - placed = false; - } - if (!placed) - for (auto &p : range_points) { - int i, j; - for (i = p.startZ; i <= p.endZ; i++) { - for (j = p.startX; j <= p.endX; - j++) { - currentX = j; - currentZ = i; - const Ogre::String &bit = bits_walls - [p.rotation]; + // Use getline to extract each token based on the delimiter + while (std::getline(ss, token, delimiter)) { + // Trim whitespace from the extracted token + std::string trimmed_token = trim(token); + // Add the trimmed token to the vector (optional: skip empty strings) + if (!trimmed_token.empty()) { + tokens.push_back(trimmed_token); + } + } + return tokens; + } + void buildCellIndex() + { + ZoneScoped; + for (auto &cell : cells) + cell["id"] = makeCellKey(cell); + } + void buildFCellIndex() + { + ZoneScoped; + for (auto &fucell : fucells) + fucell["id"] = makeCellKey(fucell); + } + int findCell(int X, int Y, int Z) + { + ZoneScoped; + int64_t key = makeCellKey(X, Y, Z); + int result = -1; + int i; + for (i = 0; i < cells.size(); i++) { + int64_t ckey = makeCellKey(cells[i]); + if (key == ckey) { + result = i; + break; + } + } + return result; + } + int findFCell(int X, int Y, int Z) + { + ZoneScoped; + int64_t key = makeCellKey(X, Y, Z); + int result = -1; + int i; + for (i = 0; i < fucells.size(); i++) { + int64_t ckey = makeCellKey(fucells[i]); + if (key == ckey) { + result = i; + break; + } + } + return result; + } + void bitCmd(const Ogre::String &cmd, const Ogre::String &bit) + { + ZoneScoped; + uint64_t flags = 0; + std::vector bitconv = { + "floor", "ceiling", "wallx-", "wallx+", + "wallz+", "wallz-", "doorx-", "doorx+", + "doorz+", "doorz-", "windowx-", "windowx+", + "windowz+", "windowz-", "iwallx-", "iwallx+", + "iwallz+", "iwallz-", "idoorx-", "idoorx+", + "idoorz+", "idoorz-", "iwindowx-", "iwindowx+", + "iwindowz+", "iwindowz-" + }; + std::vector bits = split_and_trim(bit, ','); + bool cmdSet = cmd == "set"; + bool cmdClear = cmd == "clear"; + int cellIndex = findCell(currentX, currentY, currentZ); + if (cellIndex >= 0) + flags = cells[cellIndex]["flags"].get(); + for (auto &sbit : bits) { + auto loc = + std::find(bitconv.begin(), bitconv.end(), sbit); + if (loc != bitconv.end()) { + int index = std::distance(bitconv.begin(), loc); + if (cmdSet) + flags |= (1 << (uint64_t)index); + if (cmdClear) + flags &= ~(1 << (uint64_t)index); + } + } + cell(flags); + } + bool isBit(const Ogre::String &bit) + { + ZoneScoped; + uint64_t flags = 0; + std::vector bitconv = { + "floor", "ceiling", "wallx-", "wallx+", + "wallz+", "wallz-", "doorx-", "doorx+", + "doorz+", "doorz-", "windowx-", "windowx+", + "windowz+", "windowz-", "iwallx-", "iwallx+", + "iwallz+", "iwallz-", "idoorx-", "idoorx+", + "idoorz+", "idoorz-", "iwindowx-", "iwindowx+", + "iwindowz+", "iwindowz-" + }; + std::vector bits = split_and_trim(bit, ','); + int cellIndex = findCell(currentX, currentY, currentZ); + if (cellIndex >= 0) + flags = cells[cellIndex]["flags"].get(); + uint64_t bitset = 0; + for (auto &sbit : bits) { + auto loc = + std::find(bitconv.begin(), bitconv.end(), sbit); + if (loc != bitconv.end()) { + int index = std::distance(bitconv.begin(), loc); + bitset |= (1ULL << (uint64_t)index); + } + } + return (flags & bitset) == bitset; + } + static bool isBit(const nlohmann::json &cell, const Ogre::String &bit) + { + ZoneScoped; + uint64_t flags = 0; + std::vector bitconv = { + "floor", "ceiling", "wallx-", "wallx+", + "wallz+", "wallz-", "doorx-", "doorx+", + "doorz+", "doorz-", "windowx-", "windowx+", + "windowz+", "windowz-", "iwallx-", "iwallx+", + "iwallz+", "iwallz-", "idoorx-", "idoorx+", + "idoorz+", "idoorz-", "iwindowx-", "iwindowx+", + "iwindowz+", "iwindowz-" + }; + std::vector bits = split_and_trim(bit, ','); + flags = cell["flags"].get(); + uint64_t bitset = 0; + for (auto &sbit : bits) { + auto loc = + std::find(bitconv.begin(), bitconv.end(), sbit); + if (loc != bitconv.end()) { + int index = std::distance(bitconv.begin(), loc); + bitset |= (1ULL << (uint64_t)index); + } + } + return (flags & bitset) == bitset; + } + void cell(uint64_t flags) + { + ZoneScoped; + if (findCell(currentX, currentY, currentZ) == -1) { + nlohmann::json cell; + buildCellIndex(); + cell["x"] = currentX; + cell["y"] = currentY; + cell["z"] = currentZ; + cell["flags"] = flags; + cell["id"] = makeCellKey(cell); + cells.push_back(cell); + } else { + int index = findCell(currentX, currentY, currentZ); + if (index >= 0) + cells[index]["flags"] = flags; + } + } + void clear() + { + ZoneScoped; + int index = findCell(currentX, currentY, currentZ); + if (index >= 0) + cells.erase(index); + } + void clear_area(int minX, int minZ, int sizeX, int sizeZ) + { + ZoneScoped; + int i, j; + for (i = 0; i < sizeZ; i++) + for (j = 0; j < sizeX; j++) { + currentX = minX + j; + currentZ = minZ + i; + clear(); + } + } + void clear_furniture() + { + ZoneScoped; + int index = findFCell(currentX, currentY, currentZ); + if (index >= 0) + fucells.erase(index); + } + void clear_furniture_area(int minX, int minZ, int sizeX, int sizeZ) + { + ZoneScoped; + int i, j; + for (i = 0; i < sizeZ; i++) + for (j = 0; j < sizeX; j++) { + currentX = minX + j; + currentZ = minZ + i; + clear_furniture(); + } + } + int room(int minX, int minZ, int sizeX, int sizeZ) + { + ZoneScoped; + int i, j, ret; + clear_area(minX, minZ, sizeX, sizeZ); + for (i = 0; i < sizeZ; i++) + for (j = 0; j < sizeX; j++) { + currentX = minX + j; + currentZ = minZ + i; + bitCmd("set", "floor,ceiling"); + } + for (i = 0; i < sizeX; i++) { + currentX = minX + i; + currentZ = minZ; + bitCmd("set", "iwallz-"); + } + for (i = 0; i < sizeX; i++) { + currentX = minX + i; + currentZ = minZ + sizeZ - 1; + bitCmd("set", "iwallz+"); + } + for (i = 0; i < sizeZ; i++) { + currentX = minX; + currentZ = minZ + i; + bitCmd("set", "iwallx-"); + } + for (i = 0; i < sizeZ; i++) { + currentX = minX + sizeX - 1; + currentZ = minZ + i; + bitCmd("set", "iwallx+"); + } + ret = rooms.size(); + rooms.push_back({ minX, minZ, sizeX, sizeZ }); + return ret; + } + int roof(int minX, int minZ, int sizeX, int sizeZ, float height, + int type) + { + ZoneScoped; + nlohmann::json roofs = nlohmann::json::array(); + if (lot.find("roofs") != lot.end()) + roofs = lot["roofs"]; + int ret = roofs.size(); + nlohmann::json roof; + roof["type"] = type; + roof["position_x"] = minX; + roof["position_y"] = currentY; + roof["position_z"] = minZ; + roof["size_x"] = sizeX; + roof["size_z"] = sizeZ; + roof["offset_x"] = 0.0f; + roof["offset_y"] = 0.0f; + roof["offset_z"] = 0.0f; + roof["base_height"] = height; + roof["max_height"] = height; + roofs.push_back(roof); + lot["roofs"] = roofs; + return ret; + } + void clear_roofs() + { + ZoneScoped; + lot["roofs"] = nlohmann::json::array(); + } + void fcell(const std::vector &tags, + nlohmann::json furniture, int rotation) + { + ZoneScoped; + nlohmann::json jtags = nlohmann::json::array(); + for (const auto &tag : tags) + jtags.push_back(tag); + if (findFCell(currentX, currentY, currentZ) == -1) { + nlohmann::json fucell; + buildFCellIndex(); + fucell["x"] = currentX; + fucell["y"] = currentY; + fucell["z"] = currentZ; + fucell["tags"] = jtags; + fucell["id"] = makeCellKey(fucell); + fucell["furniture"] = furniture; + fucell["rotation"] = rotation; + fucells.push_back(fucell); + } else { + int index = findFCell(currentX, currentY, currentZ); + if (index >= 0) { + fucells[index]["tags"] = jtags; + fucells[index]["furniture"] = furniture; + fucells[index]["rotation"] = rotation; + } + } + } + nlohmann::json select_furniture(const std::vector &tags, + const std::vector ¬ags) + { + ZoneScoped; + nlohmann::json adata = nlohmann::json::array(); + ECS::get().query_builder().build().each( + [&](flecs::entity e, const FurnitureItem &item) { + bool apply = true; + // if at least one tag not found, do not add + for (auto &t : item.tags) { + std::cout << "tag: " << t << std::endl; + for (auto ¬ag : notags) { + std::cout << "notag: " << notag + << std::endl; + } + } + for (auto &t : tags) { + if (std::find(item.tags.begin(), + item.tags.end(), + t) == item.tags.end()) { + apply = false; + break; + } + } + if (apply) + // if at least one notag found, do not add + for (auto &t : item.tags) { + if (std::find(notags.begin(), + notags.end(), + t) != + notags.end()) { + apply = false; + break; + } + } + if (apply) { + nlohmann::json jdata = + nlohmann::json::parse( + item.properties); + adata.push_back(jdata); + } + }); + if (adata.size() == 0) + return nlohmann::json(); + float nvalue = noise.GetNoise((float)currentX, (float)currentY, + (float)currentZ); + float selectionf = (nvalue + 1) / 2.0f; + int selection = Ogre::Math::Floor(selectionf * adata.size()); + return adata[selection]; + } + bool place_furniture(int room, Ogre::String tags) + { + ZoneScoped; + bool ret = true; + std::vector atags = split_and_trim(tags, ','); + int i, j; + int minX = rooms[room].minX; + int minZ = rooms[room].minZ; + int sizeX = rooms[room].sizeX; + int sizeZ = rooms[room].sizeZ; + int midX = minX + sizeX / 2; + int midZ = minZ + sizeZ / 2; + std::cout << "room: " << room << " " << minX << " " << minZ + << " " << sizeX << " " << sizeZ << std::endl; + clear_furniture_area(minX, minZ, sizeX, sizeZ); + auto nodoors = [&]() -> bool { + return !isBit("idoorz+") && !isBit("idoorz-") && + !isBit("idoorx+") && !isBit("idoorx-"); + }; + auto nowindows = [&]() -> bool { + return !isBit("windowz+") && !isBit("windowz-") && + !isBit("windowx+") && !isBit("windowx-"); + }; + auto placeOne = [&](const Ogre::String &bit, + const std::vector &tags, + const std::vector ¬ags, + int rotation) -> bool { + if (findFCell(currentX, currentY, currentZ) >= 0) + return false; + if (isBit(bit) && nodoors()) { + nlohmann::json furniture = + select_furniture(tags, notags); + if (furniture.empty()) // got nothing + return false; + std::cout << currentX << " " << currentY << " " + << currentZ << std::endl; + fcell(tags, furniture, rotation); + return true; + } + return false; + }; + std::vector etags = atags; + std::vector itags = atags; + std::vector otags = atags; + std::vector ftags = atags; + struct midpoints { + int X, Z; + int rotation; + }; + struct ranges { + int startX, endX; + int startZ, endZ; + int rotation; + }; + struct tagdata { + std::vector tags, notagswalls, + notagswindows; + bool essential; + bool filler; + }; + etags.push_back("essential"); + itags.push_back("important"); + otags.push_back("optional"); + ftags.push_back("filler"); + struct tagdata taglist[] = { + { etags, + { "nowall", "nowindow" }, + { "nowindow" }, + true, + false }, + { itags, + { "nowall", "nowindow" }, + { "nowindow" }, + false, + false }, + { otags, + { "nowall", "nowindow" }, + { "nowindow" }, + false, + false }, + { ftags, + { "nowall", "nowindow" }, + { "nowindow" }, + false, + true }, + }; + Ogre::String bits_walls[] = { "iwallz+", "iwallx+", "iwallz-", + "iwallx-" }; + Ogre::String bits_windows[] = { "windowz+", "windowx+", + "windowz-", "windowx-" }; + struct midpoints mpoints[] = { + { midX, minZ, 2 }, { midX, minZ + sizeZ - 1, 0 }, + { minX, midZ, 3 }, { minX + sizeX - 1, midZ, 1 }, + { midX, minZ, 2 }, { midX, minZ + sizeZ - 1, 0 }, + { minX, midZ, 3 }, { minX + sizeX - 1, midZ, 1 } + }; + struct ranges range_points[] = { + { minX, sizeX - 1, minZ, minZ, 2 }, + { minX, sizeX - 1, minZ + sizeZ - 1, minZ + sizeZ - 1, + 0 }, + { minX, minX, minZ, minZ + sizeZ - 1, 3 }, + { minX + sizeX - 1, minX + sizeX - 1, minZ, + minZ + sizeZ - 1, 1 }, + }; + for (const auto &mtags : taglist) { + bool placed = false; + if (!placed) + for (auto &p : mpoints) { + currentX = p.X; + currentZ = p.Z; + if (!placed && nodoors()) { + const Ogre::String &bit = + bits_walls[p.rotation]; + placed = placeOne( + bit, mtags.tags, + mtags.notagswalls, + p.rotation); + if (placed && !mtags.filler) + break; + } + if (mtags.filler) + placed = false; + } + if (!placed) + for (auto &p : range_points) { + int i, j; + for (i = p.startZ; i <= p.endZ; i++) { + for (j = p.startX; j <= p.endX; + j++) { + currentX = j; + currentZ = i; + const Ogre::String &bit = bits_walls + [p.rotation]; - placed = placeOne( - bit, mtags.tags, - mtags.notagswalls, - p.rotation); - if (placed && - !mtags.filler) - break; - } - if (placed && !mtags.filler) - break; - } - if (placed && !mtags.filler) - break; - } - if (mtags.filler) - placed = false; - if (!placed) - for (auto &p : mpoints) { - if (!placed && nodoors()) { - const Ogre::String &bit = - bits_windows[p.rotation]; - placed = placeOne( - bit, mtags.tags, - mtags.notagswindows, - p.rotation); - if (placed && !mtags.filler) - break; - } - } - if (mtags.filler) - placed = false; - if (!placed) - for (auto &p : range_points) { - int i, j; - for (i = p.startZ; i <= p.endZ; i++) { - for (j = p.startX; j <= p.endX; - j++) { - currentX = j; - currentZ = i; - const Ogre::String &bit = - bits_windows - [p.rotation]; - placed = placeOne( - bit, mtags.tags, - mtags.notagswindows, - p.rotation); - if (placed && - !mtags.filler) - break; - } - if (placed && !mtags.filler) - break; - } - if (placed && !mtags.filler) - break; - } - if (!placed && !mtags.filler) { - ret = false; - break; // do not place anything if essentials were not placed - } - if (!placed && !mtags.filler) - break; - } - return ret; - } + placed = placeOne( + bit, mtags.tags, + mtags.notagswalls, + p.rotation); + if (placed && + !mtags.filler) + break; + } + if (placed && !mtags.filler) + break; + } + if (placed && !mtags.filler) + break; + } + if (mtags.filler) + placed = false; + if (!placed) + for (auto &p : mpoints) { + if (!placed && nodoors()) { + const Ogre::String &bit = + bits_windows[p.rotation]; + placed = placeOne( + bit, mtags.tags, + mtags.notagswindows, + p.rotation); + if (placed && !mtags.filler) + break; + } + } + if (mtags.filler) + placed = false; + if (!placed) + for (auto &p : range_points) { + int i, j; + for (i = p.startZ; i <= p.endZ; i++) { + for (j = p.startX; j <= p.endX; + j++) { + currentX = j; + currentZ = i; + const Ogre::String &bit = + bits_windows + [p.rotation]; + placed = placeOne( + bit, mtags.tags, + mtags.notagswindows, + p.rotation); + if (placed && + !mtags.filler) + break; + } + if (placed && !mtags.filler) + break; + } + if (placed && !mtags.filler) + break; + } + if (!placed && !mtags.filler) { + ret = false; + break; // do not place anything if essentials were not placed + } + if (!placed && !mtags.filler) + break; + } + return ret; + } - std::vector > roomEdge(int room) - { - ZoneScoped; - std::vector > seg; - std::set > seen; - int i; - if (rooms[room].sizeX <= 0 || rooms[room].sizeZ <= 0) - goto out; - else if (rooms[room].sizeX == 1 && rooms[room].sizeZ == 1) { - seg.push_back({ rooms[room].minX, rooms[room].minZ }); - goto out; - } else if (rooms[room].sizeZ == 1) { - for (i = 0; i < rooms[room].sizeX; i++) { - seg.push_back({ rooms[room].minX + i, - rooms[room].minZ }); - } - goto out; - } else if (rooms[room].sizeX == 1) { - for (i = 0; i < rooms[room].sizeZ; i++) { - seg.push_back({ rooms[room].minX, - rooms[room].minZ + i }); - } - goto out; - } + std::vector > roomEdge(int room) + { + ZoneScoped; + std::vector > seg; + std::set > seen; + int i; + if (rooms[room].sizeX <= 0 || rooms[room].sizeZ <= 0) + goto out; + else if (rooms[room].sizeX == 1 && rooms[room].sizeZ == 1) { + seg.push_back({ rooms[room].minX, rooms[room].minZ }); + goto out; + } else if (rooms[room].sizeZ == 1) { + for (i = 0; i < rooms[room].sizeX; i++) { + seg.push_back({ rooms[room].minX + i, + rooms[room].minZ }); + } + goto out; + } else if (rooms[room].sizeX == 1) { + for (i = 0; i < rooms[room].sizeZ; i++) { + seg.push_back({ rooms[room].minX, + rooms[room].minZ + i }); + } + goto out; + } - for (i = 0; i < rooms[room].sizeX; i++) { - // filling values for minZ == 0 - // starting with X = 0 - seen.insert({ rooms[room].minX + i, rooms[room].minZ }); - } - for (i = 0; i < rooms[room].sizeZ; i++) { - // zero part is laready filled - seen.insert({ rooms[room].minX, rooms[room].minZ + i }); - } - for (i = 0; i < rooms[room].sizeX; i++) { - seen.insert( - { rooms[room].minX + i, - rooms[room].minZ + rooms[room].sizeZ - 1 }); - } - for (i = 0; i < rooms[room].sizeZ; i++) { - seen.insert({ rooms[room].minX + rooms[room].sizeX - 1, - rooms[room].minZ + i }); - } - for (auto &cell : seen) - seg.push_back(cell); + for (i = 0; i < rooms[room].sizeX; i++) { + // filling values for minZ == 0 + // starting with X = 0 + seen.insert({ rooms[room].minX + i, rooms[room].minZ }); + } + for (i = 0; i < rooms[room].sizeZ; i++) { + // zero part is laready filled + seen.insert({ rooms[room].minX, rooms[room].minZ + i }); + } + for (i = 0; i < rooms[room].sizeX; i++) { + seen.insert( + { rooms[room].minX + i, + rooms[room].minZ + rooms[room].sizeZ - 1 }); + } + for (i = 0; i < rooms[room].sizeZ; i++) { + seen.insert({ rooms[room].minX + rooms[room].sizeX - 1, + rooms[room].minZ + i }); + } + for (auto &cell : seen) + seg.push_back(cell); out: - dumpSeg(seg); - OgreAssert(seg.size() <= rooms[room].sizeX * rooms[room].sizeZ, - "bad edge returned"); - return seg; - } - bool adjacent(std::pair c1, std::pair c2) - { - ZoneScoped; - int dx = std::abs(c1.first - c2.first); - int dz = std::abs(c1.second - c2.second); - return (dx == 0 && dz == 1) || (dx == 1 && dz == 0); - } - void dumpSeg(const std::vector > &seg) - { - ZoneScoped; - int count = 0; - for (auto &cell : seg) { - std::cout << count << " " << cell.first << " " - << cell.second << std::endl; - count++; - } - } - void adjacentCells(int room, int other, - std::vector > &ret1, - std::vector > &ret2) - { - ZoneScoped; - std::vector > room_seg = roomEdge(room); - std::vector > other_seg = roomEdge(other); - std::vector > ret; - std::cout << "main: " << std::endl; - dumpSeg(room_seg); - std::cout << "other: " << std::endl; - dumpSeg(other_seg); - for (auto &cell : room_seg) - for (auto &ocell : other_seg) { - if (adjacent(cell, ocell)) { - ret1.push_back(cell); - ret2.push_back(ocell); - } - } - } - void createExit0(int room) - { - ZoneScoped; - int posX = rooms[room].minX; - int posZ = rooms[room].minZ; - int i; - int sumX = -1; - int count = 0; - for (i = 0; i < rooms[room].sizeX; i++) { - currentX = posX + i; - currentZ = posZ; - if (findCell(posX + i, currentY, posZ - 1) != -1) - continue; - if (isBit("iwallz-")) { - if (sumX == -1) - sumX = posX + i; - else - sumX += posX + i; - count++; - } - } - if (count > 0) { - int rposX = sumX / count; - currentX = rposX; - currentZ = posZ; - bitCmd("clear", "iwallz-"); - bitCmd("set", "idoorz-"); - } - } - void createExit1(int room) - { - ZoneScoped; - int posX = rooms[room].minX; - int posZ = rooms[room].minZ + rooms[room].sizeZ - 1; - int i; - int sumX = -1; - int count = 0; - for (i = 0; i < rooms[room].sizeX; i++) { - currentX = posX + i; - currentZ = posZ; - if (findCell(posX + i, currentY, posZ + 1) != -1) - continue; - if (isBit("iwallz+")) { - if (sumX == -1) - sumX = posX + i; - else - sumX += posX + i; - count++; - } - } - if (count > 0) { - int rposX = sumX / count; - currentX = rposX; - currentZ = posZ; - bitCmd("clear", "iwallz+"); - bitCmd("set", "idoorz+"); - } - } - void createExit2(int room) - { - ZoneScoped; - int posX = rooms[room].minX + rooms[room].sizeX - 1; - int posZ = rooms[room].minZ; - int i; - int sumZ = -1; - int count = 0; - for (i = 0; i < rooms[room].sizeZ; i++) { - currentX = posX; - currentZ = posZ + i; - if (findCell(posX + 1, currentY, posZ + i) != -1) - continue; - if (isBit("iwallx+")) { - if (sumZ == -1) - sumZ = posZ + i; - else - sumZ += posZ + i; - count++; - } - } - if (count > 0) { - int rposZ = sumZ / count; - currentX = posX; - currentZ = rposZ; - bitCmd("clear", "iwallx+"); - bitCmd("set", "idoorx+"); - } - } - void createExit3(int room) - { - ZoneScoped; - int posX = rooms[room].minX; - int posZ = rooms[room].minZ; - int i; - int sumZ = -1; - int count = 0; - for (i = 0; i < rooms[room].sizeZ; i++) { - currentX = posX; - currentZ = posZ + i; - if (findCell(posX - 1, currentY, posZ + i) != -1) - continue; - if (isBit("iwallx-")) { - if (sumZ == -1) - sumZ = posZ + i; - else - sumZ += posZ + i; - count++; - } - } - if (count > 0) { - int rposZ = sumZ / count; - currentX = posX; - currentZ = rposZ; - bitCmd("clear", "iwallx-"); - bitCmd("set", "idoorx-"); - } - } - void createWindows(int room) - { - ZoneScoped; - int posX = rooms[room].minX; - int posZ = rooms[room].minZ; - int i; - for (i = 0; i < rooms[room].sizeX; i++) { - currentX = posX + i; - currentZ = posZ; - if (findCell(posX + i, currentY, posZ - 1) != -1) - continue; - if (isBit("iwallz-")) { - bitCmd("clear", "iwallz-"); - bitCmd("set", "iwindowz-"); - } - } - posX = rooms[room].minX; - posZ = rooms[room].minZ + rooms[room].sizeZ - 1; - for (i = 0; i < rooms[room].sizeX; i++) { - currentX = posX + i; - currentZ = posZ; - if (findCell(posX + i, currentY, posZ + 1) != -1) - continue; - if (isBit("iwallz+")) { - bitCmd("clear", "iwallz+"); - bitCmd("set", "iwindowz+"); - } - } - posX = rooms[room].minX + rooms[room].sizeX - 1; - posZ = rooms[room].minZ; - for (i = 0; i < rooms[room].sizeZ; i++) { - currentX = posX; - currentZ = posZ + i; - if (findCell(posX + 1, currentY, posZ + i) != -1) - continue; - if (isBit("iwallx+")) { - bitCmd("clear", "iwallx+"); - bitCmd("set", "iwindowx+"); - } - } - posX = rooms[room].minX; - posZ = rooms[room].minZ; - for (i = 0; i < rooms[room].sizeZ; i++) { - currentX = posX; - currentZ = posZ + i; - if (findCell(posX - 1, currentY, posZ + i) != -1) - continue; - if (isBit("iwallx-")) { - bitCmd("clear", "iwallx-"); - bitCmd("set", "iwindowx-"); - } - } - } - void createExterior() - { - ZoneScoped; - int room; - for (room = 0; room < rooms.size(); room++) { - int posX = rooms[room].minX; - int posZ = rooms[room].minZ; - int i; - for (i = 0; i < rooms[room].sizeX; i++) { - currentX = posX + i; - currentZ = posZ; - if (findCell(posX + i, currentY, posZ - 1) != - -1) - continue; - if (isBit("iwallz-")) - bitCmd("set", "wallz-"); - if (isBit("idoorz-")) - bitCmd("set", "doorz-"); - if (isBit("iwindowz-")) - bitCmd("set", "windowz-"); - } - posX = rooms[room].minX; - posZ = rooms[room].minZ + rooms[room].sizeZ - 1; - for (i = 0; i < rooms[room].sizeX; i++) { - currentX = posX + i; - currentZ = posZ; - if (findCell(posX + i, currentY, posZ + 1) != - -1) - continue; - if (isBit("iwallz+")) - bitCmd("set", "wallz+"); - if (isBit("idoorz+")) - bitCmd("set", "doorz+"); - if (isBit("iwindowz+")) - bitCmd("set", "windowz+"); - } - posX = rooms[room].minX + rooms[room].sizeX - 1; - posZ = rooms[room].minZ; - for (i = 0; i < rooms[room].sizeZ; i++) { - currentX = posX; - currentZ = posZ + i; - if (findCell(posX + 1, currentY, posZ + i) != - -1) - continue; - if (isBit("iwallx+")) - bitCmd("set", "wallx+"); - if (isBit("idoorx+")) - bitCmd("set", "doorx+"); - if (isBit("iwindowx+")) - bitCmd("set", "windowx+"); - } - posX = rooms[room].minX; - posZ = rooms[room].minZ; - for (i = 0; i < rooms[room].sizeZ; i++) { - currentX = posX; - currentZ = posZ + i; - if (findCell(posX - 1, currentY, posZ + i) != - -1) - continue; - if (isBit("iwallx-")) - bitCmd("set", "wallx-"); - if (isBit("idoorx-")) - bitCmd("set", "doorx-"); - if (isBit("iwindowx-")) - bitCmd("set", "windowx-"); - } - } - } - void connectRooms(int r1, int r2) - { - ZoneScoped; - std::vector > seg1, seg2; - int index = 0; - adjacentCells(r1, r2, seg1, seg2); - OgreAssert(seg1.size() == seg2.size(), "bad edges"); - if (seg1.size() == 0 || seg2.size() == 0) - return; - for (auto &cell : seg1) { - std::cout << "seg1: " << cell.first << " " - << cell.second << std::endl; - } - for (auto &cell : seg2) { - std::cout << "seg2: " << cell.first << " " - << cell.second << std::endl; - } - if (seg1.size() > 1) { - int sumX = 0, sumZ = 0; - int count = 0; - // find average point of first room cells - for (count = 0; count < seg1.size(); count++) { - sumX += seg1[count].first; - sumZ += seg1[count].second; - } - sumX /= seg1.size(); - sumZ /= seg1.size(); - // find closest point to average; - int distance = -1; - for (count = 0; count < seg1.size(); count++) { - int mdx = seg1[count].first - sumX; - int mdz = seg1[count].second - sumZ; - if (count == 0) { - index = 0; - distance = mdx * mdx + mdz * mdz; - } else { - if (distance > mdx * mdx + mdz * mdz) { - distance = - mdx * mdx + mdz * mdz; - index = count; - } - } - } - } else - index = 0; - OgreAssert(adjacent(seg1[index], seg2[index]), - "connected points are not adjacent!"); - int dx = seg1[index].first - seg2[index].first; - int dz = seg1[index].second - seg2[index].second; - std::cout << dx << " " << dz << std::endl; - if (dx == 0 && dz == 0) { - std::cerr << "can't connect rooms" << std::endl; - return; - } - OgreAssert(std::abs(dx) == 1 && dz == 0 || - dx == 0 && std::abs(dz) == 1, - "shit happens"); - std::cout << "points: " << seg1[index].first << " " - << seg1[index].second << " "; - std::cout << seg2[index].first << " " << seg2[index].second - << std::endl; - if (dz < 0) { - currentX = seg1[index].first; - currentZ = seg1[index].second; - OgreAssert(isBit("iwallz+"), "bad bit"); - bitCmd("clear", "iwallz+"); - bitCmd("set", "idoorz+"); - currentX = seg2[index].first; - currentZ = seg2[index].second; - OgreAssert(isBit("iwallz-"), "bad bit"); - bitCmd("clear", "iwallz-"); - bitCmd("set", "idoorz-"); - } - if (dz > 0) { - currentX = seg1[index].first; - currentZ = seg1[index].second; - OgreAssert(isBit("iwallz-"), "bad bit"); - bitCmd("clear", "iwallz-"); - bitCmd("set", "idoorz-"); - currentX = seg2[index].first; - currentZ = seg2[index].second; - OgreAssert(isBit("iwallz+"), "bad bit"); - bitCmd("clear", "iwallz+"); - bitCmd("set", "idoorz+"); - } - if (dx < 0) { - currentX = seg1[index].first; - currentZ = seg1[index].second; - OgreAssert(isBit("iwallx+"), "bad bit"); - bitCmd("clear", "iwallx+"); - bitCmd("set", "idoorx+"); - currentX = seg2[index].first; - currentZ = seg2[index].second; - OgreAssert(isBit("iwallx-"), "bad bit"); - bitCmd("clear", "iwallx-"); - bitCmd("set", "idoorx-"); - } - if (dx > 0) { - currentX = seg1[index].first; - currentZ = seg1[index].second; - OgreAssert(isBit("iwallx-"), "bad bit"); - bitCmd("clear", "iwallx-"); - bitCmd("set", "idoorx-"); - currentX = seg2[index].first; - currentZ = seg2[index].second; - OgreAssert(isBit("iwallx+"), "bad bit"); - bitCmd("clear", "iwallx+"); - bitCmd("set", "idoorx+"); - } - /* + dumpSeg(seg); + OgreAssert(seg.size() <= rooms[room].sizeX * rooms[room].sizeZ, + "bad edge returned"); + return seg; + } + bool adjacent(std::pair c1, std::pair c2) + { + ZoneScoped; + int dx = std::abs(c1.first - c2.first); + int dz = std::abs(c1.second - c2.second); + return (dx == 0 && dz == 1) || (dx == 1 && dz == 0); + } + void dumpSeg(const std::vector > &seg) + { + ZoneScoped; + int count = 0; + for (auto &cell : seg) { + std::cout << count << " " << cell.first << " " + << cell.second << std::endl; + count++; + } + } + void adjacentCells(int room, int other, + std::vector > &ret1, + std::vector > &ret2) + { + ZoneScoped; + std::vector > room_seg = roomEdge(room); + std::vector > other_seg = roomEdge(other); + std::vector > ret; + std::cout << "main: " << std::endl; + dumpSeg(room_seg); + std::cout << "other: " << std::endl; + dumpSeg(other_seg); + for (auto &cell : room_seg) + for (auto &ocell : other_seg) { + if (adjacent(cell, ocell)) { + ret1.push_back(cell); + ret2.push_back(ocell); + } + } + } + void createExit0(int room) + { + ZoneScoped; + int posX = rooms[room].minX; + int posZ = rooms[room].minZ; + int i; + int sumX = -1; + int count = 0; + for (i = 0; i < rooms[room].sizeX; i++) { + currentX = posX + i; + currentZ = posZ; + if (findCell(posX + i, currentY, posZ - 1) != -1) + continue; + if (isBit("iwallz-")) { + if (sumX == -1) + sumX = posX + i; + else + sumX += posX + i; + count++; + } + } + if (count > 0) { + int rposX = sumX / count; + currentX = rposX; + currentZ = posZ; + bitCmd("clear", "iwallz-"); + bitCmd("set", "idoorz-"); + } + } + void createExit1(int room) + { + ZoneScoped; + int posX = rooms[room].minX; + int posZ = rooms[room].minZ + rooms[room].sizeZ - 1; + int i; + int sumX = -1; + int count = 0; + for (i = 0; i < rooms[room].sizeX; i++) { + currentX = posX + i; + currentZ = posZ; + if (findCell(posX + i, currentY, posZ + 1) != -1) + continue; + if (isBit("iwallz+")) { + if (sumX == -1) + sumX = posX + i; + else + sumX += posX + i; + count++; + } + } + if (count > 0) { + int rposX = sumX / count; + currentX = rposX; + currentZ = posZ; + bitCmd("clear", "iwallz+"); + bitCmd("set", "idoorz+"); + } + } + void createExit2(int room) + { + ZoneScoped; + int posX = rooms[room].minX + rooms[room].sizeX - 1; + int posZ = rooms[room].minZ; + int i; + int sumZ = -1; + int count = 0; + for (i = 0; i < rooms[room].sizeZ; i++) { + currentX = posX; + currentZ = posZ + i; + if (findCell(posX + 1, currentY, posZ + i) != -1) + continue; + if (isBit("iwallx+")) { + if (sumZ == -1) + sumZ = posZ + i; + else + sumZ += posZ + i; + count++; + } + } + if (count > 0) { + int rposZ = sumZ / count; + currentX = posX; + currentZ = rposZ; + bitCmd("clear", "iwallx+"); + bitCmd("set", "idoorx+"); + } + } + void createExit3(int room) + { + ZoneScoped; + int posX = rooms[room].minX; + int posZ = rooms[room].minZ; + int i; + int sumZ = -1; + int count = 0; + for (i = 0; i < rooms[room].sizeZ; i++) { + currentX = posX; + currentZ = posZ + i; + if (findCell(posX - 1, currentY, posZ + i) != -1) + continue; + if (isBit("iwallx-")) { + if (sumZ == -1) + sumZ = posZ + i; + else + sumZ += posZ + i; + count++; + } + } + if (count > 0) { + int rposZ = sumZ / count; + currentX = posX; + currentZ = rposZ; + bitCmd("clear", "iwallx-"); + bitCmd("set", "idoorx-"); + } + } + void createWindows(int room) + { + ZoneScoped; + int posX = rooms[room].minX; + int posZ = rooms[room].minZ; + int i; + for (i = 0; i < rooms[room].sizeX; i++) { + currentX = posX + i; + currentZ = posZ; + if (findCell(posX + i, currentY, posZ - 1) != -1) + continue; + if (isBit("iwallz-")) { + bitCmd("clear", "iwallz-"); + bitCmd("set", "iwindowz-"); + } + } + posX = rooms[room].minX; + posZ = rooms[room].minZ + rooms[room].sizeZ - 1; + for (i = 0; i < rooms[room].sizeX; i++) { + currentX = posX + i; + currentZ = posZ; + if (findCell(posX + i, currentY, posZ + 1) != -1) + continue; + if (isBit("iwallz+")) { + bitCmd("clear", "iwallz+"); + bitCmd("set", "iwindowz+"); + } + } + posX = rooms[room].minX + rooms[room].sizeX - 1; + posZ = rooms[room].minZ; + for (i = 0; i < rooms[room].sizeZ; i++) { + currentX = posX; + currentZ = posZ + i; + if (findCell(posX + 1, currentY, posZ + i) != -1) + continue; + if (isBit("iwallx+")) { + bitCmd("clear", "iwallx+"); + bitCmd("set", "iwindowx+"); + } + } + posX = rooms[room].minX; + posZ = rooms[room].minZ; + for (i = 0; i < rooms[room].sizeZ; i++) { + currentX = posX; + currentZ = posZ + i; + if (findCell(posX - 1, currentY, posZ + i) != -1) + continue; + if (isBit("iwallx-")) { + bitCmd("clear", "iwallx-"); + bitCmd("set", "iwindowx-"); + } + } + } + void createExterior() + { + ZoneScoped; + int room; + for (room = 0; room < rooms.size(); room++) { + int posX = rooms[room].minX; + int posZ = rooms[room].minZ; + int i; + for (i = 0; i < rooms[room].sizeX; i++) { + currentX = posX + i; + currentZ = posZ; + if (findCell(posX + i, currentY, posZ - 1) != + -1) + continue; + if (isBit("iwallz-")) + bitCmd("set", "wallz-"); + if (isBit("idoorz-")) + bitCmd("set", "doorz-"); + if (isBit("iwindowz-")) + bitCmd("set", "windowz-"); + } + posX = rooms[room].minX; + posZ = rooms[room].minZ + rooms[room].sizeZ - 1; + for (i = 0; i < rooms[room].sizeX; i++) { + currentX = posX + i; + currentZ = posZ; + if (findCell(posX + i, currentY, posZ + 1) != + -1) + continue; + if (isBit("iwallz+")) + bitCmd("set", "wallz+"); + if (isBit("idoorz+")) + bitCmd("set", "doorz+"); + if (isBit("iwindowz+")) + bitCmd("set", "windowz+"); + } + posX = rooms[room].minX + rooms[room].sizeX - 1; + posZ = rooms[room].minZ; + for (i = 0; i < rooms[room].sizeZ; i++) { + currentX = posX; + currentZ = posZ + i; + if (findCell(posX + 1, currentY, posZ + i) != + -1) + continue; + if (isBit("iwallx+")) + bitCmd("set", "wallx+"); + if (isBit("idoorx+")) + bitCmd("set", "doorx+"); + if (isBit("iwindowx+")) + bitCmd("set", "windowx+"); + } + posX = rooms[room].minX; + posZ = rooms[room].minZ; + for (i = 0; i < rooms[room].sizeZ; i++) { + currentX = posX; + currentZ = posZ + i; + if (findCell(posX - 1, currentY, posZ + i) != + -1) + continue; + if (isBit("iwallx-")) + bitCmd("set", "wallx-"); + if (isBit("idoorx-")) + bitCmd("set", "doorx-"); + if (isBit("iwindowx-")) + bitCmd("set", "windowx-"); + } + } + } + void connectRooms(int r1, int r2) + { + ZoneScoped; + std::vector > seg1, seg2; + int index = 0; + adjacentCells(r1, r2, seg1, seg2); + OgreAssert(seg1.size() == seg2.size(), "bad edges"); + if (seg1.size() == 0 || seg2.size() == 0) + return; + for (auto &cell : seg1) { + std::cout << "seg1: " << cell.first << " " + << cell.second << std::endl; + } + for (auto &cell : seg2) { + std::cout << "seg2: " << cell.first << " " + << cell.second << std::endl; + } + if (seg1.size() > 1) { + int sumX = 0, sumZ = 0; + int count = 0; + // find average point of first room cells + for (count = 0; count < seg1.size(); count++) { + sumX += seg1[count].first; + sumZ += seg1[count].second; + } + sumX /= seg1.size(); + sumZ /= seg1.size(); + // find closest point to average; + int distance = -1; + for (count = 0; count < seg1.size(); count++) { + int mdx = seg1[count].first - sumX; + int mdz = seg1[count].second - sumZ; + if (count == 0) { + index = 0; + distance = mdx * mdx + mdz * mdz; + } else { + if (distance > mdx * mdx + mdz * mdz) { + distance = + mdx * mdx + mdz * mdz; + index = count; + } + } + } + } else + index = 0; + OgreAssert(adjacent(seg1[index], seg2[index]), + "connected points are not adjacent!"); + int dx = seg1[index].first - seg2[index].first; + int dz = seg1[index].second - seg2[index].second; + std::cout << dx << " " << dz << std::endl; + if (dx == 0 && dz == 0) { + std::cerr << "can't connect rooms" << std::endl; + return; + } + OgreAssert(std::abs(dx) == 1 && dz == 0 || + dx == 0 && std::abs(dz) == 1, + "shit happens"); + std::cout << "points: " << seg1[index].first << " " + << seg1[index].second << " "; + std::cout << seg2[index].first << " " << seg2[index].second + << std::endl; + if (dz < 0) { + currentX = seg1[index].first; + currentZ = seg1[index].second; + OgreAssert(isBit("iwallz+"), "bad bit"); + bitCmd("clear", "iwallz+"); + bitCmd("set", "idoorz+"); + currentX = seg2[index].first; + currentZ = seg2[index].second; + OgreAssert(isBit("iwallz-"), "bad bit"); + bitCmd("clear", "iwallz-"); + bitCmd("set", "idoorz-"); + } + if (dz > 0) { + currentX = seg1[index].first; + currentZ = seg1[index].second; + OgreAssert(isBit("iwallz-"), "bad bit"); + bitCmd("clear", "iwallz-"); + bitCmd("set", "idoorz-"); + currentX = seg2[index].first; + currentZ = seg2[index].second; + OgreAssert(isBit("iwallz+"), "bad bit"); + bitCmd("clear", "iwallz+"); + bitCmd("set", "idoorz+"); + } + if (dx < 0) { + currentX = seg1[index].first; + currentZ = seg1[index].second; + OgreAssert(isBit("iwallx+"), "bad bit"); + bitCmd("clear", "iwallx+"); + bitCmd("set", "idoorx+"); + currentX = seg2[index].first; + currentZ = seg2[index].second; + OgreAssert(isBit("iwallx-"), "bad bit"); + bitCmd("clear", "iwallx-"); + bitCmd("set", "idoorx-"); + } + if (dx > 0) { + currentX = seg1[index].first; + currentZ = seg1[index].second; + OgreAssert(isBit("iwallx-"), "bad bit"); + bitCmd("clear", "iwallx-"); + bitCmd("set", "idoorx-"); + currentX = seg2[index].first; + currentZ = seg2[index].second; + OgreAssert(isBit("iwallx+"), "bad bit"); + bitCmd("clear", "iwallx+"); + bitCmd("set", "idoorx+"); + } + /* int cell1 = findCell(seg1[index].first, currentY, seg1[index].second); int cell2 = findCell(seg2[index].first, currentY, seg2[index].second); std::cout << sumX << " " << sumZ << "..." << sumOX << " " @@ -1497,1824 +1497,1824 @@ out: // OgreAssert(false, "eeeeeh"); // OgreAssert(false, "eeeeeh"); */ - } - virtual ~CellsScript() - { - ZoneScoped; - lua_close(L); - } - void run() - { - ZoneScoped; - int result = luaL_dostring(L, cellScript.c_str()); - if (result != LUA_OK) { - std::cerr << "Lua script execution failed: " - << lua_tostring(L, -1) << std::endl; - lua_pop(L, 1); - } else - std::cout << "Running script OK" << std::endl; - } + } + virtual ~CellsScript() + { + ZoneScoped; + lua_close(L); + } + void run() + { + ZoneScoped; + int result = luaL_dostring(L, cellScript.c_str()); + if (result != LUA_OK) { + std::cerr << "Lua script execution failed: " + << lua_tostring(L, -1) << std::endl; + lua_pop(L, 1); + } else + std::cout << "Running script OK" << std::endl; + } }; bool editRoofs(const Ogre::String &lotLabel, nlohmann::json &lot) { - ZoneScoped; - bool changed = false; - static int roofPosition[3] = { 0, 0 }; - static int roofSize[2] = { 1, 1 }; - static float roofOffset[3] = { 0, 0, 0 }; - static float baseHeight = 0.5f; - static float maxHeight = 0.5f; - static int roofType = 0; - const char *items[] = { "Flat", "Normal", "Normal2", "Cone", - "Cylinder" }; - nlohmann::json roofs = nlohmann::json::array(); - if (lot.find("roofs") != lot.end()) - roofs = lot["roofs"]; - Ogre::String addNewLabel = lotLabel + "_AddNewRoof"; - if (ImGui::CollapsingHeader(("Roofs..." + lotLabel).c_str())) { - ImGui::Text("Roofs"); - ImGui::Separator(); - ImGui::SeparatorText("in cell sizes"); - int roofCount = 0; - for (auto &roof : roofs) { - Ogre::String roofLabel = - lotLabel + "_" + - Ogre::StringConverter::toString(roofCount); - ImGui::Text("roof - %d", roofCount); - int mroofType = roof["type"].get(); - int mroofPosition[3]; - int mroofSize[2]; - float mroofOffset[3]; - float mbaseHeight, mmaxHeight; - mroofPosition[0] = roof["position_x"].get(); - mroofPosition[1] = roof["position_y"].get(); - mroofPosition[2] = roof["position_z"].get(); - mroofSize[0] = roof["size_x"].get(); - mroofSize[1] = roof["size_z"].get(); - mroofOffset[0] = roof["offset_x"].get(); - mroofOffset[1] = roof["offset_y"].get(); - mroofOffset[2] = roof["offset_z"].get(); - mbaseHeight = roof["base_height"].get(); - mmaxHeight = roof["max_height"].get(); - if (ImGui::Combo(("Roof Type##" + lotLabel).c_str(), - &mroofType, items, - IM_ARRAYSIZE(items))) - changed = true; - if (ImGui::SliderInt( - ("Roof Position X##" + lotLabel).c_str(), - &mroofPosition[0], -100, 100)) - changed = true; - if (ImGui::SliderInt( - ("Roof Position Y##" + lotLabel).c_str(), - &mroofPosition[1], -100, 100)) - changed = true; - if (ImGui::SliderInt( - ("Roof Position Z##" + lotLabel).c_str(), - &mroofPosition[2], -100, 100)) - changed = true; - if (ImGui::SliderInt( - ("Roof Size X##" + lotLabel).c_str(), - &mroofSize[0], 1, 50)) - changed = true; - if (ImGui::SliderInt( - ("Roof Size Z##" + lotLabel).c_str(), - &mroofSize[1], 1, 50)) - changed = true; - if (ImGui::SliderFloat( - ("Roof Offset X##" + lotLabel).c_str(), - &mroofOffset[0], -10.0f, 10.0f)) - changed = true; - if (ImGui::SliderFloat( - ("Roof Offset Y##" + lotLabel).c_str(), - &mroofOffset[1], -10.0f, 10.0f)) - changed = true; - if (ImGui::SliderFloat( - ("Roof Offset Z##" + lotLabel).c_str(), - &mroofOffset[2], -10.0f, 10.0f)) - changed = true; - if (ImGui::SliderFloat( - ("Roof Base Height##" + lotLabel).c_str(), - &mbaseHeight, 0.1f, 100.0f)) - changed = true; - mmaxHeight = Ogre::Math::Clamp(mmaxHeight, mbaseHeight, - 100.0f); - if (ImGui::SliderFloat( - ("Roof Max Height##" + lotLabel).c_str(), - &mmaxHeight, 0.1f, 100.0f)) - changed = true; - if (changed) { - roof["type"] = mroofType; - roof["position_x"] = mroofPosition[0]; - roof["position_y"] = mroofPosition[1]; - roof["position_z"] = mroofPosition[2]; - roof["size_x"] = mroofSize[0]; - roof["size_z"] = mroofSize[1]; - roof["offset_x"] = mroofOffset[0]; - roof["offset_y"] = mroofOffset[1]; - roof["offset_z"] = mroofOffset[2]; - roof["base_height"] = mbaseHeight; - roof["max_height"] = mmaxHeight; - } - if (ImGui::SmallButton( - ("Delete##" + roofLabel).c_str())) { - roofs.erase(roofCount); - changed = true; - break; - } - } - roofCount++; - ImGui::Combo(("Roof Type##" + addNewLabel).c_str(), &roofType, - items, IM_ARRAYSIZE(items)); - ImGui::SliderInt(("Roof Position X##" + addNewLabel).c_str(), - &roofPosition[0], -100, 100); - ImGui::SliderInt(("Roof Position Y##" + addNewLabel).c_str(), - &roofPosition[1], 0, 100); - ImGui::SliderInt(("Roof Position Z##" + addNewLabel).c_str(), - &roofPosition[2], -100, 100); - ImGui::SliderInt(("Roof Size X##" + addNewLabel).c_str(), - &roofSize[0], 1, 50); - ImGui::SliderInt(("Roof Size Z##" + addNewLabel).c_str(), - &roofSize[1], 1, 50); - ImGui::SliderFloat(("Roof Offset X##" + addNewLabel).c_str(), - &roofOffset[0], -10.0f, 10.0f); - ImGui::SliderFloat(("Roof Offset Y##" + addNewLabel).c_str(), - &roofOffset[1], -10.0f, 10.0f); - ImGui::SliderFloat(("Roof Offset Z##" + addNewLabel).c_str(), - &roofOffset[2], -10.0f, 10.0f); - ImGui::SliderFloat(("Roof Base Height##" + addNewLabel).c_str(), - &baseHeight, 0.1f, 100.0f); - ImGui::SliderFloat(("Roof Max Height##" + addNewLabel).c_str(), - &maxHeight, 0.1f, 100.0f); - if (ImGui::SmallButton(("Add##" + addNewLabel).c_str())) { - nlohmann::json roof; - roof["type"] = roofType; - roof["position_x"] = roofPosition[0]; - roof["position_y"] = roofPosition[1]; - roof["position_z"] = roofPosition[2]; - roof["size_x"] = roofSize[0]; - roof["size_z"] = roofSize[1]; - roof["offset_x"] = roofOffset[0]; - roof["offset_y"] = roofOffset[1]; - roof["offset_z"] = roofOffset[2]; - roof["base_height"] = baseHeight; - roof["max_height"] = maxHeight; - roofs.push_back(roof); - changed = true; - } - if (changed) - lot["roofs"] = roofs; - } - return changed; + ZoneScoped; + bool changed = false; + static int roofPosition[3] = { 0, 0 }; + static int roofSize[2] = { 1, 1 }; + static float roofOffset[3] = { 0, 0, 0 }; + static float baseHeight = 0.5f; + static float maxHeight = 0.5f; + static int roofType = 0; + const char *items[] = { "Flat", "Normal", "Normal2", "Cone", + "Cylinder" }; + nlohmann::json roofs = nlohmann::json::array(); + if (lot.find("roofs") != lot.end()) + roofs = lot["roofs"]; + Ogre::String addNewLabel = lotLabel + "_AddNewRoof"; + if (ImGui::CollapsingHeader(("Roofs..." + lotLabel).c_str())) { + ImGui::Text("Roofs"); + ImGui::Separator(); + ImGui::SeparatorText("in cell sizes"); + int roofCount = 0; + for (auto &roof : roofs) { + Ogre::String roofLabel = + lotLabel + "_" + + Ogre::StringConverter::toString(roofCount); + ImGui::Text("roof - %d", roofCount); + int mroofType = roof["type"].get(); + int mroofPosition[3]; + int mroofSize[2]; + float mroofOffset[3]; + float mbaseHeight, mmaxHeight; + mroofPosition[0] = roof["position_x"].get(); + mroofPosition[1] = roof["position_y"].get(); + mroofPosition[2] = roof["position_z"].get(); + mroofSize[0] = roof["size_x"].get(); + mroofSize[1] = roof["size_z"].get(); + mroofOffset[0] = roof["offset_x"].get(); + mroofOffset[1] = roof["offset_y"].get(); + mroofOffset[2] = roof["offset_z"].get(); + mbaseHeight = roof["base_height"].get(); + mmaxHeight = roof["max_height"].get(); + if (ImGui::Combo(("Roof Type##" + lotLabel).c_str(), + &mroofType, items, + IM_ARRAYSIZE(items))) + changed = true; + if (ImGui::SliderInt( + ("Roof Position X##" + lotLabel).c_str(), + &mroofPosition[0], -100, 100)) + changed = true; + if (ImGui::SliderInt( + ("Roof Position Y##" + lotLabel).c_str(), + &mroofPosition[1], -100, 100)) + changed = true; + if (ImGui::SliderInt( + ("Roof Position Z##" + lotLabel).c_str(), + &mroofPosition[2], -100, 100)) + changed = true; + if (ImGui::SliderInt( + ("Roof Size X##" + lotLabel).c_str(), + &mroofSize[0], 1, 50)) + changed = true; + if (ImGui::SliderInt( + ("Roof Size Z##" + lotLabel).c_str(), + &mroofSize[1], 1, 50)) + changed = true; + if (ImGui::SliderFloat( + ("Roof Offset X##" + lotLabel).c_str(), + &mroofOffset[0], -10.0f, 10.0f)) + changed = true; + if (ImGui::SliderFloat( + ("Roof Offset Y##" + lotLabel).c_str(), + &mroofOffset[1], -10.0f, 10.0f)) + changed = true; + if (ImGui::SliderFloat( + ("Roof Offset Z##" + lotLabel).c_str(), + &mroofOffset[2], -10.0f, 10.0f)) + changed = true; + if (ImGui::SliderFloat( + ("Roof Base Height##" + lotLabel).c_str(), + &mbaseHeight, 0.1f, 100.0f)) + changed = true; + mmaxHeight = Ogre::Math::Clamp(mmaxHeight, mbaseHeight, + 100.0f); + if (ImGui::SliderFloat( + ("Roof Max Height##" + lotLabel).c_str(), + &mmaxHeight, 0.1f, 100.0f)) + changed = true; + if (changed) { + roof["type"] = mroofType; + roof["position_x"] = mroofPosition[0]; + roof["position_y"] = mroofPosition[1]; + roof["position_z"] = mroofPosition[2]; + roof["size_x"] = mroofSize[0]; + roof["size_z"] = mroofSize[1]; + roof["offset_x"] = mroofOffset[0]; + roof["offset_y"] = mroofOffset[1]; + roof["offset_z"] = mroofOffset[2]; + roof["base_height"] = mbaseHeight; + roof["max_height"] = mmaxHeight; + } + if (ImGui::SmallButton( + ("Delete##" + roofLabel).c_str())) { + roofs.erase(roofCount); + changed = true; + break; + } + } + roofCount++; + ImGui::Combo(("Roof Type##" + addNewLabel).c_str(), &roofType, + items, IM_ARRAYSIZE(items)); + ImGui::SliderInt(("Roof Position X##" + addNewLabel).c_str(), + &roofPosition[0], -100, 100); + ImGui::SliderInt(("Roof Position Y##" + addNewLabel).c_str(), + &roofPosition[1], 0, 100); + ImGui::SliderInt(("Roof Position Z##" + addNewLabel).c_str(), + &roofPosition[2], -100, 100); + ImGui::SliderInt(("Roof Size X##" + addNewLabel).c_str(), + &roofSize[0], 1, 50); + ImGui::SliderInt(("Roof Size Z##" + addNewLabel).c_str(), + &roofSize[1], 1, 50); + ImGui::SliderFloat(("Roof Offset X##" + addNewLabel).c_str(), + &roofOffset[0], -10.0f, 10.0f); + ImGui::SliderFloat(("Roof Offset Y##" + addNewLabel).c_str(), + &roofOffset[1], -10.0f, 10.0f); + ImGui::SliderFloat(("Roof Offset Z##" + addNewLabel).c_str(), + &roofOffset[2], -10.0f, 10.0f); + ImGui::SliderFloat(("Roof Base Height##" + addNewLabel).c_str(), + &baseHeight, 0.1f, 100.0f); + ImGui::SliderFloat(("Roof Max Height##" + addNewLabel).c_str(), + &maxHeight, 0.1f, 100.0f); + if (ImGui::SmallButton(("Add##" + addNewLabel).c_str())) { + nlohmann::json roof; + roof["type"] = roofType; + roof["position_x"] = roofPosition[0]; + roof["position_y"] = roofPosition[1]; + roof["position_z"] = roofPosition[2]; + roof["size_x"] = roofSize[0]; + roof["size_z"] = roofSize[1]; + roof["offset_x"] = roofOffset[0]; + roof["offset_y"] = roofOffset[1]; + roof["offset_z"] = roofOffset[2]; + roof["base_height"] = baseHeight; + roof["max_height"] = maxHeight; + roofs.push_back(roof); + changed = true; + } + if (changed) + lot["roofs"] = roofs; + } + return changed; } bool editLot(const Ogre::String &lotLabel, nlohmann::json &lot) { - ZoneScoped; - bool changed = false; - float angle = lot["angle"].get(); - if (ImGui::SliderFloat(("Lot Angle##" + lotLabel).c_str(), &angle, - -180.0f, 180.0f)) { - lot["angle"] = angle; - changed = true; - } - float elevation = lot["elevation"].get(); - if (ImGui::SliderFloat(("Lot Elevation##" + lotLabel).c_str(), - &elevation, -10.0f, 10.0f)) { - lot["elevation"] = elevation; - changed = true; - } - int width = lot["width"].get(); - if (ImGui::SliderInt(("Lot Width##" + lotLabel).c_str(), &width, 4, - 50)) { - lot["width"] = width; - changed = true; - } - int depth = lot["depth"].get(); - if (ImGui::SliderInt(("Lot Depth##" + lotLabel).c_str(), &depth, 4, - 50)) { - lot["depth"] = depth; - changed = true; - } - nlohmann::json cells = nlohmann::json::array(); - static char text_buffer[16384]; - strcpy(text_buffer, ""); - /* copy script data from json to a buffer */ - if (lot.find("cellScript") != lot.end()) { - Ogre::String script = lot["cellScript"].get(); - strncpy(text_buffer, script.c_str(), sizeof(text_buffer)); - } - /* edit a buffer and if changed, copy a buffer back to json */ - if (ImGui::InputTextMultiline(("Cells Script##" + lotLabel).c_str(), - text_buffer, IM_ARRAYSIZE(text_buffer), - ImVec2(1000, - ImGui::GetTextLineHeight() * 20), - ImGuiInputTextFlags_AllowTabInput)) { - lot["cellScript"] = Ogre::String(text_buffer); - } - if (ImGui::IsItemDeactivatedAfterEdit()) { - lot["cellScript"] = Ogre::String(text_buffer); - changed = true; - } - if (ImGui::SmallButton(("Execute script...##" + lotLabel).c_str())) { - CellsScript script(lot["cellScript"].get(), lot); - script.run(); - changed = true; - } + ZoneScoped; + bool changed = false; + float angle = lot["angle"].get(); + if (ImGui::SliderFloat(("Lot Angle##" + lotLabel).c_str(), &angle, + -180.0f, 180.0f)) { + lot["angle"] = angle; + changed = true; + } + float elevation = lot["elevation"].get(); + if (ImGui::SliderFloat(("Lot Elevation##" + lotLabel).c_str(), + &elevation, -10.0f, 10.0f)) { + lot["elevation"] = elevation; + changed = true; + } + int width = lot["width"].get(); + if (ImGui::SliderInt(("Lot Width##" + lotLabel).c_str(), &width, 4, + 50)) { + lot["width"] = width; + changed = true; + } + int depth = lot["depth"].get(); + if (ImGui::SliderInt(("Lot Depth##" + lotLabel).c_str(), &depth, 4, + 50)) { + lot["depth"] = depth; + changed = true; + } + nlohmann::json cells = nlohmann::json::array(); + static char text_buffer[16384]; + strcpy(text_buffer, ""); + /* copy script data from json to a buffer */ + if (lot.find("cellScript") != lot.end()) { + Ogre::String script = lot["cellScript"].get(); + strncpy(text_buffer, script.c_str(), sizeof(text_buffer)); + } + /* edit a buffer and if changed, copy a buffer back to json */ + if (ImGui::InputTextMultiline(("Cells Script##" + lotLabel).c_str(), + text_buffer, IM_ARRAYSIZE(text_buffer), + ImVec2(1000, + ImGui::GetTextLineHeight() * 20), + ImGuiInputTextFlags_AllowTabInput)) { + lot["cellScript"] = Ogre::String(text_buffer); + } + if (ImGui::IsItemDeactivatedAfterEdit()) { + lot["cellScript"] = Ogre::String(text_buffer); + changed = true; + } + if (ImGui::SmallButton(("Execute script...##" + lotLabel).c_str())) { + CellsScript script(lot["cellScript"].get(), lot); + script.run(); + changed = true; + } - for (const auto &cell : lot["cells"]) - cells.push_back(cell); - if (ImGui::CollapsingHeader(("Cells...##" + lotLabel).c_str())) { - if (cells.size() == 0) { - Ogre::String createCellsLabel = - "Create cells...##" + lotLabel; - if (ImGui::SmallButton(createCellsLabel.c_str())) { - nlohmann::json cell; - cell["x"] = 0; - cell["y"] = 0; - cell["z"] = 0; - cell["flags"] = 0U; - cell["id"] = makeCellKey(cell); - lot["cells"].push_back(cell); - changed = true; - } - } else { - int cellCount = 0; - for (auto &cell : cells) { - Ogre::String cellLabel = - lotLabel + "cell" + - Ogre::StringConverter::toString( - cellCount); - ImGui::Text("x = %d", cell["x"].get()); - ImGui::Text("y = %d", cell["y"].get()); - ImGui::Text("z = %d", cell["z"].get()); - ImGui::Text("flags = %016lx", - cell["flags"].get()); - changed = changed || editCell(cellLabel, cell); - ImGui::Separator(); - auto makeCreateButton = [&](const Ogre::String - &label, - int offsetX, - int offsetY, - int offsetZ) { - if (ImGui::SmallButton(label.c_str())) { - int currentX = - cell["x"].get(); - int currentY = - cell["y"].get(); - int currentZ = - cell["z"].get(); - nlohmann::json newcell; - newcell["x"] = - currentX + offsetX; - newcell["y"] = - currentY + offsetY; - newcell["z"] = - currentZ + offsetZ; - newcell["flags"] = 0U; - bool ok = true; - for (const auto &chk : cells) { - int64_t main_key = - makeCellKey( - newcell); - int64_t chk_key = - makeCellKey( - chk); - if (main_key == - chk_key) { - ok = false; - break; - } - } - if (ok) { - newcell["id"] = - makeCellKey( - newcell); - cells.push_back( - newcell); - changed = true; - } - } - }; - struct CreateButtons { - Ogre::String label; - int x, y, z; - }; - struct CreateButtons cbuttons[] = { - { "NewX+##" + cellLabel, 1, 0, 0 }, - { "NewX-##" + cellLabel, -1, 0, 0 }, - { "NewY+##" + cellLabel, 0, 1, 0 }, - { "NewY-##" + cellLabel, 0, -1, 0 }, - { "NewZ+##" + cellLabel, 0, 0, 1 }, - { "NewZ-##" + cellLabel, 0, 0, -1 }, - }; - int i; - for (i = 0; - i < sizeof(cbuttons) / sizeof(cbuttons[0]); - i++) { - if (i > 0) - ImGui::SameLine(); - makeCreateButton(cbuttons[i].label, - cbuttons[i].x, - cbuttons[i].y, - cbuttons[i].z); - } - Ogre::String cellDeleteLabel = - "Delete##" + cellLabel; + for (const auto &cell : lot["cells"]) + cells.push_back(cell); + if (ImGui::CollapsingHeader(("Cells...##" + lotLabel).c_str())) { + if (cells.size() == 0) { + Ogre::String createCellsLabel = + "Create cells...##" + lotLabel; + if (ImGui::SmallButton(createCellsLabel.c_str())) { + nlohmann::json cell; + cell["x"] = 0; + cell["y"] = 0; + cell["z"] = 0; + cell["flags"] = 0U; + cell["id"] = makeCellKey(cell); + lot["cells"].push_back(cell); + changed = true; + } + } else { + int cellCount = 0; + for (auto &cell : cells) { + Ogre::String cellLabel = + lotLabel + "cell" + + Ogre::StringConverter::toString( + cellCount); + ImGui::Text("x = %d", cell["x"].get()); + ImGui::Text("y = %d", cell["y"].get()); + ImGui::Text("z = %d", cell["z"].get()); + ImGui::Text("flags = %016lx", + cell["flags"].get()); + changed = changed || editCell(cellLabel, cell); + ImGui::Separator(); + auto makeCreateButton = [&](const Ogre::String + &label, + int offsetX, + int offsetY, + int offsetZ) { + if (ImGui::SmallButton(label.c_str())) { + int currentX = + cell["x"].get(); + int currentY = + cell["y"].get(); + int currentZ = + cell["z"].get(); + nlohmann::json newcell; + newcell["x"] = + currentX + offsetX; + newcell["y"] = + currentY + offsetY; + newcell["z"] = + currentZ + offsetZ; + newcell["flags"] = 0U; + bool ok = true; + for (const auto &chk : cells) { + int64_t main_key = + makeCellKey( + newcell); + int64_t chk_key = + makeCellKey( + chk); + if (main_key == + chk_key) { + ok = false; + break; + } + } + if (ok) { + newcell["id"] = + makeCellKey( + newcell); + cells.push_back( + newcell); + changed = true; + } + } + }; + struct CreateButtons { + Ogre::String label; + int x, y, z; + }; + struct CreateButtons cbuttons[] = { + { "NewX+##" + cellLabel, 1, 0, 0 }, + { "NewX-##" + cellLabel, -1, 0, 0 }, + { "NewY+##" + cellLabel, 0, 1, 0 }, + { "NewY-##" + cellLabel, 0, -1, 0 }, + { "NewZ+##" + cellLabel, 0, 0, 1 }, + { "NewZ-##" + cellLabel, 0, 0, -1 }, + }; + int i; + for (i = 0; + i < sizeof(cbuttons) / sizeof(cbuttons[0]); + i++) { + if (i > 0) + ImGui::SameLine(); + makeCreateButton(cbuttons[i].label, + cbuttons[i].x, + cbuttons[i].y, + cbuttons[i].z); + } + Ogre::String cellDeleteLabel = + "Delete##" + cellLabel; - if (ImGui::SmallButton( - cellDeleteLabel.c_str())) { - cells.erase(cellCount); - changed = true; - } - if (changed) { - lot["cells"] = cells; - break; - } - cellCount++; - } - } - } - changed = changed || editRoofs(lotLabel, lot); - return changed; + if (ImGui::SmallButton( + cellDeleteLabel.c_str())) { + cells.erase(cellCount); + changed = true; + } + if (changed) { + lot["cells"] = cells; + break; + } + cellCount++; + } + } + } + changed = changed || editRoofs(lotLabel, lot); + return changed; } void commandEraseLot(nlohmann::json &district, int lotIndex) { - ZoneScoped; - nlohmann::json lots = nlohmann::json::array(); - for (const auto &lot : district["lots"]) - lots.push_back(lot); - lots.erase(lotIndex); - district["lots"] = lots; + ZoneScoped; + nlohmann::json lots = nlohmann::json::array(); + for (const auto &lot : district["lots"]) + lots.push_back(lot); + lots.erase(lotIndex); + district["lots"] = lots; } void cleanupLot(nlohmann::json &lot) { - ZoneScoped; - lot.erase("cells"); - lot.erase("furniture_cells"); - lot.erase("roofs"); + ZoneScoped; + lot.erase("cells"); + lot.erase("furniture_cells"); + lot.erase("roofs"); } void addLotTemplate(nlohmann::json &district, nlohmann::json &lotTemplates, - int lotIndex) + int lotIndex) { - ZoneScoped; - if (district.find("lots") != district.end()) { - nlohmann::json &lots = district["lots"]; - nlohmann::json lotTemplate = lots[lotIndex]; - cleanupLot(lotTemplate); - lotTemplates.push_back(lotTemplate); - } + ZoneScoped; + if (district.find("lots") != district.end()) { + nlohmann::json &lots = district["lots"]; + nlohmann::json lotTemplate = lots[lotIndex]; + cleanupLot(lotTemplate); + lotTemplates.push_back(lotTemplate); + } } void addLotFromTemplate(nlohmann::json &district, - const nlohmann::json &lotTemplates, - int lotTemplateIndex) + const nlohmann::json &lotTemplates, + int lotTemplateIndex) { - ZoneScoped; - nlohmann::json lots = nlohmann::json::array(); - OgreAssert(lotTemplateIndex < lotTemplates.size() && - lotTemplates.size() > 0, - "bad template"); - if (lotTemplates.size() == 0 || lotTemplateIndex >= lotTemplates.size()) - return; - for (const auto &lot : district["lots"]) - lots.push_back(lot); - nlohmann::json t = lotTemplates[lotTemplateIndex]; - float angle = 0.0f; - float nextAngle = angle; - float radius = district["radius"].get(); - if (lots.size() > 0) { - angle = lots[0]["angle"].get(); - nextAngle = angle; - for (auto &lot : lots) { - float width = lot["width"].get(); - if (angle < lot["angle"].get()) { - angle = lot["angle"].get(); - nextAngle = angle + - Ogre::Math::ASin(width / - (radius * 2.0f)) - .valueDegrees(); - } - } - } - t["angle"] = nextAngle; - CellsScript script(t["cellScript"].get(), t); - script.run(); - lots.push_back(t); - district["lots"] = lots; + ZoneScoped; + nlohmann::json lots = nlohmann::json::array(); + OgreAssert(lotTemplateIndex < lotTemplates.size() && + lotTemplates.size() > 0, + "bad template"); + if (lotTemplates.size() == 0 || lotTemplateIndex >= lotTemplates.size()) + return; + for (const auto &lot : district["lots"]) + lots.push_back(lot); + nlohmann::json t = lotTemplates[lotTemplateIndex]; + float angle = 0.0f; + float nextAngle = angle; + float radius = district["radius"].get(); + if (lots.size() > 0) { + angle = lots[0]["angle"].get(); + nextAngle = angle; + for (auto &lot : lots) { + float width = lot["width"].get(); + if (angle < lot["angle"].get()) { + angle = lot["angle"].get(); + nextAngle = angle + + Ogre::Math::ASin(width / + (radius * 2.0f)) + .valueDegrees(); + } + } + } + t["angle"] = nextAngle; + CellsScript script(t["cellScript"].get(), t); + script.run(); + lots.push_back(t); + district["lots"] = lots; } void addLot(nlohmann::json &district, float angle, int width, int depth, - float elevation, const Ogre::String &script) + float elevation, const Ogre::String &script) { - ZoneScoped; - nlohmann::json lots = nlohmann::json::array(); - for (const auto &lot : district["lots"]) - lots.push_back(lot); - nlohmann::json l; - l["angle"] = angle; - l["width"] = width; - l["depth"] = depth; - l["elevation"] = elevation; - l["cellScript"] = script; - l["objects"] = nlohmann::json::array(); - CellsScript cellScript(l["cellScript"].get(), l); - cellScript.run(); - lots.push_back(l); - district["lots"] = lots; + ZoneScoped; + nlohmann::json lots = nlohmann::json::array(); + for (const auto &lot : district["lots"]) + lots.push_back(lot); + nlohmann::json l; + l["angle"] = angle; + l["width"] = width; + l["depth"] = depth; + l["elevation"] = elevation; + l["cellScript"] = script; + l["objects"] = nlohmann::json::array(); + CellsScript cellScript(l["cellScript"].get(), l); + cellScript.run(); + lots.push_back(l); + district["lots"] = lots; } bool editDistrict(const Ogre::String &districtLabel, nlohmann::json &district, - nlohmann::json &lotTemplates) + nlohmann::json &lotTemplates) { - ZoneScoped; - bool changed = false; - nlohmann::json lots = nlohmann::json::array(); - for (const auto &lot : district["lots"]) - lots.push_back(lot); - int lotCount = 0; - for (auto &lot : lots) { - Ogre::String lotLabel = - districtLabel + "_lot" + - Ogre::StringConverter::toString(lotCount); - ImGui::Text("%s", lotLabel.c_str()); - if (ImGui::CollapsingHeader( - ("Edit lot... ##" + lotLabel).c_str())) { - bool lotChanged = editLot(lotLabel, lot); - lot["_dirty"] = lotChanged; - changed = changed || lotChanged; - ImGui::Separator(); - if (ImGui::SmallButton( - ("Add as template##" + lotLabel).c_str())) { - addLotTemplate(district, lotTemplates, - lotCount); - changed = true; - } - if (ImGui::SmallButton( - ("Lot Delete##" + lotLabel).c_str())) { - commandEraseLot(district, lotCount); - changed = true; - break; - } - } - lotCount++; - } - ImGui::Separator(); - int templateCount = 0; - for (auto &t : lotTemplates) { - Ogre::String templateLabel = - districtLabel + "_template" + - Ogre::StringConverter::toString(templateCount); - Ogre::String templateName; - if (t.find("templateName") != t.end()) - templateName = t["templateName"]; - char nameBuffer[64]; - strncpy(nameBuffer, templateName.c_str(), sizeof(nameBuffer)); - ImGui::Text("%d", templateCount); - if (ImGui::InputText(("Name##" + templateLabel).c_str(), - nameBuffer, sizeof(nameBuffer))) { - templateName = Ogre::String(nameBuffer); - t["templateName"] = templateName; - changed = true; - } - if (ImGui::SmallButton( - ("Add lot with template##" + districtLabel + - Ogre::StringConverter::toString(templateCount)) - .c_str())) { - int d = district["lots"].size(); - addLotFromTemplate(district, lotTemplates, - templateCount); - int d2 = district["lots"].size(); - OgreAssert(d2 > d, "failed to add lot"); - lots = district["lots"]; - changed = true; - } - templateCount++; - } - ImGui::Separator(); - if (ImGui::SmallButton("Add lot")) { - addLot(district, 0.0f, 10, 10, 0.0f, "-- cell creation script"); - changed = true; - } - district["lots"] = lots; - float radius = 50.0f; - bool plazza = false; - if (district.find("plazza") != district.end()) - plazza = district["plazza"].get(); - if (district.find("radius") != district.end()) - radius = district["radius"].get(); - if (ImGui::Checkbox("Plazza", &plazza)) { - changed = true; - district["plazza"] = plazza; - } - float elevation = 0.0f, height = 0.2f; - if (district.find("elevation") != district.end()) - elevation = district["elevation"].get(); - if (district.find("height") != district.end()) - height = district["height"].get(); - if (ImGui::SliderFloat("Radius", &radius, 20.0f, 100.0f)) { - district["radius"] = radius; - changed = true; - } - if (ImGui::SliderFloat("Height", &height, 0.1f, 10.0f)) { - district["height"] = height; - changed = true; - } - if (ImGui::SliderFloat("Elevation", &elevation, -10.0f, 10.0f)) { - district["elevation"] = elevation; - changed = true; - } - return changed; + ZoneScoped; + bool changed = false; + nlohmann::json lots = nlohmann::json::array(); + for (const auto &lot : district["lots"]) + lots.push_back(lot); + int lotCount = 0; + for (auto &lot : lots) { + Ogre::String lotLabel = + districtLabel + "_lot" + + Ogre::StringConverter::toString(lotCount); + ImGui::Text("%s", lotLabel.c_str()); + if (ImGui::CollapsingHeader( + ("Edit lot... ##" + lotLabel).c_str())) { + bool lotChanged = editLot(lotLabel, lot); + lot["_dirty"] = lotChanged; + changed = changed || lotChanged; + ImGui::Separator(); + if (ImGui::SmallButton( + ("Add as template##" + lotLabel).c_str())) { + addLotTemplate(district, lotTemplates, + lotCount); + changed = true; + } + if (ImGui::SmallButton( + ("Lot Delete##" + lotLabel).c_str())) { + commandEraseLot(district, lotCount); + changed = true; + break; + } + } + lotCount++; + } + ImGui::Separator(); + int templateCount = 0; + for (auto &t : lotTemplates) { + Ogre::String templateLabel = + districtLabel + "_template" + + Ogre::StringConverter::toString(templateCount); + Ogre::String templateName; + if (t.find("templateName") != t.end()) + templateName = t["templateName"]; + char nameBuffer[64]; + strncpy(nameBuffer, templateName.c_str(), sizeof(nameBuffer)); + ImGui::Text("%d", templateCount); + if (ImGui::InputText(("Name##" + templateLabel).c_str(), + nameBuffer, sizeof(nameBuffer))) { + templateName = Ogre::String(nameBuffer); + t["templateName"] = templateName; + changed = true; + } + if (ImGui::SmallButton( + ("Add lot with template##" + districtLabel + + Ogre::StringConverter::toString(templateCount)) + .c_str())) { + int d = district["lots"].size(); + addLotFromTemplate(district, lotTemplates, + templateCount); + int d2 = district["lots"].size(); + OgreAssert(d2 > d, "failed to add lot"); + lots = district["lots"]; + changed = true; + } + templateCount++; + } + ImGui::Separator(); + if (ImGui::SmallButton("Add lot")) { + addLot(district, 0.0f, 10, 10, 0.0f, "-- cell creation script"); + changed = true; + } + district["lots"] = lots; + float radius = 50.0f; + bool plazza = false; + if (district.find("plazza") != district.end()) + plazza = district["plazza"].get(); + if (district.find("radius") != district.end()) + radius = district["radius"].get(); + if (ImGui::Checkbox("Plazza", &plazza)) { + changed = true; + district["plazza"] = plazza; + } + float elevation = 0.0f, height = 0.2f; + if (district.find("elevation") != district.end()) + elevation = district["elevation"].get(); + if (district.find("height") != district.end()) + height = district["height"].get(); + if (ImGui::SliderFloat("Radius", &radius, 20.0f, 100.0f)) { + district["radius"] = radius; + changed = true; + } + if (ImGui::SliderFloat("Height", &height, 0.1f, 10.0f)) { + district["height"] = height; + changed = true; + } + if (ImGui::SliderFloat("Elevation", &elevation, -10.0f, 10.0f)) { + district["elevation"] = elevation; + changed = true; + } + return changed; } bool editColorRects(nlohmann::json &rects) { - ZoneScoped; - bool changed = false; - ImGui::Text("Color Rects"); - for (auto it = rects.begin(); it != rects.end(); it++) { - Ogre::String key = it.key(); - ImGui::Text("%s", key.c_str()); - float left = 0.0f, top = 0.0f, right = 0.1f, bottom = 0.1f; - nlohmann::json nrect = it.value(); - left = nrect["left"].get(); - top = nrect["top"].get(); - right = nrect["right"].get(); - bottom = nrect["bottom"].get(); - float ccolor[4] = { 0, 0, 0, 1 }; - Ogre::ColourValue colour; - from_json(nrect["color"], colour); - ccolor[0] = colour.r; - ccolor[1] = colour.g; - ccolor[2] = colour.b; - ccolor[3] = colour.a; - if (ImGui::InputFloat(("left##" + key).c_str(), &left)) - changed = true; - if (ImGui::InputFloat(("top##" + key).c_str(), &top)) - changed = true; - if (ImGui::InputFloat(("right##" + key).c_str(), &right)) - changed = true; - if (ImGui::InputFloat(("bottom##" + key).c_str(), &bottom)) - changed = true; - if (ImGui::ColorPicker4(("Color##" + key).c_str(), ccolor)) - changed = true; - if (changed) { - left = Ogre::Math::Clamp(left, 0.0f, 1.0f); - top = Ogre::Math::Clamp(top, 0.0f, 1.0f); - right = Ogre::Math::Clamp(right, left, 1.0f); - bottom = Ogre::Math::Clamp(bottom, top, 1.0f); - nrect["left"] = left; - nrect["top"] = top; - nrect["right"] = right; - nrect["bottom"] = bottom; - colour.r = ccolor[0]; - colour.g = ccolor[1]; - colour.b = ccolor[2]; - colour.a = ccolor[3]; - to_json(nrect["color"], colour); - rects[key] = nrect; - } - } - if (rects.size() > 0) - ImGui::Separator(); - { - static char colorName[64] = { 0 }; - static float left = 0.0f, top = 0.0f, right = 0.1f, - bottom = 0.1f; - ImGui::InputText("New color rect", colorName, - sizeof(colorName)); - ImGui::InputFloat("left##New_Color_Rect", &left); - ImGui::InputFloat("top##New_Color_Rect", &top); - ImGui::InputFloat("right##New_Color_Rect", &right); - ImGui::InputFloat("bottom##New_Color_Rect", &bottom); - left = Ogre::Math::Clamp(left, 0.0f, 1.0f); - top = Ogre::Math::Clamp(top, 0.0f, 1.0f); - right = Ogre::Math::Clamp(right, left, 1.0f); - bottom = Ogre::Math::Clamp(bottom, top, 1.0f); - static float ccolor[4] = { 0, 0, 0, 1 }; - ImGui::ColorPicker4("Color##New_Color_Rect", ccolor); - ImGui::Text("%f %f %f %f", ccolor[0], ccolor[1], ccolor[2], - ccolor[3]); - bool valid = true; - if (right - left <= 0.0f || bottom - top <= 0.0f) - valid = false; - if (strlen(colorName) == 0) - valid = false; + ZoneScoped; + bool changed = false; + ImGui::Text("Color Rects"); + for (auto it = rects.begin(); it != rects.end(); it++) { + Ogre::String key = it.key(); + ImGui::Text("%s", key.c_str()); + float left = 0.0f, top = 0.0f, right = 0.1f, bottom = 0.1f; + nlohmann::json nrect = it.value(); + left = nrect["left"].get(); + top = nrect["top"].get(); + right = nrect["right"].get(); + bottom = nrect["bottom"].get(); + float ccolor[4] = { 0, 0, 0, 1 }; + Ogre::ColourValue colour; + from_json(nrect["color"], colour); + ccolor[0] = colour.r; + ccolor[1] = colour.g; + ccolor[2] = colour.b; + ccolor[3] = colour.a; + if (ImGui::InputFloat(("left##" + key).c_str(), &left)) + changed = true; + if (ImGui::InputFloat(("top##" + key).c_str(), &top)) + changed = true; + if (ImGui::InputFloat(("right##" + key).c_str(), &right)) + changed = true; + if (ImGui::InputFloat(("bottom##" + key).c_str(), &bottom)) + changed = true; + if (ImGui::ColorPicker4(("Color##" + key).c_str(), ccolor)) + changed = true; + if (changed) { + left = Ogre::Math::Clamp(left, 0.0f, 1.0f); + top = Ogre::Math::Clamp(top, 0.0f, 1.0f); + right = Ogre::Math::Clamp(right, left, 1.0f); + bottom = Ogre::Math::Clamp(bottom, top, 1.0f); + nrect["left"] = left; + nrect["top"] = top; + nrect["right"] = right; + nrect["bottom"] = bottom; + colour.r = ccolor[0]; + colour.g = ccolor[1]; + colour.b = ccolor[2]; + colour.a = ccolor[3]; + to_json(nrect["color"], colour); + rects[key] = nrect; + } + } + if (rects.size() > 0) + ImGui::Separator(); + { + static char colorName[64] = { 0 }; + static float left = 0.0f, top = 0.0f, right = 0.1f, + bottom = 0.1f; + ImGui::InputText("New color rect", colorName, + sizeof(colorName)); + ImGui::InputFloat("left##New_Color_Rect", &left); + ImGui::InputFloat("top##New_Color_Rect", &top); + ImGui::InputFloat("right##New_Color_Rect", &right); + ImGui::InputFloat("bottom##New_Color_Rect", &bottom); + left = Ogre::Math::Clamp(left, 0.0f, 1.0f); + top = Ogre::Math::Clamp(top, 0.0f, 1.0f); + right = Ogre::Math::Clamp(right, left, 1.0f); + bottom = Ogre::Math::Clamp(bottom, top, 1.0f); + static float ccolor[4] = { 0, 0, 0, 1 }; + ImGui::ColorPicker4("Color##New_Color_Rect", ccolor); + ImGui::Text("%f %f %f %f", ccolor[0], ccolor[1], ccolor[2], + ccolor[3]); + bool valid = true; + if (right - left <= 0.0f || bottom - top <= 0.0f) + valid = false; + if (strlen(colorName) == 0) + valid = false; - if (ImGui::SmallButton("Create##New_Color_Rect")) { - Ogre::ColourValue newColour; - newColour.r = ccolor[0]; - newColour.g = ccolor[1]; - newColour.b = ccolor[2]; - newColour.a = ccolor[3]; - Ogre::String sColorName(colorName); - if (valid) { - nlohmann::json nrect; - nrect["left"] = left; - nrect["top"] = top; - nrect["right"] = right; - nrect["bottom"] = bottom; - to_json(nrect["color"], newColour); - rects[sColorName] = nrect; - changed = true; - } - ccolor[0] = 0; - ccolor[1] = 0; - ccolor[2] = 0; - ccolor[3] = 1; - strcpy(colorName, ""); - } - } - return changed; + if (ImGui::SmallButton("Create##New_Color_Rect")) { + Ogre::ColourValue newColour; + newColour.r = ccolor[0]; + newColour.g = ccolor[1]; + newColour.b = ccolor[2]; + newColour.a = ccolor[3]; + Ogre::String sColorName(colorName); + if (valid) { + nlohmann::json nrect; + nrect["left"] = left; + nrect["top"] = top; + nrect["right"] = right; + nrect["bottom"] = bottom; + to_json(nrect["color"], newColour); + rects[sColorName] = nrect; + changed = true; + } + ccolor[0] = 0; + ccolor[1] = 0; + ccolor[2] = 0; + ccolor[3] = 1; + strcpy(colorName, ""); + } + } + return changed; } void runAllScriptsForTown(flecs::entity e) { - ZoneScoped; - Ogre::String prop = StaticGeometryModule::getItemProperties(e); - nlohmann::json j = nlohmann::json::parse(prop); - auto &districts = j["districts"]; + ZoneScoped; + Ogre::String prop = StaticGeometryModule::getItemProperties(e); + nlohmann::json j = nlohmann::json::parse(prop); + auto &districts = j["districts"]; for (auto &district : districts) { - if (district.find("lots") == district.end()) - continue; - auto &lots = district["lots"]; - for (auto &lot : lots) { - if (lot.find("cellScript") == lot.end()) - continue; - CellsScript script( - lot["cellScript"].get(), lot); - script.run(); - } - district["lots"] = lots; + if (district.find("lots") == district.end()) + continue; + auto &lots = district["lots"]; + for (auto &lot : lots) { + if (lot.find("cellScript") == lot.end()) + continue; + CellsScript script( + lot["cellScript"].get(), lot); + script.run(); + } + district["lots"] = lots; } - j["districts"] = districts; - StaticGeometryModule::setItemProperties(e, j.dump()); + j["districts"] = districts; + StaticGeometryModule::setItemProperties(e, j.dump()); } void runSingleLotScript(flecs::entity e, nlohmann::json &lot) { - if (lot.find("cellScript") == lot.end()) - return; - CellsScript script(lot["cellScript"].get(), lot); - script.run(); + if (lot.find("cellScript") == lot.end()) + return; + CellsScript script(lot["cellScript"].get(), lot); + script.run(); } struct Selector { - int selection; - Ogre::String result; - Ogre::String label; - std::vector options; - Selector(const Ogre::String &label, - const std::vector &options) - : label(label) - , options(options) - , selection(-1) - { - } - bool select() - { - bool changed = false; - if (selection < 0) - selection = 0; - if (selection >= options.size()) - selection = (options.size() > 0) ? options.size() - 1 : - 0; - if (options.size() == 0) { - ImGui::Text("None: %s", label.c_str()); - return false; - } - if (ImGui::BeginCombo(label.c_str(), - options[selection].c_str())) { - int i; - for (i = 0; i < options.size(); i++) { - bool selected = selection == i; - if (ImGui::Selectable(options[i].c_str(), - selected)) { - selection = i; - changed = true; - } - } - ImGui::EndCombo(); - } - if (changed || result.empty()) - result = options[selection]; - return changed; - } - void set_default(const Ogre::String &def) - { - int index = -1; - auto pos = std::find(options.begin(), options.end(), def); - if (pos == options.end()) - index = -1; - else { - index = std::distance(options.begin(), pos); - selection = index; - result = options[index]; - } - } + int selection; + Ogre::String result; + Ogre::String label; + std::vector options; + Selector(const Ogre::String &label, + const std::vector &options) + : label(label) + , options(options) + , selection(-1) + { + } + bool select() + { + bool changed = false; + if (selection < 0) + selection = 0; + if (selection >= options.size()) + selection = (options.size() > 0) ? options.size() - 1 : + 0; + if (options.size() == 0) { + ImGui::Text("None: %s", label.c_str()); + return false; + } + if (ImGui::BeginCombo(label.c_str(), + options[selection].c_str())) { + int i; + for (i = 0; i < options.size(); i++) { + bool selected = selection == i; + if (ImGui::Selectable(options[i].c_str(), + selected)) { + selection = i; + changed = true; + } + } + ImGui::EndCombo(); + } + if (changed || result.empty()) + result = options[selection]; + return changed; + } + void set_default(const Ogre::String &def) + { + int index = -1; + auto pos = std::find(options.begin(), options.end(), def); + if (pos == options.end()) + index = -1; + else { + index = std::distance(options.begin(), pos); + selection = index; + result = options[index]; + } + } }; bool editNPCs(nlohmann::json &npcs) { - struct slotEdit { - const Ogre::String &label; - const Ogre::String &slotBase; - std::vector *options_m; - std::vector *options_f; - const Ogre::String &slot; - }; - static std::vector faces_a_m, hairs_a_m, tops_a_m, - bottoms_a_m, feet_a_m; - static std::vector faces_a_f, hairs_a_f, tops_a_f, - bottoms_a_f, feet_a_f; - ZoneScoped; - bool changed = false; - ImGui::Text("NPC"); - int id = 0; - struct slotEdit pslots_a[] = { - { "Face", "face", &faces_a_m, &faces_a_f, "slot_face" }, - { "Hair", "hair", &hairs_a_m, &hairs_a_f, "slot_hair" }, - { "Top", "top", &tops_a_m, &tops_a_f, "slot_top" }, - { "Bottom", "bottom", &bottoms_a_m, &bottoms_a_f, - "slot_bottom" }, - { "Feet", "feet", &feet_a_m, &feet_a_f, "slot_feet" }, - }; - for (auto g : pslots_a) { - g.options_m->clear(); - g.options_f->clear(); - ECS::get_mut().getSlotMeshes( - "adult", "male", g.slotBase, *g.options_m); - ECS::get_mut().getSlotMeshes( - "adult", "female", g.slotBase, *g.options_f); - } - for (auto &npc : npcs) { - Ogre::String meid = Ogre::StringConverter::toString(id); - static char firstName[64] = { 0 }; - static char lastName[64] = { 0 }; - static char nickName[64] = { 0 }; - static char tags[256] = { 0 }; - if (npc.find("firstName") == npc.end()) - npc["firstName"] = ""; - if (npc.find("lastName") == npc.end()) - npc["lastName"] = ""; - if (npc.find("nickName") == npc.end()) - npc["nickName"] = ""; - if (npc.find("tags") == npc.end()) - npc["tags"] = ""; - if (npc.find("sex") == npc.end()) - npc["sex"] = 1; - if (npc["sex"].get() == 0) { - for (const auto &m : pslots_a) { - if (npc.find(m.slot) == npc.end()) { - npc[m.slot] = m.options_m->at(0); - changed = true; - } - } - } else if (npc["sex"].get() == 1) { - for (const auto &m : pslots_a) { - if (npc.find(m.slot) == npc.end()) { - npc[m.slot] = m.options_m->at(0); - changed = true; - } - } - } + struct slotEdit { + const Ogre::String &label; + const Ogre::String &slotBase; + std::vector *options_m; + std::vector *options_f; + const Ogre::String &slot; + }; + static std::vector faces_a_m, hairs_a_m, tops_a_m, + bottoms_a_m, feet_a_m; + static std::vector faces_a_f, hairs_a_f, tops_a_f, + bottoms_a_f, feet_a_f; + ZoneScoped; + bool changed = false; + ImGui::Text("NPC"); + int id = 0; + struct slotEdit pslots_a[] = { + { "Face", "face", &faces_a_m, &faces_a_f, "slot_face" }, + { "Hair", "hair", &hairs_a_m, &hairs_a_f, "slot_hair" }, + { "Top", "top", &tops_a_m, &tops_a_f, "slot_top" }, + { "Bottom", "bottom", &bottoms_a_m, &bottoms_a_f, + "slot_bottom" }, + { "Feet", "feet", &feet_a_m, &feet_a_f, "slot_feet" }, + }; + for (auto g : pslots_a) { + g.options_m->clear(); + g.options_f->clear(); + ECS::get_mut().getSlotMeshes( + "adult", "male", g.slotBase, *g.options_m); + ECS::get_mut().getSlotMeshes( + "adult", "female", g.slotBase, *g.options_f); + } + for (auto &npc : npcs) { + Ogre::String meid = Ogre::StringConverter::toString(id); + static char firstName[64] = { 0 }; + static char lastName[64] = { 0 }; + static char nickName[64] = { 0 }; + static char tags[256] = { 0 }; + if (npc.find("firstName") == npc.end()) + npc["firstName"] = ""; + if (npc.find("lastName") == npc.end()) + npc["lastName"] = ""; + if (npc.find("nickName") == npc.end()) + npc["nickName"] = ""; + if (npc.find("tags") == npc.end()) + npc["tags"] = ""; + if (npc.find("sex") == npc.end()) + npc["sex"] = 1; + if (npc["sex"].get() == 0) { + for (const auto &m : pslots_a) { + if (npc.find(m.slot) == npc.end()) { + npc[m.slot] = m.options_m->at(0); + changed = true; + } + } + } else if (npc["sex"].get() == 1) { + for (const auto &m : pslots_a) { + if (npc.find(m.slot) == npc.end()) { + npc[m.slot] = m.options_m->at(0); + changed = true; + } + } + } - strncpy(firstName, npc["firstName"].get().c_str(), - sizeof(firstName)); - strncpy(lastName, npc["lastName"].get().c_str(), - sizeof(lastName)); - strncpy(nickName, npc["nickName"].get().c_str(), - sizeof(lastName)); - strncpy(tags, npc["tags"].get().c_str(), - sizeof(tags)); + strncpy(firstName, npc["firstName"].get().c_str(), + sizeof(firstName)); + strncpy(lastName, npc["lastName"].get().c_str(), + sizeof(lastName)); + strncpy(nickName, npc["nickName"].get().c_str(), + sizeof(lastName)); + strncpy(tags, npc["tags"].get().c_str(), + sizeof(tags)); - ImGui::InputText(("Last name##" + meid).c_str(), lastName, - sizeof(lastName)); - if (ImGui::IsItemDeactivatedAfterEdit()) { - npc["lastName"] = Ogre::String(lastName); - changed = true; - } - ImGui::InputText(("First name##" + meid).c_str(), firstName, - sizeof(firstName)); - if (ImGui::IsItemDeactivatedAfterEdit()) { - npc["firstName"] = Ogre::String(firstName); - changed = true; - } - ImGui::InputText(("Nickname##" + meid).c_str(), nickName, - sizeof(nickName)); - if (ImGui::IsItemDeactivatedAfterEdit()) { - npc["nickName"] = Ogre::String(nickName); - changed = true; - } - Selector race(("Race##" + meid).c_str(), { "human" }); - Selector age(("Age##" + meid).c_str(), { "adult" }); - Selector sex(("Sex##" + meid).c_str(), { "male", "female" }); - if (npc.find("race") != npc.end()) - race.set_default(npc["race"].get()); - if (npc.find("age") != npc.end()) - age.set_default(npc["age"].get()); - if (npc.find("sex") != npc.end()) - sex.selection = npc["sex"].get(); - if (race.select()) { - npc["race"] = race.result; - changed = true; - } - if (age.select()) { - npc["age"] = age.result; - changed = true; - } - /* sex is integer */ - if (sex.select()) { - npc["sex"] = sex.selection; - changed = true; - } - if (sex.selection == 0) { - for (const auto &es : pslots_a) { - Selector sel((es.label + "##" + meid).c_str(), - *es.options_m); - sel.set_default( - npc[es.slot].get()); - if (sel.select()) { - npc[es.slot] = sel.result; - changed = true; - } - } - } else if (sex.selection == 1) { - for (const auto &es : pslots_a) { - Selector sel((es.label + "##" + meid).c_str(), - *es.options_f); - sel.set_default( - npc[es.slot].get()); - if (sel.select()) { - npc[es.slot] = sel.result; - changed = true; - } - } - } + ImGui::InputText(("Last name##" + meid).c_str(), lastName, + sizeof(lastName)); + if (ImGui::IsItemDeactivatedAfterEdit()) { + npc["lastName"] = Ogre::String(lastName); + changed = true; + } + ImGui::InputText(("First name##" + meid).c_str(), firstName, + sizeof(firstName)); + if (ImGui::IsItemDeactivatedAfterEdit()) { + npc["firstName"] = Ogre::String(firstName); + changed = true; + } + ImGui::InputText(("Nickname##" + meid).c_str(), nickName, + sizeof(nickName)); + if (ImGui::IsItemDeactivatedAfterEdit()) { + npc["nickName"] = Ogre::String(nickName); + changed = true; + } + Selector race(("Race##" + meid).c_str(), { "human" }); + Selector age(("Age##" + meid).c_str(), { "adult" }); + Selector sex(("Sex##" + meid).c_str(), { "male", "female" }); + if (npc.find("race") != npc.end()) + race.set_default(npc["race"].get()); + if (npc.find("age") != npc.end()) + age.set_default(npc["age"].get()); + if (npc.find("sex") != npc.end()) + sex.selection = npc["sex"].get(); + if (race.select()) { + npc["race"] = race.result; + changed = true; + } + if (age.select()) { + npc["age"] = age.result; + changed = true; + } + /* sex is integer */ + if (sex.select()) { + npc["sex"] = sex.selection; + changed = true; + } + if (sex.selection == 0) { + for (const auto &es : pslots_a) { + Selector sel((es.label + "##" + meid).c_str(), + *es.options_m); + sel.set_default( + npc[es.slot].get()); + if (sel.select()) { + npc[es.slot] = sel.result; + changed = true; + } + } + } else if (sex.selection == 1) { + for (const auto &es : pslots_a) { + Selector sel((es.label + "##" + meid).c_str(), + *es.options_f); + sel.set_default( + npc[es.slot].get()); + if (sel.select()) { + npc[es.slot] = sel.result; + changed = true; + } + } + } - ImGui::InputText(("Tags##" + meid).c_str(), tags, sizeof(tags)); - if (ImGui::IsItemDeactivatedAfterEdit()) { - npc["tags"] = Ogre::String(tags); - changed = true; - } + ImGui::InputText(("Tags##" + meid).c_str(), tags, sizeof(tags)); + if (ImGui::IsItemDeactivatedAfterEdit()) { + npc["tags"] = Ogre::String(tags); + changed = true; + } - if (ImGui::SmallButton(("Spawn##" + meid).c_str())) { - Ogre::Vector3 npcPosition; - Ogre::Quaternion npcOrientation; - from_json(npc["position"], npcPosition); - from_json(npc["orientation"], npcOrientation); + if (ImGui::SmallButton(("Spawn##" + meid).c_str())) { + Ogre::Vector3 npcPosition; + Ogre::Quaternion npcOrientation; + from_json(npc["position"], npcPosition); + from_json(npc["orientation"], npcOrientation); - // FIXME: create TownCharacterManager and register NPCs through there - ECS::get_mut() - .createCharacterData( - npc["slot_face"].get(), - npc["slot_hair"].get(), - npc["slot_top"].get(), - npc["slot_bottom"].get(), - npc["slot_feet"].get(), - npcPosition, npcOrientation); - } - if (ImGui::SmallButton( - ("Delete##" + Ogre::StringConverter::toString(id)) - .c_str())) { - npcs.erase(id); - changed = true; - break; - } - id++; - } - { - ImGui::Text("New NPC"); - static char lastName[64] = { 0 }; - ImGui::InputText("Last name", lastName, sizeof(lastName)); - static char firstName[64] = { 0 }; - ImGui::InputText("First name", firstName, sizeof(firstName)); - static char tags[256] = { 0 }; - ImGui::InputText("Tags", tags, sizeof(tags)); - static Selector race("Race##new_npc", { "human" }); - static Selector age("Age##new_npc", { "adult" }); - static Selector sex("Sex##new_npc", { "male", "female" }); - changed = changed || race.select(); - changed = changed || age.select(); - changed = changed || sex.select(); - static Selector sel_face("Face##new_npc", {}); - static Selector sel_hair("Hair##new_npc", {}); - static Selector sel_top("Top##new_npc", {}); - static Selector sel_bottom("Bottom##new_npc", {}); - static Selector sel_feet("Feet##new_npc", {}); - if (changed || sel_face.options.size() == 0) { - if (sex.selection == 0) { - sel_face = Selector("Face##new_npc", faces_a_m); - sel_hair = Selector("Hair##new_npc", hairs_a_m); - sel_top = Selector("Top##new_npc", tops_a_m); - sel_bottom = Selector("Bottom##new_npc", - bottoms_a_m); - sel_feet = Selector("Feet##new_npc", feet_a_m); - } else if (sex.selection == 1) { - sel_face = Selector("Face##new_npc", faces_a_f); - sel_hair = Selector("Hair##new_npc", hairs_a_f); - sel_top = Selector("Top##new_npc", tops_a_f); - sel_bottom = Selector("Bottom##new_npc", - bottoms_a_f); - sel_feet = Selector("Feet##new_npc", feet_a_f); - } - } - changed = changed || sel_face.select(); - changed = changed || sel_hair.select(); - changed = changed || sel_top.select(); - changed = changed || sel_bottom.select(); - changed = changed || sel_feet.select(); - if (ImGui::SmallButton("Add NPC")) { - nlohmann::json npc; - npc["lastName"] = Ogre::String(lastName); - npc["firstName"] = Ogre::String(firstName); - npc["tags"] = Ogre::String(tags); - Ogre::Vector3 npcPosition = - ECS::get() - .sceneNode->_getDerivedPosition(); - Ogre::Quaternion npcOrientation = - ECS::get() - .sceneNode->_getDerivedOrientation(); - to_json(npc["position"], npcPosition); - to_json(npc["orientation"], npcOrientation); - npc["sex"] = sex.selection; - npc["slot_hair"] = sel_hair.result; - npc["slot_face"] = sel_face.result; - npc["slot_top"] = sel_top.result; - npc["slot_bottom"] = sel_bottom.result; - npc["slot_feet"] = sel_feet.result; - npc["health"] = 100; - npc["stamina"] = 100; - npcs.push_back(npc); - changed = true; - } - } - ImGui::Separator(); - return changed; + // FIXME: create TownCharacterManager and register NPCs through there + ECS::get_mut() + .createCharacterData( + npc["slot_face"].get(), + npc["slot_hair"].get(), + npc["slot_top"].get(), + npc["slot_bottom"].get(), + npc["slot_feet"].get(), + npcPosition, npcOrientation); + } + if (ImGui::SmallButton( + ("Delete##" + Ogre::StringConverter::toString(id)) + .c_str())) { + npcs.erase(id); + changed = true; + break; + } + id++; + } + { + ImGui::Text("New NPC"); + static char lastName[64] = { 0 }; + ImGui::InputText("Last name", lastName, sizeof(lastName)); + static char firstName[64] = { 0 }; + ImGui::InputText("First name", firstName, sizeof(firstName)); + static char tags[256] = { 0 }; + ImGui::InputText("Tags", tags, sizeof(tags)); + static Selector race("Race##new_npc", { "human" }); + static Selector age("Age##new_npc", { "adult" }); + static Selector sex("Sex##new_npc", { "male", "female" }); + changed = changed || race.select(); + changed = changed || age.select(); + changed = changed || sex.select(); + static Selector sel_face("Face##new_npc", {}); + static Selector sel_hair("Hair##new_npc", {}); + static Selector sel_top("Top##new_npc", {}); + static Selector sel_bottom("Bottom##new_npc", {}); + static Selector sel_feet("Feet##new_npc", {}); + if (changed || sel_face.options.size() == 0) { + if (sex.selection == 0) { + sel_face = Selector("Face##new_npc", faces_a_m); + sel_hair = Selector("Hair##new_npc", hairs_a_m); + sel_top = Selector("Top##new_npc", tops_a_m); + sel_bottom = Selector("Bottom##new_npc", + bottoms_a_m); + sel_feet = Selector("Feet##new_npc", feet_a_m); + } else if (sex.selection == 1) { + sel_face = Selector("Face##new_npc", faces_a_f); + sel_hair = Selector("Hair##new_npc", hairs_a_f); + sel_top = Selector("Top##new_npc", tops_a_f); + sel_bottom = Selector("Bottom##new_npc", + bottoms_a_f); + sel_feet = Selector("Feet##new_npc", feet_a_f); + } + } + changed = changed || sel_face.select(); + changed = changed || sel_hair.select(); + changed = changed || sel_top.select(); + changed = changed || sel_bottom.select(); + changed = changed || sel_feet.select(); + if (ImGui::SmallButton("Add NPC")) { + nlohmann::json npc; + npc["lastName"] = Ogre::String(lastName); + npc["firstName"] = Ogre::String(firstName); + npc["tags"] = Ogre::String(tags); + Ogre::Vector3 npcPosition = + ECS::get() + .sceneNode->_getDerivedPosition(); + Ogre::Quaternion npcOrientation = + ECS::get() + .sceneNode->_getDerivedOrientation(); + to_json(npc["position"], npcPosition); + to_json(npc["orientation"], npcOrientation); + npc["sex"] = sex.selection; + npc["slot_hair"] = sel_hair.result; + npc["slot_face"] = sel_face.result; + npc["slot_top"] = sel_top.result; + npc["slot_bottom"] = sel_bottom.result; + npc["slot_feet"] = sel_feet.result; + npc["health"] = 100; + npc["stamina"] = 100; + npcs.push_back(npc); + changed = true; + } + } + ImGui::Separator(); + return changed; } void createTownPopup(const std::pair item) { - ZoneScoped; - Ogre::String prop = StaticGeometryModule::getItemProperties(item.first); - Ogre::Vector3 townPosition; - Ogre::Quaternion townRotation; - StaticGeometryModule::getItemPositionAndRotation( - item.first, townPosition, townRotation); - nlohmann::json j = nlohmann::json::parse(prop); - bool changed = false; - int count = 0; - ImGui::Text("Town"); - char townNameBuf[64]; - strcpy(townNameBuf, ""); - if (j.find("name") != j.end()) - strncpy(townNameBuf, j["name"].get().c_str(), - sizeof(townNameBuf)); - ImGui::InputText("Town Name", townNameBuf, sizeof(townNameBuf)); - if (ImGui::IsItemDeactivatedAfterEdit()) { - j["name"] = Ogre::String(townNameBuf); - changed = true; - } - if (ImGui::SmallButton("Run all town scripts")) { - runAllScriptsForTown(item.first); - StaticGeometryModule::saveItems(); - changed = true; - } - nlohmann::json colorRects = nlohmann::json::object(); - nlohmann::json lotTemplates = nlohmann::json::array(); - if (j.find("colorRects") != j.end()) - colorRects = j["colorRects"]; - if (j.find("lotTemplates") != j.end()) - lotTemplates = j["lotTemplates"]; - if (ImGui::CollapsingHeader("Edit Color Rects")) { - changed = changed || editColorRects(colorRects); - ImGui::Separator(); - } - nlohmann::json npcs = nlohmann::json::array(); - if (j.find("npcs") != j.end()) - npcs = j["npcs"]; + ZoneScoped; + Ogre::String prop = StaticGeometryModule::getItemProperties(item.first); + Ogre::Vector3 townPosition; + Ogre::Quaternion townRotation; + StaticGeometryModule::getItemPositionAndRotation( + item.first, townPosition, townRotation); + nlohmann::json j = nlohmann::json::parse(prop); + bool changed = false; + int count = 0; + ImGui::Text("Town"); + char townNameBuf[64]; + strcpy(townNameBuf, ""); + if (j.find("name") != j.end()) + strncpy(townNameBuf, j["name"].get().c_str(), + sizeof(townNameBuf)); + ImGui::InputText("Town Name", townNameBuf, sizeof(townNameBuf)); + if (ImGui::IsItemDeactivatedAfterEdit()) { + j["name"] = Ogre::String(townNameBuf); + changed = true; + } + if (ImGui::SmallButton("Run all town scripts")) { + runAllScriptsForTown(item.first); + StaticGeometryModule::saveItems(); + changed = true; + } + nlohmann::json colorRects = nlohmann::json::object(); + nlohmann::json lotTemplates = nlohmann::json::array(); + if (j.find("colorRects") != j.end()) + colorRects = j["colorRects"]; + if (j.find("lotTemplates") != j.end()) + lotTemplates = j["lotTemplates"]; + if (ImGui::CollapsingHeader("Edit Color Rects")) { + changed = changed || editColorRects(colorRects); + ImGui::Separator(); + } + nlohmann::json npcs = nlohmann::json::array(); + if (j.find("npcs") != j.end()) + npcs = j["npcs"]; - changed = changed || editNPCs(npcs); - nlohmann::json districts = nlohmann::json::array(); - for (auto &district : j["districts"]) - districts.push_back(district); - count = 0; - for (auto &district : districts) { - ImGui::Separator(); - Ogre::String districtLabel = - "district" + Ogre::StringConverter::toString(count); - ImGui::Text("%s", districtLabel.c_str()); - bool districtChanged = - editDistrict(districtLabel, district, lotTemplates); - district["_dirty"] = districtChanged; - changed = changed || districtChanged; - ImGui::Separator(); - if (ImGui::SmallButton(("Delete##" + districtLabel).c_str())) { - districts.erase(count); - changed = true; - break; - } - count++; - } - ImGui::Separator(); - if (ImGui::SmallButton("Add district")) { - Ogre::Vector3 cursorPosition = - ECS::get().sceneNode->_getDerivedPosition(); - Ogre::Quaternion cursorOrientation = - ECS::get() - .sceneNode->_getDerivedOrientation(); - Ogre::Vector3 localPosition = cursorPosition - townPosition; - Ogre::Quaternion localRotation = - townRotation.Inverse() * cursorOrientation; - nlohmann::json d; - d["radius"] = 50.0f; - d["lots"] = nlohmann::json::array(); - to_json(d["position"], localPosition); - to_json(d["rotation"], localRotation); - d["elevation"] = 0.0f; - d["plazza"] = false; - districts.push_back(d); - changed = true; - } - ImGui::Separator(); - ImGui::Text("%s", j.dump(4).c_str()); - if (changed) { - j["npcs"] = npcs; - j["districts"] = districts; - j["colorRects"] = colorRects; - j["lotTemplates"] = lotTemplates; - StaticGeometryModule::setItemProperties(item.first, j.dump()); - StaticGeometryModule::saveItems(); - Geometry::createTownMaterial(item.first, true); - StaticGeometryModule::updateItemGeometry(item.first); + changed = changed || editNPCs(npcs); + nlohmann::json districts = nlohmann::json::array(); + for (auto &district : j["districts"]) + districts.push_back(district); + count = 0; + for (auto &district : districts) { + ImGui::Separator(); + Ogre::String districtLabel = + "district" + Ogre::StringConverter::toString(count); + ImGui::Text("%s", districtLabel.c_str()); + bool districtChanged = + editDistrict(districtLabel, district, lotTemplates); + district["_dirty"] = districtChanged; + changed = changed || districtChanged; + ImGui::Separator(); + if (ImGui::SmallButton(("Delete##" + districtLabel).c_str())) { + districts.erase(count); + changed = true; + break; + } + count++; + } + ImGui::Separator(); + if (ImGui::SmallButton("Add district")) { + Ogre::Vector3 cursorPosition = + ECS::get().sceneNode->_getDerivedPosition(); + Ogre::Quaternion cursorOrientation = + ECS::get() + .sceneNode->_getDerivedOrientation(); + Ogre::Vector3 localPosition = cursorPosition - townPosition; + Ogre::Quaternion localRotation = + townRotation.Inverse() * cursorOrientation; + nlohmann::json d; + d["radius"] = 50.0f; + d["lots"] = nlohmann::json::array(); + to_json(d["position"], localPosition); + to_json(d["rotation"], localRotation); + d["elevation"] = 0.0f; + d["plazza"] = false; + districts.push_back(d); + changed = true; + } + ImGui::Separator(); + ImGui::Text("%s", j.dump(4).c_str()); + if (changed) { + j["npcs"] = npcs; + j["districts"] = districts; + j["colorRects"] = colorRects; + j["lotTemplates"] = lotTemplates; + StaticGeometryModule::setItemProperties(item.first, j.dump()); + StaticGeometryModule::saveItems(); + Geometry::createTownMaterial(item.first, true); + StaticGeometryModule::updateItemGeometry(item.first); } } } namespace Geometry { struct BitSet { - uint64_t bit; - float sizeX; - float sizeY; - Ogre::Vector3 normal, offset; - Procedural::TriangleBuffer *tb; + uint64_t bit; + float sizeX; + float sizeY; + Ogre::Vector3 normal, offset; + Procedural::TriangleBuffer *tb; }; struct ProcessCells { - const float cellHeight = 4.0f; - const float cornerWidth = 0.2f; - Procedural::TriangleBuffer floortb; - Procedural::TriangleBuffer ceilingtb; - Procedural::TriangleBuffer extwalltb; - Procedural::TriangleBuffer intwalltb; - Procedural::TriangleBuffer intwindowstb; - std::vector bits_ext_corners; - std::vector bits_solid; - std::vector bits_doors; - std::vector bits_windows; - std::vector bits_int_corners1; - std::vector bits_int_corners2; - ProcessCells() - { - ZoneScoped; - bits_ext_corners = { - { 4 | 16, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { -1.0 - 0.2f, 2.0f, 1.0f + 0.1f }, - &extwalltb }, - { 4 | 16, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::UNIT_Z, - { -1.0 - 0.1f, 2.0f, 1.0f + 0.2f }, - &extwalltb }, - { 4 | 32, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { -1.0 - 0.2f, 2.0f, -1.0f - 0.1f }, - &extwalltb }, - { 4 | 32, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { -1.0 - 0.1f, 2.0f, -1.0f - 0.2f }, - &extwalltb }, - { 8 | 16, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::UNIT_X, - { 1.0f + 0.2f, 2.0f, 1.0f + 0.1f }, - &extwalltb }, - { 8 | 16, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::UNIT_Z, - { 1.0f + 0.1f, 2.0f, 1.0f + 0.2f }, - &extwalltb }, - { 8 | 32, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::UNIT_X, - { 1.0f + 0.2f, 2.0f, -1.0f - 0.1f }, - &extwalltb }, - { 8 | 32, // external wall - 4.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { 1.0f + 0.1f, 2.0f, -1.0f - 0.2f }, - &extwalltb }, - }; - float solidCellHeight = 4.0f; - float solidExtOffset = 0.0f; - float solidExtHeight = solidCellHeight - solidExtOffset; - float solidIntOffset = 0.1f; - float solidIntHeight = solidCellHeight - 0.3f - solidExtOffset; + const float cellHeight = 4.0f; + const float cornerWidth = 0.2f; + Procedural::TriangleBuffer floortb; + Procedural::TriangleBuffer ceilingtb; + Procedural::TriangleBuffer extwalltb; + Procedural::TriangleBuffer intwalltb; + Procedural::TriangleBuffer intwindowstb; + std::vector bits_ext_corners; + std::vector bits_solid; + std::vector bits_doors; + std::vector bits_windows; + std::vector bits_int_corners1; + std::vector bits_int_corners2; + ProcessCells() + { + ZoneScoped; + bits_ext_corners = { + { 4 | 16, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { -1.0 - 0.2f, 2.0f, 1.0f + 0.1f }, + &extwalltb }, + { 4 | 16, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::UNIT_Z, + { -1.0 - 0.1f, 2.0f, 1.0f + 0.2f }, + &extwalltb }, + { 4 | 32, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { -1.0 - 0.2f, 2.0f, -1.0f - 0.1f }, + &extwalltb }, + { 4 | 32, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { -1.0 - 0.1f, 2.0f, -1.0f - 0.2f }, + &extwalltb }, + { 8 | 16, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::UNIT_X, + { 1.0f + 0.2f, 2.0f, 1.0f + 0.1f }, + &extwalltb }, + { 8 | 16, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::UNIT_Z, + { 1.0f + 0.1f, 2.0f, 1.0f + 0.2f }, + &extwalltb }, + { 8 | 32, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::UNIT_X, + { 1.0f + 0.2f, 2.0f, -1.0f - 0.1f }, + &extwalltb }, + { 8 | 32, // external wall + 4.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { 1.0f + 0.1f, 2.0f, -1.0f - 0.2f }, + &extwalltb }, + }; + float solidCellHeight = 4.0f; + float solidExtOffset = 0.0f; + float solidExtHeight = solidCellHeight - solidExtOffset; + float solidIntOffset = 0.1f; + float solidIntHeight = solidCellHeight - 0.3f - solidExtOffset; - bits_solid = { - { 1ULL << 0, // floor - 2.0f, - 2.0f, - Ogre::Vector3::UNIT_Y, - { 0, 0.1f, 0 }, - &floortb }, - { 1ULL << 1, // ceiling - 2.0f, - 2.0f, - Ogre::Vector3::NEGATIVE_UNIT_Y, - { 0, 3.7f, 0 }, - &ceilingtb }, - { 1ULL << 2, // external wall - solidExtHeight, - 2.0f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { -1.0 - 0.2f, solidExtHeight / 2.0f + solidExtOffset, - 0 }, - &extwalltb }, - { 1ULL << 3, // external wall - solidExtHeight, - 2.0f, - Ogre::Vector3::UNIT_X, - { 1.0 + 0.2f, solidExtHeight / 2.0f + solidExtOffset, - 0 }, - &extwalltb }, - { 1ULL << 4, // external wall - solidExtHeight, - 2.0f, - Ogre::Vector3::UNIT_Z, - { 0, solidExtHeight / 2.0f + solidExtOffset, - 1.0f + 0.2f }, - &extwalltb }, - { 1ULL << 5, // external wall - solidExtHeight, - 2.0f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { 0, solidExtHeight / 2.0f + solidExtOffset, - -1.0f - 0.2f }, - &extwalltb }, - { 1ULL << 14, // internal wall - solidIntHeight, - 1.8f, - Ogre::Vector3::UNIT_X, - { -1.0 + 0.1f, solidIntHeight / 2.0f + solidIntOffset, - 0 }, - &intwalltb }, - { 1ULL << 15, // internal wall - solidIntHeight, - 1.8f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { 1.0 - 0.1f, solidIntHeight / 2.0f + solidIntOffset, - 0 }, - &intwalltb }, - { 1ULL << 16, // internal wall - solidIntHeight, - 1.8f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { 0, solidIntHeight / 2.0f + solidIntOffset, - 1.0f - 0.1f }, - &intwalltb }, - { 1ULL << 17, // internal wall - solidIntHeight, - 1.8f, - Ogre::Vector3::UNIT_Z, - { 0, solidIntHeight / 2.0f + solidIntOffset, - -1.0f + 0.1f }, - &intwalltb }, - }; - bits_int_corners1 = { - { 1ULL << 14, // internal wall corner - solidIntHeight, - 0.1f, - Ogre::Vector3::UNIT_X, - { -1.0f + 0.1f, - solidIntHeight / 2.0f + solidIntOffset, - (1.8f + 0.1f) / 2.0f }, - &intwalltb }, - { 1ULL << 15, // internal wall - solidIntHeight, - 0.1f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { 1.0 - 0.1f, solidIntHeight / 2.0f + solidIntOffset, - (1.8f + 0.1f) / 2.0f }, - &intwalltb }, - { 1ULL << 16, // internal wall - solidIntHeight, - 0.1f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { (1.8f + 0.1f) / 2.0f, - solidIntHeight / 2.0f + solidIntOffset, - 1.0f - 0.1f }, - &intwalltb }, - { 1ULL << 17, // internal wall - solidIntHeight, - 0.1f, - Ogre::Vector3::UNIT_Z, - { (1.8f + 0.1f) / 2.0f, - solidIntHeight / 2.0f + solidIntOffset, - -1.0f + 0.1f }, - &intwalltb }, - }; - bits_int_corners2 = { - { 1ULL << 14, // internal wall corner - solidIntHeight, - 0.1f, - Ogre::Vector3::UNIT_X, - { -1.0f + 0.1f, - solidIntHeight / 2.0f + solidIntOffset, - (-1.8f - 0.1f) / 2.0f }, - &intwalltb }, - { 1ULL << 15, // internal wall - solidIntHeight, - 0.1f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { 1.0 - 0.1f, solidIntHeight / 2.0f + solidIntOffset, - -(1.8f + 0.1f) / 2.0f }, - &intwalltb }, - { 1ULL << 16, // internal wall - solidIntHeight, - 0.1f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { -(1.8f + 0.1f) / 2.0f, - solidIntHeight / 2.0f + solidIntOffset, - 1.0f - 0.1f }, - &intwalltb }, - { 1ULL << 17, // internal wall - solidIntHeight, - 0.1f, - Ogre::Vector3::UNIT_Z, - { -(1.8f + 0.1f) / 2.0f, - solidIntHeight / 2.0f + solidIntOffset, - -1.0f + 0.1f }, - &intwalltb }, - }; - struct BitSet doorbits[] = { - { 1ULL << 6, // external door - 3.0f, - 0.4f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { -1.0 - 0.2f, 1.5f, 0 }, - &extwalltb }, - { 1ULL << 7, // external door - 3.0f, - 0.4f, - Ogre::Vector3::UNIT_X, - { 1.0 + 0.2f, 1.5f, 0 }, - &extwalltb }, - { 1ULL << 8, // external door - 3.0f, - 0.4f, - Ogre::Vector3::UNIT_Z, - { 0, 1.5f, 1.0f + 0.2f }, - &extwalltb }, - { 1ULL << 9, // external door - 3.0f, - 0.4f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { 0, 1.5f, -1.0f - 0.2f }, - &extwalltb }, - { 1ULL << 18, // internal door - 3.0f, - 0.4f, - Ogre::Vector3::UNIT_X, - { -1.0 + 0.1f, 1.5f, 0 }, - &intwalltb }, - { 1ULL << 19, // internal door - 3.0f, - 0.4f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { 1.0 - 0.1f, 1.5f, 0 }, - &intwalltb }, - { 1ULL << 20, // internal door - 3.0f, - 0.4f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { 0, 1.5f, 1.0f - 0.1f }, - &intwalltb }, - { 1ULL << 21, // internal door - 3.0f, - 0.4f, - Ogre::Vector3::UNIT_Z, - { 0, 1.5f, -1.0f + 0.1f }, - &intwalltb }, - }; - // const float doorm = 0.8f; - const float doorWidth = 1.4f; - const float doorHeightBase = 3.0f; - float doorHeight = doorHeightBase - solidExtOffset; - float baseOffsetY = solidExtOffset; - float doorTopHeight = solidExtHeight - doorHeight; - for (const struct BitSet &bits : doorbits) { - float sideWidth = (2.0f - doorWidth) / 2.0f; - float moffset = (2.0f - sideWidth) / 2.0f; - if (bits.tb == &intwalltb) { - sideWidth = (1.8f - doorWidth) / 2.0f; - moffset = (1.8f - sideWidth) / 2.0f; - baseOffsetY = solidIntOffset; - doorHeight = doorHeightBase - solidIntOffset; - doorTopHeight = solidIntHeight - doorHeight; - } - if (bits.offset.x == 0.0f) { //z+ or z- - struct BitSet pbits = bits; - pbits.sizeY = sideWidth; - pbits.offset.x = -moffset; - pbits.offset.y = - baseOffsetY + doorHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.offset.x = moffset; - pbits.offset.y = - baseOffsetY + doorHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.offset.x = -moffset; - pbits.sizeX = doorTopHeight; - pbits.offset.y = baseOffsetY + doorHeight + - doorTopHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.offset.x = moffset; - pbits.sizeX = doorTopHeight; - pbits.offset.y = baseOffsetY + doorHeight + - doorTopHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.offset.x = 0; - pbits.sizeX = doorTopHeight; - pbits.sizeY = doorWidth; - pbits.offset.y = baseOffsetY + doorHeight + - doorTopHeight / 2.0f; - bits_doors.push_back(pbits); - } else if (bits.offset.z == 0.0f) { - struct BitSet pbits = bits; - pbits.sizeY = sideWidth; - pbits.offset.z = -moffset; - pbits.offset.y = - baseOffsetY + doorHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.offset.z = moffset; - pbits.offset.y = - baseOffsetY + doorHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.offset.z = -moffset; - pbits.sizeX = doorTopHeight; - pbits.offset.y = baseOffsetY + doorHeight + - doorTopHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.offset.z = moffset; - pbits.sizeX = doorTopHeight; - pbits.offset.y = baseOffsetY + doorHeight + - doorTopHeight / 2.0f; - bits_doors.push_back(pbits); - pbits.offset.z = 0; - pbits.sizeX = doorTopHeight; - pbits.sizeY = doorWidth; - pbits.offset.y = baseOffsetY + doorHeight + - doorTopHeight / 2.0f; - bits_doors.push_back(pbits); - } - } - struct BitSet windowbits[] = { - { 1ULL << 10, // external window - 2.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { -1.0 - 0.2f, 1.5f, 0 }, - &extwalltb }, - { 1ULL << 11, // external window - 2.0f, - 0.2f, - Ogre::Vector3::UNIT_X, - { 1.0 + 0.2f, 1.5f, 0 }, - &extwalltb }, - { 1ULL << 12, // external window - 2.0f, - 0.2f, - Ogre::Vector3::UNIT_Z, - { 0, 1.5f, 1.0f + 0.2f }, - &extwalltb }, - { 1ULL << 13, // external window - 2.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { 0, 1.5f, -1.0f - 0.2f }, - &extwalltb }, - { 1ULL << 22, // internal window - 2.0f, - 0.2f, - Ogre::Vector3::UNIT_X, - { -1.0 + 0.1f, 1.5f, 0 }, - &intwindowstb }, - { 1ULL << 23, // internal window - 2.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_X, - { 1.0 - 0.1f, 1.5f, 0 }, - &intwindowstb }, - { 1ULL << 24, // internal window - 2.0f, - 0.2f, - Ogre::Vector3::NEGATIVE_UNIT_Z, - { 0, 1.5f, 1.0f - 0.1f }, - &intwindowstb }, - { 1ULL << 25, // internal window - 2.0f, - 0.2f, - Ogre::Vector3::UNIT_Z, - { 0, 1.5f, -1.0f + 0.1f }, - &intwindowstb }, - }; - const float windowWidth = 1.6f; - for (const struct BitSet &bits : windowbits) { - float windowBottomOffset = 0.8f; - float sideWidth = (2.0f - windowWidth) / 2.0f; - float moffset = (2.0f - sideWidth) / 2.0f; - float midSize = 2.0f; - float bottomSize = windowBottomOffset - solidExtOffset; - float topOffset = 3.0f; - float topSize = solidExtHeight - midSize - bottomSize; - float offsetY = solidExtOffset; - if (bits.tb == &intwindowstb) { - bottomSize = - windowBottomOffset - solidIntOffset; - topSize = solidIntHeight - midSize - bottomSize; - sideWidth = (1.8f - windowWidth) / 2.0f; - moffset = (1.8f - sideWidth) / 2.0f; - offsetY = solidIntOffset; - } - if (bits.offset.x == 0.0f) { - struct BitSet pbits = bits; - pbits.sizeY = sideWidth; - pbits.sizeX = bottomSize; - pbits.offset.x = -moffset; - pbits.offset.y = bottomSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = bottomSize; - pbits.offset.x = moffset; - pbits.offset.y = bottomSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = midSize; - pbits.offset.x = -moffset; - pbits.offset.y = - bottomSize + midSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = midSize; - pbits.offset.x = moffset; - pbits.offset.y = - bottomSize + midSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = topSize; - pbits.offset.x = -moffset; - pbits.offset.y = bottomSize + midSize + - topSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = topSize; - pbits.offset.x = moffset; - pbits.offset.y = bottomSize + midSize + - topSize / 2.0f + offsetY; - bits_windows.push_back(pbits); + bits_solid = { + { 1ULL << 0, // floor + 2.0f, + 2.0f, + Ogre::Vector3::UNIT_Y, + { 0, 0.1f, 0 }, + &floortb }, + { 1ULL << 1, // ceiling + 2.0f, + 2.0f, + Ogre::Vector3::NEGATIVE_UNIT_Y, + { 0, 3.7f, 0 }, + &ceilingtb }, + { 1ULL << 2, // external wall + solidExtHeight, + 2.0f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { -1.0 - 0.2f, solidExtHeight / 2.0f + solidExtOffset, + 0 }, + &extwalltb }, + { 1ULL << 3, // external wall + solidExtHeight, + 2.0f, + Ogre::Vector3::UNIT_X, + { 1.0 + 0.2f, solidExtHeight / 2.0f + solidExtOffset, + 0 }, + &extwalltb }, + { 1ULL << 4, // external wall + solidExtHeight, + 2.0f, + Ogre::Vector3::UNIT_Z, + { 0, solidExtHeight / 2.0f + solidExtOffset, + 1.0f + 0.2f }, + &extwalltb }, + { 1ULL << 5, // external wall + solidExtHeight, + 2.0f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { 0, solidExtHeight / 2.0f + solidExtOffset, + -1.0f - 0.2f }, + &extwalltb }, + { 1ULL << 14, // internal wall + solidIntHeight, + 1.8f, + Ogre::Vector3::UNIT_X, + { -1.0 + 0.1f, solidIntHeight / 2.0f + solidIntOffset, + 0 }, + &intwalltb }, + { 1ULL << 15, // internal wall + solidIntHeight, + 1.8f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { 1.0 - 0.1f, solidIntHeight / 2.0f + solidIntOffset, + 0 }, + &intwalltb }, + { 1ULL << 16, // internal wall + solidIntHeight, + 1.8f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { 0, solidIntHeight / 2.0f + solidIntOffset, + 1.0f - 0.1f }, + &intwalltb }, + { 1ULL << 17, // internal wall + solidIntHeight, + 1.8f, + Ogre::Vector3::UNIT_Z, + { 0, solidIntHeight / 2.0f + solidIntOffset, + -1.0f + 0.1f }, + &intwalltb }, + }; + bits_int_corners1 = { + { 1ULL << 14, // internal wall corner + solidIntHeight, + 0.1f, + Ogre::Vector3::UNIT_X, + { -1.0f + 0.1f, + solidIntHeight / 2.0f + solidIntOffset, + (1.8f + 0.1f) / 2.0f }, + &intwalltb }, + { 1ULL << 15, // internal wall + solidIntHeight, + 0.1f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { 1.0 - 0.1f, solidIntHeight / 2.0f + solidIntOffset, + (1.8f + 0.1f) / 2.0f }, + &intwalltb }, + { 1ULL << 16, // internal wall + solidIntHeight, + 0.1f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { (1.8f + 0.1f) / 2.0f, + solidIntHeight / 2.0f + solidIntOffset, + 1.0f - 0.1f }, + &intwalltb }, + { 1ULL << 17, // internal wall + solidIntHeight, + 0.1f, + Ogre::Vector3::UNIT_Z, + { (1.8f + 0.1f) / 2.0f, + solidIntHeight / 2.0f + solidIntOffset, + -1.0f + 0.1f }, + &intwalltb }, + }; + bits_int_corners2 = { + { 1ULL << 14, // internal wall corner + solidIntHeight, + 0.1f, + Ogre::Vector3::UNIT_X, + { -1.0f + 0.1f, + solidIntHeight / 2.0f + solidIntOffset, + (-1.8f - 0.1f) / 2.0f }, + &intwalltb }, + { 1ULL << 15, // internal wall + solidIntHeight, + 0.1f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { 1.0 - 0.1f, solidIntHeight / 2.0f + solidIntOffset, + -(1.8f + 0.1f) / 2.0f }, + &intwalltb }, + { 1ULL << 16, // internal wall + solidIntHeight, + 0.1f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { -(1.8f + 0.1f) / 2.0f, + solidIntHeight / 2.0f + solidIntOffset, + 1.0f - 0.1f }, + &intwalltb }, + { 1ULL << 17, // internal wall + solidIntHeight, + 0.1f, + Ogre::Vector3::UNIT_Z, + { -(1.8f + 0.1f) / 2.0f, + solidIntHeight / 2.0f + solidIntOffset, + -1.0f + 0.1f }, + &intwalltb }, + }; + struct BitSet doorbits[] = { + { 1ULL << 6, // external door + 3.0f, + 0.4f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { -1.0 - 0.2f, 1.5f, 0 }, + &extwalltb }, + { 1ULL << 7, // external door + 3.0f, + 0.4f, + Ogre::Vector3::UNIT_X, + { 1.0 + 0.2f, 1.5f, 0 }, + &extwalltb }, + { 1ULL << 8, // external door + 3.0f, + 0.4f, + Ogre::Vector3::UNIT_Z, + { 0, 1.5f, 1.0f + 0.2f }, + &extwalltb }, + { 1ULL << 9, // external door + 3.0f, + 0.4f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { 0, 1.5f, -1.0f - 0.2f }, + &extwalltb }, + { 1ULL << 18, // internal door + 3.0f, + 0.4f, + Ogre::Vector3::UNIT_X, + { -1.0 + 0.1f, 1.5f, 0 }, + &intwalltb }, + { 1ULL << 19, // internal door + 3.0f, + 0.4f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { 1.0 - 0.1f, 1.5f, 0 }, + &intwalltb }, + { 1ULL << 20, // internal door + 3.0f, + 0.4f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { 0, 1.5f, 1.0f - 0.1f }, + &intwalltb }, + { 1ULL << 21, // internal door + 3.0f, + 0.4f, + Ogre::Vector3::UNIT_Z, + { 0, 1.5f, -1.0f + 0.1f }, + &intwalltb }, + }; + // const float doorm = 0.8f; + const float doorWidth = 1.4f; + const float doorHeightBase = 3.0f; + float doorHeight = doorHeightBase - solidExtOffset; + float baseOffsetY = solidExtOffset; + float doorTopHeight = solidExtHeight - doorHeight; + for (const struct BitSet &bits : doorbits) { + float sideWidth = (2.0f - doorWidth) / 2.0f; + float moffset = (2.0f - sideWidth) / 2.0f; + if (bits.tb == &intwalltb) { + sideWidth = (1.8f - doorWidth) / 2.0f; + moffset = (1.8f - sideWidth) / 2.0f; + baseOffsetY = solidIntOffset; + doorHeight = doorHeightBase - solidIntOffset; + doorTopHeight = solidIntHeight - doorHeight; + } + if (bits.offset.x == 0.0f) { //z+ or z- + struct BitSet pbits = bits; + pbits.sizeY = sideWidth; + pbits.offset.x = -moffset; + pbits.offset.y = + baseOffsetY + doorHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.offset.x = moffset; + pbits.offset.y = + baseOffsetY + doorHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.offset.x = -moffset; + pbits.sizeX = doorTopHeight; + pbits.offset.y = baseOffsetY + doorHeight + + doorTopHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.offset.x = moffset; + pbits.sizeX = doorTopHeight; + pbits.offset.y = baseOffsetY + doorHeight + + doorTopHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.offset.x = 0; + pbits.sizeX = doorTopHeight; + pbits.sizeY = doorWidth; + pbits.offset.y = baseOffsetY + doorHeight + + doorTopHeight / 2.0f; + bits_doors.push_back(pbits); + } else if (bits.offset.z == 0.0f) { + struct BitSet pbits = bits; + pbits.sizeY = sideWidth; + pbits.offset.z = -moffset; + pbits.offset.y = + baseOffsetY + doorHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.offset.z = moffset; + pbits.offset.y = + baseOffsetY + doorHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.offset.z = -moffset; + pbits.sizeX = doorTopHeight; + pbits.offset.y = baseOffsetY + doorHeight + + doorTopHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.offset.z = moffset; + pbits.sizeX = doorTopHeight; + pbits.offset.y = baseOffsetY + doorHeight + + doorTopHeight / 2.0f; + bits_doors.push_back(pbits); + pbits.offset.z = 0; + pbits.sizeX = doorTopHeight; + pbits.sizeY = doorWidth; + pbits.offset.y = baseOffsetY + doorHeight + + doorTopHeight / 2.0f; + bits_doors.push_back(pbits); + } + } + struct BitSet windowbits[] = { + { 1ULL << 10, // external window + 2.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { -1.0 - 0.2f, 1.5f, 0 }, + &extwalltb }, + { 1ULL << 11, // external window + 2.0f, + 0.2f, + Ogre::Vector3::UNIT_X, + { 1.0 + 0.2f, 1.5f, 0 }, + &extwalltb }, + { 1ULL << 12, // external window + 2.0f, + 0.2f, + Ogre::Vector3::UNIT_Z, + { 0, 1.5f, 1.0f + 0.2f }, + &extwalltb }, + { 1ULL << 13, // external window + 2.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { 0, 1.5f, -1.0f - 0.2f }, + &extwalltb }, + { 1ULL << 22, // internal window + 2.0f, + 0.2f, + Ogre::Vector3::UNIT_X, + { -1.0 + 0.1f, 1.5f, 0 }, + &intwindowstb }, + { 1ULL << 23, // internal window + 2.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_X, + { 1.0 - 0.1f, 1.5f, 0 }, + &intwindowstb }, + { 1ULL << 24, // internal window + 2.0f, + 0.2f, + Ogre::Vector3::NEGATIVE_UNIT_Z, + { 0, 1.5f, 1.0f - 0.1f }, + &intwindowstb }, + { 1ULL << 25, // internal window + 2.0f, + 0.2f, + Ogre::Vector3::UNIT_Z, + { 0, 1.5f, -1.0f + 0.1f }, + &intwindowstb }, + }; + const float windowWidth = 1.6f; + for (const struct BitSet &bits : windowbits) { + float windowBottomOffset = 0.8f; + float sideWidth = (2.0f - windowWidth) / 2.0f; + float moffset = (2.0f - sideWidth) / 2.0f; + float midSize = 2.0f; + float bottomSize = windowBottomOffset - solidExtOffset; + float topOffset = 3.0f; + float topSize = solidExtHeight - midSize - bottomSize; + float offsetY = solidExtOffset; + if (bits.tb == &intwindowstb) { + bottomSize = + windowBottomOffset - solidIntOffset; + topSize = solidIntHeight - midSize - bottomSize; + sideWidth = (1.8f - windowWidth) / 2.0f; + moffset = (1.8f - sideWidth) / 2.0f; + offsetY = solidIntOffset; + } + if (bits.offset.x == 0.0f) { + struct BitSet pbits = bits; + pbits.sizeY = sideWidth; + pbits.sizeX = bottomSize; + pbits.offset.x = -moffset; + pbits.offset.y = bottomSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = bottomSize; + pbits.offset.x = moffset; + pbits.offset.y = bottomSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = midSize; + pbits.offset.x = -moffset; + pbits.offset.y = + bottomSize + midSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = midSize; + pbits.offset.x = moffset; + pbits.offset.y = + bottomSize + midSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = topSize; + pbits.offset.x = -moffset; + pbits.offset.y = bottomSize + midSize + + topSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = topSize; + pbits.offset.x = moffset; + pbits.offset.y = bottomSize + midSize + + topSize / 2.0f + offsetY; + bits_windows.push_back(pbits); - pbits.sizeY = windowWidth; - pbits.sizeX = bottomSize; - pbits.offset.x = 0; - pbits.offset.y = bottomSize / 2.0f + offsetY; - bits_windows.push_back(pbits); + pbits.sizeY = windowWidth; + pbits.sizeX = bottomSize; + pbits.offset.x = 0; + pbits.offset.y = bottomSize / 2.0f + offsetY; + bits_windows.push_back(pbits); - pbits.sizeY = windowWidth; - pbits.sizeX = topSize; - pbits.offset.x = 0; - pbits.offset.y = bottomSize + midSize + - topSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - } else if (bits.offset.z == 0.0f) { - struct BitSet pbits = bits; - pbits.sizeY = sideWidth; - pbits.sizeX = bottomSize; - pbits.offset.z = -moffset; - pbits.offset.y = bottomSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = bottomSize; - pbits.offset.z = moffset; - pbits.offset.y = bottomSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = midSize; - pbits.offset.z = -moffset; - pbits.offset.y = - bottomSize + midSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = midSize; - pbits.offset.z = moffset; - pbits.offset.y = - bottomSize + midSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = topSize; - pbits.offset.z = -moffset; - pbits.offset.y = bottomSize + midSize + - topSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - pbits.sizeY = sideWidth; - pbits.sizeX = topSize; - pbits.offset.z = moffset; - pbits.offset.y = bottomSize + midSize + - topSize / 2.0f + offsetY; - bits_windows.push_back(pbits); + pbits.sizeY = windowWidth; + pbits.sizeX = topSize; + pbits.offset.x = 0; + pbits.offset.y = bottomSize + midSize + + topSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + } else if (bits.offset.z == 0.0f) { + struct BitSet pbits = bits; + pbits.sizeY = sideWidth; + pbits.sizeX = bottomSize; + pbits.offset.z = -moffset; + pbits.offset.y = bottomSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = bottomSize; + pbits.offset.z = moffset; + pbits.offset.y = bottomSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = midSize; + pbits.offset.z = -moffset; + pbits.offset.y = + bottomSize + midSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = midSize; + pbits.offset.z = moffset; + pbits.offset.y = + bottomSize + midSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = topSize; + pbits.offset.z = -moffset; + pbits.offset.y = bottomSize + midSize + + topSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + pbits.sizeY = sideWidth; + pbits.sizeX = topSize; + pbits.offset.z = moffset; + pbits.offset.y = bottomSize + midSize + + topSize / 2.0f + offsetY; + bits_windows.push_back(pbits); - pbits.sizeY = windowWidth; - pbits.sizeX = bottomSize; - pbits.offset.z = 0; - pbits.offset.y = bottomSize / 2.0f + offsetY; - bits_windows.push_back(pbits); + pbits.sizeY = windowWidth; + pbits.sizeX = bottomSize; + pbits.offset.z = 0; + pbits.offset.y = bottomSize / 2.0f + offsetY; + bits_windows.push_back(pbits); - pbits.sizeY = windowWidth; - pbits.sizeX = topSize; - pbits.offset.z = 0; - pbits.offset.y = bottomSize + midSize + - topSize / 2.0f + offsetY; - bits_windows.push_back(pbits); - } - } - } - void process(flecs::entity e, const Ogre::Vector3 &cellOffset, - uint64_t flags, Procedural::TriangleBuffer &cellTb, - Procedural::TriangleBuffer &intwinTb, - Procedural::TriangleBuffer &exteriorTb) - { - auto gen = [cellOffset](float sizeX, float sizeY, - const Ogre::Vector3 &normal, - const Ogre::Vector3 offset, - Procedural::TriangleBuffer &tb) { - int nsegY = 1; - if (sizeY < 1.0f) - nsegY = 1; - Procedural::PlaneGenerator() - .setNormal(normal) - .setSizeX(sizeX) - .setSizeY(sizeY) - .setNumSegX(1) - .setNumSegY(nsegY) - .setEnableNormals(true) - .setPosition(cellOffset + offset) - .addToTriangleBuffer(tb); - }; - uint64_t corners_flags = 0; - corners_flags |= ((flags >> 0) & 0x3c); - corners_flags |= ((flags >> 4) & 0x3c); - corners_flags |= ((flags >> 8) & 0x3c); - // corners_flags |= ((flags >> 12) & 0x3c); - uint64_t corners_flags2 = 0; - corners_flags2 |= ((flags >> 0) & 0x3c000); - corners_flags2 |= ((flags >> 4) & 0x3c000); - corners_flags2 |= ((flags >> 8) & 0x3c000); - for (struct BitSet &bit : bits_ext_corners) { - if ((corners_flags & bit.bit) == bit.bit) - gen(bit.sizeX, bit.sizeY, bit.normal, - bit.offset, *bit.tb); - } - for (struct BitSet &bit : bits_solid) { - if ((flags & bit.bit) == bit.bit) - gen(bit.sizeX, bit.sizeY, bit.normal, - bit.offset, *bit.tb); - } - for (struct BitSet &bit : bits_doors) { - if ((flags & bit.bit) == bit.bit) - gen(bit.sizeX, bit.sizeY, bit.normal, - bit.offset, *bit.tb); - } - for (struct BitSet &bit : bits_windows) { - if ((flags & bit.bit) == bit.bit) - gen(bit.sizeX, bit.sizeY, bit.normal, - bit.offset, *bit.tb); - } - for (struct BitSet &bit : bits_int_corners1) { - if ((corners_flags2 & bit.bit) == bit.bit) { - if (bit.bit == (1ULL << 14) && - (corners_flags2 & (1ULL << 16))) - continue; - if (bit.bit == (1ULL << 15) && - (corners_flags2 & (1ULL << 16))) - continue; - if (bit.bit == (1ULL << 16) && - (corners_flags2 & (1ULL << 15))) - continue; - if (bit.bit == (1ULL << 17) && - (corners_flags2 & (1ULL << 15))) - continue; - gen(bit.sizeX, bit.sizeY, bit.normal, - bit.offset, *bit.tb); - } - } - for (struct BitSet &bit : bits_int_corners2) { - if ((corners_flags2 & bit.bit) == bit.bit) { - if (bit.bit == (1ULL << 14) && - (corners_flags2 & (1ULL << 17))) - continue; - if (bit.bit == (1ULL << 15) && - (corners_flags2 & (1ULL << 17))) - continue; - if (bit.bit == (1ULL << 16) && - (corners_flags2 & (1ULL << 14))) - continue; - if (bit.bit == (1ULL << 17) && - (corners_flags2 & (1ULL << 14))) - continue; - gen(bit.sizeX, bit.sizeY, bit.normal, - bit.offset, *bit.tb); - } - } - for (auto &v : floortb.getVertices()) { - // red floor color - v.mUV *= 0.08f; - v.mUV.x += 0.51f; - v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.5f, 0.6f); - v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); - } - for (auto &v : ceilingtb.getVertices()) { - // ceiling color - v.mUV *= 0.08f; - v.mUV.x += 0.61f; - v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.6f, 0.7f); - v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); - } - for (auto &v : extwalltb.getVertices()) { - // yellow wall color - v.mUV *= 0.08f; - v.mUV.x += 0.71f; - v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.7f, 0.8f); - v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); - } - clampUV(e, intwalltb, "internalWalls"); - clampUV(e, intwindowstb, "internalWalls"); - for (auto &tb : std::vector( - { &floortb, &ceilingtb, &intwalltb })) { - if ((*tb).getVertices().size() > 0) - cellTb.append(*tb); - } - if (intwindowstb.getVertices().size() > 0) - intwinTb.append(intwindowstb); - if (extwalltb.getVertices().size() > 0) - exteriorTb.append(extwalltb); - } + pbits.sizeY = windowWidth; + pbits.sizeX = topSize; + pbits.offset.z = 0; + pbits.offset.y = bottomSize + midSize + + topSize / 2.0f + offsetY; + bits_windows.push_back(pbits); + } + } + } + void process(flecs::entity e, const Ogre::Vector3 &cellOffset, + uint64_t flags, Procedural::TriangleBuffer &cellTb, + Procedural::TriangleBuffer &intwinTb, + Procedural::TriangleBuffer &exteriorTb) + { + auto gen = [cellOffset](float sizeX, float sizeY, + const Ogre::Vector3 &normal, + const Ogre::Vector3 offset, + Procedural::TriangleBuffer &tb) { + int nsegY = 1; + if (sizeY < 1.0f) + nsegY = 1; + Procedural::PlaneGenerator() + .setNormal(normal) + .setSizeX(sizeX) + .setSizeY(sizeY) + .setNumSegX(1) + .setNumSegY(nsegY) + .setEnableNormals(true) + .setPosition(cellOffset + offset) + .addToTriangleBuffer(tb); + }; + uint64_t corners_flags = 0; + corners_flags |= ((flags >> 0) & 0x3c); + corners_flags |= ((flags >> 4) & 0x3c); + corners_flags |= ((flags >> 8) & 0x3c); + // corners_flags |= ((flags >> 12) & 0x3c); + uint64_t corners_flags2 = 0; + corners_flags2 |= ((flags >> 0) & 0x3c000); + corners_flags2 |= ((flags >> 4) & 0x3c000); + corners_flags2 |= ((flags >> 8) & 0x3c000); + for (struct BitSet &bit : bits_ext_corners) { + if ((corners_flags & bit.bit) == bit.bit) + gen(bit.sizeX, bit.sizeY, bit.normal, + bit.offset, *bit.tb); + } + for (struct BitSet &bit : bits_solid) { + if ((flags & bit.bit) == bit.bit) + gen(bit.sizeX, bit.sizeY, bit.normal, + bit.offset, *bit.tb); + } + for (struct BitSet &bit : bits_doors) { + if ((flags & bit.bit) == bit.bit) + gen(bit.sizeX, bit.sizeY, bit.normal, + bit.offset, *bit.tb); + } + for (struct BitSet &bit : bits_windows) { + if ((flags & bit.bit) == bit.bit) + gen(bit.sizeX, bit.sizeY, bit.normal, + bit.offset, *bit.tb); + } + for (struct BitSet &bit : bits_int_corners1) { + if ((corners_flags2 & bit.bit) == bit.bit) { + if (bit.bit == (1ULL << 14) && + (corners_flags2 & (1ULL << 16))) + continue; + if (bit.bit == (1ULL << 15) && + (corners_flags2 & (1ULL << 16))) + continue; + if (bit.bit == (1ULL << 16) && + (corners_flags2 & (1ULL << 15))) + continue; + if (bit.bit == (1ULL << 17) && + (corners_flags2 & (1ULL << 15))) + continue; + gen(bit.sizeX, bit.sizeY, bit.normal, + bit.offset, *bit.tb); + } + } + for (struct BitSet &bit : bits_int_corners2) { + if ((corners_flags2 & bit.bit) == bit.bit) { + if (bit.bit == (1ULL << 14) && + (corners_flags2 & (1ULL << 17))) + continue; + if (bit.bit == (1ULL << 15) && + (corners_flags2 & (1ULL << 17))) + continue; + if (bit.bit == (1ULL << 16) && + (corners_flags2 & (1ULL << 14))) + continue; + if (bit.bit == (1ULL << 17) && + (corners_flags2 & (1ULL << 14))) + continue; + gen(bit.sizeX, bit.sizeY, bit.normal, + bit.offset, *bit.tb); + } + } + for (auto &v : floortb.getVertices()) { + // red floor color + v.mUV *= 0.08f; + v.mUV.x += 0.51f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.5f, 0.6f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } + for (auto &v : ceilingtb.getVertices()) { + // ceiling color + v.mUV *= 0.08f; + v.mUV.x += 0.61f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.6f, 0.7f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } + for (auto &v : extwalltb.getVertices()) { + // yellow wall color + v.mUV *= 0.08f; + v.mUV.x += 0.71f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.7f, 0.8f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } + clampUV(e, intwalltb, "internalWalls"); + clampUV(e, intwindowstb, "internalWalls"); + for (auto &tb : std::vector( + { &floortb, &ceilingtb, &intwalltb })) { + if ((*tb).getVertices().size() > 0) + cellTb.append(*tb); + } + if (intwindowstb.getVertices().size() > 0) + intwinTb.append(intwindowstb); + if (extwalltb.getVertices().size() > 0) + exteriorTb.append(extwalltb); + } }; void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb, - const Ogre::String &rectKey) + const Ogre::String &rectKey) { - ZoneScoped; - Ogre::String props = e.get().properties; - nlohmann::json jp = nlohmann::json::parse(props); - nlohmann::json colorRects = nlohmann::json::object(); - if (jp.find("colorRects") != jp.end()) - colorRects = jp["colorRects"]; - if (colorRects.find(rectKey) == colorRects.end()) - return; - float left = colorRects[rectKey]["left"].get(); - float right = colorRects[rectKey]["right"].get(); - float top = colorRects[rectKey]["top"].get(); - float bottom = colorRects[rectKey]["bottom"].get(); - float umul = (right - left) * 0.8f; - float vmul = (bottom - top) * 0.8f; - for (auto &v : tb.getVertices()) { - v.mUV.x *= umul; - v.mUV.y *= vmul; - v.mUV.x += left + 0.01f; - v.mUV.y += top + 0.01f; - v.mUV.x = Ogre::Math::Clamp(v.mUV.x, left, right); - v.mUV.y = Ogre::Math::Clamp(v.mUV.y, top, bottom); - } + ZoneScoped; + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + nlohmann::json colorRects = nlohmann::json::object(); + if (jp.find("colorRects") != jp.end()) + colorRects = jp["colorRects"]; + if (colorRects.find(rectKey) == colorRects.end()) + return; + float left = colorRects[rectKey]["left"].get(); + float right = colorRects[rectKey]["right"].get(); + float top = colorRects[rectKey]["top"].get(); + float bottom = colorRects[rectKey]["bottom"].get(); + float umul = (right - left) * 0.8f; + float vmul = (bottom - top) * 0.8f; + for (auto &v : tb.getVertices()) { + v.mUV.x *= umul; + v.mUV.y *= vmul; + v.mUV.x += left + 0.01f; + v.mUV.y += top + 0.01f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, left, right); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, top, bottom); + } } Ogre::MaterialPtr createTownMaterial(flecs::entity e, bool force) { - ZoneScoped; - Ogre::MaterialPtr townMaterial; - Ogre::String props = e.get().properties; - nlohmann::json jp = nlohmann::json::parse(props); - nlohmann::json colorRects = nlohmann::json::object(); - if (jp.find("colorRects") != jp.end()) - colorRects = jp["colorRects"]; - Ogre::String materialName = "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id()); - townMaterial = - Ogre::MaterialManager::getSingleton().getByName(materialName); - if (!townMaterial || force) { - Procedural::TextureBuffer colorAtlas(1024); - Procedural::RectangleTexture drawAtlas(&colorAtlas); - Ogre::ColourValue normalYellow(0.8f, 0.6f, 0, 1); - Ogre::ColourValue roadBrown(0.4f, 0.3f, 0.3f, 1); - Ogre::ColourValue bollardGrey(0.2f, 0.2f, 0.2f, 1); - Ogre::ColourValue floorRed(0.5f, 0.2f, 0.2f, 1); - Ogre::ColourValue ceilingWhite(0.8f, 0.8f, 0.85f, 1); - Ogre::ColourValue wallYellow(0.8f, 0.6f, 0, 1); - Ogre::ColourValue intwallBlue(0.6f, 0.6f, 0.8f, 1); - drawAtlas.setRectangle(Ogre::RealRect(0.0f, 0.0f, 0.4f, 1.0f)) - .setColour(normalYellow) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.2f, 0.0f, 0.3f, 1.0f)) - .setColour(bollardGrey) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.4f, 0.0f, 1.0f, 1.0f)) - .setColour(roadBrown) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.5f, 0.0f, 0.6f, 0.1f)) - .setColour(floorRed) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.6f, 0.0f, 0.7f, 0.1f)) - .setColour(ceilingWhite) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.7f, 0.0f, 0.8f, 0.1f)) - .setColour(wallYellow) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.8f, 0.0f, 0.9f, 0.1f)) - .setColour(intwallBlue) - .process(); - for (auto it = colorRects.begin(); it != colorRects.end(); - it++) { - std::cout << it.key() << std::endl; - nlohmann::json rect = it.value(); - float left = rect["left"].get(); - float top = rect["top"].get(); - float right = rect["right"].get(); - float bottom = rect["bottom"].get(); - Ogre::ColourValue colour; - from_json(rect["color"], colour); - drawAtlas - .setRectangle(Ogre::RealRect(left, top, right, - bottom)) - .setColour(colour) - .process(); - } - Ogre::String textureName = - "proceduralTextureTown" + - Ogre::StringConverter::toString(e.id()); - Ogre::TexturePtr townTexture = - Ogre::TextureManager::getSingleton().getByName( - textureName); - if (townTexture) { - Ogre::TexturePtr newTownTexture = - colorAtlas.createTexture(textureName + "_copy"); - newTownTexture->copyToTexture(townTexture); - Ogre::TextureManager::getSingleton().remove( - newTownTexture); - } else - Ogre::TexturePtr townTexture = - colorAtlas.createTexture(textureName); + ZoneScoped; + Ogre::MaterialPtr townMaterial; + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + nlohmann::json colorRects = nlohmann::json::object(); + if (jp.find("colorRects") != jp.end()) + colorRects = jp["colorRects"]; + Ogre::String materialName = "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id()); + townMaterial = + Ogre::MaterialManager::getSingleton().getByName(materialName); + if (!townMaterial || force) { + Procedural::TextureBuffer colorAtlas(1024); + Procedural::RectangleTexture drawAtlas(&colorAtlas); + Ogre::ColourValue normalYellow(0.8f, 0.6f, 0, 1); + Ogre::ColourValue roadBrown(0.4f, 0.3f, 0.3f, 1); + Ogre::ColourValue bollardGrey(0.2f, 0.2f, 0.2f, 1); + Ogre::ColourValue floorRed(0.5f, 0.2f, 0.2f, 1); + Ogre::ColourValue ceilingWhite(0.8f, 0.8f, 0.85f, 1); + Ogre::ColourValue wallYellow(0.8f, 0.6f, 0, 1); + Ogre::ColourValue intwallBlue(0.6f, 0.6f, 0.8f, 1); + drawAtlas.setRectangle(Ogre::RealRect(0.0f, 0.0f, 0.4f, 1.0f)) + .setColour(normalYellow) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.2f, 0.0f, 0.3f, 1.0f)) + .setColour(bollardGrey) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.4f, 0.0f, 1.0f, 1.0f)) + .setColour(roadBrown) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.5f, 0.0f, 0.6f, 0.1f)) + .setColour(floorRed) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.6f, 0.0f, 0.7f, 0.1f)) + .setColour(ceilingWhite) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.7f, 0.0f, 0.8f, 0.1f)) + .setColour(wallYellow) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.8f, 0.0f, 0.9f, 0.1f)) + .setColour(intwallBlue) + .process(); + for (auto it = colorRects.begin(); it != colorRects.end(); + it++) { + std::cout << it.key() << std::endl; + nlohmann::json rect = it.value(); + float left = rect["left"].get(); + float top = rect["top"].get(); + float right = rect["right"].get(); + float bottom = rect["bottom"].get(); + Ogre::ColourValue colour; + from_json(rect["color"], colour); + drawAtlas + .setRectangle(Ogre::RealRect(left, top, right, + bottom)) + .setColour(colour) + .process(); + } + Ogre::String textureName = + "proceduralTextureTown" + + Ogre::StringConverter::toString(e.id()); + Ogre::TexturePtr townTexture = + Ogre::TextureManager::getSingleton().getByName( + textureName); + if (townTexture) { + Ogre::TexturePtr newTownTexture = + colorAtlas.createTexture(textureName + "_copy"); + newTownTexture->copyToTexture(townTexture); + Ogre::TextureManager::getSingleton().remove( + newTownTexture); + } else + Ogre::TexturePtr townTexture = + colorAtlas.createTexture(textureName); - colorAtlas.saveImage("tmp4.png"); - if (!townMaterial) { - townMaterial = - Ogre::MaterialManager::getSingletonPtr()->create( - "proceduralMaterialTown" + - Ogre::StringConverter::toString( - e.id()), - Ogre::ResourceGroupManager:: - DEFAULT_RESOURCE_GROUP_NAME); - townMaterial->getTechnique(0)->getPass(0)->setShininess( - 0); - townMaterial->getTechnique(0)->getPass(0)->setDiffuse( - Ogre::ColourValue::White); - townMaterial->getTechnique(0)->getPass(0)->setSpecular( - Ogre::ColourValue(1.0f, 1.0f, 0.9f)); - townMaterial->getTechnique(0) - ->getPass(0) - ->createTextureUnitState(textureName); - if (Ogre::RTShader::ShaderGenerator::initialize()) { - townMaterial->prepare(); - Ogre::RTShader::ShaderGenerator - *mShaderGenerator = - Ogre::RTShader::ShaderGenerator:: - getSingletonPtr(); - mShaderGenerator->createShaderBasedTechnique( - *townMaterial, - Ogre::MaterialManager::DEFAULT_SCHEME_NAME, - Ogre::RTShader::ShaderGenerator:: - DEFAULT_SCHEME_NAME); - Ogre::RTShader::RenderState *pMainRenderState = - mShaderGenerator->getRenderState( - Ogre::RTShader::ShaderGenerator:: - DEFAULT_SCHEME_NAME, - *townMaterial); - } - } else { + colorAtlas.saveImage("tmp4.png"); + if (!townMaterial) { + townMaterial = + Ogre::MaterialManager::getSingletonPtr()->create( + "proceduralMaterialTown" + + Ogre::StringConverter::toString( + e.id()), + Ogre::ResourceGroupManager:: + DEFAULT_RESOURCE_GROUP_NAME); + townMaterial->getTechnique(0)->getPass(0)->setShininess( + 0); + townMaterial->getTechnique(0)->getPass(0)->setDiffuse( + Ogre::ColourValue::White); + townMaterial->getTechnique(0)->getPass(0)->setSpecular( + Ogre::ColourValue(1.0f, 1.0f, 0.9f)); + townMaterial->getTechnique(0) + ->getPass(0) + ->createTextureUnitState(textureName); + if (Ogre::RTShader::ShaderGenerator::initialize()) { + townMaterial->prepare(); + Ogre::RTShader::ShaderGenerator + *mShaderGenerator = + Ogre::RTShader::ShaderGenerator:: + getSingletonPtr(); + mShaderGenerator->createShaderBasedTechnique( + *townMaterial, + Ogre::MaterialManager::DEFAULT_SCHEME_NAME, + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME); + Ogre::RTShader::RenderState *pMainRenderState = + mShaderGenerator->getRenderState( + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME, + *townMaterial); + } + } else { #if 0 Ogre::TextureUnitState *state = townMaterial->getTechnique(0) @@ -3322,1596 +3322,1596 @@ Ogre::MaterialPtr createTownMaterial(flecs::entity e, bool force) ->getTextureUnitState(textureName); state-> #endif - } - } - return townMaterial; + } + } + return townMaterial; } void createTownWindows(flecs::entity e) { - ZoneScoped; - Ogre::MeshPtr frame1mesh = - Ogre::MeshManager::getSingleton().getByName("window-frame1"); - if (!frame1mesh) { - Procedural::TriangleBuffer frame1tb; - Procedural::TriangleBuffer glass1tb; - Procedural::BoxGenerator() - .setSizeX(1.6f) - .setSizeY(2.0f) - //.setSizeZ(0.34f) - .setSizeZ(0.05f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0, 1.0f, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(glass1tb); - Procedural::BoxGenerator() - .setSizeX(0.1f) - .setSizeY(2.0f) - .setSizeZ(0.34f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(-0.8f + 0.05f, 1.0f, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(frame1tb); - Procedural::BoxGenerator() - .setSizeX(0.1f) - .setSizeY(2.0f) - .setSizeZ(0.34f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0.8f - 0.05f, 1.0f, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(frame1tb); - Procedural::BoxGenerator() - .setSizeX(1.6f) - .setSizeY(0.1f) - .setSizeZ(0.34f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0, 2.0f, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(frame1tb); - float l = 0.36f; - Procedural::BoxGenerator() - .setSizeX(1.6f) - .setSizeY(0.15f) - .setSizeZ(l) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0, 0.0f, -(l - 0.34f))) - .setEnableNormals(true) - .addToTriangleBuffer(frame1tb); - clampUV(e, frame1tb, "windowsFrameColor"); - for (const auto &v : frame1tb.getVertices()) - std::cout << v.mPosition << " " << v.mUV << std::endl; - frame1mesh = frame1tb.transformToMesh("window-frame1"); - std::cout << "submeshes: " << frame1mesh->getSubMeshes().size() - << std::endl; - while (frame1mesh->getSubMeshes().size() > 1) { - std::cout << "destroying submesh: " - << frame1mesh->getSubMeshes().size() - 1 - << std::endl; - frame1mesh->destroySubMesh( - frame1mesh->getSubMeshes().size() - 1); - } - int count = 0; - bool crash = false; - for (count = 0; count < frame1mesh->getSubMeshes().size(); - count++) { - Ogre::SubMesh *submesh = - frame1mesh->getSubMeshes()[count]; - std::cout << frame1mesh->getName() - << ": submesh: " << count << " " << submesh - << std::endl; - if (submesh) - submesh->parent = frame1mesh.get(); - else - crash = true; - } - OgreAssert(!crash, "no submesh"); - Ogre::LodConfig configFrame(frame1mesh); - setupLods(configFrame); - Ogre::MeshPtr meshGlass = - glass1tb.transformToMesh("window-glass1"); - Ogre::LodConfig configGlass(meshGlass); - setupLods(configGlass); - } + ZoneScoped; + Ogre::MeshPtr frame1mesh = + Ogre::MeshManager::getSingleton().getByName("window-frame1"); + if (!frame1mesh) { + Procedural::TriangleBuffer frame1tb; + Procedural::TriangleBuffer glass1tb; + Procedural::BoxGenerator() + .setSizeX(1.6f) + .setSizeY(2.0f) + //.setSizeZ(0.34f) + .setSizeZ(0.05f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0, 1.0f, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(glass1tb); + Procedural::BoxGenerator() + .setSizeX(0.1f) + .setSizeY(2.0f) + .setSizeZ(0.34f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(-0.8f + 0.05f, 1.0f, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(frame1tb); + Procedural::BoxGenerator() + .setSizeX(0.1f) + .setSizeY(2.0f) + .setSizeZ(0.34f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0.8f - 0.05f, 1.0f, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(frame1tb); + Procedural::BoxGenerator() + .setSizeX(1.6f) + .setSizeY(0.1f) + .setSizeZ(0.34f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0, 2.0f, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(frame1tb); + float l = 0.36f; + Procedural::BoxGenerator() + .setSizeX(1.6f) + .setSizeY(0.15f) + .setSizeZ(l) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0, 0.0f, -(l - 0.34f))) + .setEnableNormals(true) + .addToTriangleBuffer(frame1tb); + clampUV(e, frame1tb, "windowsFrameColor"); + for (const auto &v : frame1tb.getVertices()) + std::cout << v.mPosition << " " << v.mUV << std::endl; + frame1mesh = frame1tb.transformToMesh("window-frame1"); + std::cout << "submeshes: " << frame1mesh->getSubMeshes().size() + << std::endl; + while (frame1mesh->getSubMeshes().size() > 1) { + std::cout << "destroying submesh: " + << frame1mesh->getSubMeshes().size() - 1 + << std::endl; + frame1mesh->destroySubMesh( + frame1mesh->getSubMeshes().size() - 1); + } + int count = 0; + bool crash = false; + for (count = 0; count < frame1mesh->getSubMeshes().size(); + count++) { + Ogre::SubMesh *submesh = + frame1mesh->getSubMeshes()[count]; + std::cout << frame1mesh->getName() + << ": submesh: " << count << " " << submesh + << std::endl; + if (submesh) + submesh->parent = frame1mesh.get(); + else + crash = true; + } + OgreAssert(!crash, "no submesh"); + Ogre::LodConfig configFrame(frame1mesh); + setupLods(configFrame); + Ogre::MeshPtr meshGlass = + glass1tb.transformToMesh("window-glass1"); + Ogre::LodConfig configGlass(meshGlass); + setupLods(configGlass); + } } void createTownDoors(flecs::entity e) { - ZoneScoped; - Ogre::MeshPtr extframe1mesh = - Ogre::MeshManager::getSingleton().getByName( - "external-door-frame1"); - if (!extframe1mesh) { - Procedural::TriangleBuffer extframe1tb; - Procedural::TriangleBuffer intframe1tb; - Procedural::TriangleBuffer extdoor1tb; - Procedural::TriangleBuffer intdoor1tb; - // external - Procedural::BoxGenerator() - .setSizeX(0.1f) - .setSizeY(3.0f) - .setSizeZ(0.34f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(-0.7f + 0.05f, 1.5f, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(extframe1tb); - Procedural::BoxGenerator() - .setSizeX(0.1f) - .setSizeY(3.0f) - .setSizeZ(0.34f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0.7f - 0.05f, 1.5f, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(extframe1tb); - Procedural::BoxGenerator() - .setSizeX(1.4f) - .setSizeY(0.1f) - .setSizeZ(0.34f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0, 3.0f, 0)) - .setEnableNormals(true) - .addToTriangleBuffer(extframe1tb); - Procedural::BoxGenerator() - .setSizeX(1.4f) - .setSizeY(0.15f) - .setSizeZ(0.45f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0, 0.0f, (0.45f - 0.34f))) - .setEnableNormals(true) - .addToTriangleBuffer(extframe1tb); - // internal - Procedural::BoxGenerator() - .setSizeX(0.1f) - .setSizeY(3.0f) - .setSizeZ(0.2f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(-0.7f + 0.05f, 1.5f, - 0.2f / 2.0f - 0.05f)) - .setEnableNormals(true) - .addToTriangleBuffer(intframe1tb); - Procedural::BoxGenerator() - .setSizeX(0.1f) - .setSizeY(3.0f) - .setSizeZ(0.2f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition(Ogre::Vector3(0.7f - 0.05f, 1.5f, - 0.2f / 2.0f - 0.05f)) - .setEnableNormals(true) - .addToTriangleBuffer(intframe1tb); - Procedural::BoxGenerator() - .setSizeX(1.4f) - .setSizeY(0.1f) - .setSizeZ(0.2f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition( - Ogre::Vector3(0, 3.0f, 0.2f / 2.0f - 0.05f)) - .setEnableNormals(true) - .addToTriangleBuffer(intframe1tb); - Procedural::BoxGenerator() - .setSizeX(1.4f) - .setSizeY(0.15f) - .setSizeZ(0.2f) - .setNumSegY(2) - .setNumSegX(2) - .setNumSegZ(2) - .setPosition( - Ogre::Vector3(0, 0.0f, 0.2f / 2.0f - 0.05f)) - .setEnableNormals(true) - .addToTriangleBuffer(intframe1tb); - clampUV(e, extframe1tb, "externalDoorsFrameColor"); - clampUV(e, intframe1tb, "internalDoorsFrameColor"); - clampUV(e, extdoor1tb, "externalDoorColor"); - clampUV(e, intdoor1tb, "internalDoorColor"); - if (extframe1tb.getVertices().size() > 0) { - extframe1mesh = extframe1tb.transformToMesh( - "external-door-frame1"); - Ogre::LodConfig configExtFrame(extframe1mesh); - setupLods(configExtFrame); - } - if (intframe1tb.getVertices().size() > 0) { - Ogre::MeshPtr intframe1mesh = - intframe1tb.transformToMesh( - "internal-door-frame1"); - Ogre::LodConfig configIntFrame(intframe1mesh); - setupLods(configIntFrame); - } - if (extdoor1tb.getVertices().size() > 0) { - Ogre::MeshPtr meshExtDoor = - extdoor1tb.transformToMesh("external-door1"); - Ogre::LodConfig configExtDoor(meshExtDoor); - setupLods(configExtDoor); - } - if (intdoor1tb.getVertices().size() > 0) { - Ogre::MeshPtr meshIntDoor = - intdoor1tb.transformToMesh("internal-door1"); - Ogre::LodConfig configIntDoor(meshIntDoor); - setupLods(configIntDoor); - } - } + ZoneScoped; + Ogre::MeshPtr extframe1mesh = + Ogre::MeshManager::getSingleton().getByName( + "external-door-frame1"); + if (!extframe1mesh) { + Procedural::TriangleBuffer extframe1tb; + Procedural::TriangleBuffer intframe1tb; + Procedural::TriangleBuffer extdoor1tb; + Procedural::TriangleBuffer intdoor1tb; + // external + Procedural::BoxGenerator() + .setSizeX(0.1f) + .setSizeY(3.0f) + .setSizeZ(0.34f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(-0.7f + 0.05f, 1.5f, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(extframe1tb); + Procedural::BoxGenerator() + .setSizeX(0.1f) + .setSizeY(3.0f) + .setSizeZ(0.34f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0.7f - 0.05f, 1.5f, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(extframe1tb); + Procedural::BoxGenerator() + .setSizeX(1.4f) + .setSizeY(0.1f) + .setSizeZ(0.34f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0, 3.0f, 0)) + .setEnableNormals(true) + .addToTriangleBuffer(extframe1tb); + Procedural::BoxGenerator() + .setSizeX(1.4f) + .setSizeY(0.15f) + .setSizeZ(0.45f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0, 0.0f, (0.45f - 0.34f))) + .setEnableNormals(true) + .addToTriangleBuffer(extframe1tb); + // internal + Procedural::BoxGenerator() + .setSizeX(0.1f) + .setSizeY(3.0f) + .setSizeZ(0.2f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(-0.7f + 0.05f, 1.5f, + 0.2f / 2.0f - 0.05f)) + .setEnableNormals(true) + .addToTriangleBuffer(intframe1tb); + Procedural::BoxGenerator() + .setSizeX(0.1f) + .setSizeY(3.0f) + .setSizeZ(0.2f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition(Ogre::Vector3(0.7f - 0.05f, 1.5f, + 0.2f / 2.0f - 0.05f)) + .setEnableNormals(true) + .addToTriangleBuffer(intframe1tb); + Procedural::BoxGenerator() + .setSizeX(1.4f) + .setSizeY(0.1f) + .setSizeZ(0.2f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition( + Ogre::Vector3(0, 3.0f, 0.2f / 2.0f - 0.05f)) + .setEnableNormals(true) + .addToTriangleBuffer(intframe1tb); + Procedural::BoxGenerator() + .setSizeX(1.4f) + .setSizeY(0.15f) + .setSizeZ(0.2f) + .setNumSegY(2) + .setNumSegX(2) + .setNumSegZ(2) + .setPosition( + Ogre::Vector3(0, 0.0f, 0.2f / 2.0f - 0.05f)) + .setEnableNormals(true) + .addToTriangleBuffer(intframe1tb); + clampUV(e, extframe1tb, "externalDoorsFrameColor"); + clampUV(e, intframe1tb, "internalDoorsFrameColor"); + clampUV(e, extdoor1tb, "externalDoorColor"); + clampUV(e, intdoor1tb, "internalDoorColor"); + if (extframe1tb.getVertices().size() > 0) { + extframe1mesh = extframe1tb.transformToMesh( + "external-door-frame1"); + Ogre::LodConfig configExtFrame(extframe1mesh); + setupLods(configExtFrame); + } + if (intframe1tb.getVertices().size() > 0) { + Ogre::MeshPtr intframe1mesh = + intframe1tb.transformToMesh( + "internal-door-frame1"); + Ogre::LodConfig configIntFrame(intframe1mesh); + setupLods(configIntFrame); + } + if (extdoor1tb.getVertices().size() > 0) { + Ogre::MeshPtr meshExtDoor = + extdoor1tb.transformToMesh("external-door1"); + Ogre::LodConfig configExtDoor(meshExtDoor); + setupLods(configExtDoor); + } + if (intdoor1tb.getVertices().size() > 0) { + Ogre::MeshPtr meshIntDoor = + intdoor1tb.transformToMesh("internal-door1"); + Ogre::LodConfig configIntDoor(meshIntDoor); + setupLods(configIntDoor); + } + } } struct TownTask { - virtual void operator()(flecs::entity e, - const nlohmann::json &jdistrict, int index, - Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) = 0; - virtual void wait() = 0; - virtual ~TownTask(){}; - TownTask(){}; - static void addMeshToStatic(Ogre::StaticGeometry *geo, - Ogre::MeshPtr mesh, - Ogre::MaterialPtr material, - const Ogre::Vector3 &position, - const Ogre::Quaternion &orientation) - { - ZoneScoped; - Ogre::Entity *ent = - ECS::get().mScnMgr->createEntity(mesh); - ent->setMaterial(material); - geo->addEntity(ent, position, orientation); - ECS::get().mScnMgr->destroyEntity(ent); - } - static void addStaticBodyMesh(flecs::entity e, Ogre::MeshPtr mesh, - const Ogre::Vector3 &position, - const Ogre::Quaternion &orientation) - { - ZoneScoped; - JPH::ShapeRefC shape = - JoltPhysicsWrapper::getSingleton().createMeshShape( - mesh); - JPH::BodyID id = JoltPhysicsWrapper::getSingleton().createBody( - shape, 0, position, orientation, - JPH::EMotionType::Static, Layers::NON_MOVING); - JoltPhysicsWrapper::getSingleton().addBody( - id, JPH::EActivation::Activate); - flecs::entity ce = - ECS::get().entity().child_of(e).set(id); - } + virtual void operator()(flecs::entity e, + const nlohmann::json &jdistrict, int index, + Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) = 0; + virtual void wait() = 0; + virtual ~TownTask() {}; + TownTask() {}; + static void addMeshToStatic(Ogre::StaticGeometry *geo, + Ogre::MeshPtr mesh, + Ogre::MaterialPtr material, + const Ogre::Vector3 &position, + const Ogre::Quaternion &orientation) + { + ZoneScoped; + Ogre::Entity *ent = + ECS::get().mScnMgr->createEntity(mesh); + ent->setMaterial(material); + geo->addEntity(ent, position, orientation); + ECS::get().mScnMgr->destroyEntity(ent); + } + static void addStaticBodyMesh(flecs::entity e, Ogre::MeshPtr mesh, + const Ogre::Vector3 &position, + const Ogre::Quaternion &orientation) + { + ZoneScoped; + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton().createMeshShape( + mesh); + JPH::BodyID id = JoltPhysicsWrapper::getSingleton().createBody( + shape, 0, position, orientation, + JPH::EMotionType::Static, Layers::NON_MOVING); + JoltPhysicsWrapper::getSingleton().addBody( + id, JPH::EActivation::Activate); + flecs::entity ce = + ECS::get().entity().child_of(e).set(id); + } }; struct TownPlazza : TownTask { - std::shared_future townPlazzaComplete; - void createTownPlazza(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScopedN("createTownPlazza"); - struct QueueData { - Procedural::TriangleBuffer tb; - Ogre::Vector3 position; - Ogre::Quaternion rotation; - nlohmann::json jp; - Procedural::Shape *shape; - Ogre::String meshName; - Ogre::MaterialPtr material; - Ogre::StaticGeometry *geo; - flecs::entity e; - }; - if (townPlazzaComplete.valid() && - townPlazzaComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) - townPlazzaComplete.wait(); + std::shared_future townPlazzaComplete; + void createTownPlazza(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScopedN("createTownPlazza"); + struct QueueData { + Procedural::TriangleBuffer tb; + Ogre::Vector3 position; + Ogre::Quaternion rotation; + nlohmann::json jp; + Procedural::Shape *shape; + Ogre::String meshName; + Ogre::MaterialPtr material; + Ogre::StaticGeometry *geo; + flecs::entity e; + }; + if (townPlazzaComplete.valid() && + townPlazzaComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) + townPlazzaComplete.wait(); - auto promise = std::make_shared >(); - townPlazzaComplete = promise->get_future(); - Ogre::MaterialPtr townMaterial; - townMaterial = Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id())); - Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); - Ogre::Quaternion worldOrientation = - sceneNode->_getDerivedOrientation(); - Procedural::TriangleBuffer tb; - Ogre::String meshName = - "plazzaMesh" + Ogre::StringConverter::toString(index) + - "_" + Ogre::StringConverter::toString(e.id()); - QueueData *queueData = - new QueueData({ tb, worldPosition, worldOrientation, - jdistrict, new Procedural::Shape, - meshName, townMaterial, geo, e }); - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - from_json(queueData->jp["position"], localPosition); - from_json(queueData->jp["rotation"], localRotation); - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton().getByName( - queueData->meshName); - if (mesh) - Ogre::MeshManager::getSingleton().remove(mesh); - Ogre::Root::getSingleton().getWorkQueue()->addTask([promise, - queueData, - localPosition, - localRotation]() { - ZoneScoped; - const nlohmann::json &jp = queueData->jp; - float radius = 5.0f; - float height = 0.2f; - float elevation = 0.0f; - bool plazza = false; - if (jp.find("plazza") != jp.end()) - plazza = jp["plazza"].get(); - if (!plazza) - return; - if (jp.find("radius") != jp.end()) - radius = jp["radius"].get(); - if (jp.find("height") != jp.end()) - height = jp["height"].get(); - if (jp.find("elevation") != jp.end()) - elevation = jp["elevation"].get(); - if (height < 0.1f) - height = 0.1f; - if (radius < 5.0f) - radius = 5.0f; - float mh = 4.0f; - Procedural::Shape *plazzaShape = queueData->shape; - plazzaShape->addPoint(0, -height - mh - mh); - plazzaShape->addPoint(radius * 0.5f + mh, - -height - mh - mh); - plazzaShape->addPoint(radius + mh, -height - mh); - plazzaShape->addPoint(radius, -height); - plazzaShape->addPoint(radius, 0.0f); - plazzaShape->addPoint(radius - 0.1f, 0.1f); - plazzaShape->addPoint(radius - mh + 0.1f, height); - plazzaShape->addPoint(radius - mh, height + 0.1f); - plazzaShape->addPoint(radius * 0.5f + mh, height); - plazzaShape->addPoint(0, height); - Procedural::Lathe() - .setShapeToExtrude(plazzaShape) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - 0.0f, height / 2.0f + elevation, 0.0f)) - .setNumSeg(24) - .addToTriangleBuffer(queueData->tb); - for (auto &v : queueData->tb.getVertices()) { - v.mUV *= 0.08f; - v.mUV.x += 0.41f; - v.mUV.x = - Ogre::Math::Clamp(v.mUV.x, 0.4f, 0.5f); - v.mUV.y = - Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); - } - Ogre::Root::getSingleton() - .getWorkQueue() - ->addMainThreadTask([queueData, localPosition, - localRotation]() { - ZoneScopedN( - "createTownPlazza::MainThread"); - Ogre::Vector3 worldPlazzaCenter = - queueData->position + - localPosition; - Ogre::MeshPtr mesh = - queueData->tb.transformToMesh( - queueData->meshName); - Ogre::LodConfig config(mesh); - setupLods(config); - addMeshToStatic(queueData->geo, mesh, - queueData->material, - worldPlazzaCenter, - queueData->rotation * - localRotation); - addStaticBodyMesh( - queueData->e, mesh, - worldPlazzaCenter, - queueData->rotation * - localRotation); - delete queueData; - }); - promise->set_value(true); - }); - } - void operator()(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - createTownPlazza(e, jdistrict, index, sceneNode, geo); - } - void wait() - { - ZoneScoped; - if (townPlazzaComplete.valid() && - townPlazzaComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) - townPlazzaComplete.wait(); - } + auto promise = std::make_shared >(); + townPlazzaComplete = promise->get_future(); + Ogre::MaterialPtr townMaterial; + townMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id())); + Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion worldOrientation = + sceneNode->_getDerivedOrientation(); + Procedural::TriangleBuffer tb; + Ogre::String meshName = + "plazzaMesh" + Ogre::StringConverter::toString(index) + + "_" + Ogre::StringConverter::toString(e.id()); + QueueData *queueData = + new QueueData({ tb, worldPosition, worldOrientation, + jdistrict, new Procedural::Shape, + meshName, townMaterial, geo, e }); + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + from_json(queueData->jp["position"], localPosition); + from_json(queueData->jp["rotation"], localRotation); + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton().getByName( + queueData->meshName); + if (mesh) + Ogre::MeshManager::getSingleton().remove(mesh); + Ogre::Root::getSingleton().getWorkQueue()->addTask([promise, + queueData, + localPosition, + localRotation]() { + ZoneScoped; + const nlohmann::json &jp = queueData->jp; + float radius = 5.0f; + float height = 0.2f; + float elevation = 0.0f; + bool plazza = false; + if (jp.find("plazza") != jp.end()) + plazza = jp["plazza"].get(); + if (!plazza) + return; + if (jp.find("radius") != jp.end()) + radius = jp["radius"].get(); + if (jp.find("height") != jp.end()) + height = jp["height"].get(); + if (jp.find("elevation") != jp.end()) + elevation = jp["elevation"].get(); + if (height < 0.1f) + height = 0.1f; + if (radius < 5.0f) + radius = 5.0f; + float mh = 4.0f; + Procedural::Shape *plazzaShape = queueData->shape; + plazzaShape->addPoint(0, -height - mh - mh); + plazzaShape->addPoint(radius * 0.5f + mh, + -height - mh - mh); + plazzaShape->addPoint(radius + mh, -height - mh); + plazzaShape->addPoint(radius, -height); + plazzaShape->addPoint(radius, 0.0f); + plazzaShape->addPoint(radius - 0.1f, 0.1f); + plazzaShape->addPoint(radius - mh + 0.1f, height); + plazzaShape->addPoint(radius - mh, height + 0.1f); + plazzaShape->addPoint(radius * 0.5f + mh, height); + plazzaShape->addPoint(0, height); + Procedural::Lathe() + .setShapeToExtrude(plazzaShape) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + 0.0f, height / 2.0f + elevation, 0.0f)) + .setNumSeg(24) + .addToTriangleBuffer(queueData->tb); + for (auto &v : queueData->tb.getVertices()) { + v.mUV *= 0.08f; + v.mUV.x += 0.41f; + v.mUV.x = + Ogre::Math::Clamp(v.mUV.x, 0.4f, 0.5f); + v.mUV.y = + Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } + Ogre::Root::getSingleton() + .getWorkQueue() + ->addMainThreadTask([queueData, localPosition, + localRotation]() { + ZoneScopedN( + "createTownPlazza::MainThread"); + Ogre::Vector3 worldPlazzaCenter = + queueData->position + + localPosition; + Ogre::MeshPtr mesh = + queueData->tb.transformToMesh( + queueData->meshName); + Ogre::LodConfig config(mesh); + setupLods(config); + addMeshToStatic(queueData->geo, mesh, + queueData->material, + worldPlazzaCenter, + queueData->rotation * + localRotation); + addStaticBodyMesh( + queueData->e, mesh, + worldPlazzaCenter, + queueData->rotation * + localRotation); + delete queueData; + }); + promise->set_value(true); + }); + } + void operator()(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + createTownPlazza(e, jdistrict, index, sceneNode, geo); + } + void wait() + { + ZoneScoped; + if (townPlazzaComplete.valid() && + townPlazzaComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) + townPlazzaComplete.wait(); + } }; struct TownLots : TownTask { - std::shared_future townLotsComplete; - void createTownLots(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScopedN("createTownLots"); - struct QueueData { - Procedural::TriangleBuffer tb; - Ogre::Vector3 position; - Ogre::Quaternion rotation; - nlohmann::json jp; - Procedural::Shape *shape; - Ogre::String meshName; - Ogre::MaterialPtr material; - Ogre::StaticGeometry *geo; - flecs::entity e; - }; - struct LotData { - int width, depth; - float angle, elevation; - struct QueueData queueData; - }; + std::shared_future townLotsComplete; + void createTownLots(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScopedN("createTownLots"); + struct QueueData { + Procedural::TriangleBuffer tb; + Ogre::Vector3 position; + Ogre::Quaternion rotation; + nlohmann::json jp; + Procedural::Shape *shape; + Ogre::String meshName; + Ogre::MaterialPtr material; + Ogre::StaticGeometry *geo; + flecs::entity e; + }; + struct LotData { + int width, depth; + float angle, elevation; + struct QueueData queueData; + }; - if (townLotsComplete.valid() && - townLotsComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) - townLotsComplete.wait(); + if (townLotsComplete.valid() && + townLotsComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) + townLotsComplete.wait(); - auto promise = std::make_shared >(); - townLotsComplete = promise->get_future(); - Ogre::MaterialPtr townMaterial; - townMaterial = Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id())); - nlohmann::json jlots = nlohmann::json::array(); - if (jdistrict.find("lots") != jdistrict.end()) - jlots = jdistrict["lots"]; - Ogre::Vector3 centerPosition = sceneNode->_getDerivedPosition(); - Ogre::Quaternion centerOrientation = - sceneNode->_getDerivedOrientation(); - float baseHeight = 4.0f; - const nlohmann::json &jp = jdistrict; - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - float delevation = 0.0f; - float radius = 50.0f; - if (jp.find("elevation") != jp.end()) - delevation = jp["elevation"].get(); - if (jp.find("radius") != jp.end()) - radius = jp["radius"].get(); - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); - centerPosition = centerPosition + localPosition + - Ogre::Vector3(0, delevation, 0); - centerOrientation = centerOrientation * localRotation; - static std::vector lots; - lots.resize(0); - lots.reserve(jlots.size()); - { - int count = 0; - for (const auto &jb : jlots) { - Procedural::TriangleBuffer tb; - Ogre::String meshName = - "lotbase" + - Ogre::StringConverter::toString(count) + - "_" + - Ogre::StringConverter::toString( - e.id()) + - "_" + - Ogre::StringConverter::toString(index); - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton() - .getByName(meshName); - if (mesh) - Ogre::MeshManager::getSingleton().remove( - mesh); - int depth = 10; - int width = 10; - float angle = 0.0f; - float elevation = 0.0f; - if (jb.find("depth") != jb.end()) - depth = jb["depth"].get(); - if (jb.find("width") != jb.end()) - width = jb["width"].get(); - if (jb.find("angle") != jb.end()) - angle = jb["angle"].get(); - if (jb.find("elevation") != jb.end()) - elevation = - jb["elevation"].get(); - OgreAssert(width > 1 && depth > 1 && - baseHeight > 1, - "Bad stuff happen"); - lots.push_back( - { width, - depth, - angle, - elevation, - { tb, centerPosition, - centerOrientation, jdistrict, - new Procedural::Shape, meshName, - townMaterial, geo, e } }); - count++; - } - } - OgreAssert(lots.size() > 0, "bad lots count"); - Ogre::Root::getSingleton().getWorkQueue()->addTask([radius, - baseHeight, - promise]() { - ZoneScoped; - std::cout << "lots count: " << lots.size() << std::endl; - OgreAssert(lots.size() > 0, "bad lots count"); - for (auto &lot : lots) { - float distance = radius; + auto promise = std::make_shared >(); + townLotsComplete = promise->get_future(); + Ogre::MaterialPtr townMaterial; + townMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id())); + nlohmann::json jlots = nlohmann::json::array(); + if (jdistrict.find("lots") != jdistrict.end()) + jlots = jdistrict["lots"]; + Ogre::Vector3 centerPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion centerOrientation = + sceneNode->_getDerivedOrientation(); + float baseHeight = 4.0f; + const nlohmann::json &jp = jdistrict; + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + float delevation = 0.0f; + float radius = 50.0f; + if (jp.find("elevation") != jp.end()) + delevation = jp["elevation"].get(); + if (jp.find("radius") != jp.end()) + radius = jp["radius"].get(); + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); + centerPosition = centerPosition + localPosition + + Ogre::Vector3(0, delevation, 0); + centerOrientation = centerOrientation * localRotation; + static std::vector lots; + lots.resize(0); + lots.reserve(jlots.size()); + { + int count = 0; + for (const auto &jb : jlots) { + Procedural::TriangleBuffer tb; + Ogre::String meshName = + "lotbase" + + Ogre::StringConverter::toString(count) + + "_" + + Ogre::StringConverter::toString( + e.id()) + + "_" + + Ogre::StringConverter::toString(index); + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton() + .getByName(meshName); + if (mesh) + Ogre::MeshManager::getSingleton().remove( + mesh); + int depth = 10; + int width = 10; + float angle = 0.0f; + float elevation = 0.0f; + if (jb.find("depth") != jb.end()) + depth = jb["depth"].get(); + if (jb.find("width") != jb.end()) + width = jb["width"].get(); + if (jb.find("angle") != jb.end()) + angle = jb["angle"].get(); + if (jb.find("elevation") != jb.end()) + elevation = + jb["elevation"].get(); + OgreAssert(width > 1 && depth > 1 && + baseHeight > 1, + "Bad stuff happen"); + lots.push_back( + { width, + depth, + angle, + elevation, + { tb, centerPosition, + centerOrientation, jdistrict, + new Procedural::Shape, meshName, + townMaterial, geo, e } }); + count++; + } + } + OgreAssert(lots.size() > 0, "bad lots count"); + Ogre::Root::getSingleton().getWorkQueue()->addTask([radius, + baseHeight, + promise]() { + ZoneScoped; + std::cout << "lots count: " << lots.size() << std::endl; + OgreAssert(lots.size() > 0, "bad lots count"); + for (auto &lot : lots) { + float distance = radius; - Ogre::Quaternion rotation = Ogre::Quaternion( - Ogre::Degree(lot.angle), - Ogre::Vector3::UNIT_Y); - Ogre::Vector3 offset = - lot.queueData.rotation * rotation * - (Ogre::Vector3::UNIT_Z * distance); - Procedural::BoxGenerator() - .setSizeX(4.0f * (float)lot.width) - .setSizeY(baseHeight) - .setSizeZ(4.0f * (float)lot.depth) - .setNumSegY(8) - .setNumSegX(8) - .setNumSegZ(8) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - 0.0f, - -baseHeight / 2.0f + - lot.elevation - 0.01f, - 0.0f)) - .addToTriangleBuffer(lot.queueData.tb); - OgreAssert( - lot.queueData.tb.getVertices().size() > - 8, - "bad box"); - for (auto &v : lot.queueData.tb.getVertices()) { - v.mUV *= 0.08f; - v.mUV.x += 0.41f; - v.mUV.x = Ogre::Math::Clamp(v.mUV.x, - 0.4f, 0.5f); - v.mUV.y = Ogre::Math::Clamp(v.mUV.y, - 0.0f, 0.1f); - } - } - Ogre::Root::getSingleton() - .getWorkQueue() - ->addMainThreadTask([promise, radius]() { - ZoneScopedN( - "createTownLots::MainThread"); - float distance = radius; - for (auto &lot : lots) { - std::cout - << lot.queueData.meshName - << std::endl; - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton() - .getByName( - lot.queueData - .meshName); - if (mesh) - Ogre::MeshManager:: - getSingleton() - .remove(mesh); - mesh = lot.queueData.tb.transformToMesh( - lot.queueData.meshName); - Ogre::Quaternion rotation = - Ogre::Quaternion( - Ogre::Degree( - lot.angle), - Ogre::Vector3:: - UNIT_Y); - Ogre::Vector3 offset = - lot.queueData.rotation * - rotation * - (Ogre::Vector3::UNIT_Z * - distance); - Ogre::LodConfig config(mesh); - setupLods(config); - addMeshToStatic( - lot.queueData.geo, mesh, - lot.queueData.material, - lot.queueData.position + - offset, - lot.queueData.rotation * - rotation); - addStaticBodyMesh( - lot.queueData.e, mesh, - lot.queueData.position + - offset, - lot.queueData.rotation * - rotation); - } - //OgreAssert(false, "TownLots"); - }); - promise->set_value(true); - }); - } - void operator()(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - createTownLots(e, jdistrict, index, sceneNode, geo); - } - void wait() - { - ZoneScoped; - if (townLotsComplete.valid() && - townLotsComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) - townLotsComplete.wait(); - } + Ogre::Quaternion rotation = Ogre::Quaternion( + Ogre::Degree(lot.angle), + Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = + lot.queueData.rotation * rotation * + (Ogre::Vector3::UNIT_Z * distance); + Procedural::BoxGenerator() + .setSizeX(4.0f * (float)lot.width) + .setSizeY(baseHeight) + .setSizeZ(4.0f * (float)lot.depth) + .setNumSegY(8) + .setNumSegX(8) + .setNumSegZ(8) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + 0.0f, + -baseHeight / 2.0f + + lot.elevation - 0.01f, + 0.0f)) + .addToTriangleBuffer(lot.queueData.tb); + OgreAssert( + lot.queueData.tb.getVertices().size() > + 8, + "bad box"); + for (auto &v : lot.queueData.tb.getVertices()) { + v.mUV *= 0.08f; + v.mUV.x += 0.41f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, + 0.4f, 0.5f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, + 0.0f, 0.1f); + } + } + Ogre::Root::getSingleton() + .getWorkQueue() + ->addMainThreadTask([promise, radius]() { + ZoneScopedN( + "createTownLots::MainThread"); + float distance = radius; + for (auto &lot : lots) { + std::cout + << lot.queueData.meshName + << std::endl; + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton() + .getByName( + lot.queueData + .meshName); + if (mesh) + Ogre::MeshManager:: + getSingleton() + .remove(mesh); + mesh = lot.queueData.tb.transformToMesh( + lot.queueData.meshName); + Ogre::Quaternion rotation = + Ogre::Quaternion( + Ogre::Degree( + lot.angle), + Ogre::Vector3:: + UNIT_Y); + Ogre::Vector3 offset = + lot.queueData.rotation * + rotation * + (Ogre::Vector3::UNIT_Z * + distance); + Ogre::LodConfig config(mesh); + setupLods(config); + addMeshToStatic( + lot.queueData.geo, mesh, + lot.queueData.material, + lot.queueData.position + + offset, + lot.queueData.rotation * + rotation); + addStaticBodyMesh( + lot.queueData.e, mesh, + lot.queueData.position + + offset, + lot.queueData.rotation * + rotation); + } + //OgreAssert(false, "TownLots"); + }); + promise->set_value(true); + }); + } + void operator()(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + createTownLots(e, jdistrict, index, sceneNode, geo); + } + void wait() + { + ZoneScoped; + if (townLotsComplete.valid() && + townLotsComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) + townLotsComplete.wait(); + } }; struct TownCells : TownTask { - std::shared_future townCellsComplete; - void createCells(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - struct QueueData { - Procedural::TriangleBuffer tb; - Ogre::Vector3 position; - Ogre::Quaternion rotation; - nlohmann::json jp; - Procedural::Shape *shape; - Ogre::String meshName; - Ogre::MaterialPtr material; - Ogre::StaticGeometry *geo; - flecs::entity e; - }; - struct LotData { - int width, depth; - float angle, elevation; - nlohmann::json jlot; - Procedural::TriangleBuffer cellTb; - Procedural::TriangleBuffer intwinTb; - Procedural::TriangleBuffer exteriorTb; - struct QueueData queueData; - }; + std::shared_future townCellsComplete; + void createCells(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + struct QueueData { + Procedural::TriangleBuffer tb; + Ogre::Vector3 position; + Ogre::Quaternion rotation; + nlohmann::json jp; + Procedural::Shape *shape; + Ogre::String meshName; + Ogre::MaterialPtr material; + Ogre::StaticGeometry *geo; + flecs::entity e; + }; + struct LotData { + int width, depth; + float angle, elevation; + nlohmann::json jlot; + Procedural::TriangleBuffer cellTb; + Procedural::TriangleBuffer intwinTb; + Procedural::TriangleBuffer exteriorTb; + struct QueueData queueData; + }; - if (townCellsComplete.valid() && - townCellsComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) - townCellsComplete.wait(); + if (townCellsComplete.valid() && + townCellsComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) + townCellsComplete.wait(); - auto promise = std::make_shared >(); - townCellsComplete = promise->get_future(); - Ogre::MaterialPtr townMaterial; - townMaterial = Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id())); - nlohmann::json jlots = nlohmann::json::array(); - if (jdistrict.find("lots") != jdistrict.end()) - jlots = jdistrict["lots"]; - Ogre::Vector3 centerPosition = sceneNode->_getDerivedPosition(); - Ogre::Quaternion centerOrientation = - sceneNode->_getDerivedOrientation(); - float baseHeight = 4.0f; - const nlohmann::json &jp = jdistrict; - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - float delevation = 0.0f; - float radius = 50.0f; - if (jp.find("elevation") != jp.end()) - delevation = jp["elevation"].get(); - if (jp.find("radius") != jp.end()) - radius = jp["radius"].get(); - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); - centerPosition = centerPosition + localPosition + - Ogre::Vector3(0, delevation, 0); - centerOrientation = centerOrientation * localRotation; - static std::vector lots; - lots.resize(0); - lots.reserve(jlots.size()); - { - int count = 0; - for (const auto &jb : jlots) { - Procedural::TriangleBuffer tb; - Procedural::TriangleBuffer cellTb; - Procedural::TriangleBuffer intwinTb; - Procedural::TriangleBuffer exteriorTb; - Ogre::String meshName = - "lotcells" + - Ogre::StringConverter::toString(count) + - "_" + - Ogre::StringConverter::toString( - e.id()) + - "_" + - Ogre::StringConverter::toString(index); - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton() - .getByName(meshName); - if (mesh) - Ogre::MeshManager::getSingleton().remove( - mesh); - int depth = 10; - int width = 10; - float angle = 0.0f; - float elevation = 0.0f; - if (jb.find("depth") != jb.end()) - depth = jb["depth"].get(); - if (jb.find("width") != jb.end()) - width = jb["width"].get(); - if (jb.find("angle") != jb.end()) - angle = jb["angle"].get(); - if (jb.find("elevation") != jb.end()) - elevation = - jb["elevation"].get(); - OgreAssert(width > 1 && depth > 1 && - baseHeight > 1, - "Bad stuff happen"); - if (jb.find("cells") != jb.end()) - lots.push_back( - { width, - depth, - angle, - elevation, - jb, - cellTb, - intwinTb, - exteriorTb, - { tb, centerPosition, - centerOrientation, - jdistrict, - new Procedural::Shape, - meshName, townMaterial, geo, - e } }); - count++; - } - } - Ogre::Root::getSingleton().getWorkQueue()->addTask([radius, - baseHeight, - promise]() { - { - ZoneScoped; - int count = 0; - for (auto &lot : lots) { - for (auto &jcell : lot.jlot["cells"]) { - struct ProcessCells pcells; - int x = jcell["x"].get(); - int y = jcell["y"].get(); - int z = jcell["z"].get(); - uint64_t flags = - jcell["flags"] - .get(); - Ogre::Vector3 cellOffset( - x * 2.0f, y * 4.0f, - z * 2.0f); - if (flags == 0) { - Procedural::BoxGenerator() - .setSizeX(2.0f + - 0.4f) - .setSizeY(0.2f) - .setSizeZ(2.0f + - 0.4f) - .setNumSegY(8) - .setNumSegX(8) - .setNumSegZ(8) - .setEnableNormals( - true) - .setPosition( - cellOffset) - .addToTriangleBuffer( - pcells.floortb); - lot.cellTb.append( - pcells.floortb); + auto promise = std::make_shared >(); + townCellsComplete = promise->get_future(); + Ogre::MaterialPtr townMaterial; + townMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id())); + nlohmann::json jlots = nlohmann::json::array(); + if (jdistrict.find("lots") != jdistrict.end()) + jlots = jdistrict["lots"]; + Ogre::Vector3 centerPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion centerOrientation = + sceneNode->_getDerivedOrientation(); + float baseHeight = 4.0f; + const nlohmann::json &jp = jdistrict; + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + float delevation = 0.0f; + float radius = 50.0f; + if (jp.find("elevation") != jp.end()) + delevation = jp["elevation"].get(); + if (jp.find("radius") != jp.end()) + radius = jp["radius"].get(); + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); + centerPosition = centerPosition + localPosition + + Ogre::Vector3(0, delevation, 0); + centerOrientation = centerOrientation * localRotation; + static std::vector lots; + lots.resize(0); + lots.reserve(jlots.size()); + { + int count = 0; + for (const auto &jb : jlots) { + Procedural::TriangleBuffer tb; + Procedural::TriangleBuffer cellTb; + Procedural::TriangleBuffer intwinTb; + Procedural::TriangleBuffer exteriorTb; + Ogre::String meshName = + "lotcells" + + Ogre::StringConverter::toString(count) + + "_" + + Ogre::StringConverter::toString( + e.id()) + + "_" + + Ogre::StringConverter::toString(index); + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton() + .getByName(meshName); + if (mesh) + Ogre::MeshManager::getSingleton().remove( + mesh); + int depth = 10; + int width = 10; + float angle = 0.0f; + float elevation = 0.0f; + if (jb.find("depth") != jb.end()) + depth = jb["depth"].get(); + if (jb.find("width") != jb.end()) + width = jb["width"].get(); + if (jb.find("angle") != jb.end()) + angle = jb["angle"].get(); + if (jb.find("elevation") != jb.end()) + elevation = + jb["elevation"].get(); + OgreAssert(width > 1 && depth > 1 && + baseHeight > 1, + "Bad stuff happen"); + if (jb.find("cells") != jb.end()) + lots.push_back( + { width, + depth, + angle, + elevation, + jb, + cellTb, + intwinTb, + exteriorTb, + { tb, centerPosition, + centerOrientation, + jdistrict, + new Procedural::Shape, + meshName, townMaterial, geo, + e } }); + count++; + } + } + Ogre::Root::getSingleton().getWorkQueue()->addTask([radius, + baseHeight, + promise]() { + { + ZoneScoped; + int count = 0; + for (auto &lot : lots) { + for (auto &jcell : lot.jlot["cells"]) { + struct ProcessCells pcells; + int x = jcell["x"].get(); + int y = jcell["y"].get(); + int z = jcell["z"].get(); + uint64_t flags = + jcell["flags"] + .get(); + Ogre::Vector3 cellOffset( + x * 2.0f, y * 4.0f, + z * 2.0f); + if (flags == 0) { + Procedural::BoxGenerator() + .setSizeX(2.0f + + 0.4f) + .setSizeY(0.2f) + .setSizeZ(2.0f + + 0.4f) + .setNumSegY(8) + .setNumSegX(8) + .setNumSegZ(8) + .setEnableNormals( + true) + .setPosition( + cellOffset) + .addToTriangleBuffer( + pcells.floortb); + lot.cellTb.append( + pcells.floortb); - } else - pcells.process( - lot.queueData.e, - cellOffset, - flags, - lot.cellTb, - lot.intwinTb, - lot.exteriorTb); - } - } - } - Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([radius, - baseHeight, - promise]() { - ZoneScopedN("createCells::MainThread"); - int count = 0; - for (auto &lot : lots) { - float distance = radius; - Ogre::Quaternion rotation = - Ogre::Quaternion( - Ogre::Degree(lot.angle), - Ogre::Vector3::UNIT_Y); - Ogre::Vector3 offset = - lot.queueData.rotation * - rotation * - (Ogre::Vector3::UNIT_Z * - distance); - Ogre::Vector3 worldCenterPosition = - lot.queueData.position + - offset + - Ogre::Vector3(0, lot.elevation, - 0); - Ogre::Quaternion worldCenterOrientation = - lot.queueData.rotation * - rotation; - if (lot.cellTb.getVertices().size() > - 0) { - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton() - .getByName( - lot.queueData - .meshName + - "_cells"); - if (mesh) - Ogre::MeshManager:: - getSingleton() - .remove(mesh); - std::cout - << "vertex count: " - << lot.cellTb - .getVertices() - .size() - << std::endl; - mesh = lot.cellTb.transformToMesh( - lot.queueData.meshName); - /* debug save mesh */ - // serializeMesh(mesh, meshName); - Ogre::LodConfig config(mesh); - setupLods(config); - addMeshToStatic( - lot.queueData.geo, mesh, - lot.queueData.material, - worldCenterPosition, - worldCenterOrientation); - addStaticBodyMesh( - lot.queueData.e, mesh, - worldCenterPosition, - worldCenterOrientation); - } - if (lot.intwinTb.getVertices().size() > - 0) { - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton() - .getByName( - lot.queueData - .meshName + - "_intwin"); - if (mesh) - Ogre::MeshManager:: - getSingleton() - .remove(mesh); - std::cout - << "vertex count: " - << lot.intwinTb - .getVertices() - .size() - << std::endl; - mesh = lot.intwinTb.transformToMesh( - lot.queueData.meshName + - "_intwin"); - OgreAssert(mesh, "bad mesh"); - /* debug save mesh */ - // serializeMesh(mesh, meshName); - Ogre::LodConfig config(mesh); - setupLods(config); - addMeshToStatic( - lot.queueData.geo, mesh, - lot.queueData.material, - worldCenterPosition, - worldCenterOrientation); - addStaticBodyMesh( - lot.queueData.e, mesh, - worldCenterPosition, - worldCenterOrientation); - } - if (lot.exteriorTb.getVertices().size() > - 0) { - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton() - .getByName( - lot.queueData - .meshName + - "_exterior"); - if (mesh) - Ogre::MeshManager:: - getSingleton() - .remove(mesh); - std::cout - << "vertex count: " - << lot.exteriorTb - .getVertices() - .size() - << std::endl; - mesh = lot.exteriorTb.transformToMesh( - lot.queueData.meshName + - "_exterior"); - /* debug save mesh */ - // serializeMesh(mesh, meshName); - Ogre::LodConfig config(mesh); - setupLods(config); - addMeshToStatic( - lot.queueData.geo, mesh, - lot.queueData.material, - worldCenterPosition, - worldCenterOrientation); - addStaticBodyMesh( - lot.queueData.e, mesh, - worldCenterPosition, - worldCenterOrientation); - } - count++; - } - }); - promise->set_value(true); - }); - } - void operator()(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - createCells(e, jdistrict, index, sceneNode, geo); - } - void wait() - { - ZoneScoped; - if (townCellsComplete.valid() && - townCellsComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) - townCellsComplete.wait(); - } + } else + pcells.process( + lot.queueData.e, + cellOffset, + flags, + lot.cellTb, + lot.intwinTb, + lot.exteriorTb); + } + } + } + Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([radius, + baseHeight, + promise]() { + ZoneScopedN("createCells::MainThread"); + int count = 0; + for (auto &lot : lots) { + float distance = radius; + Ogre::Quaternion rotation = + Ogre::Quaternion( + Ogre::Degree(lot.angle), + Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = + lot.queueData.rotation * + rotation * + (Ogre::Vector3::UNIT_Z * + distance); + Ogre::Vector3 worldCenterPosition = + lot.queueData.position + + offset + + Ogre::Vector3(0, lot.elevation, + 0); + Ogre::Quaternion worldCenterOrientation = + lot.queueData.rotation * + rotation; + if (lot.cellTb.getVertices().size() > + 0) { + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton() + .getByName( + lot.queueData + .meshName + + "_cells"); + if (mesh) + Ogre::MeshManager:: + getSingleton() + .remove(mesh); + std::cout + << "vertex count: " + << lot.cellTb + .getVertices() + .size() + << std::endl; + mesh = lot.cellTb.transformToMesh( + lot.queueData.meshName); + /* debug save mesh */ + // serializeMesh(mesh, meshName); + Ogre::LodConfig config(mesh); + setupLods(config); + addMeshToStatic( + lot.queueData.geo, mesh, + lot.queueData.material, + worldCenterPosition, + worldCenterOrientation); + addStaticBodyMesh( + lot.queueData.e, mesh, + worldCenterPosition, + worldCenterOrientation); + } + if (lot.intwinTb.getVertices().size() > + 0) { + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton() + .getByName( + lot.queueData + .meshName + + "_intwin"); + if (mesh) + Ogre::MeshManager:: + getSingleton() + .remove(mesh); + std::cout + << "vertex count: " + << lot.intwinTb + .getVertices() + .size() + << std::endl; + mesh = lot.intwinTb.transformToMesh( + lot.queueData.meshName + + "_intwin"); + OgreAssert(mesh, "bad mesh"); + /* debug save mesh */ + // serializeMesh(mesh, meshName); + Ogre::LodConfig config(mesh); + setupLods(config); + addMeshToStatic( + lot.queueData.geo, mesh, + lot.queueData.material, + worldCenterPosition, + worldCenterOrientation); + addStaticBodyMesh( + lot.queueData.e, mesh, + worldCenterPosition, + worldCenterOrientation); + } + if (lot.exteriorTb.getVertices().size() > + 0) { + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton() + .getByName( + lot.queueData + .meshName + + "_exterior"); + if (mesh) + Ogre::MeshManager:: + getSingleton() + .remove(mesh); + std::cout + << "vertex count: " + << lot.exteriorTb + .getVertices() + .size() + << std::endl; + mesh = lot.exteriorTb.transformToMesh( + lot.queueData.meshName + + "_exterior"); + /* debug save mesh */ + // serializeMesh(mesh, meshName); + Ogre::LodConfig config(mesh); + setupLods(config); + addMeshToStatic( + lot.queueData.geo, mesh, + lot.queueData.material, + worldCenterPosition, + worldCenterOrientation); + addStaticBodyMesh( + lot.queueData.e, mesh, + worldCenterPosition, + worldCenterOrientation); + } + count++; + } + }); + promise->set_value(true); + }); + } + void operator()(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + createCells(e, jdistrict, index, sceneNode, geo); + } + void wait() + { + ZoneScoped; + if (townCellsComplete.valid() && + townCellsComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) + townCellsComplete.wait(); + } }; struct TownRoofs : TownTask { - std::shared_future townRoofsComplete; + std::shared_future townRoofsComplete; private: - // Constants - static constexpr float CELL_WIDTH = 2.0f; - static constexpr float CELL_HEIGHT = 4.0f; - static constexpr float CELL_DEPTH = 2.0f; - static constexpr float EXTEND = 0.24f; - static constexpr float SQRT2 = 1.4142f; - struct DistrictContext { - Ogre::Vector3 centerPosition; - Ogre::Quaternion centerOrientation; - float radius; - }; - struct LotContext { - int width, depth; - float angle; - float elevation; - nlohmann::json jlot; - Ogre::Vector3 worldPosition; - Ogre::Quaternion worldOrientation; - }; - struct RoofPlacement { - int type; - int posX, posY, posZ; - int sizeX, sizeZ; - float baseHeight, maxHeight; - }; - struct RoofGenerationData { - flecs::entity entity; - Ogre::MaterialPtr material; - Ogre::StaticGeometry *geo; - Ogre::Vector3 districtPosition; - Ogre::Quaternion districtOrientation; - float districtRadius; - std::string baseMeshName; - }; - DistrictContext parseDistrictContext(const nlohmann::json &jp, - Ogre::SceneNode *sceneNode) - { - DistrictContext ctx; + // Constants + static constexpr float CELL_WIDTH = 2.0f; + static constexpr float CELL_HEIGHT = 4.0f; + static constexpr float CELL_DEPTH = 2.0f; + static constexpr float EXTEND = 0.24f; + static constexpr float SQRT2 = 1.4142f; + struct DistrictContext { + Ogre::Vector3 centerPosition; + Ogre::Quaternion centerOrientation; + float radius; + }; + struct LotContext { + int width, depth; + float angle; + float elevation; + nlohmann::json jlot; + Ogre::Vector3 worldPosition; + Ogre::Quaternion worldOrientation; + }; + struct RoofPlacement { + int type; + int posX, posY, posZ; + int sizeX, sizeZ; + float baseHeight, maxHeight; + }; + struct RoofGenerationData { + flecs::entity entity; + Ogre::MaterialPtr material; + Ogre::StaticGeometry *geo; + Ogre::Vector3 districtPosition; + Ogre::Quaternion districtOrientation; + float districtRadius; + std::string baseMeshName; + }; + DistrictContext parseDistrictContext(const nlohmann::json &jp, + Ogre::SceneNode *sceneNode) + { + DistrictContext ctx; - // Parse base position and rotation - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); + // Parse base position and rotation + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); - // Parse elevation and radius - float elevation = jp.value("elevation", 0.0f); - ctx.radius = jp.value("radius", 50.0f); + // Parse elevation and radius + float elevation = jp.value("elevation", 0.0f); + ctx.radius = jp.value("radius", 50.0f); - // Calculate world transforms for district center - ctx.centerPosition = sceneNode->_getDerivedPosition() + - localPosition + - Ogre::Vector3(0, elevation, 0); - ctx.centerOrientation = - sceneNode->_getDerivedOrientation() * localRotation; + // Calculate world transforms for district center + ctx.centerPosition = sceneNode->_getDerivedPosition() + + localPosition + + Ogre::Vector3(0, elevation, 0); + ctx.centerOrientation = + sceneNode->_getDerivedOrientation() * localRotation; - return ctx; - } - LotContext createLotContext(const DistrictContext &districtCtx, - const nlohmann::json &jlot, int lotIndex) - { - LotContext lot; - lot.jlot = jlot; + return ctx; + } + LotContext createLotContext(const DistrictContext &districtCtx, + const nlohmann::json &jlot, int lotIndex) + { + LotContext lot; + lot.jlot = jlot; - // Parse lot properties - lot.width = jlot.value("width", 10); - lot.depth = jlot.value("depth", 10); - lot.angle = jlot.value("angle", 0.0f); - lot.elevation = jlot.value("elevation", 0.0f); + // Parse lot properties + lot.width = jlot.value("width", 10); + lot.depth = jlot.value("depth", 10); + lot.angle = jlot.value("angle", 0.0f); + lot.elevation = jlot.value("elevation", 0.0f); - OgreAssert(lot.width > 1 && lot.depth > 1, - "Invalid lot dimensions"); + OgreAssert(lot.width > 1 && lot.depth > 1, + "Invalid lot dimensions"); - // Calculate lot world transform - Ogre::Quaternion lotRotation(Ogre::Degree(lot.angle), - Ogre::Vector3::UNIT_Y); - Ogre::Vector3 offset = - districtCtx.centerOrientation * lotRotation * - (Ogre::Vector3::UNIT_Z * districtCtx.radius); + // Calculate lot world transform + Ogre::Quaternion lotRotation(Ogre::Degree(lot.angle), + Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = + districtCtx.centerOrientation * lotRotation * + (Ogre::Vector3::UNIT_Z * districtCtx.radius); - lot.worldPosition = districtCtx.centerPosition + offset; - lot.worldOrientation = - districtCtx.centerOrientation * lotRotation; + lot.worldPosition = districtCtx.centerPosition + offset; + lot.worldOrientation = + districtCtx.centerOrientation * lotRotation; - return lot; - } - std::vector - parseRoofPlacements(const nlohmann::json &jlot) - { - std::vector roofs; + return lot; + } + std::vector + parseRoofPlacements(const nlohmann::json &jlot) + { + std::vector roofs; - if (!jlot.contains("roofs") || !jlot["roofs"].is_array()) { - return roofs; - } + if (!jlot.contains("roofs") || !jlot["roofs"].is_array()) { + return roofs; + } - for (const auto &jroof : jlot["roofs"]) { - RoofPlacement roof; - roof.type = jroof["type"].get(); - roof.posX = jroof["position_x"].get(); - roof.posY = jroof["position_y"].get(); - roof.posZ = jroof["position_z"].get(); - roof.sizeX = jroof["size_x"].get(); - roof.sizeZ = jroof["size_z"].get(); - roof.baseHeight = jroof["base_height"].get(); - roof.maxHeight = jroof["max_height"].get(); + for (const auto &jroof : jlot["roofs"]) { + RoofPlacement roof; + roof.type = jroof["type"].get(); + roof.posX = jroof["position_x"].get(); + roof.posY = jroof["position_y"].get(); + roof.posZ = jroof["position_z"].get(); + roof.sizeX = jroof["size_x"].get(); + roof.sizeZ = jroof["size_z"].get(); + roof.baseHeight = jroof["base_height"].get(); + roof.maxHeight = jroof["max_height"].get(); - roofs.push_back(roof); - } + roofs.push_back(roof); + } - return roofs; - } + return roofs; + } - Ogre::Vector3 calculateLocalPosition(const RoofPlacement &roof) - { - float x = static_cast(roof.posX) * CELL_WIDTH - 1.0f + - static_cast(roof.sizeX) * CELL_WIDTH / 2.0f; - float z = static_cast(roof.posZ) * CELL_DEPTH - 1.0f + - static_cast(roof.sizeZ) * CELL_DEPTH / 2.0f; - return Ogre::Vector3(x, 0.0f, z); - } - void transformToWorld(Procedural::TriangleBuffer &tb, - const LotContext &lotCtx) - { - if (tb.getVertices().empty()) - return; + Ogre::Vector3 calculateLocalPosition(const RoofPlacement &roof) + { + float x = static_cast(roof.posX) * CELL_WIDTH - 1.0f + + static_cast(roof.sizeX) * CELL_WIDTH / 2.0f; + float z = static_cast(roof.posZ) * CELL_DEPTH - 1.0f + + static_cast(roof.sizeZ) * CELL_DEPTH / 2.0f; + return Ogre::Vector3(x, 0.0f, z); + } + void transformToWorld(Procedural::TriangleBuffer &tb, + const LotContext &lotCtx) + { + if (tb.getVertices().empty()) + return; - std::vector &vertices = - tb.getVertices(); - for (auto &v : vertices) { - // Apply lot rotation to local position - Ogre::Vector3 rotatedPos = - lotCtx.worldOrientation * v.mPosition; - // Add lot world position and elevation - v.mPosition = lotCtx.worldPosition + rotatedPos + - Ogre::Vector3(0, lotCtx.elevation, 0); + std::vector &vertices = + tb.getVertices(); + for (auto &v : vertices) { + // Apply lot rotation to local position + Ogre::Vector3 rotatedPos = + lotCtx.worldOrientation * v.mPosition; + // Add lot world position and elevation + v.mPosition = lotCtx.worldPosition + rotatedPos + + Ogre::Vector3(0, lotCtx.elevation, 0); - // Rotate normals - v.mNormal = lotCtx.worldOrientation * v.mNormal; - } - } - void generateRoofType0(const RoofPlacement &roof, - const LotContext &lotCtx, - Procedural::TriangleBuffer &tbTop, - Procedural::TriangleBuffer &tbSide) - { - float width = static_cast(roof.sizeX) * CELL_WIDTH; - float depth = static_cast(roof.sizeZ) * CELL_DEPTH; - Ogre::Vector3 localPos = calculateLocalPosition(roof); + // Rotate normals + v.mNormal = lotCtx.worldOrientation * v.mNormal; + } + } + void generateRoofType0(const RoofPlacement &roof, + const LotContext &lotCtx, + Procedural::TriangleBuffer &tbTop, + Procedural::TriangleBuffer &tbSide) + { + float width = static_cast(roof.sizeX) * CELL_WIDTH; + float depth = static_cast(roof.sizeZ) * CELL_DEPTH; + Ogre::Vector3 localPos = calculateLocalPosition(roof); - // Type 0 Y calculation from original code: - // (float)position_y * 4.0f + baseHeight / 2.0f + lot.elevation - float baseY = static_cast(roof.posY) * CELL_HEIGHT + - roof.baseHeight / 2.0f; + // Type 0 Y calculation from original code: + // (float)position_y * 4.0f + baseHeight / 2.0f + lot.elevation + float baseY = static_cast(roof.posY) * CELL_HEIGHT + + roof.baseHeight / 2.0f; - // Main roof box - position already includes baseHeight/2 - Procedural::BoxGenerator() - .setSizeX(width) - .setSizeY(roof.baseHeight) - .setSizeZ(depth) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition( - Ogre::Vector3(localPos.x, baseY, localPos.z)) - .addToTriangleBuffer(tbTop); + // Main roof box - position already includes baseHeight/2 + Procedural::BoxGenerator() + .setSizeX(width) + .setSizeY(roof.baseHeight) + .setSizeZ(depth) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition( + Ogre::Vector3(localPos.x, baseY, localPos.z)) + .addToTriangleBuffer(tbTop); - // Edge trim pieces - Y calculation from original: - // (float)position_y * 4.0f + baseHeight / 2.0f + lot.elevation + extend - float trimBaseY = static_cast(roof.posY) * CELL_HEIGHT + - roof.baseHeight / 2.0f; + // Edge trim pieces - Y calculation from original: + // (float)position_y * 4.0f + baseHeight / 2.0f + lot.elevation + extend + float trimBaseY = static_cast(roof.posY) * CELL_HEIGHT + + roof.baseHeight / 2.0f; - // Z+ edge - Procedural::BoxGenerator() - .setSizeX(width) - .setSizeY(roof.baseHeight + EXTEND * 2.0f) - .setSizeZ(EXTEND) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x, trimBaseY + EXTEND, - localPos.z + depth / 2.0f + EXTEND / 2.0f)) - .addToTriangleBuffer(tbSide); + // Z+ edge + Procedural::BoxGenerator() + .setSizeX(width) + .setSizeY(roof.baseHeight + EXTEND * 2.0f) + .setSizeZ(EXTEND) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x, trimBaseY + EXTEND, + localPos.z + depth / 2.0f + EXTEND / 2.0f)) + .addToTriangleBuffer(tbSide); - // Z- edge - Procedural::BoxGenerator() - .setSizeX(width) - .setSizeY(roof.baseHeight + EXTEND * 2.0f) - .setSizeZ(EXTEND) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x, trimBaseY + EXTEND, - localPos.z - depth / 2.0f - EXTEND / 2.0f)) - .addToTriangleBuffer(tbSide); + // Z- edge + Procedural::BoxGenerator() + .setSizeX(width) + .setSizeY(roof.baseHeight + EXTEND * 2.0f) + .setSizeZ(EXTEND) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x, trimBaseY + EXTEND, + localPos.z - depth / 2.0f - EXTEND / 2.0f)) + .addToTriangleBuffer(tbSide); - // X+ edge - Procedural::BoxGenerator() - .setSizeX(EXTEND) - .setSizeY(roof.baseHeight + EXTEND * 2.0f) - .setSizeZ(depth + EXTEND * 2.0f) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x + width / 2.0f + EXTEND / 2.0f, - trimBaseY + EXTEND, localPos.z)) - .addToTriangleBuffer(tbSide); + // X+ edge + Procedural::BoxGenerator() + .setSizeX(EXTEND) + .setSizeY(roof.baseHeight + EXTEND * 2.0f) + .setSizeZ(depth + EXTEND * 2.0f) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x + width / 2.0f + EXTEND / 2.0f, + trimBaseY + EXTEND, localPos.z)) + .addToTriangleBuffer(tbSide); - // X- edge - Procedural::BoxGenerator() - .setSizeX(EXTEND) - .setSizeY(roof.baseHeight + EXTEND * 2.0f) - .setSizeZ(depth + EXTEND * 2.0f) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x - width / 2.0f - EXTEND / 2.0f, - trimBaseY + EXTEND, localPos.z)) - .addToTriangleBuffer(tbSide); - } - void generateRoofType1(const RoofPlacement &roof, - const LotContext &lotCtx, - Procedural::TriangleBuffer &tbTop, - Procedural::TriangleBuffer &tbSide) - { - float width = static_cast(roof.sizeX) * CELL_WIDTH; - float depth = static_cast(roof.sizeZ) * CELL_DEPTH; - float q = width / 2.0f; - float m = 1.0f; - float d = SQRT2 * (q + m); + // X- edge + Procedural::BoxGenerator() + .setSizeX(EXTEND) + .setSizeY(roof.baseHeight + EXTEND * 2.0f) + .setSizeZ(depth + EXTEND * 2.0f) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x - width / 2.0f - EXTEND / 2.0f, + trimBaseY + EXTEND, localPos.z)) + .addToTriangleBuffer(tbSide); + } + void generateRoofType1(const RoofPlacement &roof, + const LotContext &lotCtx, + Procedural::TriangleBuffer &tbTop, + Procedural::TriangleBuffer &tbSide) + { + float width = static_cast(roof.sizeX) * CELL_WIDTH; + float depth = static_cast(roof.sizeZ) * CELL_DEPTH; + float q = width / 2.0f; + float m = 1.0f; + float d = SQRT2 * (q + m); - Ogre::Vector3 localPos = calculateLocalPosition(roof); - float baseY = static_cast(roof.posY) * CELL_HEIGHT; + Ogre::Vector3 localPos = calculateLocalPosition(roof); + float baseY = static_cast(roof.posY) * CELL_HEIGHT; - // First angled box - Procedural::BoxGenerator() - .setSizeX(d) - .setSizeY(roof.baseHeight / 2.0f) - .setSizeZ(depth) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setOrientation(Ogre::Quaternion( - Ogre::Degree(45), - Ogre::Vector3::NEGATIVE_UNIT_Z)) - .setPosition(Ogre::Vector3( - localPos.x - width / 2.0f + q + q / 2.0f + - m / 2.0f, - baseY + roof.baseHeight + q / 2.0f - m / 2.0f, - localPos.z)) - .addToTriangleBuffer(tbTop); + // First angled box + Procedural::BoxGenerator() + .setSizeX(d) + .setSizeY(roof.baseHeight / 2.0f) + .setSizeZ(depth) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(45), + Ogre::Vector3::NEGATIVE_UNIT_Z)) + .setPosition(Ogre::Vector3( + localPos.x - width / 2.0f + q + q / 2.0f + + m / 2.0f, + baseY + roof.baseHeight + q / 2.0f - m / 2.0f, + localPos.z)) + .addToTriangleBuffer(tbTop); - // Second angled box - Procedural::BoxGenerator() - .setSizeX(d) - .setSizeY(roof.baseHeight / 2.0f) - .setSizeZ(depth) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setOrientation(Ogre::Quaternion( - Ogre::Degree(-45), - Ogre::Vector3::NEGATIVE_UNIT_Z)) - .setPosition(Ogre::Vector3( - localPos.x - width / 2.0f + q / 2.0f - m / 2.0f, - baseY + roof.baseHeight + q / 2.0f - m / 2.0f, - localPos.z)) - .addToTriangleBuffer(tbTop); + // Second angled box + Procedural::BoxGenerator() + .setSizeX(d) + .setSizeY(roof.baseHeight / 2.0f) + .setSizeZ(depth) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(-45), + Ogre::Vector3::NEGATIVE_UNIT_Z)) + .setPosition(Ogre::Vector3( + localPos.x - width / 2.0f + q / 2.0f - m / 2.0f, + baseY + roof.baseHeight + q / 2.0f - m / 2.0f, + localPos.z)) + .addToTriangleBuffer(tbTop); - // Side trim pieces - float sideY = baseY + q / 2.0f; - float sideHeight = q + roof.baseHeight * 3.0f; + // Side trim pieces + float sideY = baseY + q / 2.0f; + float sideHeight = q + roof.baseHeight * 3.0f; - // Z+ edge - Procedural::BoxGenerator() - .setSizeX(width + EXTEND * 2.0f) - .setSizeY(sideHeight) - .setSizeZ(EXTEND) - .setNumSegX(3) - .setNumSegY(3) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x, sideY + roof.baseHeight, - localPos.z + depth / 2.0f + EXTEND / 2.0f)) - .addToTriangleBuffer(tbSide); + // Z+ edge + Procedural::BoxGenerator() + .setSizeX(width + EXTEND * 2.0f) + .setSizeY(sideHeight) + .setSizeZ(EXTEND) + .setNumSegX(3) + .setNumSegY(3) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x, sideY + roof.baseHeight, + localPos.z + depth / 2.0f + EXTEND / 2.0f)) + .addToTriangleBuffer(tbSide); - // Z- edge - Procedural::BoxGenerator() - .setSizeX(width + EXTEND * 2.0f) - .setSizeY(sideHeight) - .setSizeZ(EXTEND) - .setNumSegX(3) - .setNumSegY(3) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x, sideY + roof.baseHeight, - localPos.z - depth / 2.0f - EXTEND / 2.0f)) - .addToTriangleBuffer(tbSide); + // Z- edge + Procedural::BoxGenerator() + .setSizeX(width + EXTEND * 2.0f) + .setSizeY(sideHeight) + .setSizeZ(EXTEND) + .setNumSegX(3) + .setNumSegY(3) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x, sideY + roof.baseHeight, + localPos.z - depth / 2.0f - EXTEND / 2.0f)) + .addToTriangleBuffer(tbSide); - // Apply vertex deformation - deformSideVertices(tbSide, true); - } - void generateRoofType2(const RoofPlacement &roof, - const LotContext &lotCtx, - Procedural::TriangleBuffer &tbTop, - Procedural::TriangleBuffer &tbSide) - { - float width = static_cast(roof.sizeX) * CELL_WIDTH; - float depth = static_cast(roof.sizeZ) * CELL_DEPTH; - float q = depth / 2.0f; - float m = 1.0f; - float d = SQRT2 * (q + m); + // Apply vertex deformation + deformSideVertices(tbSide, true); + } + void generateRoofType2(const RoofPlacement &roof, + const LotContext &lotCtx, + Procedural::TriangleBuffer &tbTop, + Procedural::TriangleBuffer &tbSide) + { + float width = static_cast(roof.sizeX) * CELL_WIDTH; + float depth = static_cast(roof.sizeZ) * CELL_DEPTH; + float q = depth / 2.0f; + float m = 1.0f; + float d = SQRT2 * (q + m); - Ogre::Vector3 localPos = calculateLocalPosition(roof); - float baseY = static_cast(roof.posY) * CELL_HEIGHT; + Ogre::Vector3 localPos = calculateLocalPosition(roof); + float baseY = static_cast(roof.posY) * CELL_HEIGHT; - // First angled box - Procedural::BoxGenerator() - .setSizeX(width) - .setSizeY(roof.baseHeight / 2.0f) - .setSizeZ(d) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setOrientation(Ogre::Quaternion( - Ogre::Degree(45), - Ogre::Vector3::NEGATIVE_UNIT_X)) - .setPosition(Ogre::Vector3(localPos.x, - baseY + roof.baseHeight + - q / 2.0f - m / 2.0f, - localPos.z - depth / 2.0f + - q / 2.0f - m / 2.0f)) - .addToTriangleBuffer(tbTop); + // First angled box + Procedural::BoxGenerator() + .setSizeX(width) + .setSizeY(roof.baseHeight / 2.0f) + .setSizeZ(d) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(45), + Ogre::Vector3::NEGATIVE_UNIT_X)) + .setPosition(Ogre::Vector3(localPos.x, + baseY + roof.baseHeight + + q / 2.0f - m / 2.0f, + localPos.z - depth / 2.0f + + q / 2.0f - m / 2.0f)) + .addToTriangleBuffer(tbTop); - // Second angled box - Procedural::BoxGenerator() - .setSizeX(width) - .setSizeY(roof.baseHeight / 2.0f) - .setSizeZ(d) - .setNumSegX(1) - .setNumSegY(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setOrientation(Ogre::Quaternion( - Ogre::Degree(-45), - Ogre::Vector3::NEGATIVE_UNIT_X)) - .setPosition(Ogre::Vector3( - localPos.x, - baseY + roof.baseHeight + q / 2.0f - m / 2.0f, - localPos.z - depth / 2.0f + q + q / 2.0f + - m / 2.0f)) - .addToTriangleBuffer(tbTop); + // Second angled box + Procedural::BoxGenerator() + .setSizeX(width) + .setSizeY(roof.baseHeight / 2.0f) + .setSizeZ(d) + .setNumSegX(1) + .setNumSegY(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(-45), + Ogre::Vector3::NEGATIVE_UNIT_X)) + .setPosition(Ogre::Vector3( + localPos.x, + baseY + roof.baseHeight + q / 2.0f - m / 2.0f, + localPos.z - depth / 2.0f + q + q / 2.0f + + m / 2.0f)) + .addToTriangleBuffer(tbTop); - // Side trim pieces - float sideY = baseY + q / 2.0f; - float sideHeight = q + roof.baseHeight * 3.0f; - float sideDepth = depth + 2.0f * roof.baseHeight * 3.0f; + // Side trim pieces + float sideY = baseY + q / 2.0f; + float sideHeight = q + roof.baseHeight * 3.0f; + float sideDepth = depth + 2.0f * roof.baseHeight * 3.0f; - // X+ edge - Procedural::BoxGenerator() - .setSizeX(EXTEND) - .setSizeY(sideHeight) - .setSizeZ(sideDepth) - .setNumSegX(2) - .setNumSegY(2) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x + width / 2.0f + EXTEND / 2.0f, - sideY + roof.baseHeight, localPos.z)) - .addToTriangleBuffer(tbSide); + // X+ edge + Procedural::BoxGenerator() + .setSizeX(EXTEND) + .setSizeY(sideHeight) + .setSizeZ(sideDepth) + .setNumSegX(2) + .setNumSegY(2) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x + width / 2.0f + EXTEND / 2.0f, + sideY + roof.baseHeight, localPos.z)) + .addToTriangleBuffer(tbSide); - // X- edge - Procedural::BoxGenerator() - .setSizeX(EXTEND) - .setSizeY(sideHeight) - .setSizeZ(sideDepth) - .setNumSegX(2) - .setNumSegY(2) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - localPos.x - width / 2.0f - EXTEND / 2.0f, - sideY + roof.baseHeight, localPos.z)) - .addToTriangleBuffer(tbSide); + // X- edge + Procedural::BoxGenerator() + .setSizeX(EXTEND) + .setSizeY(sideHeight) + .setSizeZ(sideDepth) + .setNumSegX(2) + .setNumSegY(2) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + localPos.x - width / 2.0f - EXTEND / 2.0f, + sideY + roof.baseHeight, localPos.z)) + .addToTriangleBuffer(tbSide); - // Apply vertex deformation - deformSideVertices(tbSide, false); - } - void deformSideVertices(Procedural::TriangleBuffer &tbSide, - bool deformXAxis) - { - if (tbSide.getVertices().empty()) - return; + // Apply vertex deformation + deformSideVertices(tbSide, false); + } + void deformSideVertices(Procedural::TriangleBuffer &tbSide, + bool deformXAxis) + { + if (tbSide.getVertices().empty()) + return; - float minY = std::numeric_limits::max(); - float maxY = std::numeric_limits::lowest(); - float minCoord = std::numeric_limits::max(); - float maxCoord = std::numeric_limits::lowest(); + float minY = std::numeric_limits::max(); + float maxY = std::numeric_limits::lowest(); + float minCoord = std::numeric_limits::max(); + float maxCoord = std::numeric_limits::lowest(); - for (const auto &v : tbSide.getVertices()) { - minY = std::min(minY, v.mPosition.y); - maxY = std::max(maxY, v.mPosition.y); - float coord = deformXAxis ? v.mPosition.x : - v.mPosition.z; - minCoord = std::min(minCoord, coord); - maxCoord = std::max(maxCoord, coord); - } + for (const auto &v : tbSide.getVertices()) { + minY = std::min(minY, v.mPosition.y); + maxY = std::max(maxY, v.mPosition.y); + float coord = deformXAxis ? v.mPosition.x : + v.mPosition.z; + minCoord = std::min(minCoord, coord); + maxCoord = std::max(maxCoord, coord); + } - float midCoord = minCoord + (maxCoord - minCoord) / 2.0f; - float coordRange = (maxCoord - minCoord) / 2.0f; - if (coordRange < 0.001f) - return; + float midCoord = minCoord + (maxCoord - minCoord) / 2.0f; + float coordRange = (maxCoord - minCoord) / 2.0f; + if (coordRange < 0.001f) + return; - for (auto &v : tbSide.getVertices()) { - float md = maxY - v.mPosition.y; - float hm = - (deformXAxis ? v.mPosition.x : v.mPosition.z) - - midCoord; - float he = (hm / coordRange) * md; + for (auto &v : tbSide.getVertices()) { + float md = maxY - v.mPosition.y; + float hm = + (deformXAxis ? v.mPosition.x : v.mPosition.z) - + midCoord; + float he = (hm / coordRange) * md; - if (deformXAxis) { - v.mPosition.x = he + midCoord; - } else { - v.mPosition.z = he + midCoord; - } - } - } - void processLot(flecs::entity e, const LotContext &lotCtx, - const RoofGenerationData &genData, - Procedural::TriangleBuffer &tbCombined) - { - std::vector roofs = - parseRoofPlacements(lotCtx.jlot); + if (deformXAxis) { + v.mPosition.x = he + midCoord; + } else { + v.mPosition.z = he + midCoord; + } + } + } + void processLot(flecs::entity e, const LotContext &lotCtx, + const RoofGenerationData &genData, + Procedural::TriangleBuffer &tbCombined) + { + std::vector roofs = + parseRoofPlacements(lotCtx.jlot); - for (auto &roof : roofs) { - Procedural::TriangleBuffer tbTop; - Procedural::TriangleBuffer tbSide; + for (auto &roof : roofs) { + Procedural::TriangleBuffer tbTop; + Procedural::TriangleBuffer tbSide; - // Generate roof in local space - switch (roof.type) { - case 0: - generateRoofType0(roof, lotCtx, tbTop, tbSide); - break; - case 1: - generateRoofType1(roof, lotCtx, tbTop, tbSide); - break; - case 2: - generateRoofType2(roof, lotCtx, tbTop, tbSide); - break; - default: - continue; - } + // Generate roof in local space + switch (roof.type) { + case 0: + generateRoofType0(roof, lotCtx, tbTop, tbSide); + break; + case 1: + generateRoofType1(roof, lotCtx, tbTop, tbSide); + break; + case 2: + generateRoofType2(roof, lotCtx, tbTop, tbSide); + break; + default: + continue; + } - // Transform to world space - if (tbTop.getVertices().size() > 0) { - transformToWorld(tbTop, lotCtx); - clampUV(e, tbTop, "roofTop"); - tbCombined.append(tbTop); - } - if (tbSide.getVertices().size() > 0) { - transformToWorld(tbSide, lotCtx); - clampUV(e, tbSide, "roofSide"); - tbCombined.append(tbSide); - } - } - } + // Transform to world space + if (tbTop.getVertices().size() > 0) { + transformToWorld(tbTop, lotCtx); + clampUV(e, tbTop, "roofTop"); + tbCombined.append(tbTop); + } + if (tbSide.getVertices().size() > 0) { + transformToWorld(tbSide, lotCtx); + clampUV(e, tbSide, "roofSide"); + tbCombined.append(tbSide); + } + } + } public: - void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; + void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; - if (townRoofsComplete.valid() && - townRoofsComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) { - townRoofsComplete.wait(); - } + if (townRoofsComplete.valid() && + townRoofsComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) { + townRoofsComplete.wait(); + } - auto promise = std::make_shared >(); - townRoofsComplete = promise->get_future(); + auto promise = std::make_shared >(); + townRoofsComplete = promise->get_future(); - Ogre::MaterialPtr townMaterial = - Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id())); + Ogre::MaterialPtr townMaterial = + Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id())); - DistrictContext districtCtx = - parseDistrictContext(jdistrict, sceneNode); + DistrictContext districtCtx = + parseDistrictContext(jdistrict, sceneNode); - RoofGenerationData genData{ - .entity = e, - .material = townMaterial, - .geo = geo, - .districtPosition = districtCtx.centerPosition, - .districtOrientation = districtCtx.centerOrientation, - .districtRadius = districtCtx.radius, - .baseMeshName = - "roofbase_" + - Ogre::StringConverter::toString(e.id()) + "_" + - Ogre::StringConverter::toString(index) - }; + RoofGenerationData genData{ + .entity = e, + .material = townMaterial, + .geo = geo, + .districtPosition = districtCtx.centerPosition, + .districtOrientation = districtCtx.centerOrientation, + .districtRadius = districtCtx.radius, + .baseMeshName = + "roofbase_" + + Ogre::StringConverter::toString(e.id()) + "_" + + Ogre::StringConverter::toString(index) + }; - Ogre::Root::getSingleton().getWorkQueue()->addTask([this, - jdistrict, - districtCtx, - genData, - promise]() { - ZoneScoped; + Ogre::Root::getSingleton().getWorkQueue()->addTask([this, + jdistrict, + districtCtx, + genData, + promise]() { + ZoneScoped; - std::vector > - lotBuffers; + std::vector > + lotBuffers; - if (jdistrict.contains("lots") && - jdistrict["lots"].is_array()) { - const nlohmann::json &lots = jdistrict["lots"]; - int lotIndex = 0; + if (jdistrict.contains("lots") && + jdistrict["lots"].is_array()) { + const nlohmann::json &lots = jdistrict["lots"]; + int lotIndex = 0; - for (const auto &jlot : lots) { - if (!jlot.contains("roofs")) - continue; + for (const auto &jlot : lots) { + if (!jlot.contains("roofs")) + continue; - LotContext lotCtx = createLotContext( - districtCtx, jlot, lotIndex); - Procedural::TriangleBuffer tbCombined; + LotContext lotCtx = createLotContext( + districtCtx, jlot, lotIndex); + Procedural::TriangleBuffer tbCombined; - processLot(genData.entity, lotCtx, - genData, tbCombined); + processLot(genData.entity, lotCtx, + genData, tbCombined); - if (tbCombined.getVertices().size() > - 0) { - lotBuffers.emplace_back( - lotCtx, tbCombined); - } + if (tbCombined.getVertices().size() > + 0) { + lotBuffers.emplace_back( + lotCtx, tbCombined); + } - lotIndex++; - } - } + lotIndex++; + } + } - Ogre::Root::getSingleton() - .getWorkQueue() - ->addMainThreadTask([this, genData, lotBuffers, - promise]() { - ZoneScopedN( - "createTownRoofs::MainThread"); + Ogre::Root::getSingleton() + .getWorkQueue() + ->addMainThreadTask([this, genData, lotBuffers, + promise]() { + ZoneScopedN( + "createTownRoofs::MainThread"); - for (size_t i = 0; - i < lotBuffers.size(); ++i) { - std::cout - << i << ": vertices: " - << lotBuffers[i] - .second - .getVertices() - .size() - << std::endl; - } + for (size_t i = 0; + i < lotBuffers.size(); ++i) { + std::cout + << i << ": vertices: " + << lotBuffers[i] + .second + .getVertices() + .size() + << std::endl; + } - int lotIndex = 0; - for (const auto &[lotCtx, tb] : - lotBuffers) { - std::string meshName = - genData.baseMeshName + - "_" + - std::to_string( - lotIndex); + int lotIndex = 0; + for (const auto &[lotCtx, tb] : + lotBuffers) { + std::string meshName = + genData.baseMeshName + + "_" + + std::to_string( + lotIndex); - Ogre::MeshPtr existingMesh = - Ogre::MeshManager::getSingleton() - .getByName( - meshName); - if (existingMesh) { - Ogre::MeshManager::getSingleton() - .remove(existingMesh); - } + Ogre::MeshPtr existingMesh = + Ogre::MeshManager::getSingleton() + .getByName( + meshName); + if (existingMesh) { + Ogre::MeshManager::getSingleton() + .remove(existingMesh); + } - // Create mesh (vertices are already in world space) - Ogre::MeshPtr mesh = - tb.transformToMesh( - meshName); - Ogre::LodConfig config(mesh); - setupLods(config); + // Create mesh (vertices are already in world space) + Ogre::MeshPtr mesh = + tb.transformToMesh( + meshName); + Ogre::LodConfig config(mesh); + setupLods(config); - // Add to static geometry (position at origin since vertices are in world space) - addMeshToStatic( - genData.geo, mesh, - genData.material, - Ogre::Vector3::ZERO, - Ogre::Quaternion:: - IDENTITY); + // Add to static geometry (position at origin since vertices are in world space) + addMeshToStatic( + genData.geo, mesh, + genData.material, + Ogre::Vector3::ZERO, + Ogre::Quaternion:: + IDENTITY); - addStaticBodyMesh( - genData.entity, mesh, - Ogre::Vector3::ZERO, - Ogre::Quaternion:: - IDENTITY); + addStaticBodyMesh( + genData.entity, mesh, + Ogre::Vector3::ZERO, + Ogre::Quaternion:: + IDENTITY); - lotIndex++; - } - }); + lotIndex++; + } + }); - promise->set_value(true); - }); - } - void operator()(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - createTownRoofs(e, jdistrict, index, sceneNode, geo); - } + promise->set_value(true); + }); + } + void operator()(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + createTownRoofs(e, jdistrict, index, sceneNode, geo); + } - void wait() - { - ZoneScoped; - if (townRoofsComplete.valid() && - townRoofsComplete.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) { - townRoofsComplete.wait(); - } - } + void wait() + { + ZoneScoped; + if (townRoofsComplete.valid() && + townRoofsComplete.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) { + townRoofsComplete.wait(); + } + } #if 0 @@ -5935,513 +5935,513 @@ public: }; struct TownDecorateWindows : TownTask { - std::shared_future townDecorateWindowsComplete; + std::shared_future townDecorateWindowsComplete; private: - struct DistrictContext { - Ogre::Vector3 centerPosition; - Ogre::Quaternion centerOrientation; - float radius; - }; - struct LotContext { - Ogre::Vector3 worldPosition; - Ogre::Quaternion worldOrientation; - }; - struct CellInfo { - int x, y, z; - uint64_t flags; - Ogre::Vector3 offsetX; - Ogre::Vector3 offsetY; - Ogre::Vector3 offsetZ; - }; - enum class WindowDirection { - PositiveZ, - NegativeZ, - PositiveX, - NegativeX - }; + struct DistrictContext { + Ogre::Vector3 centerPosition; + Ogre::Quaternion centerOrientation; + float radius; + }; + struct LotContext { + Ogre::Vector3 worldPosition; + Ogre::Quaternion worldOrientation; + }; + struct CellInfo { + int x, y, z; + uint64_t flags; + Ogre::Vector3 offsetX; + Ogre::Vector3 offsetY; + Ogre::Vector3 offsetZ; + }; + enum class WindowDirection { + PositiveZ, + NegativeZ, + PositiveX, + NegativeX + }; - struct WindowPlacement { - WindowDirection direction; - Ogre::Vector3 position; - Ogre::Quaternion orientation; - bool valid; - }; + struct WindowPlacement { + WindowDirection direction; + Ogre::Vector3 position; + Ogre::Quaternion orientation; + bool valid; + }; - // Constants - static constexpr float OUT_OFFSET = 1.05f; - static constexpr float WINDOW_VERTICAL_OFFSET = 0.8f; - static constexpr float CELL_WIDTH = 2.0f; - static constexpr float CELL_HEIGHT = 4.0f; - static constexpr float CELL_DEPTH = 2.0f; - DistrictContext parseDistrictContext(const nlohmann::json &jp, - Ogre::SceneNode *sceneNode) - { - DistrictContext ctx; + // Constants + static constexpr float OUT_OFFSET = 1.05f; + static constexpr float WINDOW_VERTICAL_OFFSET = 0.8f; + static constexpr float CELL_WIDTH = 2.0f; + static constexpr float CELL_HEIGHT = 4.0f; + static constexpr float CELL_DEPTH = 2.0f; + DistrictContext parseDistrictContext(const nlohmann::json &jp, + Ogre::SceneNode *sceneNode) + { + DistrictContext ctx; - // Parse base position and rotation - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); + // Parse base position and rotation + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); - // Parse elevation and radius - float elevation = jp.value("elevation", 0.0f); - ctx.radius = jp.value("radius", 50.0f); + // Parse elevation and radius + float elevation = jp.value("elevation", 0.0f); + ctx.radius = jp.value("radius", 50.0f); - // Calculate world transforms for district center - ctx.centerPosition = sceneNode->_getDerivedPosition() + - localPosition + - Ogre::Vector3(0, elevation, 0); - ctx.centerOrientation = - sceneNode->_getDerivedOrientation() * localRotation; + // Calculate world transforms for district center + ctx.centerPosition = sceneNode->_getDerivedPosition() + + localPosition + + Ogre::Vector3(0, elevation, 0); + ctx.centerOrientation = + sceneNode->_getDerivedOrientation() * localRotation; - return ctx; - } - LotContext createLotContext(const DistrictContext &districtCtx, - const nlohmann::json &jlot) - { - LotContext lot; + return ctx; + } + LotContext createLotContext(const DistrictContext &districtCtx, + const nlohmann::json &jlot) + { + LotContext lot; - // Parse lot properties - float angle = jlot.value("angle", 0.0f); - float elevation = jlot.value("elevation", 0.0f); + // Parse lot properties + float angle = jlot.value("angle", 0.0f); + float elevation = jlot.value("elevation", 0.0f); - // Calculate lot rotation and position (offset from district center) - Ogre::Quaternion lotRotation(Ogre::Degree(angle), - Ogre::Vector3::UNIT_Y); - Ogre::Vector3 offset = - districtCtx.centerOrientation * lotRotation * - (Ogre::Vector3::UNIT_Z * districtCtx.radius); + // Calculate lot rotation and position (offset from district center) + Ogre::Quaternion lotRotation(Ogre::Degree(angle), + Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = + districtCtx.centerOrientation * lotRotation * + (Ogre::Vector3::UNIT_Z * districtCtx.radius); - // Lot world position = district center + offset + lot elevation - lot.worldPosition = districtCtx.centerPosition + offset + - Ogre::Vector3(0, elevation, 0); + // Lot world position = district center + offset + lot elevation + lot.worldPosition = districtCtx.centerPosition + offset + + Ogre::Vector3(0, elevation, 0); - // Lot orientation = district orientation * lot rotation - lot.worldOrientation = - districtCtx.centerOrientation * lotRotation; + // Lot orientation = district orientation * lot rotation + lot.worldOrientation = + districtCtx.centerOrientation * lotRotation; - return lot; - } - CellInfo createCellInfo(const nlohmann::json &jcell, - const LotContext &lotCtx) - { - CellInfo cell; - cell.x = jcell.value("x", 0); - cell.y = jcell.value("y", 0); - cell.z = jcell.value("z", 0); - cell.flags = jcell.value("flags", 0ULL); + return lot; + } + CellInfo createCellInfo(const nlohmann::json &jcell, + const LotContext &lotCtx) + { + CellInfo cell; + cell.x = jcell.value("x", 0); + cell.y = jcell.value("y", 0); + cell.z = jcell.value("z", 0); + cell.flags = jcell.value("flags", 0ULL); - // Calculate cell offsets - cell.offsetX = lotCtx.worldOrientation * Ogre::Vector3::UNIT_X * - static_cast(cell.x) * CELL_WIDTH; - cell.offsetZ = lotCtx.worldOrientation * Ogre::Vector3::UNIT_Z * - static_cast(cell.z) * CELL_DEPTH; - cell.offsetY = Ogre::Vector3(0, cell.y * CELL_HEIGHT, 0); + // Calculate cell offsets + cell.offsetX = lotCtx.worldOrientation * Ogre::Vector3::UNIT_X * + static_cast(cell.x) * CELL_WIDTH; + cell.offsetZ = lotCtx.worldOrientation * Ogre::Vector3::UNIT_Z * + static_cast(cell.z) * CELL_DEPTH; + cell.offsetY = Ogre::Vector3(0, cell.y * CELL_HEIGHT, 0); - return cell; - } - std::vector - checkForWindows(const nlohmann::json &jcell, const CellInfo &cell, - const LotContext &lotCtx) - { - std::vector windows; + return cell; + } + std::vector + checkForWindows(const nlohmann::json &jcell, const CellInfo &cell, + const LotContext &lotCtx) + { + std::vector windows; - // Helper lambda to create window placement - auto addWindow = [&](WindowDirection dir, - const Ogre::Vector3 &offsetDir, - float rotationDegrees) { - WindowPlacement window; - window.direction = dir; - window.valid = true; + // Helper lambda to create window placement + auto addWindow = [&](WindowDirection dir, + const Ogre::Vector3 &offsetDir, + float rotationDegrees) { + WindowPlacement window; + window.direction = dir; + window.valid = true; - // Calculate offset with vertical adjustment - Ogre::Vector3 offset = - lotCtx.worldOrientation * offsetDir * - OUT_OFFSET + - Ogre::Vector3::UNIT_Y * WINDOW_VERTICAL_OFFSET; + // Calculate offset with vertical adjustment + Ogre::Vector3 offset = + lotCtx.worldOrientation * offsetDir * + OUT_OFFSET + + Ogre::Vector3::UNIT_Y * WINDOW_VERTICAL_OFFSET; - window.position = lotCtx.worldPosition + cell.offsetX + - cell.offsetZ + cell.offsetY + offset; + window.position = lotCtx.worldPosition + cell.offsetX + + cell.offsetZ + cell.offsetY + offset; - window.orientation = - lotCtx.worldOrientation * - Ogre::Quaternion(Ogre::Degree(rotationDegrees), - Ogre::Vector3::UNIT_Y); - windows.push_back(window); - }; + window.orientation = + lotCtx.worldOrientation * + Ogre::Quaternion(Ogre::Degree(rotationDegrees), + Ogre::Vector3::UNIT_Y); + windows.push_back(window); + }; - // Check each window direction using the original jcell JSON object - if (Items::CellsScript::isBit(jcell, "windowz+")) { - addWindow(WindowDirection::PositiveZ, - Ogre::Vector3::UNIT_Z, 0.0f); - } - if (Items::CellsScript::isBit(jcell, "windowz-")) { - addWindow(WindowDirection::NegativeZ, - Ogre::Vector3::NEGATIVE_UNIT_Z, 180.0f); - } - if (Items::CellsScript::isBit(jcell, "windowx+")) { - addWindow(WindowDirection::PositiveX, - Ogre::Vector3::UNIT_X, 90.0f); - } - if (Items::CellsScript::isBit(jcell, "windowx-")) { - addWindow(WindowDirection::NegativeX, - Ogre::Vector3::NEGATIVE_UNIT_X, -90.0f); - } + // Check each window direction using the original jcell JSON object + if (Items::CellsScript::isBit(jcell, "windowz+")) { + addWindow(WindowDirection::PositiveZ, + Ogre::Vector3::UNIT_Z, 0.0f); + } + if (Items::CellsScript::isBit(jcell, "windowz-")) { + addWindow(WindowDirection::NegativeZ, + Ogre::Vector3::NEGATIVE_UNIT_Z, 180.0f); + } + if (Items::CellsScript::isBit(jcell, "windowx+")) { + addWindow(WindowDirection::PositiveX, + Ogre::Vector3::UNIT_X, 90.0f); + } + if (Items::CellsScript::isBit(jcell, "windowx-")) { + addWindow(WindowDirection::NegativeX, + Ogre::Vector3::NEGATIVE_UNIT_X, -90.0f); + } - return windows; - } + return windows; + } - void placeWindow(Ogre::StaticGeometry *geo, - const WindowPlacement &window, - Ogre::MaterialPtr townMaterial) - { - // Create window entity - Ogre::Entity *ent = - ECS::get().mScnMgr->createEntity( - "window-cell", "window-frame1"); - ent->setMaterial(townMaterial); + void placeWindow(Ogre::StaticGeometry *geo, + const WindowPlacement &window, + Ogre::MaterialPtr townMaterial) + { + // Create window entity + Ogre::Entity *ent = + ECS::get().mScnMgr->createEntity( + "window-cell", "window-frame1"); + ent->setMaterial(townMaterial); - // Add to static geometry - geo->addEntity(ent, window.position, window.orientation); + // Add to static geometry + geo->addEntity(ent, window.position, window.orientation); - // Clean up - ECS::get().mScnMgr->destroyEntity(ent); - } - void processLot(flecs::entity e, const nlohmann::json &jlot, - const DistrictContext &districtCtx, - Ogre::StaticGeometry *geo, - Ogre::MaterialPtr townMaterial) - { - // Validate lot dimensions - int depth = jlot.value("depth", 10); - int width = jlot.value("width", 10); - OgreAssert(width > 1 && depth > 1, "Invalid lot dimensions"); + // Clean up + ECS::get().mScnMgr->destroyEntity(ent); + } + void processLot(flecs::entity e, const nlohmann::json &jlot, + const DistrictContext &districtCtx, + Ogre::StaticGeometry *geo, + Ogre::MaterialPtr townMaterial) + { + // Validate lot dimensions + int depth = jlot.value("depth", 10); + int width = jlot.value("width", 10); + OgreAssert(width > 1 && depth > 1, "Invalid lot dimensions"); - // Create lot context with position offset from district center - LotContext lotCtx = createLotContext(districtCtx, jlot); + // Create lot context with position offset from district center + LotContext lotCtx = createLotContext(districtCtx, jlot); - // Process cells - if (jlot.contains("cells") && jlot["cells"].is_array()) { - const nlohmann::json &cells = jlot["cells"]; - for (nlohmann::json::const_iterator it = cells.begin(); - it != cells.end(); ++it) { - const nlohmann::json &jcell = *it; + // Process cells + if (jlot.contains("cells") && jlot["cells"].is_array()) { + const nlohmann::json &cells = jlot["cells"]; + for (nlohmann::json::const_iterator it = cells.begin(); + it != cells.end(); ++it) { + const nlohmann::json &jcell = *it; - CellInfo cell = createCellInfo(jcell, lotCtx); - std::vector windows = - checkForWindows(jcell, cell, lotCtx); + CellInfo cell = createCellInfo(jcell, lotCtx); + std::vector windows = + checkForWindows(jcell, cell, lotCtx); - for (const auto &window : windows) { - placeWindow(geo, window, townMaterial); - } - } - } - } + for (const auto &window : windows) { + placeWindow(geo, window, townMaterial); + } + } + } + } public: - void createDecorateWindows(flecs::entity e, - const nlohmann::json &jdistrict, - int /*index*/, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - // FIXME: make window placement a background task. + void createDecorateWindows(flecs::entity e, + const nlohmann::json &jdistrict, + int /*index*/, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + // FIXME: make window placement a background task. - // Create town material - Ogre::MaterialPtr townMaterial = createTownMaterial(e); + // Create town material + Ogre::MaterialPtr townMaterial = createTownMaterial(e); - // Parse district context (center point) - DistrictContext districtCtx = - parseDistrictContext(jdistrict, sceneNode); + // Parse district context (center point) + DistrictContext districtCtx = + parseDistrictContext(jdistrict, sceneNode); - // Process lots if they exist - if (jdistrict.contains("lots") && - jdistrict["lots"].is_array()) { - const nlohmann::json &lots = jdistrict["lots"]; - for (nlohmann::json::const_iterator it = lots.begin(); - it != lots.end(); ++it) { - const nlohmann::json &jlot = *it; - std::cout << jlot.dump() << std::endl; - processLot(e, jlot, districtCtx, geo, - townMaterial); - } - } - } - void operator()(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - createDecorateWindows(e, jdistrict, index, sceneNode, geo); - } - void wait() - { - ZoneScoped; - if (townDecorateWindowsComplete.valid() && - townDecorateWindowsComplete.wait_for(std::chrono::seconds( - 0)) != std::future_status::ready) - townDecorateWindowsComplete.wait(); - } + // Process lots if they exist + if (jdistrict.contains("lots") && + jdistrict["lots"].is_array()) { + const nlohmann::json &lots = jdistrict["lots"]; + for (nlohmann::json::const_iterator it = lots.begin(); + it != lots.end(); ++it) { + const nlohmann::json &jlot = *it; + std::cout << jlot.dump() << std::endl; + processLot(e, jlot, districtCtx, geo, + townMaterial); + } + } + } + void operator()(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + createDecorateWindows(e, jdistrict, index, sceneNode, geo); + } + void wait() + { + ZoneScoped; + if (townDecorateWindowsComplete.valid() && + townDecorateWindowsComplete.wait_for(std::chrono::seconds( + 0)) != std::future_status::ready) + townDecorateWindowsComplete.wait(); + } }; struct TownDecorateDoors : TownTask { - std::shared_future townDecorateDoorsComplete; + std::shared_future townDecorateDoorsComplete; private: - struct DistrictContext { - Ogre::Vector3 centerPosition; - Ogre::Quaternion centerOrientation; - float radius; - }; + struct DistrictContext { + Ogre::Vector3 centerPosition; + Ogre::Quaternion centerOrientation; + float radius; + }; - struct LotContext { - Ogre::Vector3 worldPosition; - Ogre::Quaternion worldOrientation; - }; + struct LotContext { + Ogre::Vector3 worldPosition; + Ogre::Quaternion worldOrientation; + }; - struct CellInfo { - int x, y, z; - uint64_t flags; - Ogre::Vector3 offsetX; - Ogre::Vector3 offsetY; - Ogre::Vector3 offsetZ; - }; + struct CellInfo { + int x, y, z; + uint64_t flags; + Ogre::Vector3 offsetX; + Ogre::Vector3 offsetY; + Ogre::Vector3 offsetZ; + }; - enum class DoorType { External, Internal }; + enum class DoorType { External, Internal }; - enum class DoorDirection { PositiveZ, NegativeZ, PositiveX, NegativeX }; + enum class DoorDirection { PositiveZ, NegativeZ, PositiveX, NegativeX }; - struct DoorPlacement { - DoorType type; - DoorDirection direction; - Ogre::Vector3 position; - Ogre::Quaternion orientation; - bool valid; - }; - DistrictContext parseDistrictContext(const nlohmann::json &jp, - Ogre::SceneNode *sceneNode) - { - DistrictContext ctx; + struct DoorPlacement { + DoorType type; + DoorDirection direction; + Ogre::Vector3 position; + Ogre::Quaternion orientation; + bool valid; + }; + DistrictContext parseDistrictContext(const nlohmann::json &jp, + Ogre::SceneNode *sceneNode) + { + DistrictContext ctx; - // Parse base position and rotation - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); + // Parse base position and rotation + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); - // Parse elevation and radius - float elevation = jp.value("elevation", 0.0f); - ctx.radius = jp.value("radius", 50.0f); + // Parse elevation and radius + float elevation = jp.value("elevation", 0.0f); + ctx.radius = jp.value("radius", 50.0f); - // Calculate world transforms for district center - ctx.centerPosition = sceneNode->_getDerivedPosition() + - localPosition + - Ogre::Vector3(0, elevation, 0); - ctx.centerOrientation = - sceneNode->_getDerivedOrientation() * localRotation; + // Calculate world transforms for district center + ctx.centerPosition = sceneNode->_getDerivedPosition() + + localPosition + + Ogre::Vector3(0, elevation, 0); + ctx.centerOrientation = + sceneNode->_getDerivedOrientation() * localRotation; - return ctx; - } - LotContext createLotContext(const DistrictContext &districtCtx, - const nlohmann::json &jlot) - { - LotContext lot; + return ctx; + } + LotContext createLotContext(const DistrictContext &districtCtx, + const nlohmann::json &jlot) + { + LotContext lot; - // Parse lot properties - float angle = jlot.value("angle", 0.0f); - float elevation = jlot.value("elevation", 0.0f); + // Parse lot properties + float angle = jlot.value("angle", 0.0f); + float elevation = jlot.value("elevation", 0.0f); - // Calculate lot rotation and position (offset from district center) - Ogre::Quaternion lotRotation(Ogre::Degree(angle), - Ogre::Vector3::UNIT_Y); - Ogre::Vector3 offset = - districtCtx.centerOrientation * lotRotation * - (Ogre::Vector3::UNIT_Z * districtCtx.radius); + // Calculate lot rotation and position (offset from district center) + Ogre::Quaternion lotRotation(Ogre::Degree(angle), + Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = + districtCtx.centerOrientation * lotRotation * + (Ogre::Vector3::UNIT_Z * districtCtx.radius); - // Lot world position = district center + offset + lot elevation - lot.worldPosition = districtCtx.centerPosition + offset + - Ogre::Vector3(0, elevation, 0); + // Lot world position = district center + offset + lot elevation + lot.worldPosition = districtCtx.centerPosition + offset + + Ogre::Vector3(0, elevation, 0); - // Lot orientation = district orientation * lot rotation - lot.worldOrientation = - districtCtx.centerOrientation * lotRotation; + // Lot orientation = district orientation * lot rotation + lot.worldOrientation = + districtCtx.centerOrientation * lotRotation; - return lot; - } - CellInfo createCellInfo(const nlohmann::json &jcell, - const LotContext &lotCtx) - { - CellInfo cell; - cell.x = jcell.value("x", 0); - cell.y = jcell.value("y", 0); - cell.z = jcell.value("z", 0); - cell.flags = jcell.value("flags", 0ULL); + return lot; + } + CellInfo createCellInfo(const nlohmann::json &jcell, + const LotContext &lotCtx) + { + CellInfo cell; + cell.x = jcell.value("x", 0); + cell.y = jcell.value("y", 0); + cell.z = jcell.value("z", 0); + cell.flags = jcell.value("flags", 0ULL); - // Calculate cell offsets - cell.offsetX = lotCtx.worldOrientation * Ogre::Vector3::UNIT_X * - static_cast(cell.x) * 2.0f; - cell.offsetZ = lotCtx.worldOrientation * Ogre::Vector3::UNIT_Z * - static_cast(cell.z) * 2.0f; - cell.offsetY = Ogre::Vector3(0, cell.y * 4.0f, 0); + // Calculate cell offsets + cell.offsetX = lotCtx.worldOrientation * Ogre::Vector3::UNIT_X * + static_cast(cell.x) * 2.0f; + cell.offsetZ = lotCtx.worldOrientation * Ogre::Vector3::UNIT_Z * + static_cast(cell.z) * 2.0f; + cell.offsetY = Ogre::Vector3(0, cell.y * 4.0f, 0); - return cell; - } - std::vector checkForDoors(const nlohmann::json &jcell, - const CellInfo &cell, - const LotContext &lotCtx) - { - std::vector doors; - const float outOffset = 1.05f; - auto addDoor = [&](DoorType type, DoorDirection dir, - const Ogre::Vector3 &offsetDir, - float rotationDegrees) { - DoorPlacement door; - door.type = type; - door.direction = dir; - door.valid = true; + return cell; + } + std::vector checkForDoors(const nlohmann::json &jcell, + const CellInfo &cell, + const LotContext &lotCtx) + { + std::vector doors; + const float outOffset = 1.05f; + auto addDoor = [&](DoorType type, DoorDirection dir, + const Ogre::Vector3 &offsetDir, + float rotationDegrees) { + DoorPlacement door; + door.type = type; + door.direction = dir; + door.valid = true; - // Calculate offset and rotation - Ogre::Vector3 offset = - lotCtx.worldOrientation * offsetDir * outOffset; - door.position = lotCtx.worldPosition + cell.offsetX + - cell.offsetZ + cell.offsetY + offset; - door.orientation = - lotCtx.worldOrientation * - Ogre::Quaternion(Ogre::Degree(rotationDegrees), - Ogre::Vector3::UNIT_Y); - doors.push_back(door); - }; - if (Items::CellsScript::isBit(jcell, "doorz+")) { - addDoor(DoorType::External, DoorDirection::PositiveZ, - Ogre::Vector3::UNIT_Z, 0.0f); - } - if (Items::CellsScript::isBit(jcell, "idoorz+")) { - addDoor(DoorType::Internal, DoorDirection::PositiveZ, - Ogre::Vector3::UNIT_Z, 0.0f); - } - if (Items::CellsScript::isBit(jcell, "doorz-")) { - addDoor(DoorType::External, DoorDirection::NegativeZ, - Ogre::Vector3::NEGATIVE_UNIT_Z, 180.0f); - } - if (Items::CellsScript::isBit(jcell, "idoorz-")) { - addDoor(DoorType::Internal, DoorDirection::NegativeZ, - Ogre::Vector3::NEGATIVE_UNIT_Z, 180.0f); - } - if (Items::CellsScript::isBit(jcell, "doorx+")) { - addDoor(DoorType::External, DoorDirection::PositiveX, - Ogre::Vector3::UNIT_X, 90.0f); - } - if (Items::CellsScript::isBit(jcell, "idoorx+")) { - addDoor(DoorType::Internal, DoorDirection::PositiveX, - Ogre::Vector3::UNIT_X, 90.0f); - } - if (Items::CellsScript::isBit(jcell, "doorx-")) { - addDoor(DoorType::External, DoorDirection::NegativeX, - Ogre::Vector3::NEGATIVE_UNIT_X, -90.0f); - } - if (Items::CellsScript::isBit(jcell, "idoorx-")) { - addDoor(DoorType::Internal, DoorDirection::NegativeX, - Ogre::Vector3::NEGATIVE_UNIT_X, -90.0f); - } + // Calculate offset and rotation + Ogre::Vector3 offset = + lotCtx.worldOrientation * offsetDir * outOffset; + door.position = lotCtx.worldPosition + cell.offsetX + + cell.offsetZ + cell.offsetY + offset; + door.orientation = + lotCtx.worldOrientation * + Ogre::Quaternion(Ogre::Degree(rotationDegrees), + Ogre::Vector3::UNIT_Y); + doors.push_back(door); + }; + if (Items::CellsScript::isBit(jcell, "doorz+")) { + addDoor(DoorType::External, DoorDirection::PositiveZ, + Ogre::Vector3::UNIT_Z, 0.0f); + } + if (Items::CellsScript::isBit(jcell, "idoorz+")) { + addDoor(DoorType::Internal, DoorDirection::PositiveZ, + Ogre::Vector3::UNIT_Z, 0.0f); + } + if (Items::CellsScript::isBit(jcell, "doorz-")) { + addDoor(DoorType::External, DoorDirection::NegativeZ, + Ogre::Vector3::NEGATIVE_UNIT_Z, 180.0f); + } + if (Items::CellsScript::isBit(jcell, "idoorz-")) { + addDoor(DoorType::Internal, DoorDirection::NegativeZ, + Ogre::Vector3::NEGATIVE_UNIT_Z, 180.0f); + } + if (Items::CellsScript::isBit(jcell, "doorx+")) { + addDoor(DoorType::External, DoorDirection::PositiveX, + Ogre::Vector3::UNIT_X, 90.0f); + } + if (Items::CellsScript::isBit(jcell, "idoorx+")) { + addDoor(DoorType::Internal, DoorDirection::PositiveX, + Ogre::Vector3::UNIT_X, 90.0f); + } + if (Items::CellsScript::isBit(jcell, "doorx-")) { + addDoor(DoorType::External, DoorDirection::NegativeX, + Ogre::Vector3::NEGATIVE_UNIT_X, -90.0f); + } + if (Items::CellsScript::isBit(jcell, "idoorx-")) { + addDoor(DoorType::Internal, DoorDirection::NegativeX, + Ogre::Vector3::NEGATIVE_UNIT_X, -90.0f); + } - return doors; - } + return doors; + } - void placeDoor(Ogre::StaticGeometry *geo, const DoorPlacement &door, - Ogre::MaterialPtr townMaterial) - { - const char *meshName = (door.type == DoorType::External) ? - "external-door-frame1" : - "internal-door-frame1"; + void placeDoor(Ogre::StaticGeometry *geo, const DoorPlacement &door, + Ogre::MaterialPtr townMaterial) + { + const char *meshName = (door.type == DoorType::External) ? + "external-door-frame1" : + "internal-door-frame1"; - if (door.direction == DoorDirection::PositiveZ || - door.direction == DoorDirection::NegativeZ) { - // Use entity approach for Z-axis doors (original code used this) - const char *entityName = - (door.type == DoorType::External) ? - "door-cell" : - "idoor-cell"; + if (door.direction == DoorDirection::PositiveZ || + door.direction == DoorDirection::NegativeZ) { + // Use entity approach for Z-axis doors (original code used this) + const char *entityName = + (door.type == DoorType::External) ? + "door-cell" : + "idoor-cell"; - Ogre::Entity *ent = - ECS::get().mScnMgr->createEntity( - entityName, meshName); - ent->setMaterial(townMaterial); + Ogre::Entity *ent = + ECS::get().mScnMgr->createEntity( + entityName, meshName); + ent->setMaterial(townMaterial); - geo->addEntity(ent, door.position, door.orientation); - ECS::get().mScnMgr->destroyEntity(ent); - } else { - // Use mesh approach for X-axis doors (original code used addMeshToStatic) - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton().getByName( - meshName); - if (mesh) { - addMeshToStatic(geo, mesh, townMaterial, - door.position, - door.orientation); - } - } - } - void processLot(flecs::entity e, const nlohmann::json &jlot, - const DistrictContext &districtCtx, - Ogre::StaticGeometry *geo, - Ogre::MaterialPtr townMaterial) - { - // Validate lot dimensions - int depth = jlot.value("depth", 10); - int width = jlot.value("width", 10); - OgreAssert(width > 1 && depth > 1, "Invalid lot dimensions"); + geo->addEntity(ent, door.position, door.orientation); + ECS::get().mScnMgr->destroyEntity(ent); + } else { + // Use mesh approach for X-axis doors (original code used addMeshToStatic) + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton().getByName( + meshName); + if (mesh) { + addMeshToStatic(geo, mesh, townMaterial, + door.position, + door.orientation); + } + } + } + void processLot(flecs::entity e, const nlohmann::json &jlot, + const DistrictContext &districtCtx, + Ogre::StaticGeometry *geo, + Ogre::MaterialPtr townMaterial) + { + // Validate lot dimensions + int depth = jlot.value("depth", 10); + int width = jlot.value("width", 10); + OgreAssert(width > 1 && depth > 1, "Invalid lot dimensions"); - // Create lot context with position offset from district center - LotContext lotCtx = createLotContext(districtCtx, jlot); + // Create lot context with position offset from district center + LotContext lotCtx = createLotContext(districtCtx, jlot); - // Process cells - if (jlot.contains("cells") && jlot["cells"].is_array()) { - const nlohmann::json &cells = jlot["cells"]; - for (nlohmann::json::const_iterator it = cells.begin(); - it != cells.end(); ++it) { - const nlohmann::json &jcell = *it; + // Process cells + if (jlot.contains("cells") && jlot["cells"].is_array()) { + const nlohmann::json &cells = jlot["cells"]; + for (nlohmann::json::const_iterator it = cells.begin(); + it != cells.end(); ++it) { + const nlohmann::json &jcell = *it; - CellInfo cell = createCellInfo(jcell, lotCtx); - std::vector doors = - checkForDoors(jcell, cell, lotCtx); + CellInfo cell = createCellInfo(jcell, lotCtx); + std::vector doors = + checkForDoors(jcell, cell, lotCtx); - for (const auto &door : doors) { - placeDoor(geo, door, townMaterial); - } - } - } - } + for (const auto &door : doors) { + placeDoor(geo, door, townMaterial); + } + } + } + } public: - void createDecorateDoors(flecs::entity e, - const nlohmann::json &jdistrict, int /*index*/, - Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - // FIXME: make door placement a background task. + void createDecorateDoors(flecs::entity e, + const nlohmann::json &jdistrict, int /*index*/, + Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + // FIXME: make door placement a background task. - // Create town material - Ogre::MaterialPtr townMaterial = createTownMaterial(e); + // Create town material + Ogre::MaterialPtr townMaterial = createTownMaterial(e); - // Parse district context (center point) - DistrictContext districtCtx = - parseDistrictContext(jdistrict, sceneNode); + // Parse district context (center point) + DistrictContext districtCtx = + parseDistrictContext(jdistrict, sceneNode); - // Process lots if they exist - if (jdistrict.contains("lots") && - jdistrict["lots"].is_array()) { - const nlohmann::json &lots = jdistrict["lots"]; - for (nlohmann::json::const_iterator it = lots.begin(); - it != lots.end(); ++it) { - const nlohmann::json &jlot = *it; - std::cout << jlot.dump() << std::endl; - processLot(e, jlot, districtCtx, geo, - townMaterial); - } - } - } + // Process lots if they exist + if (jdistrict.contains("lots") && + jdistrict["lots"].is_array()) { + const nlohmann::json &lots = jdistrict["lots"]; + for (nlohmann::json::const_iterator it = lots.begin(); + it != lots.end(); ++it) { + const nlohmann::json &jlot = *it; + std::cout << jlot.dump() << std::endl; + processLot(e, jlot, districtCtx, geo, + townMaterial); + } + } + } #if 0 void createDecorateDoors(flecs::entity e, const nlohmann::json &jdistrict, int index, @@ -6743,541 +6743,541 @@ public: } } #endif - void operator()(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - ZoneScoped; - createDecorateDoors(e, jdistrict, index, sceneNode, geo); - } - void wait() - { - ZoneScoped; - if (townDecorateDoorsComplete.valid() && - townDecorateDoorsComplete.wait_for(std::chrono::seconds( - 0)) != std::future_status::ready) - townDecorateDoorsComplete.wait(); - } + void operator()(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + ZoneScoped; + createDecorateDoors(e, jdistrict, index, sceneNode, geo); + } + void wait() + { + ZoneScoped; + if (townDecorateDoorsComplete.valid() && + townDecorateDoorsComplete.wait_for(std::chrono::seconds( + 0)) != std::future_status::ready) + townDecorateDoorsComplete.wait(); + } }; struct TownDecorateFurniture : TownTask { - std::shared_future townDecorateFurnitureComplete; - /* here we place all the furniture as scene objects */ + std::shared_future townDecorateFurnitureComplete; + /* here we place all the furniture as scene objects */ private: - struct DistrictContext { - Ogre::Vector3 centerPosition; - Ogre::Quaternion centerOrientation; - float radius; - }; + struct DistrictContext { + Ogre::Vector3 centerPosition; + Ogre::Quaternion centerOrientation; + float radius; + }; - struct LotContext { - Ogre::Vector3 worldPosition; - Ogre::Quaternion worldOrientation; - float elevation; - }; + struct LotContext { + Ogre::Vector3 worldPosition; + Ogre::Quaternion worldOrientation; + float elevation; + }; - struct CellPlacement { - int x, y, z; - int rotation; - Ogre::String meshName; - Ogre::Vector3 position; - Ogre::Quaternion orientation; - bool valid; - }; + struct CellPlacement { + int x, y, z; + int rotation; + Ogre::String meshName; + Ogre::Vector3 position; + Ogre::Quaternion orientation; + bool valid; + }; - Ogre::MeshPtr getFurnitureMesh(const Ogre::String &meshName) - { - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton().getByName(meshName); - if (!mesh) { - if (Ogre::ResourceGroupManager::getSingleton() - .resourceExists("General", meshName)) { - mesh = Ogre::MeshManager::getSingleton().load( - meshName, "General"); - Ogre::LodConfig meshconf(mesh); - setupLods(meshconf); - } - } - return mesh; - } - void placeFurnitureMesh(flecs::entity e, Ogre::MeshPtr mesh, - const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation) - { - static Ogre::String materialName1 = ""; - static Ogre::String materialName2 = ""; - Ogre::Entity *ent = - ECS::get().mScnMgr->createEntity( - mesh->getName()); - Ogre::String tmpMatName = - mesh->getSubMesh(0)->getMaterialName(); - if (tmpMatName.substr(0, 14) == "furniture-sofa") { - if (materialName2 == "") - materialName2 = tmpMatName; - else - ent->setMaterialName( + Ogre::MeshPtr getFurnitureMesh(const Ogre::String &meshName) + { + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton().getByName(meshName); + if (!mesh) { + if (Ogre::ResourceGroupManager::getSingleton() + .resourceExists("General", meshName)) { + mesh = Ogre::MeshManager::getSingleton().load( + meshName, "General"); + Ogre::LodConfig meshconf(mesh); + setupLods(meshconf); + } + } + return mesh; + } + void placeFurnitureMesh(flecs::entity e, Ogre::MeshPtr mesh, + const Ogre::Vector3 &position, + const Ogre::Quaternion &rotation) + { + static Ogre::String materialName1 = ""; + static Ogre::String materialName2 = ""; + Ogre::Entity *ent = + ECS::get().mScnMgr->createEntity( + mesh->getName()); + Ogre::String tmpMatName = + mesh->getSubMesh(0)->getMaterialName(); + if (tmpMatName.substr(0, 14) == "furniture-sofa") { + if (materialName2 == "") + materialName2 = tmpMatName; + else + ent->setMaterialName( - materialName2); - } else { - if (materialName1 == "") - materialName1 = tmpMatName; - else - ent->setMaterialName(materialName1); - } - Ogre::SceneNode *node = ECS::get() - .mScnMgr->getRootSceneNode() - ->createChildSceneNode(); - node->_setDerivedPosition(position); - node->_setDerivedOrientation(rotation); - node->attachObject(ent); - ent->setRenderingDistance(60.0f); - addStaticBodyMesh(e, mesh, position, rotation); - ECS::get().entity().child_of(e).set( - { node }); - } - DistrictContext parseDistrictContext(const nlohmann::json &jp, - Ogre::SceneNode *sceneNode) - { - DistrictContext ctx; + materialName2); + } else { + if (materialName1 == "") + materialName1 = tmpMatName; + else + ent->setMaterialName(materialName1); + } + Ogre::SceneNode *node = ECS::get() + .mScnMgr->getRootSceneNode() + ->createChildSceneNode(); + node->_setDerivedPosition(position); + node->_setDerivedOrientation(rotation); + node->attachObject(ent); + ent->setRenderingDistance(60.0f); + addStaticBodyMesh(e, mesh, position, rotation); + ECS::get().entity().child_of(e).set( + { node }); + } + DistrictContext parseDistrictContext(const nlohmann::json &jp, + Ogre::SceneNode *sceneNode) + { + DistrictContext ctx; - // Parse base position and rotation - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); + // Parse base position and rotation + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); - // Parse elevation and radius - float elevation = jp.value("elevation", 0.0f); - ctx.radius = jp.value("radius", 50.0f); + // Parse elevation and radius + float elevation = jp.value("elevation", 0.0f); + ctx.radius = jp.value("radius", 50.0f); - // Calculate world transforms for district center - ctx.centerPosition = sceneNode->_getDerivedPosition() + - localPosition + - Ogre::Vector3(0, elevation, 0); - ctx.centerOrientation = - sceneNode->_getDerivedOrientation() * localRotation; + // Calculate world transforms for district center + ctx.centerPosition = sceneNode->_getDerivedPosition() + + localPosition + + Ogre::Vector3(0, elevation, 0); + ctx.centerOrientation = + sceneNode->_getDerivedOrientation() * localRotation; - return ctx; - } - LotContext createLotContext(const DistrictContext &districtCtx, - const nlohmann::json &jlot) - { - LotContext lot; + return ctx; + } + LotContext createLotContext(const DistrictContext &districtCtx, + const nlohmann::json &jlot) + { + LotContext lot; - // Parse lot properties - float angle = jlot.value("angle", 0.0f); - lot.elevation = jlot.value("elevation", 0.0f); + // Parse lot properties + float angle = jlot.value("angle", 0.0f); + lot.elevation = jlot.value("elevation", 0.0f); - // Calculate lot rotation and position (offset from district center) - Ogre::Quaternion lotRotation(Ogre::Degree(angle), - Ogre::Vector3::UNIT_Y); - Ogre::Vector3 offset = - districtCtx.centerOrientation * lotRotation * - (Ogre::Vector3::UNIT_Z * districtCtx.radius); + // Calculate lot rotation and position (offset from district center) + Ogre::Quaternion lotRotation(Ogre::Degree(angle), + Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = + districtCtx.centerOrientation * lotRotation * + (Ogre::Vector3::UNIT_Z * districtCtx.radius); - // Lot world position = district center + offset + lot elevation - lot.worldPosition = districtCtx.centerPosition + offset + - Ogre::Vector3(0, lot.elevation, 0); + // Lot world position = district center + offset + lot elevation + lot.worldPosition = districtCtx.centerPosition + offset + + Ogre::Vector3(0, lot.elevation, 0); - // Lot orientation = district orientation * lot rotation - lot.worldOrientation = - districtCtx.centerOrientation * lotRotation; + // Lot orientation = district orientation * lot rotation + lot.worldOrientation = + districtCtx.centerOrientation * lotRotation; - return lot; - } - CellPlacement createCellPlacement(const nlohmann::json &jfcell, - const LotContext &lotCtx) - { - CellPlacement cell; - cell.valid = false; + return lot; + } + CellPlacement createCellPlacement(const nlohmann::json &jfcell, + const LotContext &lotCtx) + { + CellPlacement cell; + cell.valid = false; - // Check if cell has furniture with mesh - if (!jfcell.is_object() || !jfcell.contains("furniture")) { - return cell; - } + // Check if cell has furniture with mesh + if (!jfcell.is_object() || !jfcell.contains("furniture")) { + return cell; + } - const nlohmann::json &furniture = jfcell["furniture"]; - if (!furniture.is_object() || !furniture.contains("mesh")) { - return cell; - } + const nlohmann::json &furniture = jfcell["furniture"]; + if (!furniture.is_object() || !furniture.contains("mesh")) { + return cell; + } - cell.x = jfcell.value("x", 0); - cell.y = jfcell.value("y", 0); - cell.z = jfcell.value("z", 0); - cell.rotation = jfcell.value("rotation", 2); - cell.meshName = furniture["mesh"].get(); + cell.x = jfcell.value("x", 0); + cell.y = jfcell.value("y", 0); + cell.z = jfcell.value("z", 0); + cell.rotation = jfcell.value("rotation", 2); + cell.meshName = furniture["mesh"].get(); - // Calculate cell offsets within the lot - Ogre::Vector3 offsetX = lotCtx.worldOrientation * - Ogre::Vector3::UNIT_X * - static_cast(cell.x) * 2.0f; - Ogre::Vector3 offsetZ = lotCtx.worldOrientation * - Ogre::Vector3::UNIT_Z * - static_cast(cell.z) * 2.0f; - Ogre::Vector3 offsetY(0, cell.y * 4.0f, 0); + // Calculate cell offsets within the lot + Ogre::Vector3 offsetX = lotCtx.worldOrientation * + Ogre::Vector3::UNIT_X * + static_cast(cell.x) * 2.0f; + Ogre::Vector3 offsetZ = lotCtx.worldOrientation * + Ogre::Vector3::UNIT_Z * + static_cast(cell.z) * 2.0f; + Ogre::Vector3 offsetY(0, cell.y * 4.0f, 0); - // Cell position = lot position + cell offsets - cell.position = - lotCtx.worldPosition + offsetX + offsetZ + offsetY; + // Cell position = lot position + cell offsets + cell.position = + lotCtx.worldPosition + offsetX + offsetZ + offsetY; - // Cell orientation = lot orientation * rotation - cell.orientation = - lotCtx.worldOrientation * - Ogre::Quaternion(Ogre::Degree(90.0f * cell.rotation), - Ogre::Vector3::UNIT_Y); + // Cell orientation = lot orientation * rotation + cell.orientation = + lotCtx.worldOrientation * + Ogre::Quaternion(Ogre::Degree(90.0f * cell.rotation), + Ogre::Vector3::UNIT_Y); - cell.valid = true; - return cell; - } + cell.valid = true; + return cell; + } - void processLot(flecs::entity e, const nlohmann::json &jlot, - const DistrictContext &districtCtx) - { - // Validate lot dimensions - int depth = jlot.value("depth", 10); - int width = jlot.value("width", 10); - OgreAssert(width > 1 && depth > 1, "Invalid lot dimensions"); + void processLot(flecs::entity e, const nlohmann::json &jlot, + const DistrictContext &districtCtx) + { + // Validate lot dimensions + int depth = jlot.value("depth", 10); + int width = jlot.value("width", 10); + OgreAssert(width > 1 && depth > 1, "Invalid lot dimensions"); - // Create lot context with position offset from district center - LotContext lotCtx = createLotContext(districtCtx, jlot); + // Create lot context with position offset from district center + LotContext lotCtx = createLotContext(districtCtx, jlot); - // Process furniture cells - if (jlot.contains("furniture_cells") && - jlot["furniture_cells"].is_array()) { - const nlohmann::json &cells = jlot["furniture_cells"]; - for (nlohmann::json::const_iterator it = cells.begin(); - it != cells.end(); ++it) { - const nlohmann::json &jfcell = *it; + // Process furniture cells + if (jlot.contains("furniture_cells") && + jlot["furniture_cells"].is_array()) { + const nlohmann::json &cells = jlot["furniture_cells"]; + for (nlohmann::json::const_iterator it = cells.begin(); + it != cells.end(); ++it) { + const nlohmann::json &jfcell = *it; - CellPlacement cell = - createCellPlacement(jfcell, lotCtx); - if (!cell.valid) - continue; + CellPlacement cell = + createCellPlacement(jfcell, lotCtx); + if (!cell.valid) + continue; - Ogre::MeshPtr mesh = - getFurnitureMesh(cell.meshName); - if (mesh) { - placeFurnitureMesh(e, mesh, - cell.position, - cell.orientation); - } - } - } - } + Ogre::MeshPtr mesh = + getFurnitureMesh(cell.meshName); + if (mesh) { + placeFurnitureMesh(e, mesh, + cell.position, + cell.orientation); + } + } + } + } public: - void createDecorateFurniture(flecs::entity e, - const nlohmann::json &jdistrict, - int /*index*/, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry * /*geo*/) - { - ZoneScoped; - // FIXME: make furniture placement a background task. + void createDecorateFurniture(flecs::entity e, + const nlohmann::json &jdistrict, + int /*index*/, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry * /*geo*/) + { + ZoneScoped; + // FIXME: make furniture placement a background task. - // Create town material (required for furniture) - createTownMaterial(e); + // Create town material (required for furniture) + createTownMaterial(e); - // Parse district context (center point) - DistrictContext districtCtx = - parseDistrictContext(jdistrict, sceneNode); + // Parse district context (center point) + DistrictContext districtCtx = + parseDistrictContext(jdistrict, sceneNode); - // Process lots if they exist - if (jdistrict.contains("lots") && - jdistrict["lots"].is_array()) { - const nlohmann::json &lots = jdistrict["lots"]; - for (nlohmann::json::const_iterator it = lots.begin(); - it != lots.end(); ++it) { - const nlohmann::json &jlot = *it; - std::cout << jlot.dump() << std::endl; - processLot(e, jlot, districtCtx); - } - } - } - void operator()(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) - { - createDecorateFurniture(e, jdistrict, index, sceneNode, geo); - } - void wait() - { - if (townDecorateFurnitureComplete.valid() && - townDecorateFurnitureComplete.wait_for(std::chrono::seconds( - 0)) != std::future_status::ready) - townDecorateFurnitureComplete.wait(); - } + // Process lots if they exist + if (jdistrict.contains("lots") && + jdistrict["lots"].is_array()) { + const nlohmann::json &lots = jdistrict["lots"]; + for (nlohmann::json::const_iterator it = lots.begin(); + it != lots.end(); ++it) { + const nlohmann::json &jlot = *it; + std::cout << jlot.dump() << std::endl; + processLot(e, jlot, districtCtx); + } + } + } + void operator()(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) + { + createDecorateFurniture(e, jdistrict, index, sceneNode, geo); + } + void wait() + { + if (townDecorateFurnitureComplete.valid() && + townDecorateFurnitureComplete.wait_for(std::chrono::seconds( + 0)) != std::future_status::ready) + townDecorateFurnitureComplete.wait(); + } }; void registerTownNPCs(flecs::entity e) { - ECS::get_mut().registerTownCharacters(e); - ECS::modified(); + ECS::get_mut().registerTownCharacters(e); + ECS::modified(); } void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) + Ogre::StaticGeometry *geo) { - ZoneScopedN("createTown"); - std::cout << "createTown " << e.id() << std::endl; - Ogre::MaterialPtr townMaterial = createTownMaterial(e); - static std::vector townTasks; - townTasks.clear(); - createTownWindows(e); - createTownDoors(e); - { - std::list destroy; - // Remove physics entities - ECS::get() - .query_builder() - .with(flecs::ChildOf, e) - .build() - .each([&](flecs::entity de, JPH::BodyID &id) { - destroy.push_back(de); - }); - // Remove furniture entities - ECS::get() - .query_builder() - .with(flecs::ChildOf, e) - .build() - .each([&](flecs::entity de, - FurnitureInstance &instance) { - destroy.push_back(de); - }); - for (flecs::entity de : destroy) - de.destruct(); - destroy.clear(); - Ogre::String props = e.get().properties; - nlohmann::json jp = nlohmann::json::parse(props); - Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); - Ogre::Quaternion worldOrientation = - sceneNode->_getDerivedOrientation(); - int index = 0; - for (const auto &jdistrict : jp["districts"]) { - TownPlazza *townPlazzaTask = new TownPlazza; - TownLots *townLotsTask = new TownLots; - TownCells *townCellsTask = new TownCells; - TownRoofs *townRoofsTask = new TownRoofs; - TownDecorateWindows *townDecorateWindowsTask = - new TownDecorateWindows; - TownDecorateDoors *townDecorateDoorsTask = - new TownDecorateDoors; - TownDecorateFurniture *townDecorateFurnitureTask = - new TownDecorateFurniture; - townTasks.push_back(townPlazzaTask); - townTasks.push_back(townLotsTask); - townTasks.push_back(townCellsTask); - townTasks.push_back(townRoofsTask); - townTasks.push_back(townDecorateWindowsTask); - townTasks.push_back(townDecorateDoorsTask); - townTasks.push_back(townDecorateFurnitureTask); - for (auto m : townTasks) - (*m)(e, jdistrict, index, sceneNode, geo); - index++; - } - } - Ogre::Root::getSingleton().getWorkQueue()->addTask([geo]() { - ZoneScoped; - for (auto m : townTasks) - m->wait(); - Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask( - [geo]() { - ZoneScopedN("createTown::MainThread"); - for (auto m : townTasks) { - delete m; - } - townTasks.clear(); + ZoneScopedN("createTown"); + std::cout << "createTown " << e.id() << std::endl; + Ogre::MaterialPtr townMaterial = createTownMaterial(e); + static std::vector townTasks; + townTasks.clear(); + createTownWindows(e); + createTownDoors(e); + { + std::list destroy; + // Remove physics entities + ECS::get() + .query_builder() + .with(flecs::ChildOf, e) + .build() + .each([&](flecs::entity de, JPH::BodyID &id) { + destroy.push_back(de); + }); + // Remove furniture entities + ECS::get() + .query_builder() + .with(flecs::ChildOf, e) + .build() + .each([&](flecs::entity de, + FurnitureInstance &instance) { + destroy.push_back(de); + }); + for (flecs::entity de : destroy) + de.destruct(); + destroy.clear(); + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion worldOrientation = + sceneNode->_getDerivedOrientation(); + int index = 0; + for (const auto &jdistrict : jp["districts"]) { + TownPlazza *townPlazzaTask = new TownPlazza; + TownLots *townLotsTask = new TownLots; + TownCells *townCellsTask = new TownCells; + TownRoofs *townRoofsTask = new TownRoofs; + TownDecorateWindows *townDecorateWindowsTask = + new TownDecorateWindows; + TownDecorateDoors *townDecorateDoorsTask = + new TownDecorateDoors; + TownDecorateFurniture *townDecorateFurnitureTask = + new TownDecorateFurniture; + townTasks.push_back(townPlazzaTask); + townTasks.push_back(townLotsTask); + townTasks.push_back(townCellsTask); + townTasks.push_back(townRoofsTask); + townTasks.push_back(townDecorateWindowsTask); + townTasks.push_back(townDecorateDoorsTask); + townTasks.push_back(townDecorateFurnitureTask); + for (auto m : townTasks) + (*m)(e, jdistrict, index, sceneNode, geo); + index++; + } + } + Ogre::Root::getSingleton().getWorkQueue()->addTask([geo]() { + ZoneScoped; + for (auto m : townTasks) + m->wait(); + Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask( + [geo]() { + ZoneScopedN("createTown::MainThread"); + for (auto m : townTasks) { + delete m; + } + townTasks.clear(); - geo->build(); - }); - }); + geo->build(); + }); + }); } void registerTown(flecs::entity e) { - ZoneScoped; - registerTownNPCs(e); - if (ECS::get().entity().is_valid()) - if (ECS::get().has()) { - ECS::get_mut().createAI(e); - ECS::modified(); - } - createTownActionNodes(e); + ZoneScoped; + registerTownNPCs(e); + if (ECS::get().entity().is_valid()) + if (ECS::get().has()) { + ECS::get_mut().createAI(e); + ECS::modified(); + } + createTownActionNodes(e); } void createTownActionNodes(flecs::entity e) { - const TerrainItem &item = e.get(); - Ogre::String props = item.properties; - nlohmann::json jprops = nlohmann::json::parse(props); + const TerrainItem &item = e.get(); + Ogre::String props = item.properties; + nlohmann::json jprops = nlohmann::json::parse(props); #if 0 Ogre::MaterialPtr townMaterial = createTownMaterial(e); #endif - for (const auto &jdistrict : jprops["districts"]) { - const nlohmann::json &jp = jdistrict; - nlohmann::json jlots = nlohmann::json::array(); - float baseHeight = 4.0f; - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - Ogre::Vector3 centerPosition = item.position; - Ogre::Quaternion centerOrientation = item.orientation; - float delevation = 0.0f; - float radius = 50.0f; - if (jp.find("elevation") != jp.end()) - delevation = jp["elevation"].get(); - if (jp.find("radius") != jp.end()) - radius = jp["radius"].get(); - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); - centerPosition = centerPosition + localPosition + - Ogre::Vector3(0, delevation, 0); - centerOrientation = centerOrientation * localRotation; - if (jdistrict.find("lots") != jdistrict.end()) - jlots = jdistrict["lots"]; - for (const auto &jb : jlots) { - float angle = 0.0f; - int depth = 10; - int width = 10; - float distance = radius; - float elevation = 0.0f; - std::cout << jb.dump() << std::endl; - if (jb.find("angle") != jb.end()) - angle = jb["angle"].get(); - if (jb.find("depth") != jb.end()) - depth = jb["depth"].get(); - if (jb.find("width") != jb.end()) - width = jb["width"].get(); - if (jb.find("elevation") != jb.end()) - elevation = jb["elevation"].get(); + for (const auto &jdistrict : jprops["districts"]) { + const nlohmann::json &jp = jdistrict; + nlohmann::json jlots = nlohmann::json::array(); + float baseHeight = 4.0f; + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + Ogre::Vector3 centerPosition = item.position; + Ogre::Quaternion centerOrientation = item.orientation; + float delevation = 0.0f; + float radius = 50.0f; + if (jp.find("elevation") != jp.end()) + delevation = jp["elevation"].get(); + if (jp.find("radius") != jp.end()) + radius = jp["radius"].get(); + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); + centerPosition = centerPosition + localPosition + + Ogre::Vector3(0, delevation, 0); + centerOrientation = centerOrientation * localRotation; + if (jdistrict.find("lots") != jdistrict.end()) + jlots = jdistrict["lots"]; + for (const auto &jb : jlots) { + float angle = 0.0f; + int depth = 10; + int width = 10; + float distance = radius; + float elevation = 0.0f; + std::cout << jb.dump() << std::endl; + if (jb.find("angle") != jb.end()) + angle = jb["angle"].get(); + if (jb.find("depth") != jb.end()) + depth = jb["depth"].get(); + if (jb.find("width") != jb.end()) + width = jb["width"].get(); + if (jb.find("elevation") != jb.end()) + elevation = jb["elevation"].get(); - OgreAssert(width > 1 && depth > 1 && baseHeight > 1, - "Bad stuff happen"); + OgreAssert(width > 1 && depth > 1 && baseHeight > 1, + "Bad stuff happen"); - Ogre::Quaternion rotation = Ogre::Quaternion( - Ogre::Degree(angle), Ogre::Vector3::UNIT_Y); - Ogre::Vector3 offset = - centerOrientation * rotation * - (Ogre::Vector3::UNIT_Z * distance); - Ogre::Vector3 worldCenterPosition = - centerPosition + offset + - Ogre::Vector3(0, elevation, 0); - Ogre::Quaternion worldCenterOrientation = - centerOrientation * rotation; - float outOffset = 1.05f; - if (jb.find("furniture_cells") != jb.end()) { - for (auto &jfcell : jb["furniture_cells"]) { - int x = jfcell["x"].get(); - int y = jfcell["y"].get(); - int z = jfcell["z"].get(); - nlohmann::json furniture = - jfcell["furniture"]; - Ogre::Vector3 cellOffset( - x * 2.0f, y * 4.0f, z * 2.0f); - Ogre::Vector3 offsetX = - worldCenterOrientation * - Ogre::Vector3::UNIT_X * - (float)x * 2.0f; - Ogre::Vector3 offsetZ = - worldCenterOrientation * - Ogre::Vector3::UNIT_Z * - (float)z * 2.0f; - Ogre::Vector3 offsetY(0, y * 4.0f, 0); - // static Ogre::String materialName1 = ""; - // static Ogre::String materialName2 = ""; - int rotation = 2; - if (jfcell.find("rotation") != - jfcell.end()) - rotation = jfcell["rotation"] - .get(); + Ogre::Quaternion rotation = Ogre::Quaternion( + Ogre::Degree(angle), Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = + centerOrientation * rotation * + (Ogre::Vector3::UNIT_Z * distance); + Ogre::Vector3 worldCenterPosition = + centerPosition + offset + + Ogre::Vector3(0, elevation, 0); + Ogre::Quaternion worldCenterOrientation = + centerOrientation * rotation; + float outOffset = 1.05f; + if (jb.find("furniture_cells") != jb.end()) { + for (auto &jfcell : jb["furniture_cells"]) { + int x = jfcell["x"].get(); + int y = jfcell["y"].get(); + int z = jfcell["z"].get(); + nlohmann::json furniture = + jfcell["furniture"]; + Ogre::Vector3 cellOffset( + x * 2.0f, y * 4.0f, z * 2.0f); + Ogre::Vector3 offsetX = + worldCenterOrientation * + Ogre::Vector3::UNIT_X * + (float)x * 2.0f; + Ogre::Vector3 offsetZ = + worldCenterOrientation * + Ogre::Vector3::UNIT_Z * + (float)z * 2.0f; + Ogre::Vector3 offsetY(0, y * 4.0f, 0); + // static Ogre::String materialName1 = ""; + // static Ogre::String materialName2 = ""; + int rotation = 2; + if (jfcell.find("rotation") != + jfcell.end()) + rotation = jfcell["rotation"] + .get(); - Ogre::Vector3 offset = - worldCenterOrientation * - Ogre::Vector3::UNIT_Z * 0.0f; + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::UNIT_Z * 0.0f; - if (furniture.find("actions") != - furniture.end()) { - for (const auto &action : - furniture["actions"]) { - std::cout - << "SENSOR: " - << action.dump() - << std::endl; - std::cout - << furniture - .dump() - << std::endl; - Ogre::Vector3 - actionPosition; - actionPosition.x = - action["position_x"] - .get(); - actionPosition.y = - action["position_y"] - .get(); - actionPosition.z = - action["position_z"] - .get(); - Ogre::Quaternion worldSensorRotation = - worldCenterOrientation * - Ogre::Quaternion( - Ogre::Degree( - 90.0f * - (float)rotation), - Ogre::Vector3:: - UNIT_Y); - Ogre::Vector3 worldSensorPosition = - worldCenterPosition + - offsetX + - offsetZ + - offsetY + - offset + - worldSensorRotation * - actionPosition; - if (ECS::get() - .has()) { - ActionNodeList::ActionNode - anode; - anode.action = - action["action"] - .get(); - anode.action_text = - action["action_text"] - .get(); - anode.radius = - action["radius"] - .get(); - anode.height = - action["height"] - .get(); - anode.props = - action; - anode.props - ["town"] = - e.id(); - anode.props - ["index"] = - -1; - anode.position = - worldSensorPosition; - anode.rotation = - worldSensorRotation; - anode.dynamic = - false; - ECS::get_mut< - ActionNodeList>() - .addNode( - anode); - std::cout - << "action: " - << action.dump( - 4) - << std::endl; - ECS::modified< - ActionNodeList>(); - } - } - } - } - } - } - } + if (furniture.find("actions") != + furniture.end()) { + for (const auto &action : + furniture["actions"]) { + std::cout + << "SENSOR: " + << action.dump() + << std::endl; + std::cout + << furniture + .dump() + << std::endl; + Ogre::Vector3 + actionPosition; + actionPosition.x = + action["position_x"] + .get(); + actionPosition.y = + action["position_y"] + .get(); + actionPosition.z = + action["position_z"] + .get(); + Ogre::Quaternion worldSensorRotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree( + 90.0f * + (float)rotation), + Ogre::Vector3:: + UNIT_Y); + Ogre::Vector3 worldSensorPosition = + worldCenterPosition + + offsetX + + offsetZ + + offsetY + + offset + + worldSensorRotation * + actionPosition; + if (ECS::get() + .has()) { + ActionNodeList::ActionNode + anode; + anode.action = + action["action"] + .get(); + anode.action_text = + action["action_text"] + .get(); + anode.radius = + action["radius"] + .get(); + anode.height = + action["height"] + .get(); + anode.props = + action; + anode.props + ["town"] = + e.id(); + anode.props + ["index"] = + -1; + anode.position = + worldSensorPosition; + anode.rotation = + worldSensorRotation; + anode.dynamic = + false; + ECS::get_mut< + ActionNodeList>() + .addNode( + anode); + std::cout + << "action: " + << action.dump( + 4) + << std::endl; + ECS::modified< + ActionNodeList>(); + } + } + } + } + } + } + } } }