From 272e202774242d51730308615ecd026043a651bc Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Thu, 8 Jan 2026 00:16:46 +0300 Subject: [PATCH] Now can create roofs from lua script --- src/editor/CMakeLists.txt | 1 + src/gamedata/CharacterModule.cpp | 41 +- src/gamedata/StaticGeometryModule.h | 1 + src/gamedata/items/items.cpp | 9 +- src/gamedata/items/town.cpp | 1459 +++++++++++++++++++++------ 5 files changed, 1188 insertions(+), 323 deletions(-) diff --git a/src/editor/CMakeLists.txt b/src/editor/CMakeLists.txt index 424ca1f..42efd2e 100644 --- a/src/editor/CMakeLists.txt +++ b/src/editor/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(editor STATIC EditorGizmoModule.cpp EditorInputModule.cpp) target_link_libraries(editor PRIVATE OgreMain GameData + physics ) target_include_directories(editor PUBLIC .) diff --git a/src/gamedata/CharacterModule.cpp b/src/gamedata/CharacterModule.cpp index c362823..5898868 100644 --- a/src/gamedata/CharacterModule.cpp +++ b/src/gamedata/CharacterModule.cpp @@ -5,6 +5,7 @@ #include "TerrainModule.h" #include "Components.h" #include "PhysicsModule.h" +#include "physics.h" #include "CharacterAnimationModule.h" #include "CharacterManagerModule.h" #include "CharacterModule.h" @@ -582,6 +583,7 @@ void CharacterModule::updateCameraGoal(Camera &camera, Ogre::Real deltaYaw, Ogre::Real deltaPitch, Ogre::Real deltaZoom) { + static float canonDist = 0; camera.mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT); if (!(camera.mPivotPitch + deltaPitch > 25 && deltaPitch > 0) && !(camera.mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) { @@ -594,10 +596,45 @@ void CharacterModule::updateCameraGoal(Camera &camera, Ogre::Real deltaYaw, Ogre::Real distChange = deltaZoom * dist; // bound the zoom - if (!(dist + distChange < 8 && distChange < 0) && - !(dist + distChange > 25 && distChange > 0)) + if (!(dist + distChange < 1.5f && distChange < 0) && + !(dist + distChange > 10 && distChange > 0)) { camera.mCameraGoal->translate(0, 0, distChange, Ogre::Node::TS_LOCAL); + canonDist += distChange; + } + JPH::BodyID id; + Ogre::Vector3 position; + Ogre::Vector3 d = (camera.mCameraPivot->_getDerivedPosition() - + camera.mCameraGoal->_getDerivedPosition()) + .normalisedCopy(); + + if (JoltPhysicsWrapper::getSingleton().raycastQuery( + camera.mCameraPivot->_getDerivedPosition(), + camera.mCameraGoal->_getDerivedPosition() - d * 0.6, + position, id)) { + float l = camera.mCameraPivot->_getDerivedPosition() + .squaredDistance( + camera.mCameraGoal + ->_getDerivedPosition()); + float m = camera.mCameraPivot->_getDerivedPosition() + .squaredDistance(position); + if (m < l) + camera.mCameraGoal->_setDerivedPosition(position + + d * 0.6f); + } else { + Ogre::Real dist2 = + camera.mCameraGoal->_getDerivedPosition().distance( + camera.mCameraPivot->_getDerivedPosition()); + if (deltaZoom < 0.0f || deltaZoom > 0.0f) + canonDist = dist2; + else { + if (canonDist < dist2) + canonDist = dist2; + if (dist2 < canonDist) + camera.mCameraGoal->translate( + 0, 0, 0.08f, Ogre::Node::TS_LOCAL); + } + } } CharacterAIModule::CharacterAIModule(flecs::world &ecs) { diff --git a/src/gamedata/StaticGeometryModule.h b/src/gamedata/StaticGeometryModule.h index 03c568d..d79b1e4 100644 --- a/src/gamedata/StaticGeometryModule.h +++ b/src/gamedata/StaticGeometryModule.h @@ -25,6 +25,7 @@ struct TerrainItemMeshNode { Ogre::SceneNode *itemNode; Ogre::StaticGeometry *geo; }; +struct TownCollider {}; struct StaticGeometryModule { StaticGeometryModule(flecs::world &ecs); diff --git a/src/gamedata/items/items.cpp b/src/gamedata/items/items.cpp index 47059d5..cb5b895 100644 --- a/src/gamedata/items/items.cpp +++ b/src/gamedata/items/items.cpp @@ -195,13 +195,14 @@ namespace Geometry void setupLods(Ogre::LodConfig &config) { // config.advanced.useCompression = false; - // config.advanced.useVertexNormals = true; + config.advanced.useVertexNormals = true; config.advanced.preventPunchingHoles = true; config.advanced.preventBreakingLines = true; config.createGeneratedLodLevel(10, 0.15f); - config.createGeneratedLodLevel(30, 0.25f); - config.createGeneratedLodLevel(60, 0.36f); - config.createGeneratedLodLevel(150, 0.65f); + config.createGeneratedLodLevel(50, 0.25f); + config.createGeneratedLodLevel(100, 0.36f); + config.createGeneratedLodLevel(200, 0.50f); + config.createGeneratedLodLevel(500, 0.85f); config.advanced.useBackgroundQueue = false; Ogre::MeshLodGenerator::getSingleton().generateLodLevels(config); } diff --git a/src/gamedata/items/town.cpp b/src/gamedata/items/town.cpp index faa0030..f2774d4 100644 --- a/src/gamedata/items/town.cpp +++ b/src/gamedata/items/town.cpp @@ -19,6 +19,13 @@ #include "items.h" #include "town.h" +/* TODO: Create roofs with the same Lua script as tiles. + * TODO: Create doors and handle them via script. + * TODO: Handle doors direction. + * TODO: Hide hero mesh if camera is too close. + * TODO: create furniture tiles from the same Lua script. Create tile tags, Create tile templates. +*/ + void serializeMesh(Ogre::MeshPtr mesh, const Ogre::String &meshName) { Ogre::MeshSerializer meshSerializer; @@ -165,14 +172,16 @@ struct CellsScript { int currentY; int currentZ; Ogre::String cellScript; + nlohmann::json &lot; nlohmann::json &cells; - CellsScript(const Ogre::String &cellScript, nlohmann::json &cells) + CellsScript(const Ogre::String &cellScript, nlohmann::json &lot) : L(luaL_newstate()) , currentX(0) , currentY(0) , currentZ(0) , cellScript(cellScript) - , cells(cells) + , lot(lot) + , cells(lot["cells"]) { lua_pushlightuserdata(L, this); lua_pushcclosure( @@ -248,6 +257,26 @@ struct CellsScript { 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 { @@ -263,6 +292,17 @@ struct CellsScript { 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))); + _this->clear_roofs(); + return 0; + }, + 1); + lua_setglobal(L, "clear_roofs"); + lua_pushlightuserdata(L, this); lua_pushcclosure( L, [](lua_State *L) -> int { @@ -349,7 +389,7 @@ struct CellsScript { 1); lua_setglobal(L, "create_exterior"); } - std::string trim(const std::string &str) + static std::string trim(const std::string &str) { // Find the first character that is not a whitespace character const std::string ws = @@ -367,8 +407,8 @@ struct CellsScript { // Extract the substring between the first and last non-whitespace characters return str.substr(first, (last - first + 1)); } - std::vector split_and_trim(const std::string &s, - char delimiter) + static std::vector split_and_trim(const std::string &s, + char delimiter) { std::vector tokens; std::string token; @@ -462,6 +502,31 @@ struct CellsScript { } return (flags & bitset) == bitset; } + static bool isBit(const nlohmann::json &cell, const Ogre::String &bit) + { + 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) { if (findCell(currentX, currentY, currentZ) == -1) { @@ -529,6 +594,33 @@ struct CellsScript { rooms.push_back({ minX, minZ, sizeX, sizeZ }); return ret; } + int roof(int minX, int minZ, int sizeX, int sizeZ, float height, + int type) + { + 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() + { + lot["roofs"] = nlohmann::json::array(); + } std::vector > roomEdge(int room) { std::vector > seg; @@ -1156,8 +1248,7 @@ bool editLot(const Ogre::String &lotLabel, nlohmann::json &lot) changed = true; } if (ImGui::SmallButton(("Execute script...##" + lotLabel).c_str())) { - CellsScript script(lot["cellScript"].get(), - lot["cells"]); + CellsScript script(lot["cellScript"].get(), lot); script.run(); changed = true; } @@ -1499,252 +1590,6 @@ void createTownPopup(const std::pair item) } namespace Geometry { -void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb, - const Ogre::String &rectKey) -{ - 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) -{ - 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 { -#if 0 - Ogre::TextureUnitState *state = - townMaterial->getTechnique(0) - ->getPass(0) - ->getTextureUnitState(textureName); - state-> -#endif - } - } - return townMaterial; -} -void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) -{ - std::cout << "createTown " << e.id() << std::endl; - Ogre::MaterialPtr townMaterial = createTownMaterial(e); - { - 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"]) { - createTownPlazza(e, jdistrict, index, sceneNode, geo); - createTownLots(e, jdistrict, index, sceneNode, geo); - createCells(e, jdistrict, index, sceneNode, geo); - createTownRoofs(e, jdistrict, index, sceneNode, geo); - index++; - } - } - geo->build(); -} -void createTownPlazza(flecs::entity e, const nlohmann::json &jdistrict, - int index, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) -{ - Ogre::MaterialPtr townMaterial; - townMaterial = Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id())); - Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); - Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation(); - const nlohmann::json &jp = jdistrict; - Procedural::TriangleBuffer tb; - float radius = 5.0f; - float height = 0.2f; - float elevation = 0.0f; - bool plazza = false; - Ogre::Vector3 localPosition(0, 0, 0); - Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; - 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(); - from_json(jp["position"], localPosition); - from_json(jp["rotation"], localRotation); - if (height < 0.1f) - height = 0.1f; - if (radius < 5.0f) - radius = 5.0f; - Ogre::Vector3 worldPlazzaCenter = worldPosition + localPosition; - float mh = 4.0f; - Procedural::Shape *plazzaShape = new Procedural::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(tb); - for (auto &v : 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::String meshName = "plazzaMesh" + - Ogre::StringConverter::toString(index) + "_" + - Ogre::StringConverter::toString(e.id()); - Ogre::MeshPtr mesh = - Ogre::MeshManager::getSingleton().getByName(meshName); - if (mesh) - Ogre::MeshManager::getSingleton().remove(mesh); - mesh = tb.transformToMesh(meshName); - Ogre::LodConfig config(mesh); - setupLods(config); - Ogre::Entity *pathEnt = - ECS::get().mScnMgr->createEntity(mesh); - pathEnt->setMaterial(townMaterial); - geo->addEntity(pathEnt, worldPlazzaCenter, - worldOrientation * localRotation, - Ogre::Vector3(1, 1, 1)); -} struct BitSet { uint64_t bit; float sizeX; @@ -2378,6 +2223,923 @@ struct ProcessCells { } }; +void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb, + const Ogre::String &rectKey) +{ + 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) +{ + 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 { +#if 0 + Ogre::TextureUnitState *state = + townMaterial->getTechnique(0) + ->getPass(0) + ->getTextureUnitState(textureName); + state-> +#endif + } + } + return townMaterial; +} +void createTownWindows(flecs::entity e) +{ + 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); + Procedural::BoxGenerator() + .setSizeX(1.6f) + .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(frame1tb); + clampUV(e, frame1tb, "windowsFrameColor"); + frame1mesh = frame1tb.transformToMesh("window-frame1"); + Ogre::LodConfig configFrame(frame1mesh); + setupLods(configFrame); + Ogre::MeshPtr meshGlass = + glass1tb.transformToMesh("window-glass1"); + Ogre::LodConfig configGlass(meshGlass); + setupLods(configGlass); + } +} +void createTownDoors(flecs::entity e) +{ + 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); + } + } +} + +void createDecorateDoors(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + Ogre::MaterialPtr townMaterial = createTownMaterial(e); + 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 = sceneNode->_getDerivedPosition(); + Ogre::Quaternion centerOrientation = + sceneNode->_getDerivedOrientation(); + 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"); + + 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("cells") != jb.end()) { + for (auto &jcell : jb["cells"]) { + 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); + 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); + if (Items::CellsScript::isBit(jcell, + "doorz+")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "door-cell", + "external-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::UNIT_Z * + outOffset; + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + worldCenterOrientation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } else if (Items::CellsScript::isBit( + jcell, "idoorz+")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "idoor-cell", + "internal-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::UNIT_Z * + outOffset; + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + worldCenterOrientation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + if (Items::CellsScript::isBit(jcell, + "doorz-")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "door-cell", + "external-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::NEGATIVE_UNIT_Z * + outOffset; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(180), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } else if (Items::CellsScript::isBit( + jcell, "idoorz-")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "idoor-cell", + "internal-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::NEGATIVE_UNIT_Z * + outOffset; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(180), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + if (Items::CellsScript::isBit(jcell, + "doorx+")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "door-cell", + "external-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::UNIT_X * + outOffset; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(90), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } else if (Items::CellsScript::isBit( + jcell, "idoorx+")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "idoor-cell", + "internal-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::UNIT_X * + outOffset; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(90), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + if (Items::CellsScript::isBit(jcell, + "doorx-")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "door-cell", + "external-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::NEGATIVE_UNIT_X * + outOffset; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(-90), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } else if (Items::CellsScript::isBit( + jcell, "idoorx-")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "idoor-cell", + "internal-door-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::NEGATIVE_UNIT_X * + outOffset; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(-90), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + } + } + } +} + +void createDecorateWindows(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + Ogre::MaterialPtr townMaterial = createTownMaterial(e); + 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 = sceneNode->_getDerivedPosition(); + Ogre::Quaternion centerOrientation = + sceneNode->_getDerivedOrientation(); + 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"); + + 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("cells") != jb.end()) { + for (auto &jcell : jb["cells"]) { + 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); + 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); + if (Items::CellsScript::isBit(jcell, + "windowz+")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "window-cell", + "window-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::UNIT_Z * + outOffset + + Ogre::Vector3::UNIT_Y * 0.5f; + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + worldCenterOrientation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + if (Items::CellsScript::isBit(jcell, + "windowz-")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "window-cell", + "window-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3:: + NEGATIVE_UNIT_Z * + outOffset + + Ogre::Vector3::UNIT_Y * 0.5f; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(180), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + if (Items::CellsScript::isBit(jcell, + "windowx+")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "window-cell", + "window-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3::UNIT_X * + outOffset + + Ogre::Vector3::UNIT_Y * 0.5f; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(90), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + if (Items::CellsScript::isBit(jcell, + "windowx-")) { + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "window-cell", + "window-frame1"); + ent->setMaterial(townMaterial); + Ogre::Vector3 offset = + worldCenterOrientation * + Ogre::Vector3:: + NEGATIVE_UNIT_X * + outOffset + + Ogre::Vector3::UNIT_Y * 0.5f; + Ogre::Quaternion rotation = + worldCenterOrientation * + Ogre::Quaternion( + Ogre::Degree(-90), + Ogre::Vector3::UNIT_Y); + geo->addEntity(ent, + worldCenterPosition + + offsetX + + offsetZ + + offsetY + offset, + rotation); + ECS::get() + .mScnMgr->destroyEntity(ent); + } + } + } + } +} + +void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + std::cout << "createTown " << e.id() << std::endl; + Ogre::MaterialPtr townMaterial = createTownMaterial(e); + createTownWindows(e); + createTownDoors(e); + { + std::list destroy; + ECS::get() + .query_builder() + .with(flecs::ChildOf, e) + .build() + .each([&](flecs::entity de, JPH::BodyID &id) { + 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"]) { + createTownPlazza(e, jdistrict, index, sceneNode, geo); + createTownLots(e, jdistrict, index, sceneNode, geo); + createCells(e, jdistrict, index, sceneNode, geo); + createTownRoofs(e, jdistrict, index, sceneNode, geo); + createDecorateWindows(e, jdistrict, index, sceneNode, + geo); + createDecorateDoors(e, jdistrict, index, sceneNode, + geo); + index++; + } + } + geo->build(); +} +void createTownPlazza(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + Ogre::MaterialPtr townMaterial; + townMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id())); + Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation(); + const nlohmann::json &jp = jdistrict; + Procedural::TriangleBuffer tb; + float radius = 5.0f; + float height = 0.2f; + float elevation = 0.0f; + bool plazza = false; + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + 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(); + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); + if (height < 0.1f) + height = 0.1f; + if (radius < 5.0f) + radius = 5.0f; + Ogre::Vector3 worldPlazzaCenter = worldPosition + localPosition; + float mh = 4.0f; + Procedural::Shape *plazzaShape = new Procedural::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(tb); + for (auto &v : 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::String meshName = "plazzaMesh" + + Ogre::StringConverter::toString(index) + "_" + + Ogre::StringConverter::toString(e.id()); + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton().getByName(meshName); + if (mesh) + Ogre::MeshManager::getSingleton().remove(mesh); + mesh = tb.transformToMesh(meshName); + Ogre::LodConfig config(mesh); + setupLods(config); + Ogre::Entity *plazzaEnt = + ECS::get().mScnMgr->createEntity(mesh); + plazzaEnt->setMaterial(townMaterial); + geo->addEntity(plazzaEnt, worldPlazzaCenter, + worldOrientation * localRotation, + Ogre::Vector3(1, 1, 1)); + ECS::get().mScnMgr->destroyEntity(plazzaEnt); + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton().createMeshShape(mesh); + JPH::BodyID id = JoltPhysicsWrapper::getSingleton().createBody( + shape, 0, worldPlazzaCenter, worldOrientation * localRotation, + JPH::EMotionType::Static, Layers::NON_MOVING); + JoltPhysicsWrapper::getSingleton().addBody(id, + JPH::EActivation::Activate); + flecs::entity ce = ECS::get().entity().child_of(e).set(id); +} void createCells(flecs::entity e, const nlohmann::json &jdistrict, int index, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo) { @@ -2494,11 +3256,27 @@ void createCells(flecs::entity e, const nlohmann::json &jdistrict, int index, .mScnMgr->createEntity( "Ent" + meshName, mesh); ent->setMaterial(townMaterial); -#if 1 geo->addEntity(ent, worldCenterPosition, worldCenterOrientation, Ogre::Vector3::UNIT_SCALE); -#endif + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton() + .createMeshShape(mesh); + JPH::BodyID id = + JoltPhysicsWrapper::getSingleton() + .createBody( + shape, 0, + worldCenterPosition, + worldCenterOrientation, + JPH::EMotionType::Static, + Layers::NON_MOVING); + JoltPhysicsWrapper::getSingleton().addBody( + id, JPH::EActivation::Activate); + flecs::entity ce = + ECS::get() + .entity() + .child_of(e) + .set(id); ECS::get().mScnMgr->destroyEntity( ent); } @@ -2531,13 +3309,29 @@ void createCells(flecs::entity e, const nlohmann::json &jdistrict, int index, .mScnMgr->createEntity( "Ent" + meshName, mesh); ent->setMaterial(townMaterial); -#if 1 geo->addEntity(ent, worldCenterPosition, worldCenterOrientation, Ogre::Vector3::UNIT_SCALE); -#endif ECS::get().mScnMgr->destroyEntity( ent); + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton() + .createMeshShape(mesh); + JPH::BodyID id = + JoltPhysicsWrapper::getSingleton() + .createBody( + shape, 0, + worldCenterPosition, + worldCenterOrientation, + JPH::EMotionType::Static, + Layers::NON_MOVING); + JoltPhysicsWrapper::getSingleton().addBody( + id, JPH::EActivation::Activate); + flecs::entity ce = + ECS::get() + .entity() + .child_of(e) + .set(id); } if (exteriorTb.getVertices().size() > 0) { Ogre::String meshName = @@ -2568,13 +3362,29 @@ void createCells(flecs::entity e, const nlohmann::json &jdistrict, int index, .mScnMgr->createEntity( "Ent" + meshName, mesh); ent->setMaterial(townMaterial); -#if 1 geo->addEntity(ent, worldCenterPosition, worldCenterOrientation, Ogre::Vector3::UNIT_SCALE); -#endif ECS::get().mScnMgr->destroyEntity( ent); + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton() + .createMeshShape(mesh); + JPH::BodyID id = + JoltPhysicsWrapper::getSingleton() + .createBody( + shape, 0, + worldCenterPosition, + worldCenterOrientation, + JPH::EMotionType::Static, + Layers::NON_MOVING); + JoltPhysicsWrapper::getSingleton().addBody( + id, JPH::EActivation::Activate); + flecs::entity ce = + ECS::get() + .entity() + .child_of(e) + .set(id); } count++; } @@ -2671,6 +3481,17 @@ void createTownLots(flecs::entity e, const nlohmann::json &jdistrict, int index, centerOrientation * rotation, Ogre::Vector3::UNIT_SCALE); ECS::get().mScnMgr->destroyEntity(ent); + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton().createMeshShape( + mesh); + JPH::BodyID id = JoltPhysicsWrapper::getSingleton().createBody( + shape, 0, centerPosition + offset, + centerOrientation * rotation, JPH::EMotionType::Static, + Layers::NON_MOVING); + JoltPhysicsWrapper::getSingleton().addBody( + id, JPH::EActivation::Activate); + flecs::entity ce = + ECS::get().entity().child_of(e).set(id); count++; } } @@ -2915,35 +3736,6 @@ void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, float q = 2.0f * (float)width / 2.0f; float m = 1.0f; float d = 1.4142f * (q + m); -#if 0 - Procedural::BoxGenerator() - .setSizeX(2.0f * (float)width) - .setSizeY(baseHeight) - .setSizeZ(2.0f * (float)depth) - .setNumSegY(1) - .setNumSegX(1) - .setNumSegZ(1) - .setEnableNormals(true) - .setPosition(Ogre::Vector3( - (float)position_x * - 2.0f - - 1.0f + - (float)width * - 2.0f / - 2.0f, - (float)position_y * - 4.0f + - baseHeight / - 2.0f + - elevation, - (float)position_z * - 2.0f - - 1.0f + - (float)depth * - 2.0f / - 2.0f)) - .addToTriangleBuffer(tbTop); -#endif Procedural::BoxGenerator() .setSizeX(d) .setSizeY(baseHeight / 2.0f) @@ -3018,8 +3810,8 @@ void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, extend * 2.0f) .setSizeY(q + baseHeight * 2.5f) .setSizeZ(extend) - .setNumSegY(1) - .setNumSegX(1) + .setNumSegX(3) + .setNumSegY(3) .setNumSegZ(1) .setEnableNormals(true) .setPosition(Ogre::Vector3( @@ -3046,8 +3838,8 @@ void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, extend * 2.0f) .setSizeY(q + baseHeight * 2.5f) .setSizeZ(extend) - .setNumSegY(1) - .setNumSegX(1) + .setNumSegX(3) + .setNumSegY(3) .setNumSegZ(1) .setEnableNormals(true) .setPosition(Ogre::Vector3( @@ -3071,23 +3863,45 @@ void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, .addToTriangleBuffer(tbSide); float minY = 0.0f; float maxY = 0.0f; + float maxX = 0.0f; + float minX = 0.0f; + int count = 0; for (auto &v : tbSide.getVertices()) { - if (v.mPosition.y > maxY) - maxY = v.mPosition.y; - if (v.mPosition.y < minY) + if (count == 0) { minY = v.mPosition.y; + maxY = v.mPosition.y; + minX = v.mPosition.x; + maxX = v.mPosition.x; + } else { + if (v.mPosition.y > + maxY) + maxY = v.mPosition + .y; + if (v.mPosition.y < + minY) + minY = v.mPosition + .y; + if (v.mPosition.x > + maxX) + maxX = v.mPosition + .x; + if (v.mPosition.x < + minX) + minX = v.mPosition + .x; + } + count++; } + float midX = + minX + (maxX - minX) / 2.0f; for (auto &v : tbSide.getVertices()) { - if (v.mPosition.x > 0) - v.mPosition.x += - maxY - - v.mPosition.y - - q; - else if (v.mPosition.x < 0) - v.mPosition.x -= - maxY - - v.mPosition.y - - q; + float md = maxY - v.mPosition.y; + float hm = v.mPosition.x - midX; + float he = + (hm / ((maxX - minX) / + 2.0f)) * + md; + v.mPosition.x = he + midX; } clampUV(e, tbTop, "roofTop"); clampUV(e, tbSide, "roofSide"); @@ -3268,18 +4082,6 @@ void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, 2.0f)) * md; v.mPosition.z = he + midZ; -#if 0 - if (v.mPosition.z >= midZ) - v.mPosition.z = - midZ + - (maxY - - v.mPosition.y); - else if (v.mPosition.z < midZ) - v.mPosition.z = - midZ - - (maxY - - v.mPosition.y); -#endif } clampUV(e, tbTop, "roofTop"); clampUV(e, tbSide, "roofSide"); @@ -3323,6 +4125,29 @@ void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, ent); } + if (mesh) { + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton() + .createMeshShape(mesh); + JPH::BodyID id = + JoltPhysicsWrapper::getSingleton() + .createBody( + shape, 0, + centerPosition + + offset, + centerOrientation * + rotation, + JPH::EMotionType:: + Static, + Layers::NON_MOVING); + JoltPhysicsWrapper::getSingleton().addBody( + id, JPH::EActivation::Activate); + flecs::entity ce = + ECS::get() + .entity() + .child_of(e) + .set(id); + } } count++; }