diff --git a/Game.cpp b/Game.cpp index 1cafb76..2c7821e 100644 --- a/Game.cpp +++ b/Game.cpp @@ -295,9 +295,9 @@ public: }; class App : public OgreBites::ApplicationContext { Ogre::SceneNode *mCameraNode, *mCameraPivot, *mCameraGoal; - Ogre::Camera *mCamera; + Ogre::Camera *mCamera, *mCameraInterior, *mCameraInventory; Ogre::Real mPivotPitch; - Ogre::SceneManager *mScnMgr; + Ogre::SceneManager *mScnMgr, *mScnMgrInterior, *mScnMgrInventory; Ogre::Viewport *mViewport; SkyBoxRenderer *sky; bool mGrab; @@ -313,15 +313,19 @@ public: virtual ~App() { } - void setup() + void setup() override { OgreBites::ApplicationContext::setup(); Ogre::Root *root = getRoot(); Ogre::SceneManager *scnMgr = root->createSceneManager(); mScnMgr = scnMgr; - Ogre::OverlaySystem *pOverlaySystem = getOverlaySystem(); + mScnMgrInterior = root->createSceneManager(); + mScnMgrInventory = root->createSceneManager(); + Ogre::OverlaySystem *pOverlaySystem = getOverlaySystem(); mScnMgr->addRenderQueueListener(pOverlaySystem); - // mTrayMgr = new OgreBites::TrayManager("AppTrays", + mScnMgrInterior->addRenderQueueListener(pOverlaySystem); + mScnMgrInventory->addRenderQueueListener(pOverlaySystem); + // mTrayMgr = new OgreBites::TrayManager("AppTrays", // getRenderWindow()); } bool isWindowGrab() @@ -347,7 +351,32 @@ public: mGrab = grab; ApplicationContextBase::setWindowGrab(grab); } - + void initInteriorCamera() + { + Ogre::SceneNode *cameraNode = + mScnMgrInterior->getRootSceneNode() + ->createChildSceneNode("InteriorCameraNode"); + cameraNode->setPosition(0, 2, 3); + cameraNode->lookAt(Ogre::Vector3(0, 1, -1), + Ogre::Node::TS_PARENT); + mCameraInterior = mScnMgr->createCamera("interior_camera"); + mCameraInterior->setNearClipDistance(0.05f); + mCameraInterior->setAutoAspectRatio(true); + cameraNode->attachObject(mCameraInterior); + } + void initInventoryCamera() + { + Ogre::SceneNode *cameraNode = + mScnMgrInventory->getRootSceneNode() + ->createChildSceneNode("InteriorCameraNode"); + cameraNode->setPosition(0, 2, 3); + cameraNode->lookAt(Ogre::Vector3(0, 1, -1), + Ogre::Node::TS_PARENT); + mCameraInventory = mScnMgr->createCamera("inventory_camera"); + mCameraInventory->setNearClipDistance(0.05f); + mCameraInventory->setAutoAspectRatio(true); + cameraNode->attachObject(mCameraInventory); + } void initCamera() { mCameraNode = mScnMgr->getRootSceneNode()->createChildSceneNode( @@ -378,12 +407,16 @@ public: mCamera->setNearClipDistance(0.1f); mCamera->setFarClipDistance(800); mPivotPitch = 0; + initInteriorCamera(); + initInventoryCamera(); } void configure() { - std::cout << "Startup" << "\n"; + std::cout << "Startup" + << "\n"; initApp(); - std::cout << "Set up RTSS" << "\n"; + std::cout << "Set up RTSS" + << "\n"; Ogre::Root *root = getRoot(); Ogre::SceneManager *scnMgr = getSceneManager(); @@ -392,19 +425,25 @@ public: Ogre::RTShader::ShaderGenerator::getSingletonPtr(); shadergen->addSceneManager(scnMgr); setWindowGrab(true); - std::cout << "Init camera" << "\n"; + std::cout << "Init camera" + << "\n"; initCamera(); - std::cout << "Set up water" << "\n"; - std::cout << "Set up cursor" << "\n"; + std::cout << "Set up water" + << "\n"; + std::cout << "Set up cursor" + << "\n"; Ogre::ResourceGroupManager::getSingleton() .initialiseAllResourceGroups(); // OgreBites::ApplicationContext::loadResources(); // setupCursor(); - std::cout << "Setup input" << "\n"; + std::cout << "Setup input" + << "\n"; setupInput(); - std::cout << "Create content" << "\n"; + std::cout << "Create content" + << "\n"; createContent(); - std::cout << "Setup done" << "\n"; + std::cout << "Setup done" + << "\n"; #if 0 mDbgDraw->setDebugMode(mDbgDraw->getDebugMode() | btIDebugDraw::DBG_DrawContactPoints); @@ -601,8 +640,9 @@ public: "Skybox/Dynamic", "General"); OgreAssert(m, "Sky box material not found."); m->load(); - ECS::setup(mScnMgr, /*mDynWorld.get(), */ mCameraNode, mCamera, - getRenderWindow()); + ECS::setupExteriorScene(mScnMgr, + /*mDynWorld.get(), */ mCameraNode, + mCamera, getRenderWindow()); ECS::get().set( { getRenderWindow(), getDisplayDPI() }); ECS::get() @@ -736,9 +776,7 @@ public: } flecs::entity getPlayer() const { - flecs::entity player = - ECS::get().lookup("ECS::CharacterModule::player"); - return player; + return ECS::player; } void enableDbgDraw(bool enable) { diff --git a/src/editor/EditorInputModule.cpp b/src/editor/EditorInputModule.cpp index 8dc9234..b921719 100644 --- a/src/editor/EditorInputModule.cpp +++ b/src/editor/EditorInputModule.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include "Components.h" #include "GameData.h" #include "PhysicsModule.h" @@ -35,8 +37,6 @@ EditorInputModule::EditorInputModule(flecs::world &ecs) .kind(flecs::OnUpdate) .each([this](const EngineData &eng, Input &input, Camera &camera) { - if (ECS::player.is_valid()) - return; if (!camera.configured) { // create a pivot at roughly the character's shoulder camera.mCameraPivot = @@ -147,10 +147,11 @@ EditorInputModule::EditorInputModule(flecs::world &ecs) position = ray.getPoint(ogreResult.second); Ogre::Vector3 position2; + JPH::BodyID id; bool hit = PhysicsModule::raycastQuery( ray.getOrigin(), ray.getPoint(2000.0f), - position2); + position2, id); if (hit) { float d1 = ray.getOrigin() @@ -169,10 +170,11 @@ EditorInputModule::EditorInputModule(flecs::world &ecs) .sceneNode->_setDerivedPosition( position); } else { + JPH::BodyID id; bool hit = PhysicsModule::raycastQuery( ray.getOrigin(), - ray.getPoint(2000.0f), - position); + ray.getPoint(2000.0f), position, + id); if (hit) { std::cout << "HIT!: " << position @@ -238,4 +240,4 @@ EditorInputModule::EditorInputModule(flecs::world &ecs) ECS::get().modified(); }); } -} \ No newline at end of file +} diff --git a/src/editor/main.cpp b/src/editor/main.cpp index b07b9af..1d4f37c 100644 --- a/src/editor/main.cpp +++ b/src/editor/main.cpp @@ -384,9 +384,11 @@ public: } void configure() { - std::cout << "Startup" << "\n"; + std::cout << "Startup" + << "\n"; initApp(); - std::cout << "Set up RTSS" << "\n"; + std::cout << "Set up RTSS" + << "\n"; Ogre::Root *root = getRoot(); Ogre::SceneManager *scnMgr = getSceneManager(); @@ -395,19 +397,25 @@ public: Ogre::RTShader::ShaderGenerator::getSingletonPtr(); shadergen->addSceneManager(scnMgr); setWindowGrab(false); - std::cout << "Init camera" << "\n"; + std::cout << "Init camera" + << "\n"; initCamera(); - std::cout << "Set up water" << "\n"; - std::cout << "Set up cursor" << "\n"; + std::cout << "Set up water" + << "\n"; + std::cout << "Set up cursor" + << "\n"; Ogre::ResourceGroupManager::getSingleton() .initialiseAllResourceGroups(); // OgreBites::ApplicationContext::loadResources(); // setupCursor(); - std::cout << "Setup input" << "\n"; + std::cout << "Setup input" + << "\n"; setupInput(); - std::cout << "Create content" << "\n"; + std::cout << "Create content" + << "\n"; createContent(); - std::cout << "Setup done" << "\n"; + std::cout << "Setup done" + << "\n"; #if 0 mDbgDraw->setDebugMode(mDbgDraw->getDebugMode() | btIDebugDraw::DBG_DrawContactPoints); @@ -721,9 +729,7 @@ public: } flecs::entity getPlayer() const { - flecs::entity player = - ECS::get().lookup("ECS::CharacterModule::player"); - return player; + return ECS::player; } void enableDbgDraw(bool enable) { @@ -789,7 +795,7 @@ int main() { App ctx; ctx.configure(); - ctx.enableDbgDraw(false); + // ctx.enableDbgDraw(false); ctx.getRoot()->startRendering(); ctx.setWindowGrab(false); ctx.closeApp(); diff --git a/src/gamedata/CharacterManagerModule.cpp b/src/gamedata/CharacterManagerModule.cpp index 476e130..303c12a 100644 --- a/src/gamedata/CharacterManagerModule.cpp +++ b/src/gamedata/CharacterManagerModule.cpp @@ -18,12 +18,19 @@ flecs::entity CharacterManagerModule::createPlayer(const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) { + static int count = 0; + OgreAssert(count == 0, "overspawn"); + OgreAssert(!player.is_valid(), "Player already created"); player = ECS::get().entity("player"); - Ogre::Vector3 playerPos(0, 0, 4); - player.set({ rotation, position }); - player.set({ "normal-male.glb" }); - player.add(); - player.add(); + OgreAssert(player.is_valid(), "Can't create player"); + std::cout << "Begin player create" << std::endl; + player.set({ rotation, position }) + .set({ "normal-male.glb" }) + .add() + // .add() + .add(); + std::cout << "End player create" << std::endl; + count++; return player; } flecs::entity @@ -39,4 +46,4 @@ CharacterManagerModule::createCharacterData(const Ogre::String model, .add(); return e; } -} \ No newline at end of file +} diff --git a/src/gamedata/CharacterManagerModule.h b/src/gamedata/CharacterManagerModule.h index 96741d1..d9137ce 100644 --- a/src/gamedata/CharacterManagerModule.h +++ b/src/gamedata/CharacterManagerModule.h @@ -5,6 +5,7 @@ namespace ECS { struct CharacterManagerModule { std::set characters; + flecs::entity player; CharacterManagerModule(flecs::world &ecs); flecs::entity createPlayer(const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); @@ -12,6 +13,10 @@ struct CharacterManagerModule { const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); void removeCharacterData(int id); + flecs::entity getPlayer() const + { + return player; + } }; } -#endif \ No newline at end of file +#endif diff --git a/src/gamedata/CharacterModule.cpp b/src/gamedata/CharacterModule.cpp index b185aa6..c362823 100644 --- a/src/gamedata/CharacterModule.cpp +++ b/src/gamedata/CharacterModule.cpp @@ -6,6 +6,7 @@ #include "Components.h" #include "PhysicsModule.h" #include "CharacterAnimationModule.h" +#include "CharacterManagerModule.h" #include "CharacterModule.h" #include "goap.h" namespace ECS @@ -30,6 +31,7 @@ CharacterModule::CharacterModule(flecs::world &ecs) ecs.component(); ecs.component(); ecs.component().add(flecs::Singleton); + ecs.import (); ecs.import (); ecs.import (); @@ -41,8 +43,10 @@ CharacterModule::CharacterModule(flecs::world &ecs) ecs.system("HandleInput") .kind(flecs::OnUpdate) .each([this](Input &input, Camera &camera) { - if (!ECS::player.is_valid()) - return; + flecs::entity player = + ECS::get().getPlayer(); + if (!player.is_valid()) + return; /* handle input */ // if (input.control == input.control_prev) // return; @@ -263,38 +267,59 @@ CharacterModule::CharacterModule(flecs::world &ecs) } }); #endif - ecs.observer("SetupCharacterM") + static int characterCount = 0; + ecs.observer( + "SetupCharacterBaseObs") + .event(flecs::OnAdd) + .each([&](flecs::entity e, const EngineData &eng, + const CharacterLocation &loc, + const CharacterConf &conf, CharacterBase &ch) { + ch.mBodyEnt = eng.mScnMgr->createEntity(conf.type); + ch.mBodyNode = eng.mScnMgr->getRootSceneNode() + ->createChildSceneNode(); + ch.mBodyNode->setOrientation(loc.orientation); + ch.mBodyNode->setPosition(loc.position); + ch.mBodyNode->attachObject(ch.mBodyEnt); + ch.mSkeleton = ch.mBodyEnt->getSkeleton(); + OgreAssert(ch.mBodyEnt->getSkeleton()->hasBone("Root"), + "No root bone"); + OgreAssert(ch.mSkeleton->hasBone("Root"), + "No root bone"); + ch.mRootBone = ch.mSkeleton->getBone("Root"); + OgreAssert(ch.mRootBone, "No root bone"); + ch.mBoneMotion = Ogre::Vector3::ZERO; + ch.mBonePrevMotion = Ogre::Vector3::ZERO; + }); + ecs.observer("SetupAnimationControlObs") + .event(flecs::OnAdd) + .each([](flecs::entity e, AnimationControl &anim) { + anim.configured = false; + }); + + ecs.observer( + "SetupCharacterObs") .event(flecs::OnSet) .with() - .without() - .each([](flecs::entity e, const EngineData &eng, - const CharacterLocation &loc, - const CharacterConf &conf) { - CharacterBase &ch = e.ensure(); - AnimationControl &anim = e.ensure(); - ch.mBodyEnt = eng.mScnMgr->createEntity(conf.type); - ch.mBodyNode = eng.mScnMgr->getRootSceneNode() - ->createChildSceneNode(); - ch.mBodyNode->setOrientation(loc.orientation); - ch.mBodyNode->setPosition(loc.position); - ch.mBodyNode->attachObject(ch.mBodyEnt); - ch.mSkeleton = ch.mBodyEnt->getSkeleton(); - OgreAssert(ch.mBodyEnt->getSkeleton()->hasBone("Root"), - "No root bone"); - OgreAssert(ch.mSkeleton->hasBone("Root"), - "No root bone"); - ch.mRootBone = ch.mSkeleton->getBone("Root"); - OgreAssert(ch.mRootBone, "No root bone"); - // body.mController = nullptr; - ch.mBoneMotion = Ogre::Vector3::ZERO; - ch.mBonePrevMotion = Ogre::Vector3::ZERO; + .without() + .without() + .write() + .write() + .each([&](flecs::entity e, const CharacterLocation &loc, + const CharacterConf &conf) { + std::cout << "OBSERVER!!!" + << " " << e.id() << std::endl; + if (e.has() || e.has()) + return; + e.world().defer_begin(); + e.add(); + e.add(); e.set( { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); e.add(); e.add(); - anim.configured = false; - }); + e.world().defer_end(); + }); #if 0 ecs.system("SetupCharacter") diff --git a/src/gamedata/GUIModule.cpp b/src/gamedata/GUIModule.cpp index c7d1d33..1e0f7a4 100644 --- a/src/gamedata/GUIModule.cpp +++ b/src/gamedata/GUIModule.cpp @@ -20,6 +20,7 @@ #include "TerrainModule.h" #include "StaticGeometryModule.h" #include "EditorGizmoModule.h" +#include "PhysicsModule.h" #include "GUIModule.h" namespace ECS { @@ -484,7 +485,8 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { Ogre::Image worldMapImage; EditorGUIListener(Ogre::ImGuiOverlay *overlay) - : Ogre::RenderTargetListener() + : Ogre::RenderTargetListener() + , keepCameraAbove(true) { _midFont = createFont("midFont", "General", "Jupiteroid-Regular.ttf", 18.0f); @@ -561,6 +563,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { } void buttons_panel() { + bool enableDebugRender = ECS::get().enableDbgDraw; ImVec2 size = ImGui::GetMainViewport()->Size; float window_width = size.x * 0.2f; if (window_width > panel_width) @@ -577,6 +580,40 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { Ogre::Root::getSingleton().queueEndRendering(); if (ImGui::Button("Return")) ECS::get().get().finish(); + if (ImGui::Checkbox("Enable physics debug", + &enableDebugRender)) { + ECS::get_mut().enableDbgDraw = + enableDebugRender; + ECS::modified(); + PhysicsModule::setDebugDraw(enableDebugRender); + } + if (ImGui::Button("Deploy config")) { + std::function m = [&](const Ogre::String &src, + const Ogre::String &dst) { + std::ifstream source(src, std::ios::binary); + std::ofstream destination(dst, + std::ios::binary); + + OgreAssert(source.is_open(), + "Failed to copy files " + src + + " -> " + dst); + OgreAssert(destination.is_open(), + "Failed to copy files " + src + + " -> " + dst); + OgreAssert(source.is_open() && + destination.is_open(), + "Failed to copy files " + src + + " -> " + dst); + destination << source.rdbuf(); + destination.close(); + source.close(); + }; + m("resources/buildings/items.list", + "../../resources/buildings/items.list"); + m("resources/terrain/world_map.png", + "../../resources/terrain/world_map.png"); + } + ImGui::Checkbox("Keep camera above 0", &keepCameraAbove); #if 0 if (ImGui::Button("Enable/Disable item editor")) { enableEditor ^= true; @@ -765,6 +802,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { orientation = ECS::get() .sceneNode->_getDerivedOrientation(); } + bool keepCameraAbove = true; void setCameraPos() { Ogre::Vector3 cursorPos; @@ -781,8 +819,22 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { TerrainModule::get_height( ECS::get().mTerrainGroup, cameraPos) + 10.0f; - if (cameraPos.y < 0.0f) - cameraPos.y = 10.0f; + if (keepCameraAbove) { + if (cameraPos.y < 0.0f) + cameraPos.y = 10.0f; + } else { + Ogre::TerrainGroup *tg = + ECS::get().mTerrainGroup; + long x, y; + tg->convertWorldPositionToTerrainSlot(cameraPos, &x, + &y); + if (tg->getTerrain(x, y) && + tg->getTerrain(x, y)->isLoaded()) { + float height = + tg->getHeightAtWorldPosition(cameraPos); + cameraPos.y = height + 10.0f; + } + } ECS::get().mCameraPivot->_setDerivedPosition(cameraPos); ECS::get().mCameraPivot->_setDerivedOrientation( cursorOrientation); @@ -822,8 +874,22 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { TerrainModule::get_height( ECS::get().mTerrainGroup, cameraPos) + 10.0f; - if (cameraPos.y < 0.0f) - cameraPos.y = 10.0f; + if (keepCameraAbove) { + if (cameraPos.y < 0.0f) + cameraPos.y = 10.0f; + } else { + Ogre::TerrainGroup *tg = + ECS::get().mTerrainGroup; + long x, y; + tg->convertWorldPositionToTerrainSlot(cameraPos, &x, + &y); + if (tg->getTerrain(x, y) && + tg->getTerrain(x, y)->isLoaded()) { + float height = + tg->getHeightAtWorldPosition(cameraPos); + cameraPos.y = height + 10.0f; + } + } ECS::get().mCameraPivot->_setDerivedPosition(cameraPos); ECS::get().mCameraPivot->_setDerivedOrientation( cursorOrientation); @@ -988,8 +1054,11 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { length += 1.0f; } } - static void findPierPath(std::vector &path) + static void findPierPath(float pathLength, + std::vector &path) { + float minHeight = 0.2f; + int i; Ogre::Vector3 basePos = ECS::get().sceneNode->_getDerivedPosition(); Ogre::Quaternion baseRot = @@ -997,66 +1066,59 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { .sceneNode->_getDerivedOrientation(); Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1); float length = 0.0f; - while (length < 260.0f) { + while (length < pathLength) { Ogre::Vector3 currentPosition = basePos + direction * (length); float dheight = ECS::get() .mTerrainGroup->getHeightAtWorldPosition( currentPosition); + if (dheight < minHeight) + dheight = minHeight; Ogre::Vector3 localOffset = Ogre::Vector3(0, 0, 1) * length; - if (dheight < 0 && path.size() == 0) - return; - if (path.size() == 0) { - Ogre::Vector3 localFromWorld = - ECS::get() - .sceneNode - ->convertWorldToLocalPosition( - { currentPosition.x, - dheight, - currentPosition.z }); - path.push_back({ localOffset.x, - localFromWorld.y, - localOffset.z }); - } else { - float height = path.back().y; - if (height - dheight > 0.2f) - dheight = height - 0.2f; - height = dheight; - if (height < 0) { - height = 0; - Ogre::Vector3 localFromWorld = - ECS::get() - .sceneNode - ->convertWorldToLocalPosition( - { currentPosition - .x, - height, - currentPosition - .z }); - path.push_back({ localOffset.x, - localFromWorld.y, - localOffset.z }); - break; - - } else { - Ogre::Vector3 localFromWorld = - ECS::get() - .sceneNode - ->convertWorldToLocalPosition( - { currentPosition - .x, - height, - currentPosition - .z }); - path.push_back({ localOffset.x, - localFromWorld.y, - localOffset.z }); - } - } - length += 0.5f; + Ogre::Vector3 localFromWorld = + ECS::get() + .sceneNode->convertWorldToLocalPosition( + { currentPosition.x, dheight, + currentPosition.z }); + path.push_back({ localOffset.x, localFromWorld.y, + localOffset.z }); + length += 2.0f; } + if (path.size() == 0) { + path.push_back(Ogre::Vector3(0, 0, 0)); + path.push_back(Ogre::Vector3(0, 0, pathLength)); + } + std::vector tmppath = path; + path.clear(); + for (auto &pt : tmppath) { + if (path.size() == 0) + path.push_back(pt); + else { + if (path.back().z + 0.5f >= pt.z) + continue; + else + path.push_back(pt); + } + } + Ogre::Vector3 lastp = path.back(); + for (i = 1; i < path.size(); i++) { + Ogre::Vector3 &prev = path[i - 1]; + if (path[i].y > prev.y) + continue; + else if (path[i].y < prev.y) { + float d = prev.y - path[i].y; + if (d > 0.15f) + path[i].y = prev.y - 0.15f; + } + } + float dy = path.back().y - lastp.y; + if (dy > 0) + path.push_back({ lastp.x, lastp.y, + path.back().z + dy * 3.0f }); + path.push_back( + { path.back().x, path.back().y, path.back().z + 2.0f }); } static void to_json(nlohmann::json &j, const Ogre::Vector3 &position) { @@ -1079,7 +1141,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { return; findPierHeight(pierOffset + pierLength, pierHeight); std::vector pierPath; - findPierPath(pierPath); + findPierPath(pierOffset + 2.0f, pierPath); flecs::entity e = StaticGeometryModule::createItem( itemPosition, itemOrientation, "harbour"); Ogre::String prop = StaticGeometryModule::getItemProperties(e); @@ -1102,19 +1164,583 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { // updateHeightmap(); // TerrainModule::save_heightmap(); } - void createHarbourMenu() + void createTempleItem() + { + Ogre::Vector3 itemPosition = + ECS::get().sceneNode->_getDerivedPosition(); + Ogre::Quaternion itemOrientation = + ECS::get() + .sceneNode->_getDerivedOrientation(); + flecs::entity e = StaticGeometryModule::createItem( + itemPosition, itemOrientation, "temple"); + Ogre::String prop = StaticGeometryModule::getItemProperties(e); + nlohmann::json j = nlohmann::json::parse(prop); + j["size"] = 40.0f; + j["form"] = "rect"; + j["pillarHeight"] = 16.0f; + j["pillarRadius"] = 0.5f; + j["pillarCount"] = 20; + StaticGeometryModule::setItemProperties(e, j.dump()); + StaticGeometryModule::saveItems(); + } + void createHarbourMenu() { if (ImGui::MenuItem("Create")) createHarbourItem(); } + void createTempleMenu() + { + if (ImGui::MenuItem("Create")) + createTempleItem(); + } + bool editHarbourDistrict(nlohmann::json &jitem) + { + float plazzaRadius = 5.0f; + float plazzaHeight = 0.2f; + float plazzaElevation = 0.0f; + float centerOffset = 0.0f; + bool plazza = false; + bool changed = false; + struct LotData { + float distance; + float angle; + float width; + float depth; + float elevation; + bool valid; + Ogre::String type; + Ogre::String properties; + }; + std::vector centerBuildings; + nlohmann::json &j = jitem; + if (j.find("centerOffset") != j.end()) + centerOffset = j["centerOffset"].get(); + if (j.find("plazza") != j.end()) + plazza = j["plazza"].get(); + if (j.find("plazzaRadius") != j.end()) + plazzaRadius = j["plazzaRadius"].get(); + if (j.find("plazzaHeight") != j.end()) + plazzaHeight = j["plazzaHeight"].get(); + if (j.find("plazzaElevation") != j.end()) + plazzaElevation = j["plazzaElevation"].get(); + if (j.find("centerBuildings") != j.end()) { + for (auto &jb : j["centerBuildings"]) { + LotData data; + data.distance = 100.0f; + data.angle = 0; + data.width = 50.0f; + data.depth = 50.0f; + data.elevation = 0.0f; + data.type = "base"; + data.properties = "{}"; + data.valid = true; + if (jb.find("distance") != jb.end()) + data.distance = + jb["distance"].get(); + if (jb.find("angle") != jb.end()) + data.angle = jb["angle"].get(); + if (jb.find("width") != jb.end()) + data.width = jb["width"].get(); + if (jb.find("depth") != jb.end()) + data.depth = jb["depth"].get(); + if (jb.find("elevation") != jb.end()) + data.elevation = + jb["elevation"].get(); + if (jb.find("type") != jb.end()) + data.type = + jb["type"].get(); + if (jb.find("properties") != jb.end()) + data.properties = + jb["properties"] + .get(); + centerBuildings.push_back(data); + } + } + if (ImGui::SliderFloat("Center Offset", ¢erOffset, 0.0f, + 100.0f)) + changed = true; + if (ImGui::Checkbox("Plazza", &plazza)) + changed = true; + if (plazza) { + if (ImGui::SliderFloat("Plazza Radius", &plazzaRadius, + 5.0f, 100.0f)) + changed = true; + if (ImGui::SliderFloat("Plazza Height", &plazzaHeight, + 0.2f, 1.0f)) + changed = true; + if (ImGui::SliderFloat("Plazza Elevation", + &plazzaElevation, -5.0f, 5.0f)) + changed = true; + } + int count = 0; + for (auto &b : centerBuildings) { + ImGui::Text("Lot %d", count); + Ogre::String ms = + "##" + Ogre::StringConverter::toString(count); + if (ImGui::SliderFloat(("Lot distance" + ms).c_str(), + &b.distance, 0.0f, 100.0f)) + changed = true; + if (ImGui::SliderFloat(("Lot angle" + ms).c_str(), + &b.angle, 0.0f, 360.0f)) + changed = true; + if (ImGui::SliderFloat(("Width" + ms).c_str(), &b.width, + 10.0f, 200.0f)) + changed = true; + if (ImGui::SliderFloat(("Depth" + ms).c_str(), &b.depth, + 10.0f, 200.0f)) + changed = true; + if (ImGui::SliderFloat(("Elevation" + ms).c_str(), + &b.elevation, -10.0f, 10.0f)) + changed = true; + if (ImGui::SmallButton(("Delete" + ms).c_str())) + b.valid = false; + count++; + } + if (ImGui::SmallButton("Add building")) { + changed = true; + LotData data; + data.distance = 100.0f; + data.angle = 0; + data.width = 50.0f; + data.depth = 50.0f; + data.elevation = 0.0f; + data.type = "base"; + data.properties = "{}"; + data.valid = true; + centerBuildings.push_back(data); + } + if (changed) { + j["centerOffset"] = centerOffset; + j["plazza"] = plazza; + j["plazzaRadius"] = plazzaRadius; + j["plazzaHeight"] = plazzaHeight; + j["plazzaElevation"] = plazzaElevation; + nlohmann::json lots = nlohmann::json::array(); + for (const auto &d : centerBuildings) { + nlohmann::json jdata; + if (!d.valid) + continue; + jdata["distance"] = d.distance; + jdata["angle"] = d.angle; + jdata["width"] = d.width; + jdata["depth"] = d.depth; + jdata["elevation"] = d.elevation; + jdata["type"] = d.type; + jdata["properties"] = d.properties; + lots.push_back(jdata); + } + j["centerBuildings"] = lots; + } + return changed; + } + void + createHarbourPopup(const std::pair item) + { + bool lighthouse = false; + float lighthouseDistance = 0.0f; + float lighthouseAngle = 0.0f; + float centerOffset = 0.0f; + bool changed = false; + + Ogre::String prop = + StaticGeometryModule::getItemProperties(item.first); + nlohmann::json j = nlohmann::json::parse(prop); + nlohmann::json jcenter = nlohmann::json::object(); + if (j.find("lighthouse") != j.end()) + lighthouse = j["lighthouse"].get(); + if (j.find("lighthouseDistance") != j.end()) + lighthouseDistance = + j["lighthouseDistance"].get(); + if (j.find("lighthouseAngle") != j.end()) + lighthouseAngle = j["lighthouseAngle"].get(); + if (j.find("centerOffset") != j.end()) + centerOffset = j["centerOffset"].get(); + if (j.find("center") != j.end()) + jcenter = j["center"]; + if (ImGui::Checkbox("Lighthouse", &lighthouse)) + changed = true; + if (lighthouse) { + if (ImGui::SliderFloat("Lighthouse Distance", + &lighthouseDistance, 0.0f, + 100.0f)) + changed = true; + if (ImGui::SliderFloat("Lighthouse Angle", + &lighthouseAngle, -90.0f, 90.0f)) + changed = true; + } + if (ImGui::SliderFloat("Center Offset Global", ¢erOffset, + 0.0f, 100.0f)) + changed = true; + changed = changed || editHarbourDistrict(jcenter); + if (changed) { + j["lighthouse"] = lighthouse; + j["lighthouseDistance"] = lighthouseDistance; + j["lighthouseAngle"] = lighthouseAngle; + j["center"] = jcenter; + j["centerOffset"] = centerOffset; + StaticGeometryModule::setItemProperties(item.first, + j.dump()); + StaticGeometryModule::saveItems(); + StaticGeometryModule::destroyItemGeometry(item.first); + StaticGeometryModule::createItemGeometry(item.first); + } + ImGui::Text("%s", j.dump(4).c_str()); + } + void + createTemplePopup(const std::pair item) + { + float size = 40.0f; + float pillarRadius = 0.5f; + float pillarHeight = 16.0f; + int pillarCount = 20; + Ogre::String form; + + Ogre::String prop = + StaticGeometryModule::getItemProperties(item.first); + nlohmann::json j = nlohmann::json::parse(prop); + bool changed = false; + if (j.find("size") != j.end()) + size = j["size"].get(); + if (j.find("pillarRadius") != j.end()) + pillarRadius = j["pillarRadius"].get(); + if (j.find("pillarHeight") != j.end()) + pillarHeight = j["pillarHeight"].get(); + if (j.find("pillarCount") != j.end()) + pillarCount = j["pillarCount"].get(); + if (ImGui::SliderFloat("Temple Size", &size, 40.0f, 100.0f)) + changed = true; + if (ImGui::SliderFloat("Temple Pillar Radius", &pillarRadius, + 0.5f, 2.0f)) + changed = true; + if (ImGui::SliderFloat("Temple Pillar Height", &pillarHeight, + 16.0f, 60.0f)) + changed = true; + if (ImGui::SliderInt("Pillar Count", &pillarCount, 1, 200)) + changed = true; + if (changed) { + j["size"] = size; + j["pillarRadius"] = pillarRadius; + j["pillarHeight"] = pillarHeight; + j["pillarCount"] = pillarCount; + StaticGeometryModule::setItemProperties(item.first, + j.dump()); + StaticGeometryModule::saveItems(); + StaticGeometryModule::destroyItemGeometry(item.first); + StaticGeometryModule::createItemGeometry(item.first); + } + ImGui::Text("%s", j.dump(4).c_str()); + } + float setLevelValue = 0.0f; + float riseLowerChange = 0.0f; + enum { + COMMAND_NONE, + COMMAND_RISELOWER, + COMMAND_RISELOWER2, + COMMAND_SMOOTH, + COMMAND_SETLEVEL + }; + int command; + void heightmapMenu() + { + command = COMMAND_NONE; + if (ImGui::Button("Elevate")) { + riseLowerChange = strength; + command = COMMAND_RISELOWER; + } + ImGui::SameLine(); + if (ImGui::Button("Elevate2")) { + riseLowerChange = strength; + command = COMMAND_RISELOWER2; + } + ImGui::SameLine(); + if (ImGui::Button("Lower")) { + riseLowerChange = -strength; + command = COMMAND_RISELOWER; + } + std::pair setLevelCommands[] = { + { "Deepest", 0.0f }, { "Deep", 0.25f }, + { "Shallow1", 0.35f }, { "Shallow2", 0.47f }, + { "Beach", 0.517f }, { "Shore1", 0.536f }, + { "Shore2", 0.556f }, { "Shore3", 0.586f }, + { "Shore4", 0.606f }, { "Shore5", 0.626f }, + { "Shore6", 0.646f }, { "Highest", 1.0f }, + }; + int buttonCounter = 0; + for (const auto &mb : setLevelCommands) { + if (ImGui::SmallButton(mb.first.c_str())) { + setLevelValue = mb.second; + command = COMMAND_SETLEVEL; + } + if ((buttonCounter & 3) != 0) + ImGui::SameLine(); + buttonCounter++; + } + ImGui::Spacing(); + if (ImGui::Button("Smooth")) { + command = COMMAND_SMOOTH; + } + ImGui::Separator(); + if (ImGui::MenuItem("Save heightmap")) { + updateWorldTexture(); + updateHeightmap(); + TerrainModule::save_heightmap(); + } + } + void executeCommands() + { + switch (command) { + case COMMAND_RISELOWER: { + int actualSize = 1 + size * 2; + int i, j; + for (i = -actualSize; i < actualSize + 1; i++) + for (j = -actualSize; j < actualSize + 1; j++) { + if (i * i + j * j > + actualSize * actualSize) + continue; + if (selected_x + j < 0 || + selected_x + j >= + worldMap->getWidth()) + continue; + if (selected_y + i < 0 || + selected_y + i >= + worldMap->getHeight()) + continue; + Ogre::ColourValue cv = + worldMapImage.getColourAt( + selected_x + j, + selected_y + i, 0); + float original = cv.r; + original += riseLowerChange; + original = Ogre::Math::Clamp( + original, 0.0f, 1.0f); + cv.r = original; + worldMapImage.setColourAt( + cv, selected_x + j, + selected_y + i, 0); + } + updateWorldTexture(); + updateHeightmap(); + + } break; + case COMMAND_RISELOWER2: { + int actualSize = 1 + size * 2; + int i, j; + Ogre::ColourValue maxcv = worldMapImage.getColourAt( + selected_x, selected_y, 0); + for (i = -actualSize; i < actualSize + 1; i++) + for (j = -actualSize; j < actualSize + 1; j++) { + if (i * i + j * j > + actualSize * actualSize) + continue; + if (selected_x + j < 0 || + selected_x + j >= + worldMap->getWidth()) + continue; + if (selected_y + i < 0 || + selected_y + i >= + worldMap->getHeight()) + continue; + float actualStrength = + riseLowerChange / + (1.0f + (float)(i * i + j * j)); + Ogre::ColourValue cv = + worldMapImage.getColourAt( + selected_x + j, + selected_y + i, 0); + float original = + maxcv.r + actualStrength; + original = Ogre::Math::Clamp( + original, 0.0f, 1.0f); + if (cv.r >= original) + continue; + cv.r = original; + worldMapImage.setColourAt( + cv, selected_x + j, + selected_y + i, 0); + } + updateWorldTexture(); + updateHeightmap(); + } break; + case COMMAND_SMOOTH: { + int actualSize = 1 + size * 2; + int i, j, k, l; + for (i = -actualSize; i < actualSize + 1; i++) + for (j = -actualSize; j < actualSize + 1; j++) { + if (i * i + j * j > + actualSize * actualSize) + continue; + if (selected_x + j < 0 || + selected_x + j >= + worldMap->getWidth()) + continue; + if (selected_y + i < 0 || + selected_y + i >= + worldMap->getHeight()) + continue; + int kernel = 3; + float original = 0.0f; + Ogre::ColourValue cv; + float count = 0.0f; + for (k = -kernel; k < kernel + 1; k++) { + if (selected_y + i + k < 0 || + selected_y + i + k >= + worldMap->getHeight()) + continue; + for (l = -kernel; + l < kernel + 1; l++) { + if (selected_x + j + l < + 0 || + selected_x + j + + l >= + worldMap->getWidth()) + continue; + cv = worldMapImage.getColourAt( + selected_x + j, + selected_y + i, + 0); + original += cv.r; + count += 1.0f; + } + } + original /= count; + cv = worldMapImage.getColourAt( + selected_x + j, selected_y + i, + 0); + original = Ogre::Math::Clamp( + original, 0.0f, 1.0f); + cv.r = original; + worldMapImage.setColourAt( + cv, selected_x + j, + selected_y + i, 0); + } + updateWorldTexture(); + updateHeightmap(); + } break; + case COMMAND_SETLEVEL: { + int actualSize = 1 + size * 2; + int i, j; + float original = setLevelValue; + original = Ogre::Math::Clamp(original, 0.0f, 1.0f); + for (i = -actualSize; i < actualSize + 1; i++) + for (j = -actualSize; j < actualSize + 1; j++) { + if (i * i + j * j > + actualSize * actualSize) + continue; + if (selected_x + j < 0 || + selected_x + j >= + worldMap->getWidth()) + continue; + if (selected_y + i < 0 || + selected_y + i >= + worldMap->getHeight()) + continue; + Ogre::ColourValue cv = + worldMapImage.getColourAt( + selected_x + j, + selected_y + i, 0); + cv.r = original; + worldMapImage.setColourAt( + cv, selected_x + j, + selected_y + i, 0); + } + updateWorldTexture(); + updateHeightmap(); + + } break; + } + } + void showItemButtons(const std::pair &item) + { + ImGui::SameLine(); + Ogre::String upd_label = + "Update Height##" + + Ogre::StringConverter::toString(item.first.id()); + if (ImGui::SmallButton(upd_label.c_str())) { + TerrainItem &uitem = item.first.get_mut(); + uitem.position.y = + ECS::get() + .mTerrainGroup->getHeightAtWorldPosition( + uitem.position); + StaticGeometryModule::saveItems(); + } + ImGui::SameLine(); + Ogre::String edit_label = + "Edit##" + + Ogre::StringConverter::toString(item.first.id()); + Ogre::String popupLabel = + "EditPopup" + + Ogre::StringConverter::toString(item.first.id()); + if (ImGui::SmallButton(edit_label.c_str())) + ImGui::OpenPopup(popupLabel.c_str()); + ImGui::SameLine(); + Ogre::String del_label = + "delete##" + + Ogre::StringConverter::toString(item.first.id()); + if (ImGui::SmallButton(del_label.c_str())) { + item.first.destruct(); + StaticGeometryModule::saveItems(); + } + ImGui::Spacing(); + } + void showItemPopup(const std::pair &item) + { + Ogre::String popupLabel = + "EditPopup" + + Ogre::StringConverter::toString(item.first.id()); + if (ImGui::BeginPopup(popupLabel.c_str())) { + Ogre::String prop = + StaticGeometryModule::getItemProperties( + item.first); + nlohmann::json j = nlohmann::json::parse(prop); + Ogre::String itemType = j["type"].get(); + if (itemType == "harbour") + createHarbourPopup(item); + else if (itemType == "temple") + createTemplePopup(item); + ImGui::EndPopup(); + } + } + + void displayItems() + { + std::pair selected_item; + std::list > items; + StaticGeometryModule::getItemsProperties(&items); + bool item_is_selected = false; + for (const auto &item : items) { + Ogre::String label = Ogre::StringConverter::toString( + item.first.id()); + label += item.second.substr(0, 32); + if (ImGui::SmallButton(label.c_str())) { /* select */ + selected_item = item; + item_is_selected = true; + } + showItemButtons(item); + } + if (item_is_selected) + setCameraSelectedPos(selected_item.first); + for (const auto &item : items) + showItemPopup(item); + } + void displayInfo() + { + ImGui::Text("Position: %d %d", pos_x, pos_y); + ImGui::Text("Selected Position: %d %d", selected_x, selected_y); + ImGui::Text("Height: %f", + worldMapImage.getColourAt(pos_x, pos_y, 0).r); + ImGui::Text( + "Selected height: %f", + worldMapImage.getColourAt(selected_x, selected_y, 0).r); + { + Ogre::Vector3 position = + ECS::get() + .sceneNode->_getDerivedPosition(); + ImGui::Text("Cursor position %f %f %f", position.x, + position.y, position.z); + } + } void worldMapView() { - bool riseLower = false; - bool riseLower2 = false; - bool smooth = false; - bool setLevel = false; - float setLevelValue = 0.0f; - float riseLowerChange = 0.0f; OgreAssert(TerrainModule::get_img_x(0) == worldMap->getWidth() / 2, "get_img_x"); @@ -1156,7 +1782,11 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { createHarbourMenu(); ImGui::EndMenu(); } - ImGui::EndMenu(); + if (ImGui::BeginMenu("Temple")) { + createTempleMenu(); + ImGui::EndMenu(); + } + ImGui::EndMenu(); } if (ImGui::BeginMenu("Heightmap")) { if (ImGui::MenuItem("Update terrain")) @@ -1167,87 +1797,8 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { 0.0f, 1.0f); ImGui::SliderInt("Size", &size, 0, 32); ImGui::Separator(); - if (ImGui::Button("Elevate")) { - riseLower = true; - riseLowerChange = strength; - } - ImGui::SameLine(); - if (ImGui::Button("Elevate2")) { - riseLower2 = true; - riseLowerChange = strength; - } - ImGui::SameLine(); - if (ImGui::Button("Lower")) { - riseLower = true; - riseLowerChange = -strength; - } - if (ImGui::Button("Deepest")) { - setLevel = true; - setLevelValue = 0.0f; - } - ImGui::SameLine(); - if (ImGui::Button("Deep")) { - setLevel = true; - setLevelValue = 0.25f; - } - ImGui::SameLine(); - if (ImGui::Button("Shallow1")) { - setLevel = true; - setLevelValue = 0.35f; - } - ImGui::SameLine(); - if (ImGui::Button("Shallow2")) { - setLevel = true; - setLevelValue = 0.47f; - } - if (ImGui::Button("Beach")) { - setLevel = true; - setLevelValue = 0.516f; - } - ImGui::SameLine(); - if (ImGui::Button("Shore1")) { - setLevel = true; - setLevelValue = 0.536f; - } - ImGui::SameLine(); - if (ImGui::Button("Shore2")) { - setLevel = true; - setLevelValue = 0.556f; - } - if (ImGui::Button("Shore3")) { - setLevel = true; - setLevelValue = 0.586f; - } - ImGui::SameLine(); - if (ImGui::Button("Shore4")) { - setLevel = true; - setLevelValue = 0.606f; - } - ImGui::SameLine(); - if (ImGui::Button("Shore5")) { - setLevel = true; - setLevelValue = 0.626f; - } - if (ImGui::Button("Shore6")) { - setLevel = true; - setLevelValue = 0.646f; - } - ImGui::SameLine(); - if (ImGui::Button("Highest")) { - setLevel = true; - setLevelValue = 1.0f; - } - ImGui::SameLine(); - if (ImGui::Button("Smooth")) { - smooth = true; - } - ImGui::Separator(); - if (ImGui::MenuItem("Save heightmap")) { - updateWorldTexture(); - updateHeightmap(); - TerrainModule::save_heightmap(); - } - ImGui::EndMenu(); + heightmapMenu(); + ImGui::EndMenu(); } ImGui::EndMenuBar(); } @@ -1339,240 +1890,42 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { ImGui::EndChild(); ImGui::Spacing(); ImGui::BeginChild("WorldMap Bottom...", ImVec2(0, 0)); - ImGui::Text("Position: %d %d", pos_x, pos_y); - ImGui::Text("Selected Position: %d %d", selected_x, selected_y); - ImGui::Text("Height: %f", - worldMapImage.getColourAt(pos_x, pos_y, 0).r); - ImGui::Text( - "Selected height: %f", - worldMapImage.getColourAt(selected_x, selected_y, 0).r); - { - Ogre::Vector3 position = - ECS::get() - .sceneNode->_getDerivedPosition(); - ImGui::Text("Cursor position %f %f %f", position.x, - position.y, position.z); - } - if (ImGui::Button("Update cursor position")) { - Ogre::Vector3 position = - ECS::get() - .sceneNode->_getDerivedPosition(); - position.y = - ECS::get() - .mTerrainGroup - ->getHeightAtWorldPosition(position); - ECS::get().sceneNode->_setDerivedPosition( - position); - } - ImGui::SliderFloat("Cursor Angle...", &cursorAngle, -180.0f, - 180.0f); - ECS::get().sceneNode->_setDerivedOrientation( - Ogre::Quaternion(Ogre::Degree(cursorAngle), - Ogre::Vector3::UNIT_Y)); - flecs::entity selected_item; - bool item_is_selected = false; - { - std::list > items; - StaticGeometryModule::getItemsProperties(&items); - for (const auto &item : items) { - Ogre::String label = - Ogre::StringConverter::toString( - item.first.id()); - label += item.second.substr(0, 32); - if (ImGui::SmallButton( - label.c_str())) { /* select */ - selected_item = item.first; - item_is_selected = true; - setCameraSelectedPos(selected_item); - } - ImGui::SameLine(); - Ogre::String upd_label = - "Update Height##" + - Ogre::StringConverter::toString( - item.first.id()); - if (ImGui::SmallButton(upd_label.c_str())) { - TerrainItem &uitem = - item.first - .get_mut(); - uitem.position.y = - ECS::get() - .mTerrainGroup - ->getHeightAtWorldPosition( - uitem.position); - StaticGeometryModule::saveItems(); - } - ImGui::SameLine(); - Ogre::String del_label = - "delete##" + - Ogre::StringConverter::toString( - item.first.id()); - if (ImGui::SmallButton(del_label.c_str())) { - item.first.destruct(); - StaticGeometryModule::saveItems(); - } - ImGui::Spacing(); - } - } - if (riseLower) { - int actualSize = 1 + size * 2; - int i, j; - for (i = -actualSize; i < actualSize + 1; i++) - for (j = -actualSize; j < actualSize + 1; j++) { - if (i * i + j * j > - actualSize * actualSize) - continue; - if (selected_x + j < 0 || - selected_x + j >= - worldMap->getWidth()) - continue; - if (selected_y + i < 0 || - selected_y + i >= - worldMap->getHeight()) - continue; - Ogre::ColourValue cv = - worldMapImage.getColourAt( - selected_x + j, - selected_y + i, 0); - float original = cv.r; - original += riseLowerChange; - original = Ogre::Math::Clamp( - original, 0.0f, 1.0f); - cv.r = original; - worldMapImage.setColourAt( - cv, selected_x + j, - selected_y + i, 0); - } - updateWorldTexture(); - updateHeightmap(); - } - if (riseLower2) { - int actualSize = 1 + size * 2; - int i, j; - Ogre::ColourValue maxcv = worldMapImage.getColourAt( - selected_x, selected_y, 0); - for (i = -actualSize; i < actualSize + 1; i++) - for (j = -actualSize; j < actualSize + 1; j++) { - if (i * i + j * j > - actualSize * actualSize) - continue; - if (selected_x + j < 0 || - selected_x + j >= - worldMap->getWidth()) - continue; - if (selected_y + i < 0 || - selected_y + i >= - worldMap->getHeight()) - continue; - float actualStrength = - riseLowerChange / - (1.0f + (float)(i * i + j * j)); - Ogre::ColourValue cv = - worldMapImage.getColourAt( - selected_x + j, - selected_y + i, 0); - float original = - maxcv.r + actualStrength; - original = Ogre::Math::Clamp( - original, 0.0f, 1.0f); - if (cv.r >= original) - continue; - cv.r = original; - worldMapImage.setColourAt( - cv, selected_x + j, - selected_y + i, 0); - } - updateWorldTexture(); - updateHeightmap(); - } - if (smooth) { - int actualSize = 1 + size * 2; - int i, j, k, l; - for (i = -actualSize; i < actualSize + 1; i++) - for (j = -actualSize; j < actualSize + 1; j++) { - if (i * i + j * j > - actualSize * actualSize) - continue; - if (selected_x + j < 0 || - selected_x + j >= - worldMap->getWidth()) - continue; - if (selected_y + i < 0 || - selected_y + i >= - worldMap->getHeight()) - continue; - int kernel = 3; - float original = 0.0f; - Ogre::ColourValue cv; - float count = 0.0f; - for (k = -kernel; k < kernel + 1; k++) { - if (selected_y + i + k < 0 || - selected_y + i + k >= - worldMap->getHeight()) - continue; - for (l = -kernel; - l < kernel + 1; l++) { - if (selected_x + j + l < - 0 || - selected_x + j + - l >= - worldMap->getWidth()) - continue; - cv = worldMapImage.getColourAt( - selected_x + j, - selected_y + i, - 0); - original += cv.r; - count += 1.0f; - } - } - original /= count; - cv = worldMapImage.getColourAt( - selected_x + j, selected_y + i, - 0); - original = Ogre::Math::Clamp( - original, 0.0f, 1.0f); - cv.r = original; - worldMapImage.setColourAt( - cv, selected_x + j, - selected_y + i, 0); - } - updateWorldTexture(); - updateHeightmap(); - } - if (setLevel) { - int actualSize = 1 + size * 2; - int i, j; - float original = setLevelValue; - original = Ogre::Math::Clamp(original, 0.0f, 1.0f); - for (i = -actualSize; i < actualSize + 1; i++) - for (j = -actualSize; j < actualSize + 1; j++) { - if (i * i + j * j > - actualSize * actualSize) - continue; - if (selected_x + j < 0 || - selected_x + j >= - worldMap->getWidth()) - continue; - if (selected_y + i < 0 || - selected_y + i >= - worldMap->getHeight()) - continue; - Ogre::ColourValue cv = - worldMapImage.getColourAt( - selected_x + j, - selected_y + i, 0); - cv.r = original; - worldMapImage.setColourAt( - cv, selected_x + j, - selected_y + i, 0); - } - updateWorldTexture(); - updateHeightmap(); - } + displayInfo(); + bool update_cursor_height = false; + bool update_cursor_angle = false; + if (ImGui::Button("Update cursor position")) + update_cursor_height = true; + if (ImGui::SliderFloat("Cursor Angle...", &cursorAngle, -180.0f, + 180.0f)) + update_cursor_angle = true; + displayItems(); ImGui::EndChild(); ImGui::Spacing(); - ImGui::End(); - } + ImGui::End(); + if (update_cursor_height || update_cursor_angle) { + if (update_cursor_height) { + Ogre::Vector3 position = + ECS::get() + .sceneNode + ->_getDerivedPosition(); + position.y = ECS::get() + .mTerrainGroup + ->getHeightAtWorldPosition( + position); + ECS::get() + .sceneNode->_setDerivedPosition( + position); + } + if (update_cursor_angle) + ECS::get() + .sceneNode->_setDerivedOrientation( + Ogre::Quaternion( + Ogre::Degree( + cursorAngle), + Ogre::Vector3::UNIT_Y)); + } + executeCommands(); + } void panel() { ImVec2 size = ImGui::GetMainViewport()->Size; @@ -2033,4 +2386,4 @@ EditorGUIModule::EditorGUIModule(flecs::world &ecs) std::cout << "Editor GUI configure finished\n"; }); } -} \ No newline at end of file +} diff --git a/src/gamedata/GameData.cpp b/src/gamedata/GameData.cpp index aa8d086..e350853 100644 --- a/src/gamedata/GameData.cpp +++ b/src/gamedata/GameData.cpp @@ -1,5 +1,9 @@ #include #include +#include +#include +#include +#include #include "GameData.h" #include "Components.h" #include "CharacterModule.h" @@ -22,7 +26,6 @@ namespace ECS { static flecs::world ecs; -flecs::entity player; void setup_minimal() { ecs.component().add(flecs::Singleton); @@ -38,8 +41,8 @@ void setup_minimal() /* lots of things depend on it */ ecs.component().add(flecs::Singleton); } -void setup(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, - Ogre::Camera *camera, Ogre::RenderWindow *window) +void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window) { std::cout << "Setup GameData\n"; setup_minimal(); @@ -109,12 +112,61 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, // ecs.set({}); std::cout << "Setup GameData done\n"; - - /* Create player */ - player = ecs.get_mut().createPlayer( - { 0, 0, 4 }, Ogre::Quaternion(Ogre::Radian(Ogre::Math::PI), - Ogre::Vector3::UNIT_Y)); + ecs.system("SpawnPlayer").kind(flecs::OnUpdate).interval(0.5f).run([&](flecs::iter &it) { + flecs::entity player = + ECS::get().getPlayer(); + if (!player.is_valid()) { + /* Create player */ + Ogre::Vector3 position; + JPH::BodyID id; + long x, y; + Ogre::TerrainGroup *tg = + ECS::get().mTerrainGroup; + if (tg->isDerivedDataUpdateInProgress()) + return; + tg->convertWorldPositionToTerrainSlot( + Ogre::Vector3(0, 0, 4), &x, &y); + Ogre::Terrain *terrain = tg->getTerrain(x, y); + if (terrain && terrain->isLoaded()) { + if (PhysicsModule::raycastQuery( + Ogre::Vector3(0, 500, 4), + Ogre::Vector3(0, -500, 4), position, + id)) { + if (position.y < -10.0f && + position.y > -50.0f) { + player = + ecs.get_mut< + CharacterManagerModule>() + .createPlayer( + { position.x, + position.y, + position.z }, + Ogre::Quaternion( + Ogre::Radian( + Ogre::Math:: + PI), + Ogre::Vector3:: + UNIT_Y)); + std::cout << position + << std::endl; + // OgreAssert(false, "spawn"); + } + } + } + } + }); } +void setupInteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window) +{ +} + +void setupInventoryScene(Ogre::SceneManager *scnMgr, + Ogre::SceneNode *cameraNode, Ogre::Camera *camera, + Ogre::RenderWindow *window) +{ +} + void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, Ogre::Camera *camera, Ogre::RenderWindow *window) { @@ -200,6 +252,12 @@ flecs::world get() bool Vector3::zeroLength() const { float l = x * x + y * y + z * z; - return (l < 1e-06 * 1e-06); + return (l < 1e-06 * 1e-06); } + +void setupEditorAlt(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window) +{ +} + } diff --git a/src/gamedata/GameData.h b/src/gamedata/GameData.h index ac35df0..f4b54f6 100644 --- a/src/gamedata/GameData.h +++ b/src/gamedata/GameData.h @@ -5,10 +5,16 @@ namespace ECS { extern flecs::entity player; void setup_minimal(); -void setup(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, +void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, Ogre::Camera *camera, Ogre::RenderWindow *window); +void setupInteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window); +void setupInventoryScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window); void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, Ogre::Camera *camera, Ogre::RenderWindow *window); +void setupEditorAlt(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode, + Ogre::Camera *camera, Ogre::RenderWindow *window); void update(float delta); flecs::world get(); template const T &get() diff --git a/src/gamedata/PhysicsModule.cpp b/src/gamedata/PhysicsModule.cpp index e4686f3..9408625 100644 --- a/src/gamedata/PhysicsModule.cpp +++ b/src/gamedata/PhysicsModule.cpp @@ -750,10 +750,15 @@ void PhysicsModule::controlPhysics(flecs::entity e, bool enable) } bool PhysicsModule::raycastQuery(const Ogre::Vector3 &startPos, const Ogre::Vector3 &endPos, - Ogre::Vector3 &position) + Ogre::Vector3 &position, JPH::BodyID &id) { return JoltPhysicsWrapper::getSingleton().raycastQuery(startPos, endPos, - position); + position, id); +} + +void PhysicsModule::setDebugDraw(bool enable) +{ + JoltPhysicsWrapper::getSingleton().setDebugDraw(enable); } bool WaterBody::isInWater(const JPH::BodyID &id) const { diff --git a/src/gamedata/PhysicsModule.h b/src/gamedata/PhysicsModule.h index 9bc63f0..5ec9db1 100644 --- a/src/gamedata/PhysicsModule.h +++ b/src/gamedata/PhysicsModule.h @@ -59,7 +59,8 @@ struct PhysicsModule { static void controlPhysics(flecs::entity e, bool enable); static bool raycastQuery(const Ogre::Vector3 &startPos, const Ogre::Vector3 &endPos, - Ogre::Vector3 &position); + Ogre::Vector3 &position, JPH::BodyID &id); + static void setDebugDraw(bool enable); }; } #endif diff --git a/src/gamedata/StaticGeometryModule.cpp b/src/gamedata/StaticGeometryModule.cpp index 34a247f..6d3ee0e 100644 --- a/src/gamedata/StaticGeometryModule.cpp +++ b/src/gamedata/StaticGeometryModule.cpp @@ -10,60 +10,97 @@ #include "Components.h" #include "GameData.h" #include "TerrainModule.h" +#include "physics.h" +#include "PhysicsModule.h" #include "StaticGeometryModule.h" namespace ECS { +static bool itemsLoaded = false; +static std::list > addQueue; StaticGeometryModule::StaticGeometryModule(flecs::world &ecs) { ecs.module(); ecs.component(); ecs.component(); - ecs.component().on_remove( - [](flecs::entity e, TerrainItemNode &item) { - if (item.itemNode) { - item.itemNode->destroyAllChildrenAndObjects(); - item.itemNode->getCreator()->destroySceneNode( - item.itemNode); - item.itemNode = nullptr; - } - }); + ecs.component().on_remove([](flecs::entity e, + TerrainItemNode &item) { + if (item.itemNode) { + item.itemNode->destroyAllChildrenAndObjects(); + item.itemNode->getCreator()->destroySceneNode( + item.itemNode); + item.itemNode = nullptr; + } + if (item.geo) { + ECS::get().mScnMgr->destroyStaticGeometry( + item.geo); + item.geo = nullptr; + } + }); ecs.import (); - ecs.observer("LoadTerrainItems") + ecs.observer("LoadTerrainItems") .event(flecs::OnSet) - .each([](const Terrain &terrain) { - if (terrain.mTerrainGroup) - loadItems(); + .each([&](const Terrain &terrain) { + if (terrain.mTerrainGroup && !itemsLoaded) { + loadItems(); + itemsLoaded = true; + } }); if (!Ogre::MeshLodGenerator::getSingletonPtr()) new Ogre::MeshLodGenerator(); + ecs.system("AddGeometryQueue").kind(flecs::OnUpdate).run([&](flecs::iter &it) { + std::list items; + if (!ECS::get().mTerrainGroup) + return; + if (!itemsLoaded) { + loadItems(); + itemsLoaded = true; + return; + } + std::list > output; + while (!addQueue.empty()) { + std::pair item = addQueue.front(); + std::pair slot = { item.first, + item.second }; + flecs::entity parent = + ECS::get() + .query_builder() + .build() + .find([&slot](const TerrainSlotParent + &parent) { + return parent.slot == slot; + }); + if (parent.is_valid()) { + ECS::get() + .query_builder() + .with(flecs::ChildOf, parent) + .without() + .write() + .build() + .each([&](flecs::entity e, + const TerrainItem &item) { + std::cout << "item: " << e.id() + << std::endl; + items.push_back(e); + }); + for (auto e : items) { + createItemGeometry(e); + } + addQueue.pop_front(); + } else { + output.push_back(item); + addQueue.pop_front(); + } + } + OgreAssert(addQueue.empty(), "queue is not empty"); + if (!output.empty()) + addQueue = output; + }); } void StaticGeometryModule::addGeometryForSlot(long x, long y) { - std::pair slot = { x, y }; - flecs::entity parent = - ECS::get().query_builder().build().find( - [&slot](const TerrainSlotParent &parent) { - return parent.slot == slot; - }); - std::cout << "addGeometryForSlot: " << x << " " << y << std::endl; - std::list items; - if (parent.is_valid()) { - ECS::get() - .query_builder() - .with(flecs::ChildOf, parent) - .without() - .write() - .build() - .each([&](flecs::entity e, const TerrainItem &item) { - std::cout << "item: " << e.id() << std::endl; - items.push_back(e); - }); - for (auto e : items) { - createItemGeometry(e); - } - } + addQueue.push_back({ x, y }); } void StaticGeometryModule::removeGeometryForSlot(long x, long y) { @@ -199,6 +236,7 @@ void StaticGeometryModule::loadItems() from_json(v["position"], position); from_json(v["orientation"], orientation); properties = v["properties"].get(); + std::cout << v.dump(4) << std::endl; long x, y; ECS::get() .mTerrainGroup->convertWorldPositionToTerrainSlot( @@ -215,13 +253,15 @@ void StaticGeometryModule::loadItems() if (!slot.is_valid()) slot = ECS::get().entity().set( { pos }); - flecs::entity item = ECS::get().entity().child_of(slot); - item.set({ position, orientation, properties }); + OgreAssert(slot.is_valid(), "Failed to create slot"); + flecs::entity item = + ECS::get().entity().child_of(slot).set( + { position, orientation, properties }); std::cout << "createItem: " << x << " " << y << " " << item.id() << std::endl; std::cout << "position: " << item.id() << " " << position << std::endl; - } + } } void StaticGeometryModule::getItemPositionPerSlot( long x, long y, std::list *positions) @@ -275,7 +315,7 @@ void StaticGeometryModule::createItemGeometry(flecs::entity e) ->createChildSceneNode(); itemNode->_setDerivedPosition(e.get().position); itemNode->_setDerivedOrientation(e.get().orientation); - if (jp.find("staticMesh") != jp.end()) { + if (jp.find("staticMesh") != jp.end()) { Ogre::String meshName = jp["staticMesh"].get(); Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().getByName(meshName); @@ -290,53 +330,182 @@ void StaticGeometryModule::createItemGeometry(flecs::entity e) std::cout << "type: " << itemType << std::endl; std::cout << "props: " << props << std::endl; if (itemType == "harbour") { - createHarbour(e, itemNode); - e.set({ itemNode }); - } + Ogre::StaticGeometry *geo = + ECS::get() + .mScnMgr->createStaticGeometry( + "harbour_" + + Ogre::StringConverter::toString( + e.id())); + geo->setRegionDimensions(Ogre::Vector3(140, 140, 140)); + Ogre::Vector3 geoposition = + itemNode->_getDerivedPosition(); + geoposition.y = 0.0f; + geo->setOrigin(geoposition); + createHarbour(e, itemNode, geo); + e.set({ itemNode, geo }); + } else if (itemType == "temple") { + Ogre::StaticGeometry *geo = + ECS::get() + .mScnMgr->createStaticGeometry( + "harbour_" + + Ogre::StringConverter::toString( + e.id())); + geo->setRegionDimensions(Ogre::Vector3(140, 140, 140)); + Ogre::Vector3 geoposition = + itemNode->_getDerivedPosition(); + geoposition.y = 0.0f; + geo->setOrigin(geoposition); + createTemple(e, itemNode, geo); + e.set({ itemNode, geo }); + } } else { std::cout << "can't build item" << std::endl; std::cout << "props: " << props << std::endl; OgreAssert(false, "can't create item"); - } + } +} + +void StaticGeometryModule::destroyItemGeometry(flecs::entity e) +{ + OgreAssert(e.has(), "No geometry created"); +#if 0 + ECS::get().mScnMgr->destroyStaticGeometry() + e.get().geo->destroy(); + e.get_mut().geo = nullptr; + e.modified(); +#endif + e.remove(); +} +void StaticGeometryModule::setupLods(Ogre::LodConfig &config) +{ + // config.advanced.useCompression = false; + // 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.advanced.useBackgroundQueue = false; + Ogre::MeshLodGenerator::getSingleton().generateLodLevels(config); +} + +void StaticGeometryModule::createPlazza(flecs::entity e, + const nlohmann::json &district, + Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + Ogre::MaterialPtr harbourMaterial; + harbourMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialHarbour" + + Ogre::StringConverter::toString(e.id())); + Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation(); + const nlohmann::json &jp = district; + Procedural::TriangleBuffer tb; + float centerOffset = 0.0f; + float plazzaRadius = 5.0f; + float plazzaHeight = 0.2f; + float plazzaElevation = 0.0f; + if (jp.find("centerOffset") != jp.end()) + centerOffset = jp["centerOffset"].get(); + if (jp.find("plazzaRadius") != jp.end()) + plazzaRadius = jp["plazzaRadius"].get(); + if (jp.find("plazzaHeight") != jp.end()) + plazzaHeight = jp["plazzaHeight"].get(); + if (jp.find("plazzaElevation") != jp.end()) + plazzaElevation = jp["plazzaElevation"].get(); + if (plazzaHeight < 0.1f) + plazzaHeight = 0.1f; + if (plazzaRadius < 5.0f) + plazzaRadius = 5.0f; + Ogre::Vector3 worldPlazzaCenter = worldPosition; +#if 0 + Procedural::CylinderGenerator() + .setHeight(plazzaHeight) + .setRadius(plazzaRadius) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + 0.0f, plazzaHeight / 2.0f + plazzaElevation, 0.0f)) + .addToTriangleBuffer(tb); +#endif + float mh = 4.0f; + Procedural::Shape *plazzaShape = new Procedural::Shape(); + plazzaShape->addPoint(0, -plazzaHeight - mh - mh); + plazzaShape->addPoint(plazzaRadius * 0.5f + mh, + -plazzaHeight - mh - mh); + plazzaShape->addPoint(plazzaRadius + mh, -plazzaHeight - mh); + plazzaShape->addPoint(plazzaRadius, -plazzaHeight); + plazzaShape->addPoint(plazzaRadius, 0.0f); + plazzaShape->addPoint(plazzaRadius - 0.1f, 0.1f); + plazzaShape->addPoint(plazzaRadius - mh + 0.1f, plazzaHeight); + plazzaShape->addPoint(plazzaRadius - mh, plazzaHeight + 0.1f); + plazzaShape->addPoint(plazzaRadius * 0.5f + mh, plazzaHeight); + plazzaShape->addPoint(0, plazzaHeight); + Procedural::Lathe() + .setShapeToExtrude(plazzaShape) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + 0.0f, plazzaHeight / 2.0f + plazzaElevation, 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(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(harbourMaterial); + geo->addEntity(pathEnt, worldPlazzaCenter, worldOrientation, + Ogre::Vector3(1, 1, 1)); } struct harbourMaker { Ogre::Entity *planks, *pillar, *beam; + Ogre::String makeName(const Ogre::String &base, flecs::entity e) + { + return base + Ogre::StringConverter::toString(e.id()); + } harbourMaker(flecs::entity e) { - planks = ECS::get().mScnMgr->createEntity( - "Plank" + Ogre::StringConverter::toString(e.id()), - "pier-plank.glb"); - beam = ECS::get().mScnMgr->createEntity( - "Beam" + Ogre::StringConverter::toString(e.id()), - "pier-beam.glb"); - pillar = ECS::get().mScnMgr->createEntity( - "Pillar" + Ogre::StringConverter::toString(e.id()), - "pier-pillar.glb"); -#if 1 - Ogre::Entity *entities[] = { planks, pillar, beam }; - for (Ogre::Entity *ent : entities) { - Ogre::MeshPtr mesh = ent->getMesh(); - Ogre::LodConfig config(mesh); - config.advanced.useCompression = true; - config.advanced.useVertexNormals = true; - config.advanced.preventPunchingHoles = true; - config.advanced.preventBreakingLines = true; - config.createGeneratedLodLevel(10, 0.15f); - config.createGeneratedLodLevel(30, 0.25f); -#if 0 - if (ent == planks) - config.createManualLodLevel( - 20, "pier-plank-LOD.glb"); - else -#endif - config.createGeneratedLodLevel(60, 0.36f); - config.createGeneratedLodLevel(150, 0.65f); - // config.createGeneratedLodLevel(20, 0.95); - config.advanced.useBackgroundQueue = false; - Ogre::MeshLodGenerator::getSingleton().generateLodLevels( - config); - } -#endif + Ogre::String planksName = makeName("Plank", e); + Ogre::String beamName = makeName("Beam", e); + Ogre::String pillarName = makeName("Pillar", e); + std::pair sets[] = { + { planksName, &planks }, + { beamName, &beam }, + { pillarName, &pillar } + }; + std::map meshes = { + { planksName, "pier-plank.glb" }, + { beamName, "pier-beam.glb" }, + { pillarName, "pier-pillar.glb" }, + }; + for (auto &p : sets) { + if (ECS::get().mScnMgr->hasEntity(p.first)) + *p.second = + ECS::get() + .mScnMgr->getEntity(p.first); + else { + *p.second = ECS::get() + .mScnMgr->createEntity( + p.first, + meshes.at(p.first)); + Ogre::MeshPtr mesh = (*p.second)->getMesh(); + Ogre::LodConfig config(mesh); + StaticGeometryModule::setupLods(config); + } + } } }; struct TiledMeshes { @@ -748,6 +917,7 @@ void StaticGeometryModule::createBridge(flecs::entity e, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo) { + int i; Procedural::TriangleBuffer tb; Ogre::MaterialPtr harbourMaterial; harbourMaterial = Ogre::MaterialManager::getSingleton().getByName( @@ -758,6 +928,7 @@ void StaticGeometryModule::createBridge(flecs::entity e, float stepDepth = 0.25f; float stairsHeight = 0.0f; float stairsOffset = 0.0f; + std::vector pierPath; Ogre::String props = e.get().properties; nlohmann::json jp = nlohmann::json::parse(props); if (jp.find("stairsHeight") != jp.end()) @@ -768,309 +939,620 @@ void StaticGeometryModule::createBridge(flecs::entity e, stepHeight = jp["stepHeight"].get(); if (jp.find("stepDepth") != jp.end()) stepDepth = jp["stepDepth"].get(); - float rampLength = stairsHeight / Ogre::Math::Sin(Ogre::Degree(30.0f)); - float rampOffset = Ogre::Math::Sin(rampLength * rampLength - - stairsHeight * stairsHeight); - Procedural::BoxGenerator() - .setSizeX(4.0f) - .setSizeY(0.5f) - .setSizeZ(rampLength) - .setOrientation(Ogre::Quaternion(Ogre::Degree(30.0f), - Ogre::Vector3::UNIT_X)) - .setEnableNormals(true) - .setTextureRectangle(Ogre::RealRect(0.4f, 0.0f, 0.1f, 0.1f)) - .setPosition(Ogre::Vector3(0.0f, 0.8f + stairsHeight / 2.0f, - 4.0f + rampOffset / 2.0f + - stairsOffset / 2.0f)) - .addToTriangleBuffer(tb); - Procedural::BoxGenerator() - .setSizeX(4.0f) - .setSizeY(0.5f) - .setSizeZ(stairsOffset + 5.0f) - .setEnableNormals(true) - .setTextureRectangle(Ogre::RealRect(0.4f, 0.0f, 0.1f, 0.1f)) - .setPosition(Ogre::Vector3(0.0f, 0.8f + stairsHeight, - -(stairsOffset + 5.0f) / 2.0f)) - .addToTriangleBuffer(tb); - Ogre::String meshName = - "elevator" + Ogre::StringConverter::toString(e.id()); - Ogre::MeshPtr mesh = tb.transformToMesh(meshName); - Ogre::LodConfig config(mesh); - // config.advanced.useCompression = false; - // 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.advanced.useBackgroundQueue = false; - Ogre::MeshLodGenerator::getSingleton().generateLodLevels(config); - Ogre::Entity *ent = ECS::get().mScnMgr->createEntity(mesh); - ent->setMaterial(harbourMaterial); - float xofft = 0.0f; - Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition() + - sceneNode->_getDerivedOrientation() * - Ogre::Vector3::UNIT_Z * 0.0f; - Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation(); - Ogre::Vector3 xoffset = - worldOrientation * (Ogre::Vector3::UNIT_X * xofft); - geo->addEntity(ent, worldPosition + xoffset, worldOrientation, - Ogre::Vector3(1, 1, 1)); + if (jp.find("pierPath") != jp.end()) { + pierPath.reserve(jp["pierPath"].size()); + for (auto &jpt : jp["pierPath"]) { + Ogre::Vector3 pt; + from_json(jpt, pt); + pierPath.push_back(pt); + } + } +#if 1 + Procedural::Shape *pierShape = new Procedural::Shape(); + pierShape->addPoint(8.f, -0.7f); + pierShape->addPoint(6.f, 0.7f); + pierShape->addPoint(6.05f, 0.65f); + pierShape->addPoint(0.f, 0.6f); + pierShape->addPoint(-6.05f, 0.65f); + pierShape->addPoint(-6.0f, 0.7f); + pierShape->addPoint(-8.f, -0.7f); + pierShape->close(); + + Procedural::CubicHermiteSpline3 *pierCurve; + Procedural::Path pierCurvePath; + if (jp.find("pierPath") != jp.end()) { + pierPath.reserve(jp["pierPath"].size()); + pierCurve = new Procedural::CubicHermiteSpline3(); + // pierCurve = new Procedural::RoundedCornerSpline3(); +#if 0 + { + int i; + for (i = 0; i < 5; i++) { + Ogre::Vector3 pt; + from_json(jp["pierPath"][i], pt); + pierPath.push_back(pt); + pierCurve->addPoint( + pt, pt - Ogre::Vector3(0, 0, -1), + pt + Ogre::Vector3(0, 0, 1)); + } + Ogre::Vector3 pt2; + from_json(jp["pierPath"].back(), pt2); + pierPath.push_back(pt2); + pierCurve->addPoint(pt2); + for (const auto &m : pierPath) { + std::cout << m << std::endl; + } + } +#endif +#if 1 + for (auto &jpt : jp["pierPath"]) { + Ogre::Vector3 pt; + from_json(jpt, pt); + pierPath.push_back(pt); + pierCurve->addPoint(pt, Ogre::Vector3(0, 0, 1)); + // pierCurve->addPoint(pt); + } +#endif + OgreAssert(pierPath.size() > 0, "empty path"); + // pierCurve->setNumSeg(8); + pierCurvePath = pierCurve->realizePath(); + // V + Procedural::Track shapeTextureTrack = + Procedural::Track(Procedural::Track::AM_POINT) + .addKeyFrame(0, 0.0f) + .addKeyFrame(6, 0.1f); + // U + Procedural::Track pathTextureTrack = + Procedural::Track(Procedural::Track::AM_POINT) + .addKeyFrame(0, 0.45f) + .addKeyFrame(6, 0.9f); + Procedural::Extruder extruder; + extruder.setShapeTextureTrack(&shapeTextureTrack) + .setPathTextureTrack(&pathTextureTrack) + .setShapeToExtrude(pierShape) + .setExtrusionPath(&pierCurvePath) + .setEnableNormals(true) + .setUTile(1.0f) + .setVTile(1.0f) + .addToTriangleBuffer(tb); + for (auto &v : tb.getVertices()) { + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.41f, 0.9f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } +#if 0 + for (const auto &v : tb.getVertices()) { + std::cout << "UV: " << v.mUV << std::endl; + } + OgreAssert(false, "uvs"); +#endif +#if 0 + Ogre::LodConfig config(extrudedMesh); + setupLods(config); + Ogre::Entity *pathEnt = + ECS::get().mScnMgr->createEntity( + extrudedMesh); + pathEnt->setMaterial(harbourMaterial); + float xofft = 0.0f; + Ogre::Vector3 worldPosition = + sceneNode->_getDerivedPosition() + + sceneNode->_getDerivedOrientation() * + Ogre::Vector3::UNIT_Z * 0.0f; + Ogre::Quaternion worldOrientation = + sceneNode->_getDerivedOrientation(); + Ogre::Vector3 xoffset = + worldOrientation * (Ogre::Vector3::UNIT_X * xofft); + geo->addEntity(pathEnt, worldPosition + xoffset, + worldOrientation, Ogre::Vector3(1, 1, 1)); +#endif + } +#else + for (i = 0; i < pierPath.size(); i++) { + if (i == 0) + continue; + Ogre::Vector3 lvec = pierPath[i] - pierPath[i - 1]; + Ogre::Vector3 xvec = Ogre::Vector3::UNIT_Y.crossProduct(lvec); + Ogre::Vector3 n = lvec.crossProduct(xvec).normalisedCopy(); + Ogre::Vector3 pos = (pierPath[i] + pierPath[i - 1]) * 0.5f; + Procedural::PlaneGenerator() + .setNormal(n) + .setNumSegX(2) + .setNumSegY(2) + .setSizeX(1) + .setSizeY(1) + .setPosition(pos) + .addToTriangleBuffer(tb); + } +#endif + Ogre::String meshName = + "pierPathMesh" + 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(harbourMaterial); + float xofft = 0.0f; + Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition() + + sceneNode->_getDerivedOrientation() * + Ogre::Vector3::UNIT_Z * 0.0f; + Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation(); + Ogre::Vector3 xoffset = + worldOrientation * (Ogre::Vector3::UNIT_X * xofft); + geo->addEntity(pathEnt, worldPosition + xoffset, worldOrientation, + Ogre::Vector3(1, 1, 1)); + ECS::get().mScnMgr->destroyEntity(pathEnt); } void StaticGeometryModule::createPier(flecs::entity e, - Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) + Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) { - Ogre::MaterialPtr harbourMaterial; - harbourMaterial = Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialHarbour" + - Ogre::StringConverter::toString(e.id())); - harbourMaker hm(e); - Ogre::Vector3 position = sceneNode->_getDerivedPosition(); - Ogre::String props = e.get().properties; - nlohmann::json jp = nlohmann::json::parse(props); - float pierHeight = 0.0f, pierLength = 6.0f, pierDepth = 6.0f; - if (jp.find("pierLength") != jp.end()) - pierLength = jp["pierLength"].get(); - if (jp.find("pierDepth") != jp.end()) - pierDepth = jp["pierDepth"].get(); - if (jp.find("pierHeight") != jp.end()) - pierHeight = jp["pierHeight"].get(); - Procedural::TriangleBuffer tb; - float plankLength = 2.0f; - float plankWidth = 4.01f; - float plankHeight = 0.3f; - const float beamLength = 6.0f; - const float beamWidth = 5.5f; - float beamHeight = 0.3f; - if (pierLength < 12.0f) - pierLength = 12.0f; - auto processGrid = [&sceneNode, &geo](float stepLength, float length, - float zoffset, float yofft, - float xofft, Ogre::Entity *ent) { - float step = 0.0f; - while (step < length) { - Ogre::Vector3 worldPosition = - sceneNode->_getDerivedPosition() + - sceneNode->_getDerivedOrientation() * - Ogre::Vector3::UNIT_Z * - (step + zoffset); - Ogre::Quaternion worldOrientation = - sceneNode->_getDerivedOrientation(); - Ogre::Vector3 xoffset = worldOrientation * - (Ogre::Vector3::UNIT_X * xofft); - Ogre::Vector3 yoffset = worldOrientation * - (Ogre::Vector3::UNIT_Y * yofft); - geo->addEntity(ent, worldPosition + xoffset + yoffset, - worldOrientation, - Ogre::Vector3(1, 1, 1)); - step += stepLength; - } - }; - float xofftPlanks; - for (xofftPlanks = -plankWidth; xofftPlanks <= plankWidth; - xofftPlanks += plankWidth) - processGrid(plankLength, pierLength, plankLength / 2.0f, - plankHeight / 2.0f + beamHeight / 2.0f, xofftPlanks, - hm.planks); + Ogre::MaterialPtr harbourMaterial; + harbourMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialHarbour" + + Ogre::StringConverter::toString(e.id())); + harbourMaker hm(e); + Ogre::Vector3 position = sceneNode->_getDerivedPosition(); + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + float pierHeight = 0.0f, pierLength = 6.0f, pierDepth = 6.0f; + if (jp.find("pierLength") != jp.end()) + pierLength = jp["pierLength"].get(); + if (jp.find("pierDepth") != jp.end()) + pierDepth = jp["pierDepth"].get(); + if (jp.find("pierHeight") != jp.end()) + pierHeight = jp["pierHeight"].get(); + Procedural::TriangleBuffer tb; + float plankLength = 2.0f; + float plankWidth = 4.01f; + float plankHeight = 0.3f; + const float beamLength = 6.0f; + const float beamWidth = 5.5f; + float beamHeight = 0.3f; + if (pierLength < 12.0f) + pierLength = 12.0f; + auto processGrid = [&sceneNode, &geo](float stepLength, float length, + float zoffset, float yofft, + float xofft, Ogre::Entity *ent) { + float step = 0.0f; + while (step < length) { + Ogre::Vector3 worldPosition = + sceneNode->_getDerivedPosition() + + sceneNode->_getDerivedOrientation() * + Ogre::Vector3::UNIT_Z * + (step + zoffset); + Ogre::Quaternion worldOrientation = + sceneNode->_getDerivedOrientation(); + Ogre::Vector3 xoffset = worldOrientation * + (Ogre::Vector3::UNIT_X * xofft); + Ogre::Vector3 yoffset = worldOrientation * + (Ogre::Vector3::UNIT_Y * yofft); + geo->addEntity(ent, worldPosition + xoffset + yoffset, + worldOrientation, + Ogre::Vector3(1, 1, 1)); + step += stepLength; + } + }; + float xofftPlanks; + for (xofftPlanks = -plankWidth; xofftPlanks <= plankWidth; + xofftPlanks += plankWidth) + processGrid(plankLength, pierLength, plankLength / 2.0f, + plankHeight / 2.0f + beamHeight / 2.0f, xofftPlanks, + hm.planks); { - float step = 0.0f; - while (step < pierLength) { - // pillars + Procedural::TriangleBuffer tbPillars, tbBollards; + float step = 0.0f; + while (step < pierLength) { + // pillars Procedural::BoxGenerator() .setSizeX(0.5f) - .setSizeY(pierDepth) - .setSizeZ(0.5f) + .setSizeY(pierDepth) + .setSizeZ(0.5f) .setEnableNormals(true) - .setTextureRectangle( - Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f)) .setPosition(Ogre::Vector3( - -5.0f, -pierDepth / 2.0f + 0.5f, step)) - .addToTriangleBuffer(tb); + -5.0f, -pierDepth / 2.0f + 0.5f, step)) + .addToTriangleBuffer(tbPillars); Procedural::BoxGenerator() .setSizeX(0.5f) - .setSizeY(pierDepth) - .setSizeZ(0.5f) + .setSizeY(pierDepth) + .setSizeZ(0.5f) .setEnableNormals(true) - .setTextureRectangle( - Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f)) .setPosition(Ogre::Vector3( - 5.0f, -pierDepth / 2.0f + 0.5f, step)) - .addToTriangleBuffer(tb); - step += 6.0f; - } - step = pierLength - 0.5f; - while (step >= 0.0f) { - // bollards - Procedural::CylinderGenerator() - .setHeight(0.8f) - .setRadius(0.3f) - .setTextureRectangle( - Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f)) - .setPosition(Ogre::Vector3( - -5.3f, 0.4f + 0.5f + 0.1f, step)) - .addToTriangleBuffer(tb); - Procedural::CylinderGenerator() - .setHeight(0.8f) - .setRadius(0.3f) - .setTextureRectangle( - Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f)) - .setPosition(Ogre::Vector3( - 5.3f, 0.4f + 0.5f + 0.1f, step)) - .addToTriangleBuffer(tb); - step -= 12.0f; - } - // beams - Procedural::BoxGenerator() - .setSizeX(0.5f) - .setSizeY(beamHeight) - .setSizeZ(pierLength) - .setEnableNormals(true) - .setTextureRectangle( - Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f)) - .setPosition(Ogre::Vector3(-5.0f, - 0.2 + beamHeight / 2.0f, - pierLength / 2.0f)) - .addToTriangleBuffer(tb); - Procedural::BoxGenerator() - .setSizeX(0.5f) - .setSizeY(beamHeight) - .setSizeZ(pierLength) - .setEnableNormals(true) - .setTextureRectangle( - Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f)) - .setPosition(Ogre::Vector3(5.0f, - 0.2 + beamHeight / 2.0f, - pierLength / 2.0f)) - .addToTriangleBuffer(tb); - } - Ogre::String meshName = - "pier" + Ogre::StringConverter::toString(e.id()); - { - Ogre::MeshPtr mesh = tb.transformToMesh(meshName); - Ogre::LodConfig config(mesh); - // config.advanced.useCompression = false; - // 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.advanced.useBackgroundQueue = false; - Ogre::MeshLodGenerator::getSingleton().generateLodLevels( - config); - Ogre::Entity *ent = - ECS::get().mScnMgr->createEntity(mesh); - ent->setMaterial(harbourMaterial); - float xofft = 0.0f; - Ogre::Vector3 worldPosition = - sceneNode->_getDerivedPosition() + - sceneNode->_getDerivedOrientation() * - Ogre::Vector3::UNIT_Z * 0.0f; - Ogre::Quaternion worldOrientation = - sceneNode->_getDerivedOrientation(); - Ogre::Vector3 xoffset = - worldOrientation * (Ogre::Vector3::UNIT_X * xofft); - geo->addEntity(ent, worldPosition + xoffset, worldOrientation, - Ogre::Vector3(1, 1, 1)); - } - std::cout << meshName << std::endl; + 5.0f, -pierDepth / 2.0f + 0.5f, step)) + .addToTriangleBuffer(tbPillars); + step += 6.0f; + } + step = pierLength - 0.5f; + while (step >= 0.0f) { + // bollards + Procedural::CylinderGenerator() + .setHeight(0.8f) + .setRadius(0.3f) + .setPosition(Ogre::Vector3( + -5.3f, 0.4f + 0.5f + 0.1f, step)) + .addToTriangleBuffer(tbBollards); + Procedural::CylinderGenerator() + .setHeight(0.8f) + .setRadius(0.3f) + .setPosition(Ogre::Vector3( + 5.3f, 0.4f + 0.5f + 0.1f, step)) + .addToTriangleBuffer(tbBollards); + step -= 12.0f; + } + // beams + Procedural::BoxGenerator() + .setSizeX(0.5f) + .setSizeY(beamHeight) + .setSizeZ(pierLength) + .setEnableNormals(true) + .setPosition(Ogre::Vector3(-5.0f, + 0.2 + beamHeight / 2.0f, + pierLength / 2.0f)) + .addToTriangleBuffer(tbPillars); + Procedural::BoxGenerator() + .setSizeX(0.5f) + .setSizeY(beamHeight) + .setSizeZ(pierLength) + .setEnableNormals(true) + .setPosition(Ogre::Vector3(5.0f, + 0.2 + beamHeight / 2.0f, + pierLength / 2.0f)) + .addToTriangleBuffer(tbPillars); + for (auto &v : tbPillars.getVertices()) { + v.mUV *= 0.08f; + v.mUV += Ogre::Vector2(0.01f, 0.01f); + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.0f, 0.1f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } + for (auto &v : tbBollards.getVertices()) { + v.mUV *= 0.08f; + v.mUV.x += 0.21f; + v.mUV.y += 0.01f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.2f, 0.3f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } + tb.append(tbPillars); + tb.append(tbBollards); + } + Ogre::String meshName = + "pier" + 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); + // config.advanced.useCompression = false; + // config.advanced.useVertexNormals = true; + setupLods(config); + Ogre::Entity *ent = + ECS::get().mScnMgr->createEntity(mesh); + ent->setMaterial(harbourMaterial); + float xofft = 0.0f; + Ogre::Vector3 worldPosition = + sceneNode->_getDerivedPosition() + + sceneNode->_getDerivedOrientation() * + Ogre::Vector3::UNIT_Z * 0.0f; + Ogre::Quaternion worldOrientation = + sceneNode->_getDerivedOrientation(); + Ogre::Vector3 xoffset = + worldOrientation * (Ogre::Vector3::UNIT_X * xofft); + geo->addEntity(ent, worldPosition + xoffset, worldOrientation, + Ogre::Vector3(1, 1, 1)); + } + std::cout << meshName << std::endl; } + void StaticGeometryModule::createHarbour(flecs::entity e, - Ogre::SceneNode *sceneNode) + Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) { - std::cout << "createHarbour " << e.id() << std::endl; - Ogre::MaterialPtr harbourMaterial; - harbourMaterial = Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialHarbour" + - Ogre::StringConverter::toString(e.id())); - if (!harbourMaterial) { - Procedural::TextureBuffer wood(128); - Procedural::Colours(&wood) - .setColourBase(Ogre::ColourValue(0.8f, 0.6f, 0, 1)) - .setColourPercent(Ogre::ColourValue(0.15f, 0.1f, 0, 1)) - .process(); - // Procedural::RectangleTexture woodDraw(&wood); - Ogre::TexturePtr pierTexture = wood.createTexture( - "proceduralTextureHarbour" + - Ogre::StringConverter::toString(e.id())); - harbourMaterial = - Ogre::MaterialManager::getSingletonPtr()->create( - "proceduralMaterialHarbour" + - Ogre::StringConverter::toString(e.id()), - Ogre::ResourceGroupManager:: - DEFAULT_RESOURCE_GROUP_NAME); - harbourMaterial->getTechnique(0)->getPass(0)->setShininess(0); - harbourMaterial->getTechnique(0)->getPass(0)->setDiffuse( - Ogre::ColourValue::White); - harbourMaterial->getTechnique(0)->getPass(0)->setSpecular( - Ogre::ColourValue(1.0f, 1.0f, 0.9f)); - harbourMaterial->getTechnique(0) - ->getPass(0) - ->createTextureUnitState( - "proceduralTextureHarbour" + - Ogre::StringConverter::toString(e.id())); - if (Ogre::RTShader::ShaderGenerator::initialize()) { - harbourMaterial->prepare(); - Ogre::RTShader::ShaderGenerator *mShaderGenerator = - Ogre::RTShader::ShaderGenerator:: - getSingletonPtr(); - mShaderGenerator->createShaderBasedTechnique( - *harbourMaterial, - Ogre::MaterialManager::DEFAULT_SCHEME_NAME, - Ogre::RTShader::ShaderGenerator:: - DEFAULT_SCHEME_NAME); - Ogre::RTShader::RenderState *pMainRenderState = - mShaderGenerator->getRenderState( - Ogre::RTShader::ShaderGenerator:: - DEFAULT_SCHEME_NAME, - *harbourMaterial); - } - } - Ogre::StaticGeometry *geo = - ECS::get().mScnMgr->createStaticGeometry( - "pier_" + Ogre::StringConverter::toString(e.id())); - geo->setRegionDimensions(Ogre::Vector3(140, 140, 140)); - Ogre::Vector3 geoposition = sceneNode->_getDerivedPosition(); - geoposition.y = 0.0f; - geo->setOrigin(geoposition); - { - Ogre::String props = e.get().properties; - nlohmann::json jp = nlohmann::json::parse(props); - float pierOffset = 0.0f; - if (jp.find("pierOffset") != jp.end()) - pierOffset = jp["pierOffset"].get(); - Ogre::Vector3 worldPosition = - sceneNode->_getDerivedPosition() + - sceneNode->_getDerivedOrientation() * - Ogre::Vector3::UNIT_Z * (pierOffset); - float xofft = 0.0f; - float stairLengthZ = worldPosition.y; - float stairsOffset = 0.0f; - stairsOffset = stairLengthZ; - jp["stairsHeight"] = worldPosition.y; - jp["stairsOffset"] = stairsOffset; - e.get_mut().properties = jp.dump(); - e.modified(); - worldPosition.y = 0.0f; - Ogre::Quaternion worldOrientation = - sceneNode->_getDerivedOrientation(); - Ogre::Vector3 xoffset = - worldOrientation * (Ogre::Vector3::UNIT_X * xofft); - Ogre::Vector3 zoffset = - worldOrientation * - (Ogre::Vector3::UNIT_Z * (stairsOffset + 1)); - Ogre::SceneNode *elevatorNode = - sceneNode->createChildSceneNode(); - elevatorNode->_setDerivedPosition(worldPosition + xoffset); - Ogre::SceneNode *pierNode = sceneNode->createChildSceneNode(); - pierNode->_setDerivedPosition(worldPosition + zoffset + - xoffset); - createBridge(e, elevatorNode, geo); - createPier(e, pierNode, geo); - } - geo->build(); + std::cout << "createHarbour " << e.id() << std::endl; + Ogre::MaterialPtr harbourMaterial; + harbourMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialHarbour" + + Ogre::StringConverter::toString(e.id())); + if (!harbourMaterial) { + 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); + 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(); + Ogre::TexturePtr pierTexture = colorAtlas.createTexture( + "proceduralTextureHarbour" + + Ogre::StringConverter::toString(e.id())); + colorAtlas.saveImage("tmp.png"); + harbourMaterial = + Ogre::MaterialManager::getSingletonPtr()->create( + "proceduralMaterialHarbour" + + Ogre::StringConverter::toString(e.id()), + Ogre::ResourceGroupManager:: + DEFAULT_RESOURCE_GROUP_NAME); + harbourMaterial->getTechnique(0)->getPass(0)->setShininess(0); + harbourMaterial->getTechnique(0)->getPass(0)->setDiffuse( + Ogre::ColourValue::White); + harbourMaterial->getTechnique(0)->getPass(0)->setSpecular( + Ogre::ColourValue(1.0f, 1.0f, 0.9f)); + harbourMaterial->getTechnique(0) + ->getPass(0) + ->createTextureUnitState( + "proceduralTextureHarbour" + + Ogre::StringConverter::toString(e.id())); + if (Ogre::RTShader::ShaderGenerator::initialize()) { + harbourMaterial->prepare(); + Ogre::RTShader::ShaderGenerator *mShaderGenerator = + Ogre::RTShader::ShaderGenerator:: + getSingletonPtr(); + mShaderGenerator->createShaderBasedTechnique( + *harbourMaterial, + Ogre::MaterialManager::DEFAULT_SCHEME_NAME, + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME); + Ogre::RTShader::RenderState *pMainRenderState = + mShaderGenerator->getRenderState( + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME, + *harbourMaterial); + } + } + { + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + float pierOffset = 0.0f; + float centerOffset = 0.0f; + float plazzaRadius = 5.0f; + bool plazza = false; + nlohmann::json jcenter = nlohmann::json::object(); + if (jp.find("center") != jp.end()) + jcenter = jp["center"]; + if (jcenter.find("plazzaRadius") != jcenter.end()) + plazzaRadius = jcenter["plazzaRadius"]; + if (jp.find("pierOffset") != jp.end()) + pierOffset = jp["pierOffset"].get(); + if (jp.find("plazza") != jp.end()) + plazza = jp["plazza"].get(); + if (jp.find("centerOffset") != jp.end()) + centerOffset = jp["centerOffset"].get(); + Ogre::Vector3 worldPosition = + sceneNode->_getDerivedPosition() + + sceneNode->_getDerivedOrientation() * + Ogre::Vector3::UNIT_Z * (pierOffset); + float xofft = 0.0f; + float stairLengthZ = worldPosition.y; + float stairsOffset = 0.0f; + stairsOffset = stairLengthZ; + jp["stairsHeight"] = worldPosition.y; + jp["stairsOffset"] = stairsOffset; + e.get_mut().properties = jp.dump(); + e.modified(); + worldPosition.y = 0.0f; + Ogre::Quaternion worldOrientation = + sceneNode->_getDerivedOrientation(); + Ogre::Vector3 xoffset = + worldOrientation * (Ogre::Vector3::UNIT_X * xofft); + Ogre::Vector3 zoffset = + worldOrientation * + (Ogre::Vector3::UNIT_Z * (stairsOffset - 1)); + Ogre::SceneNode *elevatorNode = + sceneNode->createChildSceneNode(); + Ogre::SceneNode *pierNode = sceneNode->createChildSceneNode(); + pierNode->_setDerivedPosition(worldPosition + zoffset + + xoffset); + Ogre::Vector3 worldPlazzaCenter = + sceneNode->_getDerivedPosition() + + sceneNode->_getDerivedOrientation() * + Ogre::Vector3::UNIT_Z * + (-centerOffset - plazzaRadius + 2.0f); + Ogre::SceneNode *centerNode = sceneNode->createChildSceneNode(); + centerNode->_setDerivedPosition(worldPlazzaCenter); + createBridge(e, elevatorNode, geo); + createPier(e, pierNode, geo); + createPlazza(e, jcenter, centerNode, geo); + createBuildings(e, jcenter, centerNode, geo); + } + geo->build(); } + +void StaticGeometryModule::createBuildings(flecs::entity e, + const nlohmann::json &district, + Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + Ogre::MaterialPtr harbourMaterial; + harbourMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialHarbour" + + Ogre::StringConverter::toString(e.id())); + nlohmann::json jbuildings = nlohmann::json::array(); + if (district.find("centerBuildings") != district.end()) + jbuildings = district["centerBuildings"]; + Ogre::Vector3 centerPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion centerOrientation = + sceneNode->_getDerivedOrientation(); + int count = 0; + float baseHeight = 4.0f; + for (const auto &jb : jbuildings) { + Procedural::TriangleBuffer tb; + float angle = 0.0f; + float depth = 50.0f; + float width = 100.0f; + float distance = 100.0f; + 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("distance") != jb.end()) + distance = jb["distance"].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); + Procedural::BoxGenerator() + .setSizeX(width) + .setSizeY(baseHeight) + .setSizeZ(depth) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + 0.0f, -baseHeight / 2.0f + elevation, 0.0f)) + .addToTriangleBuffer(tb); + OgreAssert(tb.getVertices().size() > 8, "bad box"); + for (auto &v : tb.getVertices()) { + float c = 1.0 + 1.0 / (v.mPosition.y + baseHeight + + elevation); + v.mPosition.x *= c; + v.mPosition.z *= c; + 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 = + "lotbase" + Ogre::StringConverter::toString(count) + + "_" + 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 *ent = + ECS::get().mScnMgr->createEntity( + "Ent" + meshName, mesh); + ent->setMaterial(harbourMaterial); + geo->addEntity(ent, centerPosition + offset, rotation, + Ogre::Vector3::UNIT_SCALE); + ECS::get().mScnMgr->destroyEntity(ent); + count++; + } +} + +void StaticGeometryModule::createTemple(flecs::entity e, + Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + float size; + if (jp.find("size") != jp.end()) + size = jp["size"].get(); + Procedural::TriangleBuffer tb; + float elevation = 0.0f; + Ogre::MaterialPtr templeMaterial; + templeMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialTemple" + + Ogre::StringConverter::toString(e.id())); + if (!templeMaterial) { + Procedural::TextureBuffer colorAtlas(1024); + Procedural::RectangleTexture drawAtlas(&colorAtlas); + Ogre::ColourValue normalGreen(0.6f, 0.8f, 0.5f, 1); + drawAtlas.setRectangle(Ogre::RealRect(0.0f, 0.0f, 0.4f, 1.0f)) + .setColour(normalGreen) + .process(); + Ogre::TexturePtr pierTexture = colorAtlas.createTexture( + "proceduralTextureTemple" + + Ogre::StringConverter::toString(e.id())); + colorAtlas.saveImage("tmp2.png"); + templeMaterial = Ogre::MaterialManager::getSingletonPtr()->create( + "proceduralMaterialTemple" + + Ogre::StringConverter::toString(e.id()), + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + templeMaterial->getTechnique(0)->getPass(0)->setShininess(0); + templeMaterial->getTechnique(0)->getPass(0)->setDiffuse( + Ogre::ColourValue::White); + templeMaterial->getTechnique(0)->getPass(0)->setSpecular( + Ogre::ColourValue(1.0f, 1.0f, 0.9f)); + templeMaterial->getTechnique(0) + ->getPass(0) + ->createTextureUnitState( + "proceduralTextureTemple" + + Ogre::StringConverter::toString(e.id())); + if (Ogre::RTShader::ShaderGenerator::initialize()) { + templeMaterial->prepare(); + Ogre::RTShader::ShaderGenerator *mShaderGenerator = + Ogre::RTShader::ShaderGenerator:: + getSingletonPtr(); + mShaderGenerator->createShaderBasedTechnique( + *templeMaterial, + Ogre::MaterialManager::DEFAULT_SCHEME_NAME, + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME); + Ogre::RTShader::RenderState *pMainRenderState = + mShaderGenerator->getRenderState( + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME, + *templeMaterial); + } + } + Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation(); + Procedural::BoxGenerator() + .setSizeX(size) + .setSizeY(20) + .setSizeZ(size) + .setEnableNormals(true) + .setPosition(Ogre::Vector3(0.0f, -20 / 2.0f + elevation, 0.0f)) + .addToTriangleBuffer(tb); + OgreAssert(tb.getVertices().size() > 8, "bad box"); + for (auto &v : tb.getVertices()) { +#if 0 + float c = 1.0 + 1.0 / (v.mPosition.y + baseHeight + + elevation); + v.mPosition.x *= c; + v.mPosition.z *= c; +#endif + v.mUV *= 0.08f; + v.mUV.x += 0.01f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.0f, 0.4f); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); + } + Ogre::String meshName = + "Temple" + 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 *ent = ECS::get().mScnMgr->createEntity( + "Ent" + meshName, mesh); + ent->setMaterial(templeMaterial); + geo->addEntity(ent, worldPosition, worldOrientation, + Ogre::Vector3::UNIT_SCALE); + ECS::get().mScnMgr->destroyEntity(ent); + geo->build(); + JPH::ShapeRefC shape = + JoltPhysicsWrapper::getSingleton().createMeshShape(mesh); + JPH::BodyID id = JoltPhysicsWrapper::getSingleton().createBody( + shape.GetPtr(), 0, sceneNode, JPH::EMotionType::Static, + Layers::NON_MOVING); + e.set(id); + JoltPhysicsWrapper::getSingleton().addBody(id, + JPH::EActivation::Activate); +} + } diff --git a/src/gamedata/StaticGeometryModule.h b/src/gamedata/StaticGeometryModule.h index babcc63..dffbdea 100644 --- a/src/gamedata/StaticGeometryModule.h +++ b/src/gamedata/StaticGeometryModule.h @@ -1,7 +1,12 @@ #ifndef _STATIC_GEOMETRY_MODULE_H_ #define _STATIC_GEOMETRY_MODULE_H_ #include +#include #include +namespace Ogre +{ +struct LodConfig; +} namespace ECS { struct TerrainSlotParent { @@ -14,6 +19,7 @@ struct TerrainItem { }; struct TerrainItemNode { Ogre::SceneNode *itemNode; + Ogre::StaticGeometry *geo; }; struct StaticGeometryModule { @@ -37,11 +43,16 @@ struct StaticGeometryModule { static void getItemsProperties( std::list > *items); static void createItemGeometry(flecs::entity e); + static void destroyItemGeometry(flecs::entity e); + static void setupLods(Ogre::LodConfig &config); + static void createPlazza(flecs::entity e, const nlohmann::json &district, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); static void createBridge(flecs::entity e, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); static void createPier(flecs::entity e, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); - static void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode); + static void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); + static void createBuildings(flecs::entity e, const nlohmann::json &district, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); + static void createTemple(flecs::entity e, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); }; } -#endif \ No newline at end of file +#endif diff --git a/src/gamedata/TerrainModule.cpp b/src/gamedata/TerrainModule.cpp index a2a6927..34501a3 100644 --- a/src/gamedata/TerrainModule.cpp +++ b/src/gamedata/TerrainModule.cpp @@ -198,10 +198,12 @@ out: long world_grid_y = world_y + grid_center_y; float amplitude = 150.0f; if (world_grid_x < 0 || world_grid_y < 0) { +#if 0 std::cout << "world: " << world_x << " " << world_y << " "; std::cout << "grid: " << world_grid_x << " "; std::cout << world_grid_y << std::endl; +#endif return -amplitude; } OgreAssert(world_grid_x >= 0, "bad world x"); @@ -263,7 +265,6 @@ public: void createTerrainChunk(Ogre::TerrainGroup *terrainGroup, long x, long y) { - std::lock_guard guard(mtx); Ogre::Terrain *terrain = terrainGroup->getTerrain(x, y); float minH = terrain->getMinHeight(); float maxH = terrain->getMaxHeight(); @@ -277,7 +278,7 @@ public: float worldSize = terrain->getWorldSize(); float scaled = worldSize / (size - 1); Ogre::Vector3 bodyPosition = terrain->getPosition(); - bodyPosition.y += (maxH + minH) / 2.0f; + // bodyPosition.y += (maxH + minH) / 2.0f; bodyPosition.x += worldSize / 2.0f; bodyPosition.z += worldSize / 2.0f; Ogre::Vector3 offset = @@ -337,18 +338,29 @@ public: } void update() { - static bool created = false; - std::deque output; + std::lock_guard guard(mtx); + static bool created = false; while (!collider_queue.empty()) { - Ogre::TerrainGroup *group = + Ogre::TerrainGroup *group = collider_queue.front().group; - long x = collider_queue.front().x; + if (group->isDerivedDataUpdateInProgress()) + break; + long x = collider_queue.front().x; long y = collider_queue.front().y; + std::cout << x << " " << y << " " + << collider_queue.size() << std::endl; Ogre::Terrain *terrain = group->getTerrain(x, y); Ogre::Vector3 worldPos; group->convertTerrainSlotToWorldPosition(x, y, &worldPos); - if (terrain && terrain->getHeightData() && + std::cout << "terrain: " << terrain; + if (terrain) + std::cout + << terrain->getHeightData() << " " + << terrain->isLoaded() << " " + << terrain->isDerivedDataUpdateInProgress() + << std::endl; + if (terrain && terrain->getHeightData() && terrain->isLoaded() && !terrain->isDerivedDataUpdateInProgress()) { Ogre::LogManager::getSingleton().logError( @@ -356,8 +368,8 @@ public: Ogre::StringConverter::toString(x) + " " + Ogre::StringConverter::toString(y)); - float minH = terrain->getMinHeight(); - float maxH = terrain->getMaxHeight(); + // float minH = terrain->getMinHeight(); + // float maxH = terrain->getMaxHeight(); int size = terrain->getSize(); float worldSize = terrain->getWorldSize(); { @@ -404,8 +416,8 @@ public: created = true; } #endif - collider_queue.pop_front(); // FIXME: create entities and components instead +#if 0 Ogre::SceneNode *items = terrain->_getRootSceneNode() ->createChildSceneNode(); @@ -425,21 +437,25 @@ public: what->setOrientation(item.rotation); what->setPosition(item.position); } +#endif /* Spawn items */ StaticGeometryModule::addGeometryForSlot(x, y); + collider_queue.pop_front(); } else { - output.push_back(collider_queue.front()); + /* Terrain data not ready maybe move to next terrain */ + gen_collider m = collider_queue.front(); collider_queue.pop_front(); + collider_queue.push_back(m); + break; // allow system to move on } - if (collider_queue.empty() && - !ECS::get().mTerrainReady) { - ECS::get_mut().mTerrainReady = true; - ECS::modified(); - } - } - collider_queue = output; - } + } + if (collider_queue.empty() && + !ECS::get().mTerrainReady) { + ECS::get_mut().mTerrainReady = true; + ECS::modified(); + } + } }; class DummyPageProvider : public Ogre::PageProvider { public: @@ -717,11 +733,12 @@ TerrainModule::TerrainModule(flecs::world &ecs) ECS::get().add(); } }); +#if 0 ecs.system("SetPlayerPosition") .kind(flecs::OnUpdate) .with() .each([this](const Terrain &terrain) { - flecs::entity player = ECS::player; + flecs::entity player = ECS::get()) @@ -745,6 +762,7 @@ TerrainModule::TerrainModule(flecs::world &ecs) player.modified(); ECS::get().remove(); }); +#endif ecs.system("UpdateTerrainGroup") .kind(flecs::OnUpdate) .interval(2.0f) @@ -797,4 +815,4 @@ void TerrainModule::defineTerrain(long x, long y) ECS::get().definer->define(ECS::get().mTerrainGroup, x, y); } -} \ No newline at end of file +} diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 9b9e1c9..ca62ed5 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -283,6 +283,7 @@ public: Ogre::Vector3 p3 = JoltPhysics::convert(inV3); Ogre::ColourValue cv(color[0], color[1], color[2], color[3]); +#if 0 float dproj1 = p1.dotProduct(d); float dproj2 = p2.dotProduct(d); float dproj3 = p3.dotProduct(d); @@ -290,6 +291,7 @@ public: return; if (dproj1 > 50 && dproj2 > 50 && dproj3 > 50) return; +#endif mLines.push_back({ p1, p2, cv }); #if 0 mTriangles.push_back({ { { inV1[0], inV1[1], inV1[2] }, @@ -414,11 +416,14 @@ DebugRenderer::DebugRenderer(Ogre::SceneManager *scnMgr, pass->setCullingMode(Ogre::CullingMode::CULL_NONE); pass->setVertexColourTracking(Ogre::TVC_AMBIENT); pass->setLightingEnabled(false); + pass->setDepthWriteEnabled(false); + pass->setDepthCheckEnabled(false); DebugRenderer::Initialize(); scnMgr->getRootSceneNode()->attachObject(mObject); mLines.reserve(6000); mObject->estimateVertexCount(64000); mObject->estimateIndexCount(8000); + mObject->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY); } DebugRenderer::~DebugRenderer() { @@ -1469,7 +1474,7 @@ public: } } bool raycastQuery(Ogre::Vector3 startPoint, Ogre::Vector3 endPoint, - Ogre::Vector3 &position) + Ogre::Vector3 &position, JPH::BodyID &id) { int i; Ogre::Vector3 direction = endPoint - startPoint; @@ -1479,9 +1484,11 @@ public: bool hadHit = physics_system.GetNarrowPhaseQuery().CastRay( ray, hit, {}, JPH::SpecifiedObjectLayerFilter(Layers::NON_MOVING)); - if (hadHit) + if (hadHit) { position = JoltPhysics::convert( ray.GetPointOnRay(hit.mFraction)); + id = hit.mBodyID; + } return hadHit; } }; @@ -1765,9 +1772,9 @@ void JoltPhysicsWrapper::removeContactListener(const JPH::BodyID &id) } bool JoltPhysicsWrapper::raycastQuery(Ogre::Vector3 startPoint, Ogre::Vector3 endPoint, - Ogre::Vector3 &position) + Ogre::Vector3 &position, JPH::BodyID &id) { - return phys->raycastQuery(startPoint, endPoint, position); + return phys->raycastQuery(startPoint, endPoint, position, id); } template <> JoltPhysicsWrapper *Ogre::Singleton::msSingleton = 0; diff --git a/src/physics/physics.h b/src/physics/physics.h index 68fed6d..6da51e5 100644 --- a/src/physics/physics.h +++ b/src/physics/physics.h @@ -205,6 +205,6 @@ public: listener); void removeContactListener(const JPH::BodyID &id); bool raycastQuery(Ogre::Vector3 startPoint, Ogre::Vector3 endPoint, - Ogre::Vector3 &position); + Ogre::Vector3 &position, JPH::BodyID &id); }; #endif