Compare commits

...

3 Commits

Author SHA1 Message Date
92ec3e9497 Updates 2025-09-05 22:56:48 +03:00
25816c5658 Tweaked water physics 2025-09-04 01:14:10 +03:00
1c56387c35 Fixed water body presence physics 2025-09-03 22:16:53 +03:00
20 changed files with 1560 additions and 438 deletions

View File

@@ -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
)

View File

@@ -1,6 +1,7 @@
#include <iostream>
#include <Ogre.h>
#include <OgreBullet.h>
#include <OgreApplicationContext.h>
#include <OgreOverlaySystem.h>
#include <OgreOverlayManager.h>
@@ -9,8 +10,8 @@
#include <OgreTrays.h>
#include <OgreTimer.h>
#include <OgreMeshLodGenerator.h>
#include <OgreTerrain.h>
#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()

692
Game.cpp
View File

@@ -10,11 +10,12 @@
#include <OgreTimer.h>
#include <OgreMeshLodGenerator.h>
#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<Ogre::String> glb_names;
void init_glb_list()
{
int i;
const std::vector<Ogre::String> &groups =
Ogre::ResourceGroupManager::getSingleton()
.getResourceGroups();
for (i = 0; i < groups.size(); i++) {
std::vector<Ogre::String> 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<Ogre::Bullet::DynamicsWorld> mDynWorld;
std::unique_ptr<Ogre::Bullet::DebugDrawer> 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<ECS::GUI>())
return false;
return (ECS::get().get<ECS::GUI>().enabled);
}
void setGuiEnabled(bool value)
{
if (!ECS::get().has<ECS::GUI>())
return;
ECS::get().get_mut<ECS::GUI>().enabled = value;
ECS::get().modified<ECS::GUI>();
}
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<ECS::GUI>(), "");
setGuiEnabled(true);
if (ECS::get().has<ECS::GUI>())
ECS::get<ECS::GUI>().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>()) {
ECS::Input &input =
ECS::get().get_mut<ECS::Input>();
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::CharacterBase>();
ECS::CharacterBody &body =
getPlayer().get_mut<ECS::CharacterBody>();
if (!body.checkGround) {
body.checkGround = true;
getPlayer().modified<ECS::CharacterBody>();
}
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<ECS::Terrain>())
return ECS::get().get<ECS::Terrain>().mTerrainReady;
return false;
}
// TODO: implement rough water level calculation
float getWaterLevel(const Ogre::Vector3 &position)
@@ -620,28 +463,255 @@ public:
void updateWorld(float delta)
{
mDynWorld->getBtWorld()->stepSimulation(delta, 4);
/* Update window grab */
if (ECS::get().has<ECS::GUI>() &&
ECS::get().get<ECS::GUI>().grabChanged) {
setWindowGrab(ECS::get().get<ECS::GUI>().grab);
ECS::get().get_mut<ECS::GUI>().grabChanged = false;
ECS::get().modified<ECS::GUI>();
}
ECS::update(delta);
// mDbgDraw->update();
}
void updateWater(float delta)
{
#ifdef WATER
m_water.updateWater(delta);
#endif
}
class InputListenerChainFlexible : public OgreBites::InputListener {
protected:
std::vector<OgreBites::InputListener *> mListenerChain;
public:
InputListenerChainFlexible()
{
}
InputListenerChainFlexible(std::vector<InputListener *> 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::App>();
ECS::get()
.observer<ECS::GUI>("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<ECS::App>("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<ECS::GUI, ECS::App>("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<ECS::App>();
}
});
#endif
#if 0
input_update =
ECS::get()
.system<ECS::GUI, ECS::App>("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<ECS::App>();
}
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;
@@ -660,6 +730,25 @@ public:
OgreAssert(m, "Sky box material not found.");
m->load();
ECS::setup(mScnMgr, mDynWorld.get(), mCameraNode, mCamera);
ECS::get()
.system<const ECS::GUI, ECS::App>("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::App>();
}
});
ECS::get().set<ECS::RenderWindow>(
{ getRenderWindow(), getDisplayDPI() });
ECS::get().set<ECS::App>(
{ static_cast<OgreBites::ApplicationContext *>(this),
nullptr,
{} });
Sound::setup();
Sound::ding();
}
@@ -677,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<ECS::GUI>().setWindowGrab(true);
}
bool get_gui_active()
{
return mKbd.gui_active;
return ECS::get().get<ECS::GUI>().enabled;
}
void set_gui_active(bool active)
{
mKbd.gui_active = active;
ECS::get().get_mut<ECS::GUI>().enabled = active;
ECS::get().modified<ECS::GUI>();
}
Ogre::Camera *getCamera()
{
return mCamera;
}
void setupTerrain()
{
m_terrain.setupTerrain(mCamera, mSun, mDynWorld.get(),
mDbgDraw.get());
}
flecs::entity getPlayer() const
{
flecs::entity player =
@@ -705,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<Ogre::SceneNode *> tree_input_queue,
tree_output_queue;
std::vector<Ogre::SceneNode *> tree_list;
tree_input_queue.push_back(mScnMgr->getRootSceneNode());
tree_input_queue.push_back(nullptr);
std::set<Ogre::SceneNode *> 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<int> 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;

View File

@@ -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})

View File

@@ -3,6 +3,7 @@
#include <OgreBullet.h>
#include "GameData.h"
#include "CharacterModule.h"
#include "WaterModule.h"
#include "Components.h"
namespace ECS
{
@@ -14,11 +15,16 @@ CharacterModule::CharacterModule(flecs::world &ecs)
AnimationControl::ANIM_NONE, false,
false });
player.set<CharacterBase>(
{ "normal-male.glb", nullptr, nullptr, nullptr });
{ "normal-male.glb", 0.0f, nullptr, nullptr, nullptr });
player.set<CharacterBody>(
{ nullptr, nullptr, nullptr, { 0, 0, 0 }, false, false });
player.add<Character>();
player.add<Player>();
ecs.system<EngineData, CharacterBase>("UpdateTimer")
.kind(flecs::OnUpdate)
.each([this](EngineData &eng, CharacterBase &ch) {
ch.mTimer += eng.delta;
});
ecs.system<Input, Camera>("HandleInput")
.kind(flecs::OnUpdate)
.each([this](Input &input, Camera &camera) {
@@ -190,8 +196,29 @@ CharacterModule::CharacterModule(flecs::world &ecs)
Ogre::Vector3 colNormal;
bool is_on_floor = false;
bool penetration = false;
Ogre::Vector3 gravity(0, -9.8, 0);
body.gvelocity += gravity * delta;
Ogre::Vector3 gravity(0, -9.8f, 0);
if (e.has<InWater>()) {
float volume = 2.0f * 0.5f * 0.5f;
float density = 900.0f;
float full_subm = 2.0f;
float mass = 80.0f;
float multiplier = 0.25f;
float current_subm = -Ogre::Math::Clamp(
pos.y + Ogre::Math::Sin(ch.mTimer *
0.13f +
130.0f) *
0.07f,
-full_subm, 0.0f);
Ogre::Vector3 b = -gravity * density * volume *
multiplier * current_subm /
full_subm / mass;
body.gvelocity += (gravity + b) * delta;
body.gvelocity.y = Ogre::Math::Clamp(
body.gvelocity.y, -2.5f, 2.5f);
} else
body.gvelocity += gravity * delta;
body.gvelocity *= 0.99;
velocity += body.gvelocity;
Ogre::Vector3 rotMotion = velocity * delta;
btVector3 currentPosition =
@@ -293,9 +320,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
inertia);
}
body.mGhostObject->setCollisionFlags(
btCollisionObject::CF_KINEMATIC_OBJECT |
btCollisionObject::
CF_NO_CONTACT_RESPONSE);
btCollisionObject::CF_KINEMATIC_OBJECT /*|
btCollisionObject::CF_NO_CONTACT_RESPONSE */);
body.mGhostObject->setActivationState(
DISABLE_DEACTIVATION);
eng.mWorld->attachCollisionObject(
@@ -459,6 +485,50 @@ CharacterModule::CharacterModule(flecs::world &ecs)
body.checkGround = false;
}
});
ecs.system<const WaterBody, const CharacterBase, CharacterBody>(
"CharacterWater1")
.kind(flecs::OnUpdate)
.with<Character>()
.without<InWater>()
.each([](flecs::entity e, const WaterBody &waterb,
const CharacterBase &ch, CharacterBody &body) {
if (waterb.mInWater.find(body.mGhostObject) !=
waterb.mInWater.end() &&
ch.mBodyNode->_getDerivedPosition().y < -0.05f) {
e.add<InWater>();
std::cout << "Big Splash\n";
}
#if 0
if (waterb.mInWater.find(body.mGhostObject) ==
waterb.mInWater.end())
e.add<InWater>();
std::cout << waterb.mInWater.size() << " InWater\n";
#endif
});
ecs.system<const WaterBody, const CharacterBase, CharacterBody>(
"CharacterWater2")
.kind(flecs::OnUpdate)
.with<Character>()
.with<InWater>()
.each([](flecs::entity e, const WaterBody &waterb,
const CharacterBase &ch, CharacterBody &body) {
if (waterb.mInWater.find(body.mGhostObject) ==
waterb.mInWater.end() &&
ch.mBodyNode->_getDerivedPosition().y > 0.05f)
e.remove<InWater>();
});
#if 0
ecs.system<const EngineData, CharacterBase, CharacterBody>(
"DisplayPlayerPos")
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.each([](const EngineData &eng, CharacterBase &ch,
CharacterBody &body) {
std::cout << "player: " << ch.mBodyNode->getPosition()
<< "\n";
});
#endif
}
void CharacterModule::setAnimation(AnimationControl &anim)

View File

@@ -9,6 +9,7 @@ struct Character {}; /* tag */
struct Player {}; /* tag */
struct CharacterBase {
Ogre::String type;
float mTimer;
Ogre::SceneNode *mBodyNode;
Ogre::Entity *mBodyEnt;
Ogre::Skeleton *mSkeleton;

View File

@@ -2,6 +2,12 @@
#define COMPONENTS_H_
#include <Ogre.h>
#include <OgreBullet.h>
namespace OgreBites
{
class ApplicationContextSDL;
class InputListenerChain;
class InputListener;
}
namespace ECS
{
struct GameData {
@@ -46,5 +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<OgreBites::InputListener *> listeners;
};
struct InWater {};
}
#endif

314
src/gamedata/GUIModule.cpp Normal file
View File

@@ -0,0 +1,314 @@
#include <iostream>
#include <OgreOverlaySystem.h>
#include <OgreOverlayManager.h>
#include <OgreImGuiOverlay.h>
#include <OgreImGuiInputListener.h>
#include <OgreRenderTargetListener.h>
#include <OgreSceneNode.h>
#include <OgreApplicationContext.h>
#include <OgreImGuiInputListener.h>
#include "GameData.h"
#include "Components.h"
#include "GUIModule.h"
namespace ECS
{
struct GUIListener;
struct GUIData {
Ogre::ImGuiOverlay *mGuiOverlay;
std::vector<Ogre::String> 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<GUI>().enabled)
// ECS::get().get<App>().app->setWindowGrab(true);
if (ImGui::Button("Shitty Quit button"))
Ogre::Root::getSingleton().queueEndRendering();
if (ImGui::Button("Chick-chick")) {
ECS::get().get_mut<GUI>().enabled = false;
ECS::get().modified<GUI>();
// ECS::get().get<App>().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<EngineData>().mScnMgr->createEntity(
name);
Ogre::SceneNode *pnode =
ECS::get()
.get<EngineData>()
.mScnMgr->getRootSceneNode()
->createChildSceneNode(
"ent:" + name +
Ogre::StringConverter::toString(
key),
ECS::get()
.get<Camera>()
.mCameraPivot->getPosition(),
ECS::get()
.get<Camera>()
.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>().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<GUIData>().glb_names.size();
i++) {
Ogre::String id_button =
"Create entity: " +
ECS::get().get<GUIData>().glb_names[i] +
"##ent:" +
ECS::get().get<GUIData>().glb_names[i];
if (ImGui::Button(id_button.c_str())) {
create_entity_node(
ECS::get().get<GUIData>().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<GUI>().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<Ogre::SceneNode *> tree_input_queue,
tree_output_queue;
std::vector<Ogre::SceneNode *> tree_list;
tree_input_queue.push_back(
ECS::get()
.get<EngineData>()
.mScnMgr->getRootSceneNode());
tree_input_queue.push_back(nullptr);
std::set<Ogre::SceneNode *> 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<int> 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<GUI>().add(flecs::Singleton);
ecs.component<GUIData>().add(flecs::Singleton);
ecs.set<GUI>({ false, true, false, nullptr });
ecs.set<GUIData>({ nullptr, {}, nullptr });
ui_wait =
ecs.system<const RenderWindow, App, GUIData>("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<Ogre::String> &groups =
Ogre::ResourceGroupManager::
getSingleton()
.getResourceGroups();
for (i = 0; i < groups.size(); i++) {
std::vector<Ogre::String> names =
*Ogre::ResourceGroupManager::getSingleton()
.findResourceNames(
groups[i],
"*.glb");
gui.glb_names.insert(
gui.glb_names.end(),
names.begin(),
names.end());
}
ECS::get_mut<ECS::GUI>()
.mGuiInpitListener =
new OgreBites::
ImGuiInputListener();
ECS::modified<ECS::GUI>();
std::cout << "GUI configure finished\n";
}
});
}
}

30
src/gamedata/GUIModule.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef GUI_MODULE_H_
#define GUI_MODULE_H_
#include <flecs.h>
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<ECS::GUI>();
if (gui.grab != g) {
gui.grab = g;
gui.grabChanged = true;
ECS::get().modified<ECS::GUI>();
}
}
};
struct GUIModule {
flecs::entity ui_wait;
GUIModule(flecs::world &ecs);
};
}
#endif

View File

@@ -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,21 +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<EngineData>().add(flecs::Singleton);
ecs.component<GameData>().add(flecs::Singleton);
ecs.component<Input>().add(flecs::Singleton);
ecs.component<Camera>().add(flecs::Singleton);
ecs.set<EngineData>({ scnMgr, world, 0.0f });
ecs.set<Camera>({ cameraNode, camera, false });
ecs.add<GameData>();
ecs.add<Input>();
ecs.component<InWater>();
ecs.component<App>().add(flecs::Singleton);
ecs.import <WaterModule>();
ecs.import <CharacterModule>();
ecs.import <SunModule>();
ecs.import <TerrainModule>();
ecs.import <GUIModule>();
ecs.system<EngineData>("UpdateDelta")
.kind(flecs::OnUpdate)
.each([](EngineData &eng) {
eng.delta = ECS::get().delta_time();
});
ecs.import <CharacterModule>();
ecs.import <WaterModule>();
ecs.set<EngineData>({ scnMgr, world, 0.0f });
ecs.set<Camera>({ cameraNode, camera, false });
ecs.add<GameData>();
ecs.add<Input>();
ecs.set<WaterSurface>({ nullptr, nullptr, nullptr });
ecs.set<WaterBody>({ nullptr });
ecs.set<Terrain>({ nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
false,
{ 0, 0, 0 } });
std::cout << "Setup GameData done\n";
}
void update(float delta)
{

View File

@@ -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 <class T> const T &get()
{
return ECS::get().get<T>();
}
template <class T> T &get_mut()
{
return ECS::get().get_mut<T>();
}
template <class T> void modified()
{
ECS::get().modified<T>();
}
}
#endif

View File

@@ -0,0 +1,53 @@
#include <Ogre.h>
#include "Components.h"
#include "SunModule.h"
namespace ECS
{
SunModule::SunModule(flecs::world &ecs)
{
ecs.component<Sun>().add(flecs::Singleton);
ecs.set<Sun>({ nullptr, nullptr, nullptr, nullptr });
ecs.system<const EngineData, Sun>("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));
});
}
}

20
src/gamedata/SunModule.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef SUN_MODULE_H_
#define SUN_MODULE_H_
#include <flecs.h>
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

View File

@@ -0,0 +1,475 @@
#include <unordered_set>
#include <iostream>
#include <Ogre.h>
#include <OgreBullet.h>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
#include <OgreTerrain.h>
#include <OgreTerrainGroup.h>
#include <OgrePageManager.h>
#include <OgreTerrainPagedWorldSection.h>
#include <OgrePage.h>
#include <OgreTerrainPaging.h>
#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<struct gen_collider> 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<struct gen_collider> 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<Ogre::PageID, btRigidBody *> 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<Terrain>().add(flecs::Singleton);
ecs.component<TerrainPrivate>().add(flecs::Singleton);
ecs.set<TerrainPrivate>({ nullptr, {} });
ecs.system<const EngineData, const Camera, const Sun, Terrain,
TerrainPrivate>("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<CharacterBase, CharacterBody>()
.with<Character>()
.with<Player>()
.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();
}
});
}
}

View File

@@ -0,0 +1,30 @@
#ifndef TERRAIN_MODULE_H_
#define TERRAIN_MODULE_H
#include <flecs.h>
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

View File

@@ -1,3 +1,4 @@
#include <iostream>
#include <Ogre.h>
#include <OgreColourValue.h>
#include <OgreShaderSubRenderState.h>
@@ -14,14 +15,13 @@ WaterModule::WaterModule(flecs::world &ecs)
ecs.module<WaterModule>();
ecs.component<WaterSurface>().add(flecs::Singleton);
ecs.component<WaterBody>().add(flecs::Singleton);
ecs.set<WaterSurface>({ nullptr, nullptr, nullptr });
ecs.set<WaterBody>({ nullptr });
ecs.system<const EngineData, const Camera, WaterSurface>("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;
@@ -164,12 +164,23 @@ WaterModule::WaterModule(flecs::world &ecs)
texture_unit->setTextureFiltering(
Ogre::FT_MIP, Ogre::FO_LINEAR);
#if 0
bool success =
Ogre::RTShader::ShaderGenerator::getSingletonPtr()
->createShaderBasedTechnique(
*mat,
Ogre::MSN_DEFAULT,
Ogre::MSN_SHADERGEN);
OgreAssert(
success,
"createShaderBasedTechnique");
Ogre::RTShader::RenderState *renderState =
Ogre::RTShader::ShaderGenerator::
getSingletonPtr()
->createOrRetrieveRenderState(
Ogre::MSN_SHADERGEN)
.first;
->getRenderState(
Ogre::MSN_SHADERGEN,
*mat,
0);
Ogre::RTShader::SubRenderState *perPixelLightModel =
Ogre::RTShader::ShaderGenerator::getSingletonPtr()
->createSubRenderState(
@@ -261,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();
@@ -283,26 +295,154 @@ WaterModule::WaterModule(flecs::world &ecs)
ecs.system<const EngineData, const WaterSurface, WaterBody>(
"UpdateWaterBody")
.kind(flecs::OnUpdate)
.each([](const EngineData &eng, const WaterSurface &water,
WaterBody &body) {
.each([this](const EngineData &eng, const WaterSurface &water,
WaterBody &body) {
int i;
if (!body.mWaterBody) {
body.mWaterBody = new btGhostObject;
btBoxShape *boxShape = new btBoxShape(
btVector3(1000, 1000, 1000));
btCompoundShape *shape = new btCompoundShape;
shape->addChildShape(
btTransform(btQuaternion(),
btVector3(0, -1000, 0)),
boxShape);
btBoxShape *boxShape0 = new btBoxShape(
btVector3(1000, 10, 1000));
btBoxShape *boxShape1 = new btBoxShape(
btVector3(1000, 20, 1000));
btBoxShape *boxShape2 = new btBoxShape(
btVector3(1000, 100, 1000));
btBoxShape *boxShape3 = new btBoxShape(
btVector3(1000, 1000, 1000));
btTransform boxShapeXform0(btQuaternion(),
btVector3(0, -10.2f,
0));
btTransform boxShapeXform1(btQuaternion(),
btVector3(0, -30.2f,
0));
btTransform boxShapeXform2(btQuaternion(),
btVector3(0, -130.2f,
0));
btTransform boxShapeXform3(
btQuaternion(),
btVector3(0, -1120.2f, 0));
shape->addChildShape(boxShapeXform0, boxShape0);
shape->addChildShape(boxShapeXform1, boxShape1);
shape->addChildShape(boxShapeXform2, boxShape2);
shape->addChildShape(boxShapeXform3, boxShape3);
body.mWaterBody = new btPairCachingGhostObject;
body.mWaterBody->setCollisionShape(shape);
body.mWaterBody->setCollisionFlags(
body.mWaterBody->getCollisionFlags() |
btCollisionObject::CF_NO_CONTACT_RESPONSE |
btCollisionObject::CF_STATIC_OBJECT);
body.mWaterBody->setActivationState(
DISABLE_DEACTIVATION);
body.mWaterBody->getWorldTransform().setOrigin(
btVector3(0, 0, 0));
eng.mWorld->attachCollisionObject(
body.mWaterBody, water.mWaterEnt, 16,
0x7fffffff & ~2);
}
Ogre::Vector3 waterPos =
water.mWaterNode->_getDerivedPosition();
Ogre::Vector3 waterBodyPos = Ogre::Bullet::convert(
body.mWaterBody->getWorldTransform()
.getOrigin());
waterPos.y = 0;
waterBodyPos.y = 0;
Ogre::Vector3 d = waterPos - waterBodyPos;
d.y = 0;
if (d.squaredLength() > 10.0f * 10.0f)
body.mWaterBody->getWorldTransform().setOrigin(
Ogre::Bullet::convert(waterBodyPos +
d));
btCompoundShape *mshape =
static_cast<btCompoundShape *>(
body.mWaterBody->getCollisionShape());
body.mShapeAabbMin =
body.mWaterBody->getWorldTransform()
.getOrigin() +
btVector3(-1000, -1000, -1000);
body.mShapeAabbMax =
body.mWaterBody->getWorldTransform()
.getOrigin() +
btVector3(1000, -0.2, 1000);
btDispatcher *dispatch =
eng.mWorld->getBtWorld()->getDispatcher();
eng.mWorld->getBtWorld()->getBroadphase()->setAabb(
body.mWaterBody->getBroadphaseHandle(),
body.mShapeAabbMin, body.mShapeAabbMax,
eng.mWorld->getBtWorld()->getDispatcher());
dispatch->dispatchAllCollisionPairs(
body.mWaterBody->getOverlappingPairCache(),
eng.mWorld->getBtWorld()->getDispatchInfo(),
dispatch);
btBroadphasePairArray &collisionPairs =
body.mWaterBody->getOverlappingPairCache()
->getOverlappingPairArray();
std::set<btCollisionObject *> currentOverlaps;
std::set<btCollisionObject *>::iterator it;
const int numObjects = collisionPairs.size();
for (int i = 0; i < numObjects; i++) {
body.mManifoldArray.resize(0);
const btBroadphasePair &collisionPair =
collisionPairs[i];
if (collisionPair.m_algorithm)
collisionPair.m_algorithm
->getAllContactManifolds(
body.mManifoldArray);
for (int j = 0; j < body.mManifoldArray.size();
j++) {
btPersistentManifold *manifold =
body.mManifoldArray[j];
if (manifold->getNumContacts() == 0)
continue;
const btCollisionObject *obj =
(manifold->getBody0() ==
body.mWaterBody) ?
manifold->getBody1() :
manifold->getBody0();
btCollisionObject *nobj =
const_cast<btCollisionObject *>(
obj);
if (obj->getCollisionFlags() &
btCollisionObject::CF_STATIC_OBJECT)
continue;
bool ok = false;
Ogre::Vector3 contactPosA, contactPosB;
float minDist = 0.0f;
for (int p = 0;
p < manifold->getNumContacts();
p++) {
const btManifoldPoint &pt =
manifold->getContactPoint(
p);
float dist = pt.getDistance();
if (dist < minDist) {
minDist = dist;
ok = true;
}
}
if (ok) {
currentOverlaps.insert(nobj);
if (body.mInWater.find(nobj) ==
body.mInWater.end()) {
/* new body */
body.mInWater.insert(
nobj);
/* calculate proj surface */
body.mSurface[nobj] =
100.0f;
}
}
}
}
for (it = body.mInWater.begin();
it != body.mInWater.end();) {
btCollisionObject *obj = *it;
if (currentOverlaps.find(obj) ==
currentOverlaps.end()) {
/* remove body */
it = body.mInWater.erase(it);
body.mSurface.erase(obj);
} else
it++;
}
});
}
void WaterSurface::RenderTextureListener::preRenderTargetUpdate(

View File

@@ -25,7 +25,11 @@ struct WaterSurface {
Ogre::Viewport *mViewports[2];
};
struct WaterBody {
btGhostObject *mWaterBody;
btPairCachingGhostObject *mWaterBody;
std::set<btCollisionObject *> mInWater;
std::unordered_map<btCollisionObject *, float> mSurface;
btManifoldArray mManifoldArray;
btVector3 mShapeAabbMin, mShapeAabbMax;
};
struct WaterModule {
WaterModule(flecs::world &ecs);

View File

@@ -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<ECS::Sun>().mSun;
mDynWorld.reset(dynamicsWorld);
mDbgDraw.reset(dbgDraw);
mScnMgr = camera->getSceneManager();

View File

@@ -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;

View File

@@ -42,9 +42,10 @@ uniform float noise; // the noise perturb as a factor of the time
)
#line 41
//vec4 wave_a = vec4(1.0, 1.0, 0.35, 3.0); // xy = Direction, z = Steepness, w = Length
f32vec4 wave_a = vec4(1.0, 1.0, 0.55, 24.3); // xy = Direction, z = Steepness, w = Length
f32vec4 wave_b = vec4(1.0, 0.6, 0.29, 12.55); // xy = Direction, z = Steepness, w = Length
f32vec4 wave_c = vec4(1.0, 1.41, 0.11, 10.8); // xy = Direction, z = Steepness, w = Length
f32vec4 wave_a = vec4(1.0, 1.0, 0.08, 35.3); // xy = Direction, z = Steepness, w = Length
f32vec4 wave_b = vec4(1.0, 0.6, 0.02, 21.55); // xy = Direction, z = Steepness, w = Length
f32vec4 wave_c = vec4(1.0, 1.41, 0.01, 0.8); // xy = Direction, z = Steepness, w = Length
f32vec4 wave_d = vec4(-1.2, 1.0, 0.01, 0.1); // xy = Direction, z = Steepness, w = Length
f32vec4 wave(f32vec4 parameter, f32vec2 position, float32_t t, inout f32vec3 tangent, inout f32vec3 binormal)
{
@@ -102,6 +103,7 @@ MAIN_DECLARATION
position += wave(wave_a, vertex_position.xz, time, tang, bin);
position += wave(wave_b, vertex_position.xz, time, tang, bin);
position += wave(wave_c, vertex_position.xz, time, tang, bin);
position += wave(wave_d, vertex_position.xz, time, tang, bin);
vtangent = tang;
vbinormal = bin;
vertex_position = position.xyz;