From 92ec3e9497a3960b76f4d4d6b730149fd12cefba Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Fri, 5 Sep 2025 22:56:48 +0300 Subject: [PATCH] Updates --- CMakeLists.txt | 9 +- Editor.cpp | 19 +- Game.cpp | 692 ++++++++++++++----------------- src/gamedata/CMakeLists.txt | 6 +- src/gamedata/CharacterModule.cpp | 3 +- src/gamedata/Components.h | 15 + src/gamedata/GUIModule.cpp | 314 ++++++++++++++ src/gamedata/GUIModule.h | 30 ++ src/gamedata/GameData.cpp | 31 +- src/gamedata/GameData.h | 12 + src/gamedata/SunModule.cpp | 53 +++ src/gamedata/SunModule.h | 20 + src/gamedata/TerrainModule.cpp | 475 +++++++++++++++++++++ src/gamedata/TerrainModule.h | 30 ++ src/gamedata/WaterModule.cpp | 39 +- src/terrain/terrain.cpp | 3 +- water/water.frag | 22 +- 17 files changed, 1320 insertions(+), 453 deletions(-) create mode 100644 src/gamedata/GUIModule.cpp create mode 100644 src/gamedata/GUIModule.h create mode 100644 src/gamedata/SunModule.cpp create mode 100644 src/gamedata/SunModule.h create mode 100644 src/gamedata/TerrainModule.cpp create mode 100644 src/gamedata/TerrainModule.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e451f5..6cdc3b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,6 @@ set(CREATE_DIRECTORIES # # INTERFACE_LINK_DIRECTORIES "${ASSIMP_LIBRARY_DIRS}" # INTERFACE_LINK_DIRECTORIES "${CMAKE_PREFIX_PATH}/lib" #) -file(GLOB TERRAIN_SRC ${CMAKE_SOURCE_DIR}/src/terrain/*.cpp) file(GLOB WATER_SRC ${CMAKE_SOURCE_DIR}/water/*.cpp) # The COMPONENTS part checks that OGRE was built the way we need it @@ -85,7 +84,7 @@ target_link_options(0_Bootstrap PRIVATE -static-libstdc++ -static-libgcc) endif() add_dependencies(0_Bootstrap stage_files import_vrm) -add_executable(Editor Editor.cpp ${TERRAIN_SRC} ${WATER_SRC}) +add_executable(Editor Editor.cpp ${WATER_SRC}) target_link_libraries(Editor OgreBites OgreBullet OgrePaging OgreTerrain OgreMeshLodGenerator OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY} -Wl,--as-needed ) @@ -93,7 +92,7 @@ if(OGRE_STATIC) target_link_options(Editor PRIVATE -static-libstdc++ -static-libgcc) endif() add_dependencies(Editor stage_files import_buildings import_water_stuff import_vehicles import_vrm) -add_executable(Game Game.cpp ${TERRAIN_SRC} ${WATER_SRC}) +add_executable(Game Game.cpp ${WATER_SRC}) target_include_directories(Game PRIVATE src/gamedata) target_link_libraries(Game OgreBites OgreBullet OgrePaging OgreTerrain OgreMeshLodGenerator OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY} @@ -108,7 +107,7 @@ target_link_options(Game PRIVATE -static-libstdc++ -static-libgcc) endif() add_dependencies(Game stage_files import_buildings import_water_stuff import_vehicles import_vrm audio_data_gui) -add_executable(Procedural Procedural.cpp ${TERRAIN_SRC}) +add_executable(Procedural Procedural.cpp) target_link_libraries(Procedural OgreBites OgreBullet OgrePaging OgreTerrain OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY} @@ -166,7 +165,7 @@ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/water/sea.glb list(APPEND WATER_STUFF ${CMAKE_BINARY_DIR}/water/sea.glb) add_custom_target(import_water_stuff ALL DEPENDS ${WATER_STUFF}) -add_executable(TerrainTest terrain.cpp ${TERRAIN_SRC}) +add_executable(TerrainTest terrain.cpp) target_link_libraries(TerrainTest OgreBites OgreBullet OgrePaging OgreTerrain lua ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY} -Wl,--as-needed ) diff --git a/Editor.cpp b/Editor.cpp index 7038c43..0676873 100644 --- a/Editor.cpp +++ b/Editor.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -9,8 +10,8 @@ #include #include #include +#include -#include "src/terrain/terrain.h" #include "water/water.h" class App; class SkyRenderer : public Ogre::SceneManager::Listener { @@ -250,10 +251,8 @@ class App : public OgreBites::ApplicationContext { Ogre::Camera *mCamera; Ogre::Real mPivotPitch; Ogre::SceneManager *mScnMgr; - OgreBites::InputListenerChain mInput; Ogre::Viewport *mViewport; EditUI m_edit_ui; - TerrainSetup m_terrain; Ogre::Light *mSun; SkyBoxRenderer *sky; Water m_water; @@ -379,7 +378,6 @@ public: , m_edit_ui(this) , mDynWorld(new Ogre::Bullet::DynamicsWorld( Ogre::Vector3(0, -9.8, 0))) - , m_terrain(mDynWorld->getBtWorld()) { } virtual ~App() @@ -467,7 +465,6 @@ public: std::cout << "Create content" << "\n"; createContent(); std::cout << "Setup terrain" << "\n"; - setupTerrain(); m_water.init(); } void setupCursor() @@ -514,6 +511,7 @@ public: } void updateMotion(float delta) { +#if 0 if (delta == 0.0f) return; Ogre::Vector3 move(mCameraNode->getOrientation().zAxis() * @@ -536,6 +534,7 @@ public: // mKbd.motion = Ogre::Vector3(0, 0, 0); // if (move.squaredLength() > 0) // std::cout << move << "\n"; +#endif } void updateCamera(Ogre::Real delta) { @@ -582,10 +581,12 @@ public: mCameraGoal->translate(0, 0, distChange, Ogre::Node::TS_LOCAL); Ogre::Vector3 mh = mCameraGoal->_getDerivedPosition(); +#if 0 float h = m_terrain.get_height(mh); if (h + 10 > mh.y) mCameraGoal->translate(0, 10.0f * deltaZoom, distChange, Ogre::Node::TS_LOCAL); +#endif } Ogre::SceneNode *mSunGoal; Ogre::SceneNode *mSunNode; @@ -659,9 +660,6 @@ public: m_edit_ui.init_glb_list(); m_edit_ui.initGui(); createSun(); - mInput = OgreBites::InputListenerChain( - { getImGuiInputListener(), &mKbd }); - addInputListener(&mInput); getRoot()->addFrameListener(&mKbd); // mTrayMgr->showCursor(); @@ -717,11 +715,6 @@ public: { return mCamera; } - void setupTerrain() - { - m_terrain.setupTerrain(mCamera, mSun, mDynWorld.get(), - mDbgDraw.get()); - } }; void EditUI::buildings_editor() diff --git a/Game.cpp b/Game.cpp index ded5ed1..bc2fb67 100644 --- a/Game.cpp +++ b/Game.cpp @@ -10,11 +10,12 @@ #include #include -#include "src/terrain/terrain.h" -#include "water/water.h" +// #include "water/water.h" #include "GameData.h" #include "Components.h" #include "CharacterModule.h" +#include "TerrainModule.h" +#include "GUIModule.h" #include "sound.h" class App; class SkyRenderer : public Ogre::SceneManager::Listener { @@ -166,88 +167,6 @@ public: mSkyBoxGenParameters.skyBoxDistance = distance; } }; - -class EditUI : public Ogre::RenderTargetListener { - App *m_app; - Ogre::SceneManager *mScnMgr; - Ogre::ImGuiOverlay *mGuiOverlay; - OgreBites::ImGuiInputListener *mGuiListener; - void - preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override - { - preview(evt); - } - -public: - EditUI(App *app) - : Ogre::RenderTargetListener() - , m_app(app) - { - } - - void position_editor(Ogre::SceneNode *node) - { - Ogre::Vector3 position = node->getPosition(); - float v[3] = { position.x, position.y, position.z }; - ImGui::InputFloat3("position", v); - position.x = v[0]; - position.y = v[1]; - position.z = v[2]; - node->setPosition(position); - } - void orientation_editor(Ogre::SceneNode *node) - { - Ogre::Quaternion q = node->getOrientation(); - float yaw = Ogre::Radian(q.getYaw()).valueDegrees(); - float pitch = Ogre::Radian(q.getPitch()).valueDegrees(); - float roll = Ogre::Radian(q.getRoll()).valueDegrees(); - bool m1 = ImGui::InputFloat("yaw", &yaw); - bool m2 = ImGui::InputFloat("pitch", &pitch); - bool m3 = ImGui::InputFloat("roll", &roll); - if (m1 || m2 || m3) { - Ogre::Quaternion q1(Ogre::Radian(Ogre::Degree(yaw)), - Ogre::Vector3::UNIT_Y); - Ogre::Quaternion q2(Ogre::Degree(pitch), - Ogre::Vector3::UNIT_X); - Ogre::Quaternion q3(Ogre::Degree(roll), - Ogre::Vector3::UNIT_Z); - node->setOrientation(q1 * q2 * q3); - } - } - void attachments_editor(Ogre::SceneNode *node) - { - const Ogre::SceneNode::ObjectMap &pmap = - node->getAttachedObjects(); - int i; - for (i = 0; i < pmap.size(); i++) { - const Ogre::MovableObject *mobj = pmap[i]; - const Ogre::String &pname = mobj->getName(); - ImGui::Text("Name: %s", pname.c_str()); - } - } - std::vector glb_names; - void init_glb_list() - { - int i; - - const std::vector &groups = - Ogre::ResourceGroupManager::getSingleton() - .getResourceGroups(); - for (i = 0; i < groups.size(); i++) { - std::vector names = - *Ogre::ResourceGroupManager::getSingleton() - .findResourceNames(groups[i], "*.glb"); - glb_names.insert(glb_names.end(), names.begin(), - names.end()); - } - } - void buildings_editor(); - void buttons_panel(); - void preview(const Ogre::RenderTargetViewportEvent &evt); - float panel_width; - void initGui(); -}; -#undef WATER class App : public OgreBites::ApplicationContext { std::unique_ptr mDynWorld; std::unique_ptr mDbgDraw; @@ -255,16 +174,9 @@ class App : public OgreBites::ApplicationContext { Ogre::Camera *mCamera; Ogre::Real mPivotPitch; Ogre::SceneManager *mScnMgr; - OgreBites::InputListenerChain mInput; Ogre::Viewport *mViewport; - EditUI m_edit_ui; - TerrainSetup m_terrain; - Ogre::Light *mSun; SkyBoxRenderer *sky; -#ifdef WATER - Water m_water; -#endif - bool mTerrainReady; + bool mGrab; class KeyboardListener : public OgreBites::InputListener, public Ogre::FrameListener { App *mApp; @@ -275,28 +187,40 @@ class App : public OgreBites::ApplicationContext { bool mouse_moved = false, wheel_moved = false; public: - bool gui_active; Ogre::Timer fps_timer; bool fast; KeyboardListener(App *app) : OgreBites::InputListener() , Ogre::FrameListener() , mApp(app) - , gui_active(false) , fast(false) , control(0) { } + bool isGuiEnabled() + { + if (!ECS::get().has()) + return false; + return (ECS::get().get().enabled); + } + void setGuiEnabled(bool value) + { + if (!ECS::get().has()) + return; + ECS::get().get_mut().enabled = value; + ECS::get().modified(); + } bool keyPressed(const OgreBites::KeyboardEvent &evt) override { bool updated = false; - if (gui_active) + if (isGuiEnabled()) return false; if (evt.keysym.sym == OgreBites::SDLK_ESCAPE) { - gui_active = true; - // std::cout << "Escape!\n"; - // Ogre::Root::getSingleton().queueEndRendering(); - mApp->setWindowGrab(false); + OgreAssert(ECS::get().has(), ""); + setGuiEnabled(true); + if (ECS::get().has()) + ECS::get().setWindowGrab( + false); return true; } OgreBites::Keycode key = evt.keysym.sym; @@ -318,7 +242,7 @@ class App : public OgreBites::ApplicationContext { bool keyReleased(const OgreBites::KeyboardEvent &evt) override { OgreBites::Keycode key = evt.keysym.sym; - if (gui_active) + if (isGuiEnabled()) return false; if (key == 'w') control &= ~1; @@ -337,7 +261,7 @@ class App : public OgreBites::ApplicationContext { } bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override { - if (gui_active) + if (isGuiEnabled()) return false; mouse.x = evt.xrel; mouse.y = evt.yrel; @@ -348,7 +272,7 @@ class App : public OgreBites::ApplicationContext { bool mouseWheelRolled(const OgreBites::MouseWheelEvent &evt) override { - if (gui_active) + if (isGuiEnabled()) return false; /* no special mouse wheel handling */ wheel_y = evt.y; @@ -392,15 +316,14 @@ class App : public OgreBites::ApplicationContext { fps_timer.reset(); } update(evt.timeSinceLastFrame); - if (!gui_active && mApp->isTerrainReady()) { + if (!isGuiEnabled() && mApp->isTerrainReady()) { OgreAssert(mApp->isTerrainReady(), "terrain is not ready"); } - if (!gui_active) { - mApp->updateSun(evt.timeSinceLastFrame); - mApp->updateTerrain(evt.timeSinceLastFrame); - mApp->updateWater(evt.timeSinceLastFrame); + if (!isGuiEnabled()) { mApp->updateWorld(evt.timeSinceLastFrame); + } + if (!isGuiEnabled() && ECS::get().has()) { ECS::Input &input = ECS::get().get_mut(); input.control = control; @@ -420,11 +343,9 @@ public: App() : OgreBites::ApplicationContext("ChoroGame") , mKbd(this) - , m_edit_ui(this) , mDynWorld(new Ogre::Bullet::DynamicsWorld( Ogre::Vector3(0, -9.8, 0))) - , m_terrain(mDynWorld->getBtWorld()) - , mTerrainReady(false) + , mGrab(false) { } virtual ~App() @@ -443,6 +364,10 @@ public: mDbgDraw.reset(new Ogre::Bullet::DebugDrawer( mScnMgr->getRootSceneNode(), mDynWorld->getBtWorld())); } + bool isWindowGrab() + { + return mGrab; + } void locateResources() override { Ogre::ResourceGroupManager::getSingleton().createResourceGroup( @@ -452,13 +377,10 @@ public: void loadResources() override { } - void dump_water() + void setWindowGrab(bool grab = true) { -#if 0 -#ifdef WATER - m_water.dump_textures(); -#endif -#endif + mGrab = grab; + ApplicationContextBase::setWindowGrab(grab); } void initCamera() @@ -508,10 +430,6 @@ public: std::cout << "Init camera" << "\n"; initCamera(); std::cout << "Set up water" << "\n"; -#ifdef WATER - m_water.createWater(getRenderWindow(), mCamera, - mDynWorld.get()); -#endif std::cout << "Set up cursor" << "\n"; Ogre::ResourceGroupManager::getSingleton() .initialiseAllResourceGroups(); @@ -519,95 +437,20 @@ public: // setupCursor(); std::cout << "Create content" << "\n"; createContent(); - std::cout << "Setup terrain" << "\n"; - setupTerrain(); -#ifdef WATER - m_water.init(); -#endif - setupPlayer(); + std::cout << "Setup input" << "\n"; setupInput(); - } - void setupPlayer() - { - OgreAssert(mDynWorld.get(), "No physics world controller"); + std::cout << "Setup done" << "\n"; } Ogre::SceneManager *getSceneManager() { return mScnMgr; } - Ogre::SceneNode *mSunGoal; - Ogre::SceneNode *mSunNode; - Ogre::SceneNode *mSunTarget; - Ogre::Timer mSunUpdate; - void createSun() - { - Ogre::Light *light = mScnMgr->createLight("Sun"); - mSunNode = mScnMgr->getRootSceneNode()->createChildSceneNode( - "SunPivot"); - mSunGoal = mScnMgr->getRootSceneNode()->createChildSceneNode( - "SunGoal"); - mSunTarget = mSunGoal->createChildSceneNode( - "SunGoalTarget", - Ogre::Vector3(100.0f, -400.0f, -400.0f), - Ogre::Quaternion::IDENTITY); - mSunNode->attachObject(light); - light->setType(Ogre::Light::LT_DIRECTIONAL); - light->setDiffuseColour(Ogre::ColourValue::White); - light->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4)); - mSunNode->setDirection(Ogre::Vector3(100.0f, -400.0f, -400.f)); - mSun = light; - } - void updateSun(float delta) - { - static const float sun_speed = 1.0f; - float uangle = M_PI * 2.0f / 24.0f / 60.0f; - mSunNode->pitch(Ogre::Radian(uangle) * sun_speed * delta); - if (mSunUpdate.getMilliseconds() > 1000) { - Ogre::TerrainGlobalOptions::getSingleton() - .setCompositeMapAmbient( - mScnMgr->getAmbientLight()); - Ogre::TerrainGlobalOptions::getSingleton() - .setCompositeMapDiffuse( - mSun->getDiffuseColour()); - Ogre::TerrainGlobalOptions::getSingleton() - .setLightMapDirection( - mSun->getDerivedDirection()); - std::cout << "sun pitch: " - << mSunNode->getOrientation().getPitch() - << "\n"; - mSunUpdate.reset(); - } - if (mSunNode->getOrientation().getPitch().valueRadians() > 0) - mScnMgr->setAmbientLight( - Ogre::ColourValue(0.1f, 0.1f, 0.4f, 1.0f)); - else - mScnMgr->setAmbientLight( - Ogre::ColourValue(0.2f, 0.2f, 0.2f, 1.0f)); - } Ogre::Timer mTerrainUpd; - void updateTerrain(float delta) - { - // Ogre::Vector3 pos = mCharacterController->getPosition(); - const ECS::CharacterBase &ch = - getPlayer().get(); - ECS::CharacterBody &body = - getPlayer().get_mut(); - if (!body.checkGround) { - body.checkGround = true; - getPlayer().modified(); - } - if (!ch.mBodyNode) - return; - Ogre::Vector3 pos = ch.mBodyNode->getPosition(); - if (!mTerrainReady && m_terrain.isLoadedAt(pos) && - body.checkGroundResult) { - std::cout << "terrain ready\n"; - mTerrainReady = true; - } - } bool isTerrainReady() { - return mTerrainReady; + if (ECS::get().has()) + return ECS::get().get().mTerrainReady; + return false; } // TODO: implement rough water level calculation float getWaterLevel(const Ogre::Vector3 &position) @@ -620,30 +463,255 @@ public: void updateWorld(float delta) { mDynWorld->getBtWorld()->stepSimulation(delta, 4); - mDbgDraw->update(); + /* Update window grab */ + if (ECS::get().has() && + ECS::get().get().grabChanged) { + setWindowGrab(ECS::get().get().grab); + ECS::get().get_mut().grabChanged = false; + ECS::get().modified(); + } ECS::update(delta); + // mDbgDraw->update(); } - void updateWater(float delta) - { -#ifdef WATER - m_water.updateWater(delta); -#endif - } + class InputListenerChainFlexible : public OgreBites::InputListener { + protected: + std::vector mListenerChain; + + public: + InputListenerChainFlexible() + { + } + InputListenerChainFlexible(std::vector chain) + : mListenerChain(chain) + { + } + + void add(OgreBites::InputListener *listener) + { + mListenerChain.push_back(listener); + } + void erase(OgreBites::InputListener *listener) + { + mListenerChain.erase(std::find(mListenerChain.begin(), + mListenerChain.end(), + listener)); + } + bool empty() const + { + return mListenerChain.empty(); + } + + InputListenerChainFlexible & + operator=(const InputListenerChainFlexible &o) + { + mListenerChain = o.mListenerChain; + return *this; + } + + void frameRendered(const Ogre::FrameEvent &evt) override + { + for (auto listener : mListenerChain) + listener->frameRendered(evt); + } + + bool keyPressed(const OgreBites::KeyboardEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->keyPressed(evt)) + return true; + } + return false; + } + bool keyReleased(const OgreBites::KeyboardEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->keyReleased(evt)) + return true; + } + return false; + } + bool touchMoved(const OgreBites::TouchFingerEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->touchMoved(evt)) + return true; + } + return false; + } + bool + touchPressed(const OgreBites::TouchFingerEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->touchPressed(evt)) + return true; + } + return false; + } + bool + touchReleased(const OgreBites::TouchFingerEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->touchReleased(evt)) + return true; + } + return false; + } + bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->mouseMoved(evt)) + return true; + } + return false; + } + bool + mouseWheelRolled(const OgreBites::MouseWheelEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->mouseWheelRolled(evt)) + return true; + } + return false; + } + bool + mousePressed(const OgreBites::MouseButtonEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->mousePressed(evt)) + return true; + } + return false; + } + bool + mouseReleased(const OgreBites::MouseButtonEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->mouseReleased(evt)) + return true; + } + return false; + } + bool textInput(const OgreBites::TextInputEvent &evt) override + { + for (auto listner : mListenerChain) { + if (listner->textInput(evt)) + return true; + } + return false; + } + }; + flecs::entity input_update; + flecs::entity find_wait_gui; void setupInput() { - mInput = OgreBites::InputListenerChain({ - getImGuiInputListener(), - &mKbd, - }); - addInputListener(&mInput); + ECS::App &p = ECS::get().get_mut(); + ECS::get() + .observer("UpdateGrab") + .event(flecs::OnSet) + .each([this](flecs::entity e, ECS::GUI &gui) { + if (gui.grabChanged) + setWindowGrab(gui.grab); + std::cout << "grab: " << gui.grab << "\n"; + std::cout << "GUI enabled: " << gui.enabled + << "\n"; + std::cout << "grabbed: " << isWindowGrab() + << "\n"; + std::cout + << "UI active: " << mKbd.isGuiEnabled() + << "\n"; + }); + ECS::get() + .observer("UpdateInputListener") + .event(flecs::OnSet) + .each([this](flecs::entity e, ECS::App &app) { + if (app.mInput) + removeInputListener(app.mInput); + delete app.mInput; + app.mInput = new OgreBites::InputListenerChain( + app.listeners); + addInputListener(app.mInput); + std::cout << "Update listeners\n"; + }); +#if 0 + ECS::get() + .observer("SetInputListener2") + .event(flecs::OnSet) + .each([this](ECS::GUI &gui, ECS::App &app) { + if (gui.mGuiInpitListener && + app.listeners.size() == 1) { + app.listeners.clear(); + app.listeners.push_back( + gui.mGuiInpitListener); + app.listeners.push_back(&mKbd); + ECS::modified(); + } + }); +#endif +#if 0 + input_update = + ECS::get() + .system("SetInputListener") + .kind(flecs::OnUpdate) + .each([this](ECS::GUI &gui, ECS::App &app) { + if (app.listeners.size() < 2 && + gui.mGuiInpitListener) { + OgreBites::InputListener *guiListener = + gui.mGuiInpitListener; + if (guiListener) { + app.listeners.clear(); + app.listeners.push_back( + guiListener); + app.listeners.push_back( + &mKbd); + std::cout + << "input update complete\n"; + gui.mGuiInpitListener = + guiListener; + if (app.mInput) + removeInputListener( + app.mInput); + delete app.mInput; + app.mInput = new OgreBites:: + InputListenerChain( + app.listeners); + addInputListener( + app.mInput); + std::cout + << "update listeners: " + << app.listeners + .size() + << "\n"; + if (app.listeners + .size() == + 2) + OgreAssert( + app.listeners.size() == + 2, + ""); + input_update.disable(); + OgreAssert(false, ""); + } else { + app.listeners.clear(); + app.listeners.push_back( + &mKbd); + } + } else + input_update.disable(); + std::cout << "input update " + << app.listeners.size() + << "\n"; + }); +#endif + + p.listeners.clear(); + p.listeners.push_back(&mKbd); + ECS::get().modified(); } void createContent() { int i; - m_edit_ui.init_glb_list(); - m_edit_ui.initGui(); - createSun(); + std::cout << "addFrameListener\n"; getRoot()->addFrameListener(&mKbd); sky = new SkyBoxRenderer(getSceneManager()); bool drawFirst = true; @@ -662,6 +730,25 @@ public: OgreAssert(m, "Sky box material not found."); m->load(); ECS::setup(mScnMgr, mDynWorld.get(), mCameraNode, mCamera); + ECS::get() + .system("SetInputListener") + .kind(flecs::OnUpdate) + .each([this](const ECS::GUI &gui, ECS::App &app) { + if (gui.mGuiInpitListener && + app.listeners.size() == 1) { + app.listeners.clear(); + app.listeners.push_back( + gui.mGuiInpitListener); + app.listeners.push_back(&mKbd); + ECS::modified(); + } + }); + ECS::get().set( + { getRenderWindow(), getDisplayDPI() }); + ECS::get().set( + { static_cast(this), + nullptr, + {} }); Sound::setup(); Sound::ding(); } @@ -679,26 +766,22 @@ public: Ogre::Radian yaw = q.getYaw(); Ogre::Quaternion nq(yaw, Ogre::Vector3(0, 1, 0)); pnode->setOrientation(nq); - mKbd.gui_active = false; - setWindowGrab(true); + set_gui_active(false); + ECS::get().setWindowGrab(true); } bool get_gui_active() { - return mKbd.gui_active; + return ECS::get().get().enabled; } void set_gui_active(bool active) { - mKbd.gui_active = active; + ECS::get().get_mut().enabled = active; + ECS::get().modified(); } Ogre::Camera *getCamera() { return mCamera; } - void setupTerrain() - { - m_terrain.setupTerrain(mCamera, mSun, mDynWorld.get(), - mDbgDraw.get()); - } flecs::entity getPlayer() const { flecs::entity player = @@ -707,167 +790,6 @@ public: } }; -void EditUI::buildings_editor() -{ - int i; - ImVec2 size = ImGui::GetMainViewport()->Size; - float window_width = size.x * 0.2f; - if (window_width > panel_width) - window_width = panel_width; - float window_height = size.y * 0.5 - 20; - ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); - ImGui::SetNextWindowSize(ImVec2(window_width, window_height), - ImGuiCond_Always); - ImGui::Begin("Droppings..."); - for (i = 0; i < glb_names.size(); i++) { - Ogre::String id_button = "Create entity: " + glb_names[i] + - "##ent:" + glb_names[i]; - if (ImGui::Button(id_button.c_str())) { - m_app->create_entity_node(glb_names[i], i); - } - } - ImGui::End(); -} -void EditUI::buttons_panel() -{ - ImVec2 size = ImGui::GetMainViewport()->Size; - float window_width = size.x * 0.2f; - if (window_width > panel_width) - window_width = panel_width; - float window_height = size.y * 0.5f - 20; - ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.5f + 20), - ImGuiCond_Always); - ImGui::SetNextWindowSize(ImVec2(window_width, window_height), - ImGuiCond_Always); - ImGui::Begin("Dumb and Stupid"); - if (!m_app->get_gui_active()) - m_app->setWindowGrab(true); - if (ImGui::Button("Shitty Quit button")) - Ogre::Root::getSingleton().queueEndRendering(); - if (ImGui::Button("Chick-chick")) { - m_app->set_gui_active(false); - m_app->setWindowGrab(true); - } - ImGui::Text("We do stoopid..."); - ImGui::End(); -} -void EditUI::preview(const Ogre::RenderTargetViewportEvent &evt) -{ - int i; - Ogre::ImGuiOverlay::NewFrame(); - if (m_app->get_gui_active()) { - buttons_panel(); - buildings_editor(); - ImVec2 size = ImGui::GetMainViewport()->Size; - float window_width = size.x * 0.2f; - if (window_width > panel_width) - window_width = panel_width; - float window_height = size.y * 0.5f - 20; - ImGui::SetNextWindowPos(ImVec2(size.x - window_width, - size.y * 0.5f + 20), - ImGuiCond_Always); - ImGui::SetNextWindowSize(ImVec2(window_width, window_height), - ImGuiCond_Always); - // ImGui::Begin("Dumb and Stupid", &mKbd.gui_active); - ImGui::Begin("Panel..."); - std::deque tree_input_queue, - tree_output_queue; - std::vector tree_list; - tree_input_queue.push_back(mScnMgr->getRootSceneNode()); - tree_input_queue.push_back(nullptr); - std::set visited; - while (true) { - int new_nodes_count = 0; - while (!tree_input_queue.empty()) { - int child; - Ogre::SceneNode *item = - tree_input_queue.front(); - tree_input_queue.pop_front(); - if (item && visited.find(item) == - visited.end()) { // new node - new_nodes_count++; - tree_output_queue.push_back(item); - visited.insert(item); - const Ogre::Node::ChildNodeMap - &children = item->getChildren(); - for (child = 0; child < children.size(); - child++) { - tree_output_queue.push_back( - static_cast( - children[child])); - tree_output_queue.push_back( - nullptr); - } - } else - tree_output_queue.push_back(item); - } - if (new_nodes_count == 0) - break; - tree_input_queue = tree_output_queue; - tree_output_queue.clear(); - } - tree_list.insert(tree_list.begin(), tree_output_queue.begin(), - tree_output_queue.end()); - int count = 0; - int depth = 0; - std::vector check_depth; - int max_depth = 0; - check_depth.push_back(0); - for (count = 0; count < tree_list.size(); count++) { - int t; - - Ogre::SceneNode *node = tree_list[count]; - if (node && max_depth >= depth) { - Ogre::String name = node->getName(); - if (name.length() == 0) { - name = "Node #" + - Ogre::StringConverter::toString( - count); - } - if (ImGui::TreeNode(name.c_str())) { - check_depth.push_back(max_depth); - max_depth++; - ImGui::Text( - "%s", - (name + "##caption").c_str()); - position_editor(node); - ImGui::Separator(); - orientation_editor(node); - ImGui::Separator(); - ImGui::Text("Attachments"); - attachments_editor(node); - } - } else if (!node && max_depth >= depth) { - max_depth = check_depth.back(); - check_depth.pop_back(); - ImGui::TreePop(); - } - if (tree_list[count]) - depth++; - else - depth--; - } - ImGui::Spacing(); - ImGui::End(); - } -} -void EditUI::initGui() -{ - mScnMgr = m_app->getSceneManager(); - float vpScale = m_app->getDisplayDPI() / 96 * - (float)m_app->getRenderWindow()->getWidth() / 1600.0f; - panel_width = - 380.0f * (float)m_app->getRenderWindow()->getWidth() / 1600.0f; - Ogre::OverlayManager::getSingleton().setPixelRatio(vpScale); - mGuiOverlay = m_app->initialiseImGui(); - // float vpScale = - // Ogre::OverlayManager::getSingleton().getPixelRatio(); - ImGui::GetIO().FontGlobalScale = std::round(vpScale); - mGuiOverlay->setZOrder(300); - mGuiOverlay->show(); - m_app->getRenderWindow()->addListener(this); -} int main() { App ctx; diff --git a/src/gamedata/CMakeLists.txt b/src/gamedata/CMakeLists.txt index 29289e9..605182c 100644 --- a/src/gamedata/CMakeLists.txt +++ b/src/gamedata/CMakeLists.txt @@ -1,5 +1,5 @@ project(gamedata) -find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain CONFIG) -add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp) -target_link_libraries(GameData PUBLIC OgreMain OgreBullet flecs::flecs_static) +find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG) +add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp GUIModule.cpp) +target_link_libraries(GameData PUBLIC OgreMain OgreBites OgreBullet OgrePaging OgreTerrain OgreOverlay flecs::flecs_static) target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) \ No newline at end of file diff --git a/src/gamedata/CharacterModule.cpp b/src/gamedata/CharacterModule.cpp index e3877b7..101d286 100644 --- a/src/gamedata/CharacterModule.cpp +++ b/src/gamedata/CharacterModule.cpp @@ -216,7 +216,6 @@ CharacterModule::CharacterModule(flecs::world &ecs) body.gvelocity += (gravity + b) * delta; body.gvelocity.y = Ogre::Math::Clamp( body.gvelocity.y, -2.5f, 2.5f); - std::cout << "InWater!!!!!!!\n"; } else body.gvelocity += gravity * delta; body.gvelocity *= 0.99; @@ -518,6 +517,7 @@ CharacterModule::CharacterModule(flecs::world &ecs) ch.mBodyNode->_getDerivedPosition().y > 0.05f) e.remove(); }); +#if 0 ecs.system( "DisplayPlayerPos") .kind(flecs::OnUpdate) @@ -528,6 +528,7 @@ CharacterModule::CharacterModule(flecs::world &ecs) std::cout << "player: " << ch.mBodyNode->getPosition() << "\n"; }); +#endif } void CharacterModule::setAnimation(AnimationControl &anim) diff --git a/src/gamedata/Components.h b/src/gamedata/Components.h index e6b31ba..2350b8a 100644 --- a/src/gamedata/Components.h +++ b/src/gamedata/Components.h @@ -2,6 +2,12 @@ #define COMPONENTS_H_ #include #include +namespace OgreBites +{ +class ApplicationContextSDL; +class InputListenerChain; +class InputListener; +} namespace ECS { struct GameData { @@ -46,6 +52,15 @@ struct Camera { Ogre::SceneNode *mCameraGoal; Ogre::Real mPivotPitch; }; +struct RenderWindow { + Ogre::RenderWindow *window; + float dpi; +}; +struct App { + OgreBites::ApplicationContextSDL *app; + OgreBites::InputListenerChain *mInput; + std::vector listeners; +}; struct InWater {}; } #endif \ No newline at end of file diff --git a/src/gamedata/GUIModule.cpp b/src/gamedata/GUIModule.cpp new file mode 100644 index 0000000..2a994c7 --- /dev/null +++ b/src/gamedata/GUIModule.cpp @@ -0,0 +1,314 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "GameData.h" +#include "Components.h" +#include "GUIModule.h" +namespace ECS +{ +struct GUIListener; +struct GUIData { + Ogre::ImGuiOverlay *mGuiOverlay; + std::vector glb_names; + GUIListener *mGUIListener; +}; +struct GUIListener : public Ogre::RenderTargetListener { + float panel_width; + void + preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override + { + preview(evt); + } + void buttons_panel() + { + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5f - 20; + ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.5f + 20), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, window_height), + ImGuiCond_Always); + ImGui::Begin("Dumb and Stupid"); + // if (ECS::get().get().enabled) + // ECS::get().get().app->setWindowGrab(true); + if (ImGui::Button("Shitty Quit button")) + Ogre::Root::getSingleton().queueEndRendering(); + if (ImGui::Button("Chick-chick")) { + ECS::get().get_mut().enabled = false; + ECS::get().modified(); + // ECS::get().get().app->setWindowGrab(true); + } + ImGui::Text("We do stoopid..."); + ImGui::End(); + } + void create_entity_node(const Ogre::String &name, int key) + { + Ogre::Entity *ent = + ECS::get().get().mScnMgr->createEntity( + name); + Ogre::SceneNode *pnode = + ECS::get() + .get() + .mScnMgr->getRootSceneNode() + ->createChildSceneNode( + "ent:" + name + + Ogre::StringConverter::toString( + key), + ECS::get() + .get() + .mCameraPivot->getPosition(), + ECS::get() + .get() + .mCameraPivot->getOrientation()); + pnode->attachObject(ent); + Ogre::Quaternion q = pnode->getOrientation(); + Ogre::Radian yaw = q.getYaw(); + Ogre::Quaternion nq(yaw, Ogre::Vector3(0, 1, 0)); + pnode->setOrientation(nq); + + // ECS::get().get().app->setWindowGrab(true); + } + void buildings_editor() + { + int i; + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5 - 20; + ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, window_height), + ImGuiCond_Always); + ImGui::Begin("Droppings..."); + for (i = 0; i < ECS::get().get().glb_names.size(); + i++) { + Ogre::String id_button = + "Create entity: " + + ECS::get().get().glb_names[i] + + "##ent:" + + ECS::get().get().glb_names[i]; + if (ImGui::Button(id_button.c_str())) { + create_entity_node( + ECS::get().get().glb_names[i], + i); + } + } + ImGui::End(); + } + void position_editor(Ogre::SceneNode *node) + { + Ogre::Vector3 position = node->getPosition(); + float v[3] = { position.x, position.y, position.z }; + ImGui::InputFloat3("position", v); + position.x = v[0]; + position.y = v[1]; + position.z = v[2]; + node->setPosition(position); + } + void orientation_editor(Ogre::SceneNode *node) + { + Ogre::Quaternion q = node->getOrientation(); + float yaw = Ogre::Radian(q.getYaw()).valueDegrees(); + float pitch = Ogre::Radian(q.getPitch()).valueDegrees(); + float roll = Ogre::Radian(q.getRoll()).valueDegrees(); + bool m1 = ImGui::InputFloat("yaw", &yaw); + bool m2 = ImGui::InputFloat("pitch", &pitch); + bool m3 = ImGui::InputFloat("roll", &roll); + if (m1 || m2 || m3) { + Ogre::Quaternion q1(Ogre::Radian(Ogre::Degree(yaw)), + Ogre::Vector3::UNIT_Y); + Ogre::Quaternion q2(Ogre::Degree(pitch), + Ogre::Vector3::UNIT_X); + Ogre::Quaternion q3(Ogre::Degree(roll), + Ogre::Vector3::UNIT_Z); + node->setOrientation(q1 * q2 * q3); + } + } + void attachments_editor(Ogre::SceneNode *node) + { + const Ogre::SceneNode::ObjectMap &pmap = + node->getAttachedObjects(); + int i; + for (i = 0; i < pmap.size(); i++) { + const Ogre::MovableObject *mobj = pmap[i]; + const Ogre::String &pname = mobj->getName(); + ImGui::Text("Name: %s", pname.c_str()); + } + } + void preview(const Ogre::RenderTargetViewportEvent &evt) + { + int i; + Ogre::ImGuiOverlay::NewFrame(); + if (ECS::get().get().enabled) { + buttons_panel(); + buildings_editor(); + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5f - 20; + ImGui::SetNextWindowPos(ImVec2(size.x - window_width, + size.y * 0.5f + 20), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, + window_height), + ImGuiCond_Always); + // ImGui::Begin("Dumb and Stupid", &mKbd.gui_active); + ImGui::Begin("Panel..."); + std::deque tree_input_queue, + tree_output_queue; + std::vector tree_list; + tree_input_queue.push_back( + ECS::get() + .get() + .mScnMgr->getRootSceneNode()); + tree_input_queue.push_back(nullptr); + std::set visited; + while (true) { + int new_nodes_count = 0; + while (!tree_input_queue.empty()) { + int child; + Ogre::SceneNode *item = + tree_input_queue.front(); + tree_input_queue.pop_front(); + if (item && + visited.find(item) == + visited.end()) { // new node + new_nodes_count++; + tree_output_queue.push_back( + item); + visited.insert(item); + const Ogre::Node::ChildNodeMap + &children = + item->getChildren(); + for (child = 0; + child < children.size(); + child++) { + tree_output_queue.push_back( + static_cast< + Ogre::SceneNode + *>( + children[child])); + tree_output_queue + .push_back( + nullptr); + } + } else + tree_output_queue.push_back( + item); + } + if (new_nodes_count == 0) + break; + tree_input_queue = tree_output_queue; + tree_output_queue.clear(); + } + tree_list.insert(tree_list.begin(), + tree_output_queue.begin(), + tree_output_queue.end()); + int count = 0; + int depth = 0; + std::vector check_depth; + int max_depth = 0; + check_depth.push_back(0); + for (count = 0; count < tree_list.size(); count++) { + int t; + + Ogre::SceneNode *node = tree_list[count]; + if (node && max_depth >= depth) { + Ogre::String name = node->getName(); + if (name.length() == 0) { + name = "Node #" + + Ogre::StringConverter:: + toString(count); + } + if (ImGui::TreeNode(name.c_str())) { + check_depth.push_back( + max_depth); + max_depth++; + ImGui::Text("%s", + (name + "##caption") + .c_str()); + position_editor(node); + ImGui::Separator(); + orientation_editor(node); + ImGui::Separator(); + ImGui::Text("Attachments"); + attachments_editor(node); + } + } else if (!node && max_depth >= depth) { + max_depth = check_depth.back(); + check_depth.pop_back(); + ImGui::TreePop(); + } + if (tree_list[count]) + depth++; + else + depth--; + } + ImGui::Spacing(); + ImGui::End(); + } + } +}; + +GUIModule::GUIModule(flecs::world &ecs) +{ + ecs.component().add(flecs::Singleton); + ecs.component().add(flecs::Singleton); + ecs.set({ false, true, false, nullptr }); + ecs.set({ nullptr, {}, nullptr }); + ui_wait = + ecs.system("SetupGUI") + .kind(flecs::OnUpdate) + .each([this](const RenderWindow &window, App &app, + GUIData &gui) { + if (!gui.mGuiOverlay) { + float vpScale = + window.dpi / 96 * + window.window->getWidth() / + 1600.0f; + Ogre::OverlayManager::getSingleton() + .setPixelRatio(vpScale); + std::cout << "GUI configure\n"; + gui.mGuiOverlay = + app.app->initialiseImGui(); + gui.mGuiOverlay->setZOrder(300); + gui.mGuiOverlay->show(); + gui.mGUIListener = new GUIListener(); + window.window->addListener( + gui.mGUIListener); + int i; + + const std::vector &groups = + Ogre::ResourceGroupManager:: + getSingleton() + .getResourceGroups(); + for (i = 0; i < groups.size(); i++) { + std::vector names = + *Ogre::ResourceGroupManager::getSingleton() + .findResourceNames( + groups[i], + "*.glb"); + gui.glb_names.insert( + gui.glb_names.end(), + names.begin(), + names.end()); + } + ECS::get_mut() + .mGuiInpitListener = + new OgreBites:: + ImGuiInputListener(); + ECS::modified(); + std::cout << "GUI configure finished\n"; + } + }); +} +} \ No newline at end of file diff --git a/src/gamedata/GUIModule.h b/src/gamedata/GUIModule.h new file mode 100644 index 0000000..33341d7 --- /dev/null +++ b/src/gamedata/GUIModule.h @@ -0,0 +1,30 @@ +#ifndef GUI_MODULE_H_ +#define GUI_MODULE_H_ +#include +namespace OgreBites +{ +class InputListener; +} +namespace ECS +{ +struct GUI { + bool enabled; + bool grab; + bool grabChanged; + OgreBites::InputListener *mGuiInpitListener; + static void setWindowGrab(bool g = true) + { + ECS::GUI &gui = ECS::get().get_mut(); + if (gui.grab != g) { + gui.grab = g; + gui.grabChanged = true; + ECS::get().modified(); + } + } +}; +struct GUIModule { + flecs::entity ui_wait; + GUIModule(flecs::world &ecs); +}; +} +#endif \ No newline at end of file diff --git a/src/gamedata/GameData.cpp b/src/gamedata/GameData.cpp index c7cb827..dd9ec31 100644 --- a/src/gamedata/GameData.cpp +++ b/src/gamedata/GameData.cpp @@ -4,6 +4,9 @@ #include "Components.h" #include "CharacterModule.h" #include "WaterModule.h" +#include "TerrainModule.h" +#include "SunModule.h" +#include "GUIModule.h" namespace ECS { @@ -11,22 +14,38 @@ static flecs::world ecs; void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world, Ogre::SceneNode *cameraNode, Ogre::Camera *camera) { + std::cout << "Setup GameData\n"; ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.component(); - ecs.set({ scnMgr, world, 0.0f }); - ecs.set({ cameraNode, camera, false }); - ecs.add(); - ecs.add(); + ecs.component().add(flecs::Singleton); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); + ecs.import (); ecs.system("UpdateDelta") .kind(flecs::OnUpdate) .each([](EngineData &eng) { eng.delta = ECS::get().delta_time(); }); - ecs.import (); - ecs.import (); + ecs.set({ scnMgr, world, 0.0f }); + ecs.set({ cameraNode, camera, false }); + ecs.add(); + ecs.add(); + ecs.set({ nullptr, nullptr, nullptr }); + ecs.set({ nullptr }); + ecs.set({ nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + false, + { 0, 0, 0 } }); + std::cout << "Setup GameData done\n"; } void update(float delta) { diff --git a/src/gamedata/GameData.h b/src/gamedata/GameData.h index dc79c13..d6186d7 100644 --- a/src/gamedata/GameData.h +++ b/src/gamedata/GameData.h @@ -8,5 +8,17 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world, Ogre::SceneNode *cameraNode, Ogre::Camera *camera); void update(float delta); flecs::world get(); +template const T &get() +{ + return ECS::get().get(); +} +template T &get_mut() +{ + return ECS::get().get_mut(); +} +template void modified() +{ + ECS::get().modified(); +} } #endif \ No newline at end of file diff --git a/src/gamedata/SunModule.cpp b/src/gamedata/SunModule.cpp new file mode 100644 index 0000000..1ae3a4a --- /dev/null +++ b/src/gamedata/SunModule.cpp @@ -0,0 +1,53 @@ +#include +#include "Components.h" +#include "SunModule.h" + +namespace ECS +{ +SunModule::SunModule(flecs::world &ecs) +{ + ecs.component().add(flecs::Singleton); + ecs.set({ nullptr, nullptr, nullptr, nullptr }); + ecs.system("UpdateSetupSun") + .kind(flecs::OnUpdate) + .each([](const EngineData &eng, Sun &sun) { + if (!sun.mSun) { + Ogre::Light *light = + eng.mScnMgr->createLight("Sun"); + sun.mSunNode = eng.mScnMgr->getRootSceneNode() + ->createChildSceneNode( + "SunPivot"); + sun.mSunGoal = eng.mScnMgr->getRootSceneNode() + ->createChildSceneNode( + "SunGoal"); + sun.mSunTarget = + sun.mSunGoal->createChildSceneNode( + "SunGoalTarget", + Ogre::Vector3(100.0f, -400.0f, + -400.0f), + Ogre::Quaternion::IDENTITY); + sun.mSunNode->attachObject(light); + light->setType(Ogre::Light::LT_DIRECTIONAL); + light->setDiffuseColour( + Ogre::ColourValue::White); + light->setSpecularColour( + Ogre::ColourValue(0.4, 0.4, 0.4)); + sun.mSunNode->setDirection( + Ogre::Vector3(100.0f, -400.0f, -400.f)); + sun.mSun = light; + } + static const float sun_speed = 1.0f; + float uangle = M_PI * 2.0f / 24.0f / 60.0f; + sun.mSunNode->pitch(Ogre::Radian(uangle) * sun_speed * + eng.delta); + if (sun.mSunNode->getOrientation() + .getPitch() + .valueRadians() > 0) + eng.mScnMgr->setAmbientLight(Ogre::ColourValue( + 0.1f, 0.1f, 0.4f, 1.0f)); + else + eng.mScnMgr->setAmbientLight(Ogre::ColourValue( + 0.2f, 0.2f, 0.2f, 1.0f)); + }); +} +} diff --git a/src/gamedata/SunModule.h b/src/gamedata/SunModule.h new file mode 100644 index 0000000..f416fa5 --- /dev/null +++ b/src/gamedata/SunModule.h @@ -0,0 +1,20 @@ +#ifndef SUN_MODULE_H_ +#define SUN_MODULE_H_ +#include +namespace Ogre +{ +class Light; +} +namespace ECS +{ +struct Sun { + Ogre::SceneNode *mSunGoal; + Ogre::SceneNode *mSunNode; + Ogre::SceneNode *mSunTarget; + Ogre::Light *mSun; +}; +struct SunModule { + SunModule(flecs::world &ecs); +}; +} +#endif \ No newline at end of file diff --git a/src/gamedata/TerrainModule.cpp b/src/gamedata/TerrainModule.cpp new file mode 100644 index 0000000..e214d05 --- /dev/null +++ b/src/gamedata/TerrainModule.cpp @@ -0,0 +1,475 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GameData.h" +#include "Components.h" +#include "CharacterModule.h" +#include "SunModule.h" +#include "TerrainModule.h" + +#define TERRAIN_SIZE 129 +#define TERRAIN_WORLD_SIZE 4000.0f +#define ENDLESS_TERRAIN_FILE_PREFIX Ogre::String("EndlessWorldTerrain") +#define ENDLESS_TERRAIN_FILE_SUFFIX Ogre::String("dat") + +#define ENDLESS_PAGING + +// max range for a int16 +#define ENDLESS_PAGE_MIN_X (-0x7FFF) +#define ENDLESS_PAGE_MIN_Y (-0x7FFF) +#define ENDLESS_PAGE_MAX_X 0x7FFF +#define ENDLESS_PAGE_MAX_Y 0x7FFF +namespace ECS +{ + +class FlatTerrainDefiner + : public Ogre::TerrainPagedWorldSection::TerrainDefiner, + public Ogre::FrameListener { + Ogre::SceneManager *mScnMgr; + Ogre::Bullet::DynamicsWorld *mWorld; + struct gen_collider { + Ogre::TerrainGroup *group; + long x; + long y; + }; + std::deque collider_queue; + Ogre::Image img, img_noise, img_brushes; + +public: + FlatTerrainDefiner(Ogre::SceneManager *scm, + Ogre::Bullet::DynamicsWorld *world) + : Ogre::TerrainPagedWorldSection::TerrainDefiner() + , Ogre::FrameListener() + , mScnMgr(scm) + , mWorld(world) + { + Ogre::Root::getSingleton().addFrameListener(this); + img.load( + "world_map.png", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + img_noise.load( + "terrain.png", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + img_brushes.load( + "brushes.png", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + } + +private: + float get_noise_height(const Ogre::Vector2 &worldOffset, int x, int y) + { + int h; + Ogre::Vector2 noisePoint; + + struct noise_types { + Ogre::Vector2 noiseOfft; + float noiseMul; + float noiseBias; + float noiseAmp; + }; + static struct noise_types noise_pass[] = { + { { -100.0f, 70.0f }, 10.2f, -0.55f, 5.0f }, + { { -130.0f, 55.0f }, 5.35f, -0.55f, 1.0f } + }; + static float noise_values[] = { 0.0f, 0.0f }; + for (h = 0; h < (int)sizeof(noise_values) / + (int)sizeof(noise_values[0]); + h++) { + noisePoint = (worldOffset + Ogre::Vector2(x, y) + + noise_pass[h].noiseOfft) * + noise_pass[h].noiseMul; + int noise_x = + (int)(noisePoint.x + img_noise.getWidth() / 2) % + img_noise.getWidth(); + int noise_y = (int)(noisePoint.y + + img_noise.getHeight() / 2) % + img_noise.getHeight(); + Ogre::ColourValue noise_color = + img_noise.getColourAt(noise_x, noise_y, 0); + noise_values[h] = + (noise_color.r + noise_pass[h].noiseBias) * + noise_pass[h].noiseAmp; + } + return noise_values[0] + noise_values[1]; + } +#define BRUSH_SIZE 64 + float get_brush_height(int id, int x, int y) + { + int m = 0; + switch (id) { + case 0: + m = 0; + break; + case 1: + m = BRUSH_SIZE; + break; + default: + OgreAssert(false, "bad brush id"); + break; + } + return img_brushes.getColourAt(x, y + m, 0).r; + } + float get_base_height(const Ogre::Vector2 &worldOffset, int x, int y) + { + float height = 0.0f; + int world_x = worldOffset.x + x; + int world_y = worldOffset.y + y; + int world_img_x = + world_x + (int)img.getWidth() * BRUSH_SIZE / 2; + int world_img_y = + world_y + (int)img.getHeight() * BRUSH_SIZE / 2; + Ogre::ColourValue color, colorb1, colorb2; + // float d; + int map_img_x = world_img_x / (BRUSH_SIZE); + int map_img_y = world_img_y / (BRUSH_SIZE); + int brush_img_x = world_img_x % BRUSH_SIZE; + int brush_img_y = world_img_y % BRUSH_SIZE; + if (world_img_x < 0 || + world_img_x >= img.getWidth() * BRUSH_SIZE || + world_img_y < 0 || + world_img_y >= img.getWidth() * BRUSH_SIZE) { + height = -1.0f; + goto out; + } + color = img.getColourAt(map_img_x, map_img_y, 0); + colorb1 = img_brushes.getColourAt(brush_img_x, + brush_img_y + BRUSH_SIZE, 0); + colorb2 = img_brushes.getColourAt(brush_img_x, brush_img_y, 0); + // d = Ogre::Math::saturate(color.r - 0.05f); + height = color.r; +out: + return height; + } + +public: + void define(Ogre::TerrainGroup *terrainGroup, long x, long y) override + { + uint16_t terrainSize = terrainGroup->getTerrainSize(); + float *heightMap = OGRE_ALLOC_T(float, terrainSize *terrainSize, + MEMCATEGORY_GEOMETRY); + // float *heightMapCollider = OGRE_ALLOC_T( + // float, terrainSize *terrainSize, MEMCATEGORY_GEOMETRY); + Ogre::Vector2 worldOffset(Ogre::Real(x * (terrainSize - 1)), + Ogre::Real(y * (terrainSize - 1))); + Ogre::Vector2 worldOrigin = + Ogre::Vector2(img.getWidth(), img.getHeight()) * 0.5f; + float chunk = 128.0f; + Ogre::Vector2 revisedValuePoint; + for (int i = 0; i < terrainSize; i++) + for (int j = 0; j < terrainSize; j++) { + float brush_height0 = + get_brush_height(0, j % BRUSH_SIZE, + i % BRUSH_SIZE) - + 0.55f; + float brush_height1 = + get_brush_height(1, j % BRUSH_SIZE, + i % BRUSH_SIZE) - + 0.55f; + float mheight = + Ogre::Math::lerp( + brush_height1, brush_height0, + get_base_height(worldOffset, j, + i)) * + 120.0f; + float height = mheight; + if (mheight > 0.5f) + height += 2.0f + + get_noise_height(worldOffset, + j, i); + else if (mheight < -0.5f) + height -= 2.0f + + get_noise_height(worldOffset, + j, i); + + // height = -2.0f; + heightMap[i * terrainSize + j] = height; + // heightMapCollider[(terrainSize - i - 1) * + // terrainSize + + // j] = height; + } + terrainGroup->defineTerrain(x, y, heightMap); + Ogre::LogManager::getSingleton().logError( + "defined terrain at " + + Ogre::StringConverter::toString(x) + " " + + Ogre::StringConverter::toString(y)); + // collider_queue.push_back( + // { terrainGroup, x, y, heightMapCollider }); + delete[] heightMap; + collider_queue.push_back({ terrainGroup, x, y }); + } + bool frameStarted(const Ogre::FrameEvent &evt) override + { + (void)evt; + update(); + return true; + } + void update() + { + static bool created = false; + std::deque output; + while (!collider_queue.empty()) { + Ogre::TerrainGroup *group = + collider_queue.front().group; + long x = collider_queue.front().x; + long y = collider_queue.front().y; + Ogre::Terrain *terrain = group->getTerrain(x, y); + Ogre::Vector3 worldPos; + group->convertTerrainSlotToWorldPosition(x, y, + &worldPos); + if (terrain && terrain->getHeightData() && + terrain->isLoaded() && + !terrain->isDerivedDataUpdateInProgress()) { + Ogre::LogManager::getSingleton().logError( + "can create collider for " + + Ogre::StringConverter::toString(x) + + " " + + Ogre::StringConverter::toString(y)); + float minH = terrain->getMinHeight(); + float maxH = terrain->getMaxHeight(); + int size = terrain->getSize(); + float worldSize = terrain->getWorldSize(); + if (!created || true) { + btRigidBody *body = + mWorld->addTerrainRigidBody( + group, x, y, 2, + 0x7ffffffd & (~16)); + Ogre::LogManager::getSingleton().logError( + "created rigid body " + + Ogre::StringConverter::toString( + Ogre::Bullet::convert( + body->getWorldTransform() + .getOrigin()))); + Ogre::LogManager::getSingleton().logError( + "minHeight " + + Ogre::StringConverter::toString( + minH)); + Ogre::LogManager::getSingleton().logError( + "maxHeight " + + Ogre::StringConverter::toString( + maxH)); + Ogre::LogManager::getSingleton().logError( + "size " + + Ogre::StringConverter::toString( + size)); + Ogre::LogManager::getSingleton().logError( + "world size " + + Ogre::StringConverter::toString( + worldSize)); + Ogre::LogManager::getSingleton().logError( + "created collider for " + + Ogre::StringConverter::toString( + x) + + " " + + Ogre::StringConverter::toString( + y)); + created = true; + } + collider_queue.pop_front(); + } else { + output.push_back(collider_queue.front()); + collider_queue.pop_front(); + } + } + collider_queue = output; + } +}; +class DummyPageProvider : public Ogre::PageProvider { +public: + DummyPageProvider(btDynamicsWorld *world) + : Ogre::PageProvider() + , mBtWorld(world) + { + } + std::unordered_map body; + btDynamicsWorld *mBtWorld; + bool prepareProceduralPage(Ogre::Page *page, + Ogre::PagedWorldSection *section) + { + return true; + } + bool loadProceduralPage(Ogre::Page *page, + Ogre::PagedWorldSection *section) + { + return true; + } + bool unloadProceduralPage(Ogre::Page *page, + Ogre::PagedWorldSection *section) + { + return true; + } + bool unprepareProceduralPage(Ogre::Page *page, + Ogre::PagedWorldSection *section) + { + return true; + } +}; +struct TerrainPrivate { + DummyPageProvider *mDummyPageProvider; + Ogre::Timer mSunUpdate; +}; + +TerrainModule::TerrainModule(flecs::world &ecs) +{ + ecs.component().add(flecs::Singleton); + ecs.component().add(flecs::Singleton); + ecs.set({ nullptr, {} }); + ecs.system("SetupUpdateTerrain") + .kind(flecs::OnUpdate) + .each([](const EngineData &eng, const Camera &camera, + const Sun &sun, Terrain &terrain, + TerrainPrivate &priv) { + if (!terrain.mTerrainGroup) { + std::cout << "Terrain setup\n"; + if (!priv.mDummyPageProvider) + priv.mDummyPageProvider = + new DummyPageProvider( + eng.mWorld + ->getBtWorld()); + terrain.mTerrainGlobals = + OGRE_NEW Ogre::TerrainGlobalOptions(); + + Ogre::LogManager::getSingleton().setMinLogLevel( + Ogre::LML_TRIVIAL); + + terrain.mTerrainGroup = + OGRE_NEW Ogre::TerrainGroup( + eng.mScnMgr, + Ogre::Terrain::ALIGN_X_Z, + TERRAIN_SIZE, + TERRAIN_WORLD_SIZE); + terrain.mTerrainGroup->setFilenameConvention( + ENDLESS_TERRAIN_FILE_PREFIX, + ENDLESS_TERRAIN_FILE_SUFFIX); + terrain.mTerrainGroup->setOrigin( + terrain.mTerrainPos); + // Configure global + terrain.mTerrainGlobals->setMaxPixelError(0); + // testing composite map + // mTerrainGlobals->setCompositeMapDistance(30); + terrain.mTerrainGlobals->setCompositeMapDistance( + 500); + //mTerrainGlobals->setUseRayBoxDistanceCalculation(true); + terrain.mTerrainGlobals + ->getDefaultMaterialGenerator() + ->setLightmapEnabled(false); + + terrain.mTerrainGlobals->setCompositeMapAmbient( + eng.mScnMgr->getAmbientLight()); + terrain.mTerrainGlobals->setCompositeMapDiffuse( + sun.mSun->getDiffuseColour()); + terrain.mTerrainGlobals->setLightMapDirection( + sun.mSun->getDerivedDirection()); + + // Configure default import settings for if we use imported image + Ogre::Terrain::ImportData &defaultimp = + terrain.mTerrainGroup + ->getDefaultImportSettings(); + defaultimp.terrainSize = TERRAIN_SIZE; + defaultimp.worldSize = TERRAIN_WORLD_SIZE; + defaultimp.inputScale = 1.0f; + defaultimp.minBatchSize = 33; + defaultimp.maxBatchSize = 65; + Ogre::Image combined; + combined.loadTwoImagesAsRGBA( + "Ground23_col.jpg", "Ground23_spec.png", + "General"); + Ogre::TextureManager::getSingleton().loadImage( + "Ground23_diffspec", "General", + combined); + defaultimp.layerList.resize(1); + + defaultimp.layerList[0].worldSize = 60; + defaultimp.layerList[0].textureNames.push_back( + "Ground23_diffspec"); + // Paging setup + terrain.mPageManager = + OGRE_NEW Ogre::PageManager(); + // Since we're not loading any pages from .page files, we need a way just + // to say we've loaded them without them actually being loaded + terrain.mPageManager->setPageProvider( + priv.mDummyPageProvider); + terrain.mPageManager->addCamera(camera.mCamera); + terrain.mPageManager->setDebugDisplayLevel(0); + terrain.mTerrainPaging = + OGRE_NEW Ogre::TerrainPaging( + terrain.mPageManager); + terrain.mPagedWorld = + terrain.mPageManager->createWorld(); + terrain.mTerrainPagedWorldSection = + terrain.mTerrainPaging + ->createWorldSection( + terrain.mPagedWorld, + terrain.mTerrainGroup, + 300, 800, + ENDLESS_PAGE_MIN_X, + ENDLESS_PAGE_MIN_Y, + ENDLESS_PAGE_MAX_X, + ENDLESS_PAGE_MAX_Y); + + terrain.mTerrainPagedWorldSection->setDefiner( + OGRE_NEW FlatTerrainDefiner( + eng.mScnMgr, eng.mWorld)); + + terrain.mTerrainGroup->freeTemporaryResources(); + std::cout << "Terrain setup done\n"; + } + bool playerCheck = false; + ECS::get() + .query_builder() + .with() + .with() + .each([&playerCheck, + terrain](flecs::entity e, + CharacterBase &ch, + CharacterBody &body) { + if (!body.checkGround) + body.checkGround = true; + if (ch.mBodyNode && + body.checkGroundResult) { + long x, y; + Ogre::Vector3 pos = + ch.mBodyNode + ->getPosition(); + terrain.mTerrainGroup + ->convertWorldPositionToTerrainSlot( + pos, &x, &y); + if (terrain.mTerrainGroup + ->getTerrain(x, + y) && + terrain.mTerrainGroup + ->getTerrain(x, y) + ->isLoaded()) + playerCheck = true; + } + }); + if (playerCheck) + terrain.mTerrainReady = true; + if (priv.mSunUpdate.getMilliseconds() > 1000) { + Ogre::TerrainGlobalOptions::getSingleton() + .setCompositeMapAmbient( + eng.mScnMgr->getAmbientLight()); + Ogre::TerrainGlobalOptions::getSingleton() + .setCompositeMapDiffuse( + sun.mSun->getDiffuseColour()); + Ogre::TerrainGlobalOptions::getSingleton() + .setLightMapDirection( + sun.mSun->getDerivedDirection()); + std::cout << "sun pitch: " + << sun.mSunNode->getOrientation() + .getPitch() + << "\n"; + priv.mSunUpdate.reset(); + } + }); +} +} \ No newline at end of file diff --git a/src/gamedata/TerrainModule.h b/src/gamedata/TerrainModule.h new file mode 100644 index 0000000..6c7c1df --- /dev/null +++ b/src/gamedata/TerrainModule.h @@ -0,0 +1,30 @@ +#ifndef TERRAIN_MODULE_H_ +#define TERRAIN_MODULE_H +#include +namespace Ogre +{ +class TerrainGlobalOptions; +class TerrainGroup; +class TerrainPaging; +class PageManager; +class PagedWorld; +class TerrainPagedWorldSection; +} +namespace ECS +{ +struct Terrain { + Ogre::TerrainGlobalOptions *mTerrainGlobals; + Ogre::TerrainGroup *mTerrainGroup; + Ogre::TerrainPaging *mTerrainPaging; + Ogre::PageManager *mPageManager; + Ogre::PagedWorld *mPagedWorld; + Ogre::TerrainPagedWorldSection *mTerrainPagedWorldSection; + bool mTerrainReady; + + Ogre::Vector3 mTerrainPos; +}; +struct TerrainModule { + TerrainModule(flecs::world &ecs); +}; +} +#endif \ No newline at end of file diff --git a/src/gamedata/WaterModule.cpp b/src/gamedata/WaterModule.cpp index c719a8c..bd14dde 100644 --- a/src/gamedata/WaterModule.cpp +++ b/src/gamedata/WaterModule.cpp @@ -15,14 +15,13 @@ WaterModule::WaterModule(flecs::world &ecs) ecs.module(); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); - ecs.set({ nullptr, nullptr, nullptr }); - ecs.set({ nullptr }); ecs.system("UpdateWater") .kind(flecs::OnUpdate) .each([](const EngineData &eng, const Camera &camera, WaterSurface &water) { float delta = eng.delta; if (!water.mWaterEnt || !water.mWaterNode) { + std::cout << "Water setup\n"; water.mAbove = false; water.mInRefTexUpdate = false; water.mRenderTargetListener.mSurface = &water; @@ -273,6 +272,7 @@ WaterModule::WaterModule(flecs::world &ecs) refractionViewport->setSkiesEnabled(false); refractionViewport->setAutoUpdated(false); water.mViewports[1] = refractionViewport; + std::cout << "Water setup done\n"; } Ogre::Vector3 mCameraPos = camera.mCameraNode->_getDerivedPosition(); @@ -347,24 +347,10 @@ WaterModule::WaterModule(flecs::world &ecs) waterBodyPos.y = 0; Ogre::Vector3 d = waterPos - waterBodyPos; d.y = 0; - std::cout << "aabb: " - << Ogre::Bullet::convert(body.mShapeAabbMin) - << " " - << Ogre::Bullet::convert(body.mShapeAabbMax) - << "\n"; - // Ogre::Vector3 waterPosition = mCameraPos; - // mWaterNode->setPosition(waterPosition); if (d.squaredLength() > 10.0f * 10.0f) body.mWaterBody->getWorldTransform().setOrigin( Ogre::Bullet::convert(waterBodyPos + d)); - std::cout - << "node: " << water.mWaterNode->getPosition() - << " body: " - << Ogre::Bullet::convert( - body.mWaterBody->getWorldTransform() - .getOrigin()) - << "\n"; btCompoundShape *mshape = static_cast( body.mWaterBody->getCollisionShape()); @@ -376,12 +362,6 @@ WaterModule::WaterModule(flecs::world &ecs) body.mWaterBody->getWorldTransform() .getOrigin() + btVector3(1000, -0.2, 1000); -#if 0 - mshape->getChildShape(0)->getAabb( - body.mWaterBody->getWorldTransform() * - mshape->getChildTransform(0), - body.mShapeAabbMin, body.mShapeAabbMax); -#endif btDispatcher *dispatch = eng.mWorld->getBtWorld()->getDispatcher(); eng.mWorld->getBtWorld()->getBroadphase()->setAabb( @@ -435,21 +415,6 @@ WaterModule::WaterModule(flecs::world &ecs) float dist = pt.getDistance(); if (dist < minDist) { minDist = dist; - std::cout - << " distance: " - << dist << "\n"; - contactPosA = Ogre::Bullet::convert( - pt.getPositionWorldOnA()); - contactPosB = Ogre::Bullet::convert( - pt.getPositionWorldOnB()); - std::cout - << "positionA: " - << contactPosA - << "\n"; - std::cout - << "positionB: " - << contactPosA - << "\n"; ok = true; } } diff --git a/src/terrain/terrain.cpp b/src/terrain/terrain.cpp index 3666989..5f22d4b 100644 --- a/src/terrain/terrain.cpp +++ b/src/terrain/terrain.cpp @@ -302,10 +302,11 @@ public: } }; -void TerrainSetup::setupTerrain(Ogre::Camera *camera, Ogre::Light *sun, +void TerrainSetup::setupTerrain(Ogre::Camera *camera, Ogre::Bullet::DynamicsWorld *dynamicsWorld, Ogre::Bullet::DebugDrawer *dbgDraw) { + Ogre::Light *sun = ECS::get().mSun; mDynWorld.reset(dynamicsWorld); mDbgDraw.reset(dbgDraw); mScnMgr = camera->getSceneManager(); diff --git a/water/water.frag b/water/water.frag index bf25731..f183de5 100644 --- a/water/water.frag +++ b/water/water.frag @@ -8,6 +8,21 @@ uniform float renderTargetFlipping; uniform vec4 viewportSize; uniform f32vec4 cameraPosition; ) +float rand(float n){return fract(sin(n) * 43758.5453123);} +float rand2(vec2 n) { + return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); +} +float noise(vec2 n) { + const vec2 d = vec2(0.0, 1.0); + vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n)); + float fx = f.x; + vec2 e = b + d.yx; + float m = mix(rand2(b), rand2(e), fx); + vec2 p = b + d.xy; + vec2 q = b + d.yy; + float r = mix(rand2(p), rand2(q), f.y); + return mix(m, r, fx); +} MAIN_PARAMETERS IN(f32vec3 positionWS, TEXCOORD0) IN(f32vec3 vnormal, TEXCOORD1) @@ -21,9 +36,12 @@ MAIN_DECLARATION #else screenUV.y = screenUV.y * 0.6 + 0.2; #endif + float depth = saturate(length(positionWS - cameraPosition.xyz) * 0.01); - vec4 reflectionColour = texture2D(reflectMap, screenUV * vec2(0.5, 1.0)); - vec4 refractionColour = texture2D(reflectMap, screenUV * vec2(0.5, 1.0) + vec2(0.5, 0.0)); + float nx = sin(noise(vec2(1300.0 + screenUV.x * 48.11, 1100.0 + screenUV.y))); + float ny = sin(noise(vec2(100.0 + screenUV.y * 72.2, 1500.0 + screenUV.x))); + vec4 reflectionColour = texture2D(reflectMap, vec2(nx, ny) + screenUV * vec2(0.5, 1.0)); + vec4 refractionColour = texture2D(reflectMap, vec2(nx, ny) + screenUV * vec2(0.5, 1.0) + vec2(0.5, 0.0)); vec4 result = mix(mix(reflectionColour, refractionColour, 0.5), vec4(0.0, 1.0, 1.0, 1.0), depth); float mul = dot(vec3(0.0, 1.0, 0.0), vnormal); result = result * mul;