diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a49415..7673d2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,12 @@ endif() add_dependencies(TerrainTest stage_lua_scripts stage_files) +add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/stories + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/lua-scripts/stories ${CMAKE_BINARY_DIR}/stories + DEPENDS ${CMAKE_BINARY_DIR}/lua-scripts/stories +) +add_custom_target(stage_stories ALL DEPENDS stage_lua_scripts ${CMAKE_BINARY_DIR}/stories) + add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/resources.cfg COMMAND cp ${CMAKE_SOURCE_DIR}/resources.cfg ${CMAKE_BINARY_DIR}/resources.cfg diff --git a/Game.cpp b/Game.cpp index b16f54b..cc7af75 100644 --- a/Game.cpp +++ b/Game.cpp @@ -282,10 +282,6 @@ public: control &= ~256; return false; } - void update(float delta) - { - return; - } void frameRendered(const Ogre::FrameEvent &evt) override; }; class App : public OgreBites::ApplicationContext { @@ -432,18 +428,22 @@ public: } void updateWorld(float delta) { - mDynWorld->getBtWorld()->stepSimulation(delta, 4); + mDynWorld->getBtWorld()->stepSimulation(delta, 3); + if (!ECS::get().has()) + return; /* Update window grab */ - if (ECS::get().has() && - ECS::get().get().grabChanged) { - setWindowGrab(ECS::get().get().grab); - ECS::get().get_mut().grabChanged = false; + ECS::GUI &gui = ECS::get().get_mut(); + if (gui.grabChanged) { + setWindowGrab(gui.grab); + gui.grabChanged = false; ECS::get().modified(); } ECS::update(delta); + /* if (enabldDbgDraw) mDbgDraw->update(); + */ } class InputListenerChainFlexible : public OgreBites::InputListener { protected: @@ -761,7 +761,6 @@ void KeyboardListener::frameRendered(const Ogre::FrameEvent &evt) << "\n"; fps_timer.reset(); } - update(evt.timeSinceLastFrame); if (!isGuiEnabled() || (isGuiEnabled() && ECS::get().narrationBox)) { mApp->updateWorld(evt.timeSinceLastFrame); diff --git a/assets/blender/edited-normal-male.blend b/assets/blender/edited-normal-male.blend index c45240f..e9e0bef 100644 --- a/assets/blender/edited-normal-male.blend +++ b/assets/blender/edited-normal-male.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b74f1ec0e390a38c51c8c2414fc7a3c022069f04ffeac6cd38331fe3cfc9840f -size 11163011 +oid sha256:70831d1df8a6c8ce03ec4970a502c127f06f774c042f0a59bd6b8d08cebaf2a9 +size 11628701 diff --git a/assets/blender/scripts/settings.py b/assets/blender/scripts/settings.py index 0e827d8..25c693c 100644 --- a/assets/blender/scripts/settings.py +++ b/assets/blender/scripts/settings.py @@ -54,6 +54,20 @@ class ExportMappingMale: self.files.append({"name": fobj}) class ExportMappingMaleEdited: + blend_path = "assets/blender/" + "edited-normal-male.blend" + gltf_path = "characters/male/normal-male.gltf" + ogre_scene = "characters/male/vroid-normal-male.scene" + inner_path = "Object" + objs = ["male", "Body", "Hair", "Face", "BackHair"] + armature_name = "male" + outfile = "tmp-male.blend" + default_action = 'default' + def __init__(self): + self.files = [] + for fobj in self.objs: + self.files.append({"name": fobj}) + +class ExportMappingMaleClothedEdited: blend_path = "assets/blender/" + "edited-normal-male.blend" gltf_path = "characters/male/normal-male.gltf" ogre_scene = "characters/male/vroid-normal-male.scene" diff --git a/assets/blender/vehicles/boat-sails.blend b/assets/blender/vehicles/boat-sails.blend new file mode 100644 index 0000000..74a1e2c --- /dev/null +++ b/assets/blender/vehicles/boat-sails.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:301499c2a789b753156699cb565e1dfa17fa5d0cf82e9f1cd9301ccde5ed3ec6 +size 297568 diff --git a/assets/blender/vehicles/boat.blend b/assets/blender/vehicles/boat.blend index 5860360..f38451f 100644 --- a/assets/blender/vehicles/boat.blend +++ b/assets/blender/vehicles/boat.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c0722a8941624ab4449817fc7ab9c040bf79fa8dcf9009559d7c4fa562f2e09 -size 356063 +oid sha256:3eb5a1cdd5a23fbddb41cbcedc1490d19950232230e24afb2ee0e50f3c1be1c3 +size 337947 diff --git a/lua-scripts/data.lua b/lua-scripts/data.lua index 3012527..9c57179 100644 --- a/lua-scripts/data.lua +++ b/lua-scripts/data.lua @@ -63,15 +63,6 @@ dropped you into the sea. Last thing you heard before you hit the water was happ ]]-- local narrator = require('narrator.narrator') --- Parse a book from the Ink file. -local book = narrator.parse_file('stories.game') - --- Init a story from the book -local story = narrator.init_story(book) - --- Begin the story -story:begin() - function dump(o) if type(o) == 'table' then local s = '{ ' @@ -85,26 +76,45 @@ function dump(o) end end + +--[[ function _narration() local ret = "" local choices = {} if story:can_continue() then - local paragraphs = story:continue() - for _, paragraph in ipairs(paragraphs) do - local text = paragraph.text - if paragraph.tags then - text = text .. ' #' .. table.concat(paragraph.tags, ' #') + print("can continue") + local paragraph = story:continue(1) + print(dump(paragraph)) + local text = paragraph.text + if paragraph.tags then + text = text .. ' #' .. table.concat(paragraph.tags, ' #') + for i, tag in ipairs(paragraph.tags) do + if tag == "mc_is_free" then + ecs_character_set("player", "gravity", true) + ecs_character_set("player", "buoyancy", true) + end end - ret = ret .. text end + ret = text if story:can_choose() then local ch = story:get_choices() for i, choice in ipairs(ch) do table.insert(choices, choice.text) print(i, dump(choice)) end + if #choices == 1 and choices[1] == "Ascend" then + story:choose(1) + choices = {} + end + if #choices == 1 and choices[1] == "Continue" then + story:choose(1) + choices = {} + end end + else + print("can NOT continue") end + print(ret) if (#choices > 0) then print("choices!!!") narrate(ret, choices) @@ -112,9 +122,134 @@ function _narration() narrate(ret) end end +]]-- +function Quest(name, book) + local quest = { + name = name, + active = false, + activate = function(this) + this.active = true + this.story:begin() + this:_narration() + end, + event = function(this, event) + if not this.active then + return + end + if event == "narration_progress" then + this:_narration() + elseif event == "narration_answered" then + local answer = narration_get_answer() + this.story:choose(answer) + print("answered:", answer) + this:_narration() + end + end, + _handle_tag = function(this, tag) + if tag == "mc_is_free" then + ecs_character_set("player", "gravity", true) + ecs_character_set("player", "buoyancy", true) + end + end, + _narration = function(this) + local ret = "" + local choices = {} + local have_choice = false + local have_paragraph = false + if not this.active then + return + end + if this.story:can_continue() then + print("can continue") + have_paragraph = true + local paragraph = this.story:continue(1) + print(dump(paragraph)) + local text = paragraph.text + if paragraph.tags then + text = text .. ' #' .. table.concat(paragraph.tags, ' #') + for i, tag in ipairs(paragraph.tags) do + this:_handle_tag(tag) + end + end + ret = text + if this.story:can_choose() then + have_choice = true + local ch = this.story:get_choices() + for i, choice in ipairs(ch) do + table.insert(choices, choice.text) + print(i, dump(choice)) + end + if #choices == 1 and choices[1] == "Ascend" then + this.story:choose(1) + choices = {} + end + if #choices == 1 and choices[1] == "Continue" then + this.story:choose(1) + choices = {} + end + end + else + print("can NOT continue") + end + if not have_choice and not have_paragraph then + this:complete() + this.active = false + end + print(ret) + if (#choices > 0) then + print("choices!!!") + narrate(ret, choices) + else + narrate(ret) + end + end, + complete = function(this) + print(this.name .. 'complete') + end, + story = narrator.init_story(book) + } + -- Begin the story + + return quest +end +function StartGameQuest() + -- Parse a book from the Ink file. + local book = narrator.parse_file('stories.initiation') + local quest = Quest('start game', book) + quest.base = {} + quest.base.activate = quest.activate + quest.base.complete = quest.complete + quest.boat = false + quest.activate = function(this) + print('activate...') + local mc_is_free = function() + ecs_character_params_set("player", "gravity", true) + ecs_character_params_set("player", "buoyancy", true) + end + this.story:bind('mc_is_free', mc_is_free) + this.base.activate(this) + end + quest.complete = function(this) + this.base.complete(this) + this.active = false + if not this.boat then + local boat = ecs_vehicle_set("boat", 0, 0, -20, 1.75) + local trigger = ecs_child_character_trigger(boat, "entered_boat", 0, 0, 0, 3, 3) + local npc = ecs_npc_set("normal-female.glb", 0, 2, -20, 1.75) + this.boat = true + end + end + return quest +end +quests = {} setup_handler(function(event) print(event) + for k, v in pairs(quests) do + if v.active then + v:event(event) + end + end if event == "startup" then main_menu() elseif event == "narration_progress" then @@ -122,12 +257,16 @@ setup_handler(function(event) elseif event == "narration_answered" then local answer = narration_get_answer() story:choose(answer) + print("answered:", answer) _narration() elseif event == "new_game" then - local ret = "" - story = narrator.init_story(book) - story:begin() - _narration() + ecs_character_params_set("player", "gravity", true) + ecs_character_params_set("player", "buoyancy", false) + local quest = StartGameQuest() + quests[quest.name] = quest + for k, v in pairs(quests) do + print(k, v.active) + end + quest:activate() end end) - diff --git a/lua-scripts/stories/initiation.ink b/lua-scripts/stories/initiation.ink new file mode 100644 index 0000000..b72c7f5 --- /dev/null +++ b/lua-scripts/stories/initiation.ink @@ -0,0 +1,35 @@ +- The party was hot, girls were sexy the wine, beer and whisky were in <> +enormous numbers. It was anniversary since you set sail with your friends. +The sea was calm and everything promised you another great night. <> +The whole year with your friends on your ship over vast seas of the world in decay was almost over. <> +It was so good year full of adventure, romance, indecency and luxury. +You did not know what future had for you and you never thought much about it. However <> +you had zero insights on what to follow even if you cared enough about it. You thought you could not <> +wish for brigher future far away from troubles of this world. +One day (a few days ago) your trusted friends decided that you have too much, they have too much of you and you owe them a lot.<> +They waited for opportunity to get rid of you. You totally missed the point when people started conspiring against you<> + and the following events came at total surprize. +They found you drunk in your room and moved to the deck and used ropes to <> +restrain you and attach a bucket of stones or something else heavy to your body. <> +They left you lying on the deck while were checking your room, looking for papers and something of value. +After a few hours passed two strong people pulled you to the side and <> +dropped you into the sea. You did not see their faces. Last thing you heard before you hit the water was happy laugher... +Suddenly next you found yourself under water out of breath in agony. You did not know nor care about time and place, you just cared for <> +last air leaving your body. All you wished for was quick end. +Suddenly the suffering stopped and your mind cleared. Some impactful presence <> +subdued everything in your mind leaving you with question. The only thing you could see was a strange altar for some ancient deity nearby. +You had very bad feeling about this. +'You have just a few seconds, so be quick' - the voice sounded directly somewhere inside your head. +'WILL you serve me?' Something told me my life depends on the answer. +* Sure + Of course you will. +* Do I have a choice? + You have or you have not. That depends on what you expect. +* I will + I know. +- An abrupt silence. +Then I feel my restraints removed and I started rising to the surface. 'We'll talk again soon enough' - the voice in my head told me. +'Your service will be rewarded. Go enjoy your new life.' +* [Ascend] + ~ mc_is_free() +- ->END diff --git a/src/gamedata/BoatModule.cpp b/src/gamedata/BoatModule.cpp new file mode 100644 index 0000000..6cc4a25 --- /dev/null +++ b/src/gamedata/BoatModule.cpp @@ -0,0 +1,35 @@ +#include +#include +#include "Components.h" +#include "GameData.h" +#include "BoatModule.h" + +namespace ECS +{ + +BoatModule::BoatModule(flecs::world &ecs) +{ + ecs.module(); + ecs.component(); + ecs.component(); + ecs.component().on_set([](flecs::entity e, BoatType &type) { + int i; + if (e.has() || e.has()) + return; + BoatBase &boat = e.ensure(); + boat.mEnt = ECS::get().mScnMgr->createEntity( + type.resourceName); + boat.mNode = ECS::get() + .mScnMgr->getRootSceneNode() + ->createChildSceneNode(type.position, + type.orientation); + boat.mNode->attachObject(boat.mEnt); + + BoatBody &body = e.ensure(); + body.body = ECS::get().mWorld->addRigidBody( + 0, boat.mEnt, Ogre::Bullet::CT_HULL, nullptr, 2, + 0x7fffffff); + e.modified(); + }); +} +} \ No newline at end of file diff --git a/src/gamedata/BoatModule.h b/src/gamedata/BoatModule.h new file mode 100644 index 0000000..20f3b6c --- /dev/null +++ b/src/gamedata/BoatModule.h @@ -0,0 +1,28 @@ +#ifndef BOAT_MODULE_H_ +#define BOAT_MODULE_H_ +#include +#include +namespace Ogre +{ +class Entity; +class SceneNode; +} +namespace ECS +{ +struct BoatType { + Ogre::String resourceName; + Ogre::Vector3 position; + Ogre::Quaternion orientation; +}; +struct BoatBase { + Ogre::Entity *mEnt; + Ogre::SceneNode *mNode; +}; +struct BoatBody { + btRigidBody *body; +}; +struct BoatModule { + BoatModule(flecs::world &ecs); +}; +} +#endif \ No newline at end of file diff --git a/src/gamedata/CMakeLists.txt b/src/gamedata/CMakeLists.txt index dd1e81c..f3a7a35 100644 --- a/src/gamedata/CMakeLists.txt +++ b/src/gamedata/CMakeLists.txt @@ -1,5 +1,6 @@ project(gamedata) 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 LuaData.cpp WorldMapModule.cpp) +add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp GUIModule.cpp LuaData.cpp WorldMapModule.cpp + BoatModule.cpp EventTriggerModule.cpp) target_link_libraries(GameData PUBLIC OgreMain OgreBites OgreBullet OgrePaging OgreTerrain OgreOverlay flecs::flecs_static lua) 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 b5c99ef..641aef8 100644 --- a/src/gamedata/CharacterModule.cpp +++ b/src/gamedata/CharacterModule.cpp @@ -15,16 +15,7 @@ CharacterModule::CharacterModule(flecs::world &ecs) ecs.component(); ecs.component(); ecs.component(); - ecs.component().on_add( - [](flecs::entity e, CharacterBody &body) { - e.set( - { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); - body.checkGround = false; - body.checkGroundResult = false; - body.mCollisionShape = nullptr; - body.mGhostObject = nullptr; - body.mController = nullptr; - }); + ecs.component(); ecs.system("UpdateTimer") .kind(flecs::OnUpdate) .each([this](EngineData &eng, CharacterBase &ch) { @@ -211,15 +202,19 @@ CharacterModule::CharacterModule(flecs::world &ecs) ch.is_submerged = false; }); ecs.system( - "HandleGravity") + "HandleGravityBouyanceWater") .kind(flecs::OnUpdate) .with() .with() + .with() .each([this](flecs::entity e, const EngineData &eng, const CharacterBase &ch, CharacterVelocity &gr) { Ogre::Vector3 gravity(0, -9.8f, 0); Ogre::Vector3 pos = ch.mBodyNode->getPosition(); - if (e.has()) { + Ogre::Vector3 v(0, 0, 0); + if (e.has()) + v += gravity; + if (e.has()) { float volume = 2.0f * 0.5f * 0.5f; float density = 900.0f; float full_subm = 2.0f; @@ -235,22 +230,39 @@ CharacterModule::CharacterModule(flecs::world &ecs) Ogre::Vector3 b = -gravity * density * volume * multiplier * current_subm / full_subm / mass; - gr.gvelocity += (gravity + b) * eng.delta; - gr.gvelocity.y = Ogre::Math::Clamp( - gr.gvelocity.y, -2.5f, 2.5f); - } else { - gr.gvelocity += gravity * eng.delta; - if (pos.y < -1.2) { - gr.gvelocity.y = 0.0f; - } + v += b; } - gr.gvelocity *= 0.99; + gr.gvelocity += v * eng.delta; + gr.gvelocity.y = + Ogre::Math::Clamp(gr.gvelocity.y, -2.5f, 1.5f); + gr.gvelocity *= (1.0 - eng.delta); + gr.velocity.y *= (1.0 - eng.delta); + }); + ecs.system( + "HandleGravityNoWater") + .kind(flecs::OnUpdate) + .with() + .with() + .without() + .with() + .each([this](flecs::entity e, const EngineData &eng, + const CharacterBase &ch, CharacterVelocity &gr) { + Ogre::Vector3 gravity(0, -9.8f, 0); + Ogre::Vector3 pos = ch.mBodyNode->getPosition(); + gr.gvelocity += gravity * eng.delta; + if (pos.y < -1.2) { + gr.gvelocity.y = 0.0f; + } + gr.gvelocity *= (1.0 - eng.delta); + gr.velocity.y *= (1.0 - eng.delta); }); ecs.system("HandleSwimming") .kind(flecs::OnUpdate) .with() .with() + .with() + .with() .each([this](flecs::entity e, const EngineData &eng, const AnimationControl &anim, const CharacterBase &ch, CharacterVelocity &gr) { @@ -479,65 +491,11 @@ CharacterModule::CharacterModule(flecs::world &ecs) CharacterBody>("UpdateCharacterBase") .kind(flecs::OnUpdate) .with() + .with() + .with() .each([](const EngineData &eng, CharacterLocation &loc, CharacterBase &ch, CharacterBody &body) { if (!ch.mBodyNode) { - body.mController = nullptr; - ch.mBodyEnt = eng.mScnMgr->createEntity( - "normal-male.glb"); - 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(); - body.mGhostObject = - new btPairCachingGhostObject(); - body.mCollisionShape = - new btCompoundShape(false); - body.mGhostObject->setCollisionShape( - body.mCollisionShape); - { - btVector3 inertia(0, 0, 0); - // mCollisionShape = new btCompoundShape(); - btScalar height = 1.0f; - btScalar radius = 0.3f; - btCapsuleShape *shape = - new btCapsuleShape( - radius, - 2 * height - - 2 * radius); - btTransform transform; - transform.setIdentity(); - transform.setOrigin(btVector3(0, 1, 0)); - static_cast( - body.mCollisionShape) - ->addChildShape(transform, - shape); - btScalar masses[1] = { 0 }; - btTransform principal; - static_cast( - body.mCollisionShape) - ->calculatePrincipalAxisTransform( - masses, principal, - inertia); - } - body.mGhostObject->setCollisionFlags( - btCollisionObject::CF_KINEMATIC_OBJECT /*| - btCollisionObject::CF_NO_CONTACT_RESPONSE */); - body.mGhostObject->setActivationState( - DISABLE_DEACTIVATION); - eng.mWorld->attachCollisionObject( - body.mGhostObject, ch.mBodyEnt, 1, - 0x7FFFFFFF); - OgreAssert(body.mGhostObject, - "Need GhostObject"); - OgreAssert(body.mCollisionShape, - "No collision shape"); - OgreAssert(ch.mSkeleton->hasBone("Root"), - "No root bone"); - ch.mRootBone = ch.mSkeleton->getBone("Root"); - OgreAssert(ch.mRootBone, "No root bone"); } else { loc.orientation = ch.mBodyNode->_getDerivedOrientation(); @@ -545,6 +503,77 @@ CharacterModule::CharacterModule(flecs::world &ecs) ch.mBodyNode->_getDerivedPosition(); } }); + ecs.system("SetupCharacter") + .kind(flecs::OnUpdate) + .with() + .without() + .without() + .each([](flecs::entity e, const EngineData &eng, + const CharacterLocation &loc, + const CharacterConf &conf) { + CharacterBase &ch = e.ensure(); + CharacterBody &body = 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.mSkeleton->hasBone("Root"), + "No root bone"); + ch.mRootBone = ch.mSkeleton->getBone("Root"); + OgreAssert(ch.mRootBone, "No root bone"); + body.mController = nullptr; + e.set( + { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }); + body.checkGround = false; + body.checkGroundResult = false; + body.mCollisionShape = nullptr; + body.mGhostObject = nullptr; + body.mController = nullptr; + body.mGhostObject = new btPairCachingGhostObject(); + body.mCollisionShape = new btCompoundShape(false); + body.mGhostObject->setCollisionShape( + body.mCollisionShape); + { + btVector3 inertia(0, 0, 0); + // mCollisionShape = new btCompoundShape(); + btScalar height = 1.0f; + btScalar radius = 0.3f; + btCapsuleShape *shape = new btCapsuleShape( + radius, 2 * height - 2 * radius); + btTransform transform; + transform.setIdentity(); + transform.setOrigin(btVector3(0, 1, 0)); + static_cast( + body.mCollisionShape) + ->addChildShape(transform, shape); + btScalar masses[1] = { 0 }; + btTransform principal; + static_cast( + body.mCollisionShape) + ->calculatePrincipalAxisTransform( + masses, principal, inertia); + } + body.mGhostObject->setCollisionFlags( + btCollisionObject::CF_KINEMATIC_OBJECT /*| + btCollisionObject::CF_NO_CONTACT_RESPONSE */); + body.mGhostObject->setActivationState( + DISABLE_DEACTIVATION); + eng.mWorld->attachCollisionObject( + body.mGhostObject, ch.mBodyEnt, 1, 0x7FFFFFFF); + OgreAssert(body.mGhostObject, "Need GhostObject"); + OgreAssert(body.mCollisionShape, "No collision shape"); + e.add(); + e.add(); + anim.currentAnim = AnimationControl::ANIM_NONE; + anim.nextAnim = AnimationControl::ANIM_NONE; + anim.reset = false; + anim.configured = false; + }); ecs.system( "UpdateCharacterPhysics") .kind(flecs::OnUpdate) diff --git a/src/gamedata/CharacterModule.h b/src/gamedata/CharacterModule.h index 5bd948c..ee0e4e6 100644 --- a/src/gamedata/CharacterModule.h +++ b/src/gamedata/CharacterModule.h @@ -7,6 +7,8 @@ struct Camera; /* character */ struct Character {}; /* tag */ struct Player {}; /* tag */ +struct CharacterGravity {}; +struct CharacterBuoyancy {}; struct CharacterBase { Ogre::String type; float mTimer; @@ -22,6 +24,9 @@ struct CharacterLocation { Ogre::Quaternion orientation; Ogre::Vector3 position; }; +struct CharacterConf { + Ogre::String type; +}; struct CharacterBody { btPairCachingGhostObject *mGhostObject; btCompoundShape *mCollisionShape; diff --git a/src/gamedata/EventTriggerModule.cpp b/src/gamedata/EventTriggerModule.cpp new file mode 100644 index 0000000..be929ff --- /dev/null +++ b/src/gamedata/EventTriggerModule.cpp @@ -0,0 +1,255 @@ +#include +#include +#include +#include "Components.h" +#include "GameData.h" +#include "LuaData.h" +#include "EventTriggerModule.h" + +struct TriggerBody { + btPairCachingGhostObject *mBody; + btCylinderShape *shape; + Ogre::SceneNode *mSceneNode; + std::set contactBodies; +}; +struct DeepPenetrationContactResultCallback : public btManifoldResult { + DeepPenetrationContactResultCallback( + const btCollisionObjectWrapper *body0Wrap, + const btCollisionObjectWrapper *body1Wrap) + : btManifoldResult(body0Wrap, body1Wrap) + , mPenetrationDistance(0) + , mOtherIndex(0) + { + } + float mPenetrationDistance; + int mOtherIndex; + btVector3 mNormal, mPoint; + void reset() + { + mPenetrationDistance = 0.0f; + } + bool hasHit() + { + return mPenetrationDistance < 0.0f; + } + virtual void addContactPoint(const btVector3 &normalOnBInWorld, + const btVector3 &pointInWorldOnB, + btScalar depth) + { +#ifdef VDEBUG + std::cout + << "contact: " << Ogre::Bullet::convert(pointInWorldOnB) + << " " << Ogre::Bullet::convert(normalOnBInWorld) + << "\n"; +#endif + if (mPenetrationDistance > depth) { // Has penetration? + + const bool isSwapped = + m_manifoldPtr->getBody0() != + m_body0Wrap->getCollisionObject(); + mPenetrationDistance = depth; + mOtherIndex = isSwapped ? m_index0 : m_index1; + mPoint = isSwapped ? (pointInWorldOnB + + (normalOnBInWorld * depth)) : + pointInWorldOnB; + + mNormal = isSwapped ? normalOnBInWorld * -1 : + normalOnBInWorld; + } + } +}; + +ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs) +{ + ecs.module(); + ecs.component(); + ecs.component().on_add([](flecs::entity e, + TriggerBody &body) { + bool kinematic = false; + if (e.get().parent) { + body.mSceneNode = + e.get() + .parent->createChildSceneNode( + e.get().position, + Ogre::Quaternion(0, 0, 0, 1)); + kinematic = true; + } else { + body.mSceneNode = + ECS::get() + .mScnMgr->getRootSceneNode() + ->createChildSceneNode( + e.get().position, + Ogre::Quaternion(0, 0, 0, 1)); + } + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton().createManual( + "trigger", "General"); + Ogre::Entity *ent = + ECS::get().mScnMgr->createEntity(mesh); + body.mSceneNode->attachObject(ent); + body.mBody = new btPairCachingGhostObject(); + body.mBody->getWorldTransform().setOrigin(Ogre::Bullet::convert( + body.mSceneNode->_getDerivedPosition())); + float h = e.get().halfheight; + float r = e.get().radius; + Ogre::Vector3 position = e.get().position; + body.shape = new btCylinderShape(btVector3(r, h, r)); + body.mBody->setCollisionShape(body.shape); + int flags = body.mBody->getCollisionFlags(); + flags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; + if (kinematic) + flags |= btCollisionObject::CF_STATIC_OBJECT; + body.mBody->setCollisionFlags(flags); + ECS::get().mWorld->attachCollisionObject( + body.mBody, ent, 16, 0x1); + }); + ecs.component().on_set( + [](flecs::entity e, EventTrigger &ev) { + e.add(); + }); + ecs.system( + "CheckCollisions") + .kind(flecs::OnUpdate) + .each([](flecs::entity e, const EngineData &eng, + const EventTrigger &evt, TriggerBody &body) { + btDispatcher *dispatch = + eng.mWorld->getBtWorld()->getDispatcher(); + btHashedOverlappingPairCache *cache = + body.mBody->getOverlappingPairCache(); + int i; + int count = cache->getNumOverlappingPairs(); + std::set currentContactBodies; + if (count > 0) { + btManifoldArray contacts; + btBroadphasePairArray &collisionPairs = + cache->getOverlappingPairArray(); + for (i = 0; i < count; i++) { + contacts.resize(0); + if (collisionPairs[i].m_algorithm) { + collisionPairs[i] + .m_algorithm + ->getAllContactManifolds( + contacts); + OgreAssert(false, + "Not implemented"); + } else { + const btBroadphasePair *collisionPairPtr = + eng.mWorld->getBtWorld() + ->getBroadphase() + ->getOverlappingPairCache() + ->findPair( + collisionPairs[i] + .m_pProxy0, + collisionPairs[i] + .m_pProxy1); + if (collisionPairPtr) { + const btBroadphasePair + &collisionPair = + *collisionPairPtr; + const btCollisionObject *objA = static_cast< + btCollisionObject + *>( + collisionPair + .m_pProxy0 + ->m_clientObject); + const btCollisionObject *objB = static_cast< + btCollisionObject + *>( + collisionPair + .m_pProxy1 + ->m_clientObject); + const btCollisionObject + *me, + *other; + if (objA == + static_cast< + btCollisionObject + *>( + body.mBody)) { + me = objA; + other = objB; + } else { + me = objB; + other = objA; + } + const btCollisionShape *my_shape = + me->getCollisionShape(); + const btCollisionShape *other_shape = + other->getCollisionShape(); + btCollisionObjectWrapper obA( + NULL, my_shape, + body.mBody, + body.mBody + ->getWorldTransform(), + -1, i); + btCollisionObjectWrapper obB( + NULL, + other_shape, + other, + other->getWorldTransform(), + -1, 0); + btCollisionAlgorithm *algorithm = + dispatch->findAlgorithm( + &obA, + &obB, + NULL, + BT_CONTACT_POINT_ALGORITHMS); + DeepPenetrationContactResultCallback + contactPointResult( + &obA, + &obB); + + algorithm->processCollision( + &obA, &obB, + eng.mWorld + ->getBtWorld() + ->getDispatchInfo(), + &contactPointResult); + algorithm + ->~btCollisionAlgorithm(); + dispatch->freeCollisionAlgorithm( + algorithm); + if (contactPointResult + .hasHit()) { + currentContactBodies + .insert(other); + if (body.contactBodies + .find(other) == + body.contactBodies + .end()) { + body.contactBodies + .insert(other); + ECS::get< + LuaBase>() + .mLua + ->call_handler( + evt.event); + } + } + } + } + } + } + std::set::iterator it = + body.contactBodies.begin(); + while (it != body.contactBodies.end()) { + if (currentContactBodies.find(*it) == + currentContactBodies.end()) { + if (e.has()) { + const Ogre::String &exit_event = + ECS::get< + EventTriggerExit>() + .event; + ECS::get() + .mLua->call_handler( + exit_event); + } else { + std::cout << "body exited" + << std::endl; + } + body.contactBodies.erase(*it); + } + it++; + } + }); +} diff --git a/src/gamedata/EventTriggerModule.h b/src/gamedata/EventTriggerModule.h new file mode 100644 index 0000000..b2ae612 --- /dev/null +++ b/src/gamedata/EventTriggerModule.h @@ -0,0 +1,21 @@ +#ifndef EVENT_TRIGGER_MODULE_H_ +#define EVENT_TRIGGER_MODULE_H_ +#include +#include +namespace ECS +{ +struct EventTrigger { + Ogre::SceneNode *parent; + Ogre::Vector3 position; + float halfheight; + float radius; + Ogre::String event; +}; +struct EventTriggerExit { + Ogre::String event; +}; +struct EventTriggerModule { + EventTriggerModule(flecs::world &ecs); +}; +} +#endif \ No newline at end of file diff --git a/src/gamedata/GameData.cpp b/src/gamedata/GameData.cpp index 8f52f6d..961e52f 100644 --- a/src/gamedata/GameData.cpp +++ b/src/gamedata/GameData.cpp @@ -9,6 +9,8 @@ #include "GUIModule.h" #include "LuaData.h" #include "WorldMapModule.h" +#include "BoatModule.h" +#include "EventTriggerModule.h" namespace ECS { @@ -43,6 +45,9 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world, ecs.import (); ecs.import (); ecs.import (); + ecs.import (); + ecs.import (); + ecs.system("UpdateDelta") .kind(flecs::OnUpdate) .each([](EngineData &eng) { @@ -95,19 +100,7 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world, player = ecs.entity("player"); Ogre::Vector3 playerPos(0, 0, 4); player.set({ { 0, 0, 0, 1 }, playerPos }); - player.set({ AnimationControl::ANIM_NONE, - AnimationControl::ANIM_NONE, false, - false }); - player.set({ "normal-male.glb", - 0.0f, - nullptr, - nullptr, - nullptr, - nullptr, - { 0, 0, 0 }, - { 0, 0, 0 }, - false }); - player.set({ nullptr, nullptr, nullptr, false, false }); + player.set({ "normal-male.glb" }); player.add(); player.add(); } diff --git a/src/gamedata/LuaData.cpp b/src/gamedata/LuaData.cpp index 7e70968..03892d4 100644 --- a/src/gamedata/LuaData.cpp +++ b/src/gamedata/LuaData.cpp @@ -2,6 +2,9 @@ #include "GameData.h" #include "Components.h" #include "GUIModule.h" +#include "CharacterModule.h" +#include "BoatModule.h" +#include "EventTriggerModule.h" #include "LuaData.h" extern "C" { @@ -9,6 +12,32 @@ int luaopen_lpeg(lua_State *L); } namespace ECS { +struct idmap { + std::unordered_map id2entity; + int next_id; + idmap() + : id2entity({}) + , next_id(0) + { + } + int get_next_id() + { + next_id++; + return next_id; + } + int add_entity(flecs::entity e) + { + int id = get_next_id(); + id2entity[id] = e; + return id; + } + flecs::entity get_entity(int id) + { + OgreAssert(id2entity[id].is_valid(), "Invalid entity"); + return id2entity[id]; + } +}; +struct idmap idmap; int LuaData::setup_handler() { @@ -161,9 +190,6 @@ LuaData::LuaData() ECS::modified(); std::cout << "narration ended\n"; } else if (message.length() > 0) { - std::replace(message.begin(), message.end(), '\n', ' '); - std::replace(message.begin(), message.end(), '\r', ' '); - ECS::get_mut().enabled = true; ECS::get_mut().grab = false; ECS::get_mut().grabChanged = true; @@ -191,6 +217,134 @@ LuaData::LuaData() return 0; }); lua_setglobal(L, "main_menu"); + lua_pushcfunction(L, [](lua_State *L) -> int { + OgreAssert(lua_gettop(L) == 3, "Invalid parameters"); + luaL_checktype(L, 1, LUA_TSTRING); + luaL_checktype(L, 2, LUA_TSTRING); + luaL_checktype(L, 3, LUA_TBOOLEAN); + bool enable = lua_toboolean(L, 3); + flecs::entity e = ECS::get().lookup(lua_tostring(L, 1)); + Ogre::String what = lua_tostring(L, 2); + OgreAssert(e.is_valid(), "Invalid character"); + OgreAssert(e.has(), "Not a character"); + if (what == "gravity") { + /* clear momentum */ + e.get_mut().gvelocity.y = 0.0f; + e.get_mut().velocity.y = 0.0f; + e.modified(); + if (enable) + e.add(); + else + e.remove(); + } else if (what == "buoyancy") { + if (enable) + e.add(); + else + e.remove(); + } else + OgreAssert(false, "Bad parameter " + what); + return 0; + }); + lua_setglobal(L, "ecs_character_params_set"); + lua_pushcfunction(L, [](lua_State *L) -> int { + luaL_checktype(L, 1, LUA_TSTRING); + luaL_checktype(L, 2, LUA_TNUMBER); + luaL_checktype(L, 3, LUA_TNUMBER); + luaL_checktype(L, 4, LUA_TNUMBER); + luaL_checktype(L, 5, LUA_TNUMBER); + Ogre::String what = lua_tostring(L, 1); + if (what == "boat") { + float yaw = lua_tonumber(L, 5); + float x = lua_tonumber(L, 2); + float y = lua_tonumber(L, 3); + float z = lua_tonumber(L, 4); + flecs::entity e = ECS::get().entity(); + Ogre::Quaternion orientation(Ogre::Radian(yaw), + Ogre::Vector3(0, 1, 0)); + Ogre::Vector3 position(x, y, z); + e.set({ "boat.glb", position, orientation }); + lua_pushinteger(L, idmap.add_entity(e)); + return 1; + } + lua_pushinteger(L, -1); + return 1; + }); + lua_setglobal(L, "ecs_vehicle_set"); + lua_pushcfunction(L, [](lua_State *L) -> int { + OgreAssert(lua_gettop(L) == 6, "bad parameters"); + luaL_checktype(L, 1, LUA_TSTRING); // event + luaL_checktype(L, 2, LUA_TNUMBER); // x + luaL_checktype(L, 3, LUA_TNUMBER); // y + luaL_checktype(L, 4, LUA_TNUMBER); // z + luaL_checktype(L, 5, LUA_TNUMBER); // halfh + luaL_checktype(L, 6, LUA_TNUMBER); // radius + flecs::entity e = ECS::get().entity(); + Ogre::String event = lua_tostring(L, 1); + float x = lua_tonumber(L, 2); + float y = lua_tonumber(L, 3); + float z = lua_tonumber(L, 4); + float h = lua_tonumber(L, 5); + float r = lua_tonumber(L, 6); + Ogre::Vector3 position(x, y, z); + e.set({ nullptr, position, h, r, event }); + lua_pushinteger(L, idmap.add_entity(e)); + return 1; + }); + lua_setglobal(L, "ecs_character_trigger"); + lua_pushcfunction(L, [](lua_State *L) -> int { + OgreAssert(lua_gettop(L) == 7, "bad parameters"); + luaL_checktype(L, 1, LUA_TNUMBER); // parent + luaL_checktype(L, 2, LUA_TSTRING); // event + luaL_checktype(L, 3, LUA_TNUMBER); // x + luaL_checktype(L, 4, LUA_TNUMBER); // y + luaL_checktype(L, 5, LUA_TNUMBER); // z + luaL_checktype(L, 6, LUA_TNUMBER); // halfh + luaL_checktype(L, 7, LUA_TNUMBER); // radius + int parent = lua_tointeger(L, 1); + flecs::entity parent_e = idmap.get_entity(parent); + Ogre::SceneNode *parentNode = nullptr; + if (parent_e.has()) + parentNode = parent_e.get().mBodyNode; + + else if (parent_e.has()) + parentNode = parent_e.get().mNode; + flecs::entity e = ECS::get().entity().child_of(parent_e); + Ogre::String event = lua_tostring(L, 2); + float x = lua_tonumber(L, 3); + float y = lua_tonumber(L, 4); + float z = lua_tonumber(L, 5); + float h = lua_tonumber(L, 6); + float r = lua_tonumber(L, 7); + OgreAssert(parentNode, "bad parent"); + Ogre::Vector3 position(x, y, z); + e.set({ parentNode, position, h, r, event }); + lua_pushinteger(L, idmap.add_entity(e)); + return 1; + }); + lua_setglobal(L, "ecs_child_character_trigger"); + lua_pushcfunction(L, [](lua_State *L) -> int { + OgreAssert(lua_gettop(L) == 5, "Invalid parameters"); + luaL_checktype(L, 1, LUA_TSTRING); // type + luaL_checktype(L, 2, LUA_TNUMBER); + luaL_checktype(L, 3, LUA_TNUMBER); + luaL_checktype(L, 4, LUA_TNUMBER); + luaL_checktype(L, 5, LUA_TNUMBER); + Ogre::String type = lua_tostring(L, 1); + float yaw = lua_tonumber(L, 5); + float x = lua_tonumber(L, 2); + float y = lua_tonumber(L, 3); + float z = lua_tonumber(L, 4); + flecs::entity e = ECS::get().entity(); + Ogre::Quaternion orientation(Ogre::Radian(yaw), + Ogre::Vector3(0, 1, 0)); + Ogre::Vector3 npcPos(x, y, z); + e.set({ orientation, npcPos }); + e.set({ type }); + e.add(); + lua_pushinteger(L, idmap.add_entity(e)); + return 1; + }); + lua_setglobal(L, "ecs_npc_set"); } LuaData::~LuaData() @@ -200,6 +354,7 @@ LuaData::~LuaData() void LuaData::lateSetup() { +#if 0 Ogre::DataStreamList streams = Ogre::ResourceGroupManager::getSingleton().openResources( "*.lua", "LuaScripts"); @@ -212,6 +367,16 @@ void LuaData::lateSetup() OgreAssert(false, "Script failure"); } } +#endif + Ogre::DataStreamPtr stream = + Ogre::ResourceGroupManager::getSingleton().openResource( + "data.lua", "LuaScripts"); + std::cout << "stream: " << stream->getAsString() << "\n"; + if (luaL_dostring(L, stream->getAsString().c_str()) != LUA_OK) { + std::cout << "error: " << lua_tostring(L, -1) << "\n"; + OgreAssert(false, "Script failure"); + } + const char *lua_code = "\n\ function stuff()\n\ return 4\n\ @@ -226,8 +391,14 @@ void LuaData::lateSetup() LuaModule::LuaModule(flecs::world &ecs) { - ecs.component().add(flecs::Singleton); - ecs.set({ OGRE_NEW LuaData, false, false }); + ecs.component() + .on_add([](LuaBase &lua) { + lua.mLua = new LuaData; + lua.setup_called = false; + lua.startup_called = false; + }) + .add(flecs::Singleton); + ecs.add(); ecs.system("LuaUpdate") .kind(flecs::OnUpdate) .each([](const EngineData &eng, LuaBase &lua) { diff --git a/src/gamedata/TerrainModule.cpp b/src/gamedata/TerrainModule.cpp index b2b657e..90cf908 100644 --- a/src/gamedata/TerrainModule.cpp +++ b/src/gamedata/TerrainModule.cpp @@ -17,7 +17,7 @@ #include "TerrainModule.h" #define TERRAIN_SIZE 129 -#define TERRAIN_WORLD_SIZE 4000.0f +#define TERRAIN_WORLD_SIZE 1000.0f #define ENDLESS_TERRAIN_FILE_PREFIX Ogre::String("EndlessWorldTerrain") #define ENDLESS_TERRAIN_FILE_SUFFIX Ogre::String("dat") @@ -82,10 +82,11 @@ struct HeightData { 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; + int div = 1; + int map_img_x = world_img_x / (BRUSH_SIZE) / div; + int map_img_y = world_img_y / (BRUSH_SIZE) / div; + int brush_img_x = (world_img_x / div) % BRUSH_SIZE; + int brush_img_y = (world_img_y / div) % BRUSH_SIZE; if (world_img_x < 0 || world_img_x >= img.getWidth() * BRUSH_SIZE || world_img_y < 0 || @@ -316,6 +317,11 @@ public: what->attachObject(ent); what->setOrientation(item.rotation); what->setPosition(item.position); + ECS::get() + .mWorld->addRigidBody( + 0, ent, + Ogre::Bullet::CT_TRIMESH, + nullptr, 2, 0x7fffffff); } } else { output.push_back(collider_queue.front()); @@ -367,6 +373,8 @@ struct TerrainPrivate { TerrainModule::TerrainModule(flecs::world &ecs) { + struct CanSetPlayerPosition {}; + ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.set({ nullptr, {} }); @@ -528,8 +536,8 @@ TerrainModule::TerrainModule(flecs::world &ecs) 0); item.position.y = height; placement.altar_items.push_back(item); - for (i = -64000; i < 64000; i += 1000) - for (j = -64000; j < 64000; j += 1000) { + for (i = -64000; i < 64000; i += 2000) + for (j = -64000; j < 64000; j += 2000) { if (i == 0 && j == 0) continue; Ogre::Vector3 position(i, 0, j); @@ -566,6 +574,7 @@ TerrainModule::TerrainModule(flecs::world &ecs) #endif if (height > -9.0f) continue; +#ifdef VDEBUG std::cout << "worldSize: " << worldSize - 1 << std::endl; @@ -573,6 +582,7 @@ TerrainModule::TerrainModule(flecs::world &ecs) << " " << j << " " << height << std::endl; +#endif item.entity = "altar.glb"; item.rotation = Ogre::Quaternion(0, 0, @@ -582,6 +592,7 @@ TerrainModule::TerrainModule(flecs::world &ecs) placement.altar_items.push_back( item); } +#ifdef VDEBUG for (i = 0; i < placement.altar_items.size(); i++) { std::cout << "placement: " << i << " " @@ -589,20 +600,38 @@ TerrainModule::TerrainModule(flecs::world &ecs) .position << std::endl; } - flecs::entity player = ECS::player; - CharacterLocation &loc = - player.get_mut(); - height = get_height(terrain.mTerrainGroup, - loc.position); - loc.position.y = height + 0.0f; - player.get() - .mBodyNode->setPosition(loc.position); - player.get() - .mBodyNode->setOrientation( - Ogre::Quaternion()); - player.modified(); +#endif + ECS::get().add(); } }); + ecs.system("SetPlayerPosition") + .kind(flecs::OnUpdate) + .with() + .each([this](const Terrain &terrain) { + flecs::entity player = ECS::player; + if (!player.is_valid()) + return; + if (!player.has()) + return; + if (!player.has()) + return; + if (!player.has()) + return; + CharacterLocation &loc = + player.get_mut(); + const CharacterBase &ch = player.get(); + if (!ch.mBodyNode) { + std::cout << "no player yet"; + return; + } + float height = + get_height(terrain.mTerrainGroup, loc.position); + loc.position.y = height + 0.0f; + ch.mBodyNode->setPosition(loc.position); + ch.mBodyNode->setOrientation(Ogre::Quaternion()); + player.modified(); + ECS::get().remove(); + }); } float TerrainModule::get_height(Ogre::TerrainGroup *group, const Ogre::Vector3 &position) diff --git a/src/gamedata/WaterModule.cpp b/src/gamedata/WaterModule.cpp index 19c0e46..70efedd 100644 --- a/src/gamedata/WaterModule.cpp +++ b/src/gamedata/WaterModule.cpp @@ -349,7 +349,9 @@ WaterModule::WaterModule(flecs::world &ecs) water.mReflectionCamera->setNearClipDistance( camera.mCamera->getNearClipDistance()); water.mReflectionCamera->setFarClipDistance( - camera.mCamera->getFarClipDistance()); + Ogre::Math::Clamp( + camera.mCamera->getFarClipDistance(), + 10.0f, 10.0f)); water.mReflectionCamera->enableCustomNearClipPlane( water.mReflectionClipPlaneAbove); water.mReflectionCamera->enableReflection( @@ -410,7 +412,9 @@ WaterModule::WaterModule(flecs::world &ecs) water.mRefractionCamera->setNearClipDistance( camera.mCamera->getNearClipDistance()); water.mRefractionCamera->setFarClipDistance( - camera.mCamera->getFarClipDistance()); + Ogre::Math::Clamp( + camera.mCamera->getFarClipDistance(), + 1.0f, 10.0f)); water.mRefractionCamera->enableCustomNearClipPlane( water.mRefractionClipPlaneAbove); @@ -507,14 +511,14 @@ WaterModule::WaterModule(flecs::world &ecs) water.mWaterNode->translate(d * 3.0f * delta); else water.mWaterNode->translate(d); - water.mWaterEnt->setVisible(false); + // water.mWaterEnt->setVisible(false); water.mViewports[0]->update(); water.mViewports[1]->update(); - water.mRenderTargetListener.mInDepth = true; - water.mViewports[2]->update(); - water.mViewports[3]->update(); - water.mRenderTargetListener.mInDepth = false; - water.mWaterEnt->setVisible(true); + // water.mRenderTargetListener.mInDepth = true; + // water.mViewports[2]->update(); + // water.mViewports[3]->update(); + // water.mRenderTargetListener.mInDepth = false; + // water.mWaterEnt->setVisible(true); }); ecs.system( "UpdateWaterBody")