Water works!
This commit is contained in:
819
Bootstrap.cpp
819
Bootstrap.cpp
File diff suppressed because it is too large
Load Diff
@@ -71,6 +71,7 @@ add_subdirectory(src/gamedata)
|
||||
add_subdirectory(src/miniaudio)
|
||||
add_subdirectory(src/sound)
|
||||
add_subdirectory(audio/gui)
|
||||
add_subdirectory(tests)
|
||||
|
||||
# add the source files as usual
|
||||
add_executable(0_Bootstrap Bootstrap.cpp)
|
||||
|
||||
425
Game.cpp
425
Game.cpp
@@ -167,6 +167,127 @@ public:
|
||||
mSkyBoxGenParameters.skyBoxDistance = distance;
|
||||
}
|
||||
};
|
||||
class App;
|
||||
class KeyboardListener : public OgreBites::InputListener {
|
||||
App *mApp;
|
||||
|
||||
uint32_t control;
|
||||
ECS::Vector2 mouse;
|
||||
float wheel_y;
|
||||
bool mouse_moved, wheel_moved;
|
||||
float mInitDelay;
|
||||
|
||||
public:
|
||||
Ogre::Timer fps_timer;
|
||||
bool fast;
|
||||
KeyboardListener(App *app)
|
||||
: OgreBites::InputListener()
|
||||
, mApp(app)
|
||||
, fast(false)
|
||||
, control(0)
|
||||
, mouse({ 0, 0 })
|
||||
, wheel_y(0.0f)
|
||||
, mouse_moved(false)
|
||||
, wheel_moved(false)
|
||||
, mInitDelay(1.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 (isGuiEnabled())
|
||||
return false;
|
||||
if (evt.keysym.sym == OgreBites::SDLK_ESCAPE) {
|
||||
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;
|
||||
if (key == 'w')
|
||||
control |= 1;
|
||||
else if (key == 'a')
|
||||
control |= 2;
|
||||
else if (key == 's')
|
||||
control |= 4;
|
||||
else if (key == 'd')
|
||||
control |= 8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control |= 16;
|
||||
if (key == 'w' || key == 'a' || key == 's' || key == 'd' ||
|
||||
key == OgreBites::SDLK_LSHIFT)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool keyReleased(const OgreBites::KeyboardEvent &evt) override
|
||||
{
|
||||
OgreBites::Keycode key = evt.keysym.sym;
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
if (key == 'w')
|
||||
control &= ~1;
|
||||
else if (key == 'a')
|
||||
control &= ~2;
|
||||
else if (key == 's')
|
||||
control &= ~4;
|
||||
else if (key == 'd')
|
||||
control &= ~8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control &= ~16;
|
||||
if (key == 'w' || key == 'a' || key == 's' || key == 'd' ||
|
||||
key == OgreBites::SDLK_LSHIFT)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override
|
||||
{
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
mouse.x = evt.xrel;
|
||||
mouse.y = evt.yrel;
|
||||
mouse_moved = true;
|
||||
/* no special mouse handling */
|
||||
return true;
|
||||
}
|
||||
bool mouseWheelRolled(const OgreBites::MouseWheelEvent &evt) override
|
||||
{
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
/* no special mouse wheel handling */
|
||||
wheel_y = evt.y;
|
||||
wheel_moved = true;
|
||||
return true;
|
||||
}
|
||||
bool mousePressed(const OgreBites::MouseButtonEvent &evt) override
|
||||
{
|
||||
std::cout << "Mouse press " << (int)evt.button << " "
|
||||
<< (int)evt.clicks << "\n";
|
||||
if ((int)evt.button == 1)
|
||||
control |= 256;
|
||||
else
|
||||
control &= ~256;
|
||||
return false;
|
||||
}
|
||||
void update(float delta)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void frameRendered(const Ogre::FrameEvent &evt) override;
|
||||
};
|
||||
class App : public OgreBites::ApplicationContext {
|
||||
std::unique_ptr<Ogre::Bullet::DynamicsWorld> mDynWorld;
|
||||
std::unique_ptr<Ogre::Bullet::DebugDrawer> mDbgDraw;
|
||||
@@ -177,171 +298,8 @@ class App : public OgreBites::ApplicationContext {
|
||||
Ogre::Viewport *mViewport;
|
||||
SkyBoxRenderer *sky;
|
||||
bool mGrab;
|
||||
class KeyboardListener : public OgreBites::InputListener,
|
||||
public Ogre::FrameListener {
|
||||
App *mApp;
|
||||
|
||||
uint32_t control;
|
||||
ECS::Vector2 mouse{ 0, 0 };
|
||||
float wheel_y;
|
||||
bool mouse_moved = false, wheel_moved = false;
|
||||
float mInitDelay;
|
||||
|
||||
public:
|
||||
Ogre::Timer fps_timer;
|
||||
bool fast;
|
||||
KeyboardListener(App *app)
|
||||
: OgreBites::InputListener()
|
||||
, Ogre::FrameListener()
|
||||
, mApp(app)
|
||||
, fast(false)
|
||||
, control(0)
|
||||
, mInitDelay(1.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 (isGuiEnabled())
|
||||
return false;
|
||||
if (evt.keysym.sym == OgreBites::SDLK_ESCAPE) {
|
||||
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;
|
||||
if (key == 'w')
|
||||
control |= 1;
|
||||
else if (key == 'a')
|
||||
control |= 2;
|
||||
else if (key == 's')
|
||||
control |= 4;
|
||||
else if (key == 'd')
|
||||
control |= 8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control |= 16;
|
||||
if (key == 'w' || key == 'a' || key == 's' ||
|
||||
key == 'd' || key == OgreBites::SDLK_LSHIFT)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool keyReleased(const OgreBites::KeyboardEvent &evt) override
|
||||
{
|
||||
OgreBites::Keycode key = evt.keysym.sym;
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
if (key == 'w')
|
||||
control &= ~1;
|
||||
else if (key == 'a')
|
||||
control &= ~2;
|
||||
else if (key == 's')
|
||||
control &= ~4;
|
||||
else if (key == 'd')
|
||||
control &= ~8;
|
||||
else if (key == OgreBites::SDLK_LSHIFT)
|
||||
control &= ~16;
|
||||
if (key == 'w' || key == 'a' || key == 's' ||
|
||||
key == 'd' || key == OgreBites::SDLK_LSHIFT)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool mouseMoved(const OgreBites::MouseMotionEvent &evt) override
|
||||
{
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
mouse.x = evt.xrel;
|
||||
mouse.y = evt.yrel;
|
||||
mouse_moved = true;
|
||||
/* no special mouse handling */
|
||||
return true;
|
||||
}
|
||||
bool
|
||||
mouseWheelRolled(const OgreBites::MouseWheelEvent &evt) override
|
||||
{
|
||||
if (isGuiEnabled())
|
||||
return false;
|
||||
/* no special mouse wheel handling */
|
||||
wheel_y = evt.y;
|
||||
wheel_moved = true;
|
||||
return true;
|
||||
}
|
||||
bool
|
||||
mousePressed(const OgreBites::MouseButtonEvent &evt) override
|
||||
{
|
||||
std::cout << "Mouse press " << (int)evt.button << " "
|
||||
<< (int)evt.clicks << "\n";
|
||||
if ((int)evt.button == 1)
|
||||
control |= 256;
|
||||
else
|
||||
control &= ~256;
|
||||
return false;
|
||||
}
|
||||
void update(float delta)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void frameRendered(const Ogre::FrameEvent &evt) override
|
||||
{
|
||||
if (fps_timer.getMilliseconds() > 1000.0f) {
|
||||
std::cout << "FPS: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.lastFPS
|
||||
<< " ";
|
||||
std::cout << "Draw calls: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.batchCount
|
||||
<< " ";
|
||||
fps_timer.reset();
|
||||
std::cout << "Drops: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.vBlankMissCount
|
||||
<< "\n";
|
||||
fps_timer.reset();
|
||||
}
|
||||
update(evt.timeSinceLastFrame);
|
||||
if (!isGuiEnabled() && mApp->isTerrainReady()) {
|
||||
OgreAssert(mApp->isTerrainReady(),
|
||||
"terrain is not ready");
|
||||
}
|
||||
if (!isGuiEnabled()) {
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
}
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input =
|
||||
ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
}
|
||||
}
|
||||
};
|
||||
KeyboardListener mKbd;
|
||||
bool enabldDbgDraw;
|
||||
|
||||
public:
|
||||
App()
|
||||
@@ -350,6 +308,7 @@ public:
|
||||
, mDynWorld(new Ogre::Bullet::DynamicsWorld(
|
||||
Ogre::Vector3(0, -9.8, 0)))
|
||||
, mGrab(false)
|
||||
, enabldDbgDraw(false)
|
||||
{
|
||||
}
|
||||
virtual ~App()
|
||||
@@ -439,11 +398,13 @@ public:
|
||||
.initialiseAllResourceGroups();
|
||||
// OgreBites::ApplicationContext::loadResources();
|
||||
// setupCursor();
|
||||
std::cout << "Create content" << "\n";
|
||||
createContent();
|
||||
std::cout << "Setup input" << "\n";
|
||||
setupInput();
|
||||
std::cout << "Create content" << "\n";
|
||||
createContent();
|
||||
std::cout << "Setup done" << "\n";
|
||||
mDbgDraw->setDebugMode(mDbgDraw->getDebugMode() |
|
||||
btIDebugDraw::DBG_DrawContactPoints);
|
||||
}
|
||||
Ogre::SceneManager *getSceneManager()
|
||||
{
|
||||
@@ -474,9 +435,10 @@ public:
|
||||
ECS::get().get_mut<ECS::GUI>().grabChanged = false;
|
||||
ECS::get().modified<ECS::GUI>();
|
||||
}
|
||||
|
||||
ECS::update(delta);
|
||||
// mDbgDraw->update();
|
||||
|
||||
if (enabldDbgDraw)
|
||||
mDbgDraw->update();
|
||||
}
|
||||
class InputListenerChainFlexible : public OgreBites::InputListener {
|
||||
protected:
|
||||
@@ -609,7 +571,30 @@ public:
|
||||
flecs::entity find_wait_gui;
|
||||
void setupInput()
|
||||
{
|
||||
ECS::App &p = ECS::get().get_mut<ECS::App>();
|
||||
}
|
||||
void createContent()
|
||||
{
|
||||
int i;
|
||||
sky = new SkyBoxRenderer(getSceneManager());
|
||||
bool drawFirst = true;
|
||||
uint8_t renderQueue = drawFirst ?
|
||||
Ogre::RENDER_QUEUE_SKIES_EARLY :
|
||||
Ogre::RENDER_QUEUE_SKIES_LATE;
|
||||
sky->create("Skybox/Dynamic", 450, renderQueue,
|
||||
Ogre::Quaternion::IDENTITY,
|
||||
Ogre::ResourceGroupManager::
|
||||
AUTODETECT_RESOURCE_GROUP_NAME);
|
||||
sky->setEnabled(true);
|
||||
|
||||
Ogre::MaterialPtr m =
|
||||
Ogre::MaterialManager::getSingleton().getByName(
|
||||
"Skybox/Dynamic", "General");
|
||||
OgreAssert(m, "Sky box material not found.");
|
||||
m->load();
|
||||
ECS::setup(mScnMgr, mDynWorld.get(), mCameraNode, mCamera,
|
||||
getRenderWindow());
|
||||
ECS::get().set<ECS::RenderWindow>(
|
||||
{ getRenderWindow(), getDisplayDPI() });
|
||||
ECS::get()
|
||||
.observer<ECS::GUI>("UpdateGrab")
|
||||
.event(flecs::OnSet)
|
||||
@@ -619,11 +604,6 @@ public:
|
||||
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")
|
||||
@@ -632,8 +612,9 @@ public:
|
||||
if (app.mInput)
|
||||
removeInputListener(app.mInput);
|
||||
delete app.mInput;
|
||||
app.mInput = new OgreBites::InputListenerChain(
|
||||
app.listeners);
|
||||
app.mInput =
|
||||
OGRE_NEW OgreBites::InputListenerChain(
|
||||
app.listeners);
|
||||
addInputListener(app.mInput);
|
||||
std::cout << "Update listeners\n";
|
||||
});
|
||||
@@ -707,52 +688,10 @@ public:
|
||||
<< "\n";
|
||||
});
|
||||
#endif
|
||||
|
||||
p.listeners.clear();
|
||||
p.listeners.push_back(&mKbd);
|
||||
ECS::get().modified<ECS::App>();
|
||||
}
|
||||
void createContent()
|
||||
{
|
||||
int i;
|
||||
std::cout << "addFrameListener\n";
|
||||
getRoot()->addFrameListener(&mKbd);
|
||||
sky = new SkyBoxRenderer(getSceneManager());
|
||||
bool drawFirst = true;
|
||||
uint8_t renderQueue = drawFirst ?
|
||||
Ogre::RENDER_QUEUE_SKIES_EARLY :
|
||||
Ogre::RENDER_QUEUE_SKIES_LATE;
|
||||
sky->create("Skybox/Dynamic", 450, renderQueue,
|
||||
Ogre::Quaternion::IDENTITY,
|
||||
Ogre::ResourceGroupManager::
|
||||
AUTODETECT_RESOURCE_GROUP_NAME);
|
||||
sky->setEnabled(true);
|
||||
|
||||
Ogre::MaterialPtr m =
|
||||
Ogre::MaterialManager::getSingleton().getByName(
|
||||
"Skybox/Dynamic", "General");
|
||||
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),
|
||||
{ initialiseImGui(),
|
||||
nullptr,
|
||||
{} });
|
||||
{ getImGuiInputListener(), &mKbd } });
|
||||
Sound::setup();
|
||||
Sound::ding();
|
||||
}
|
||||
@@ -792,7 +731,51 @@ public:
|
||||
ECS::get().lookup("ECS::CharacterModule::player");
|
||||
return player;
|
||||
}
|
||||
void enableDbgDraw(bool enable)
|
||||
{
|
||||
enabldDbgDraw = enable;
|
||||
}
|
||||
bool isEnabledDbgDraw() const
|
||||
{
|
||||
return enabldDbgDraw;
|
||||
}
|
||||
};
|
||||
void KeyboardListener::frameRendered(const Ogre::FrameEvent &evt)
|
||||
{
|
||||
if (fps_timer.getMilliseconds() > 1000.0f) {
|
||||
std::cout << "FPS: "
|
||||
<< mApp->getRenderWindow()->getStatistics().lastFPS
|
||||
<< " ";
|
||||
std::cout << "Draw calls: "
|
||||
<< mApp->getRenderWindow()->getStatistics().batchCount
|
||||
<< " ";
|
||||
fps_timer.reset();
|
||||
std::cout << "Drops: "
|
||||
<< mApp->getRenderWindow()
|
||||
->getStatistics()
|
||||
.vBlankMissCount
|
||||
<< "\n";
|
||||
fps_timer.reset();
|
||||
}
|
||||
update(evt.timeSinceLastFrame);
|
||||
if (!isGuiEnabled()) {
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
}
|
||||
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -803,7 +786,7 @@ int main()
|
||||
// register for input events
|
||||
// KeyHandler keyHandler;
|
||||
// ctx.addInputListener(&keyHandler);
|
||||
|
||||
ctx.enableDbgDraw(false);
|
||||
ctx.getRoot()->startRendering();
|
||||
ctx.setWindowGrab(false);
|
||||
ctx.closeApp();
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
cs->calculateLocalInertia(mass, inertia);
|
||||
} break;
|
||||
case Ogre::Bullet::CT_CAPSULE: {
|
||||
cs = new btCompoundShape();
|
||||
cs = new btCompoundShape(false);
|
||||
btScalar height = 1.0f;
|
||||
btScalar radius = 0.3f;
|
||||
shape = new btCapsuleShape(radius,
|
||||
@@ -377,7 +377,7 @@ void CharacterController::setupBody()
|
||||
// mRigidBody = world->addCharacter(mBodyEnt, 0);
|
||||
// mCollisionShape = static_cast<btCompoundShape *>(mRigidBody->getCollisionShape());
|
||||
mGhostObject = new btPairCachingGhostObject();
|
||||
mCollisionShape = new btCompoundShape;
|
||||
mCollisionShape = new btCompoundShape(false);
|
||||
mGhostObject->setCollisionShape(mCollisionShape);
|
||||
|
||||
{
|
||||
|
||||
@@ -4,28 +4,31 @@
|
||||
#include "GameData.h"
|
||||
#include "CharacterModule.h"
|
||||
#include "WaterModule.h"
|
||||
#include "TerrainModule.h"
|
||||
#include "Components.h"
|
||||
namespace ECS
|
||||
{
|
||||
CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
{
|
||||
ecs.module<CharacterModule>();
|
||||
player = ecs.entity("player");
|
||||
player.set<AnimationControl>({ AnimationControl::ANIM_NONE,
|
||||
AnimationControl::ANIM_NONE, false,
|
||||
false });
|
||||
player.set<CharacterBase>(
|
||||
{ "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.component<Character>();
|
||||
ecs.component<Player>();
|
||||
ecs.component<CharacterBase>();
|
||||
ecs.component<CharacterVelocity>();
|
||||
ecs.component<CharacterBody>().on_add(
|
||||
[](flecs::entity e, CharacterBody &body) {
|
||||
e.set<CharacterVelocity>(
|
||||
{ { 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.system<EngineData, CharacterBase>("UpdateTimer")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](EngineData &eng, CharacterBase &ch) {
|
||||
ch.mTimer += eng.delta;
|
||||
if (eng.startupDelay >= 0.0f)
|
||||
eng.startupDelay -= eng.delta;
|
||||
});
|
||||
ecs.system<Input, Camera>("HandleInput")
|
||||
.kind(flecs::OnUpdate)
|
||||
@@ -38,6 +41,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
uint32_t active = input.control;
|
||||
float zaxis = input.motion.z;
|
||||
zaxis *= 0.9f;
|
||||
if (!camera.mCameraPivot || !camera.mCameraGoal)
|
||||
return;
|
||||
if (pressed & 1)
|
||||
std::cout << "W pressed\n";
|
||||
if (released & 1)
|
||||
@@ -181,25 +186,15 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
return;
|
||||
ch.mBoneMotion = ch.mRootBone->getPosition();
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, CharacterBody,
|
||||
AnimationControl>("HandleRootMotion")
|
||||
ecs.system<const EngineData, const CharacterBase, CharacterVelocity>(
|
||||
"HandleGravity")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, CharacterBody &body,
|
||||
AnimationControl &anim) {
|
||||
float delta = e.world().delta_time();
|
||||
if (!ch.mBodyNode)
|
||||
return;
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
Ogre::Vector3 boneMotion = ch.mBoneMotion;
|
||||
Ogre::Vector3 velocity = rot * boneMotion / delta;
|
||||
OgreAssert(delta > 0.0f, "Zero delta");
|
||||
int maxPen = 0;
|
||||
Ogre::Vector3 colNormal;
|
||||
bool is_on_floor = false;
|
||||
bool penetration = false;
|
||||
const CharacterBase &ch, CharacterVelocity &gr) {
|
||||
Ogre::Vector3 gravity(0, -9.8f, 0);
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
if (e.has<InWater>()) {
|
||||
float volume = 2.0f * 0.5f * 0.5f;
|
||||
float density = 900.0f;
|
||||
@@ -216,33 +211,80 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
gr.gvelocity *= 0.99;
|
||||
});
|
||||
ecs.system<const EngineData, const CharacterBase, CharacterVelocity>(
|
||||
"HandleRootMotionVelocity")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &ch, CharacterVelocity &v) {
|
||||
if (eng.delta < 0.0000001f)
|
||||
return;
|
||||
if (!ch.mBodyNode)
|
||||
return;
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
Ogre::Vector3 boneMotion = ch.mBoneMotion;
|
||||
v.velocity = rot * boneMotion / eng.delta;
|
||||
if (eng.startupDelay < 0.0f)
|
||||
v.velocity += v.gvelocity;
|
||||
v.velocity.y = Ogre::Math::Clamp(v.velocity.y, -10.5f,
|
||||
1000000.0f);
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, CharacterBody,
|
||||
AnimationControl, CharacterVelocity>("HandleRootMotion")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, CharacterBody &body,
|
||||
AnimationControl &anim, CharacterVelocity &v) {
|
||||
if (!ch.mBodyNode)
|
||||
return;
|
||||
if (eng.delta < 0.0000001f)
|
||||
return;
|
||||
OgreAssert(eng.delta > 0.0f, "Zero delta");
|
||||
int maxPen = 0;
|
||||
Ogre::Vector3 colNormal;
|
||||
bool is_on_floor = false;
|
||||
bool penetration = false;
|
||||
if (eng.startupDelay < 0.0f) {
|
||||
body.gvelocity *= 0.99;
|
||||
velocity += body.gvelocity;
|
||||
Ogre::Vector3 rotMotion = velocity * delta;
|
||||
btVector3 currentPosition =
|
||||
body.mGhostObject->getWorldTransform()
|
||||
.getOrigin();
|
||||
is_on_floor = body.mController->isOnFloor();
|
||||
penetration = body.mController->isPenetrating();
|
||||
if (is_on_floor)
|
||||
body.gvelocity =
|
||||
Ogre::Vector3(0.0f, 0.0f, 0.0f);
|
||||
if (body.mController) {
|
||||
Ogre::Vector3 rotMotion =
|
||||
v.velocity * eng.delta;
|
||||
btVector3 currentPosition =
|
||||
body.mGhostObject
|
||||
->getWorldTransform()
|
||||
.getOrigin();
|
||||
is_on_floor =
|
||||
body.mController->isOnFloor();
|
||||
penetration = body.mController
|
||||
->isPenetrating();
|
||||
if (is_on_floor)
|
||||
v.gvelocity = Ogre::Vector3(
|
||||
0.0f, 0.0f, 0.0f);
|
||||
|
||||
btTransform from(
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getOrientation()),
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode->getPosition()));
|
||||
ch.mBodyNode->setPosition(
|
||||
ch.mBodyNode->getPosition() +
|
||||
rotMotion);
|
||||
ch.mBoneMotion = Ogre::Vector3(0, 0, 0);
|
||||
btTransform from(
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode
|
||||
->getOrientation()),
|
||||
Ogre::Bullet::convert(
|
||||
ch.mBodyNode
|
||||
->getPosition()));
|
||||
ch.mBodyNode->setPosition(
|
||||
ch.mBodyNode->getPosition() +
|
||||
rotMotion);
|
||||
ch.mBoneMotion = Ogre::Vector3(0, 0, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
ecs.system<const Input, AnimationControl>("HandlePlayerAnimations")
|
||||
@@ -289,6 +331,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.each([](const EngineData &eng, CharacterBase &ch,
|
||||
CharacterBody &body) {
|
||||
if (!ch.mBodyNode) {
|
||||
body.mController = nullptr;
|
||||
ch.mBodyEnt = eng.mScnMgr->createEntity(
|
||||
"normal-male.glb");
|
||||
ch.mBodyNode = eng.mScnMgr->getRootSceneNode()
|
||||
@@ -297,7 +340,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
|
||||
body.mGhostObject =
|
||||
new btPairCachingGhostObject();
|
||||
body.mCollisionShape = new btCompoundShape;
|
||||
body.mCollisionShape =
|
||||
new btCompoundShape(false);
|
||||
body.mGhostObject->setCollisionShape(
|
||||
body.mCollisionShape);
|
||||
{
|
||||
@@ -333,16 +377,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
eng.mWorld->attachCollisionObject(
|
||||
body.mGhostObject, ch.mBodyEnt, 1,
|
||||
0x7FFFFFFF);
|
||||
body.mController =
|
||||
new Ogre::Bullet::KinematicMotionSimple(
|
||||
body.mGhostObject,
|
||||
ch.mBodyNode);
|
||||
OgreAssert(body.mGhostObject,
|
||||
"Need GhostObject");
|
||||
OgreAssert(body.mController, "Need controller");
|
||||
eng.mWorld->getBtWorld()->addAction(
|
||||
body.mController);
|
||||
|
||||
OgreAssert(body.mCollisionShape,
|
||||
"No collision shape");
|
||||
OgreAssert(ch.mSkeleton->hasBone("Root"),
|
||||
@@ -351,11 +387,31 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
OgreAssert(ch.mRootBone, "No root bone");
|
||||
}
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, CharacterBody>(
|
||||
"UpdateCharacterPhysics")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.each([](const EngineData &eng, CharacterBase &ch,
|
||||
CharacterBody &body) {
|
||||
if (ch.mBodyNode && !body.mController &&
|
||||
eng.startupDelay < 0.0f) {
|
||||
body.mController =
|
||||
new Ogre::Bullet::KinematicMotionSimple(
|
||||
body.mGhostObject,
|
||||
ch.mBodyNode);
|
||||
eng.mWorld->getBtWorld()->addAction(
|
||||
body.mController);
|
||||
OgreAssert(body.mController, "Need controller");
|
||||
}
|
||||
});
|
||||
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
|
||||
ecs.system<const EngineData, Camera, const CharacterBase>(
|
||||
"UpdateCamera")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Player>()
|
||||
.with<GroundCheckReady>()
|
||||
.each([](const EngineData &eng, Camera &camera,
|
||||
const CharacterBase &ch) {
|
||||
float delta = eng.delta;
|
||||
@@ -475,8 +531,10 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
ecs.system<const EngineData, CharacterBody>("CheckGround")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.with<Player>()
|
||||
.without<GroundCheckReady>()
|
||||
.each([](const EngineData &eng, CharacterBody &body) {
|
||||
if (body.checkGround) {
|
||||
if (body.mGhostObject) {
|
||||
btVector3 from =
|
||||
body.mGhostObject->getWorldTransform()
|
||||
.getOrigin() +
|
||||
@@ -488,7 +546,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
resultCallback);
|
||||
body.checkGroundResult =
|
||||
resultCallback.hasHit();
|
||||
body.checkGround = false;
|
||||
if (resultCallback.hasHit())
|
||||
ECS::get().add<GroundCheckReady>();
|
||||
}
|
||||
});
|
||||
ecs.system<const WaterBody, const CharacterBase, CharacterBody>(
|
||||
@@ -498,8 +557,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.without<InWater>()
|
||||
.each([](flecs::entity e, const WaterBody &waterb,
|
||||
const CharacterBase &ch, CharacterBody &body) {
|
||||
if (waterb.mInWater.find(body.mGhostObject) !=
|
||||
waterb.mInWater.end() &&
|
||||
if (waterb.isInWater(body.mGhostObject) &&
|
||||
ch.mBodyNode->_getDerivedPosition().y < -0.05f) {
|
||||
e.add<InWater>();
|
||||
std::cout << "Big Splash\n";
|
||||
@@ -518,8 +576,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.with<InWater>()
|
||||
.each([](flecs::entity e, const WaterBody &waterb,
|
||||
const CharacterBase &ch, CharacterBody &body) {
|
||||
if (waterb.mInWater.find(body.mGhostObject) ==
|
||||
waterb.mInWater.end() &&
|
||||
if (waterb.isInWater(body.mGhostObject) &&
|
||||
ch.mBodyNode->_getDerivedPosition().y > 0.05f)
|
||||
e.remove<InWater>();
|
||||
});
|
||||
@@ -535,6 +592,16 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
<< "\n";
|
||||
});
|
||||
#endif
|
||||
/* Create player */
|
||||
player = ecs.entity("player");
|
||||
player.set<AnimationControl>({ AnimationControl::ANIM_NONE,
|
||||
AnimationControl::ANIM_NONE, false,
|
||||
false });
|
||||
player.set<CharacterBase>(
|
||||
{ "normal-male.glb", 0.0f, nullptr, nullptr, nullptr });
|
||||
player.set<CharacterBody>({ nullptr, nullptr, nullptr, false, false });
|
||||
player.add<Character>();
|
||||
player.add<Player>();
|
||||
}
|
||||
|
||||
void CharacterModule::setAnimation(AnimationControl &anim)
|
||||
|
||||
@@ -21,10 +21,13 @@ struct CharacterBody {
|
||||
btPairCachingGhostObject *mGhostObject;
|
||||
btCompoundShape *mCollisionShape;
|
||||
Ogre::Bullet::KinematicMotionSimple *mController;
|
||||
Ogre::Vector3 gvelocity;
|
||||
bool checkGround;
|
||||
bool checkGroundResult;
|
||||
};
|
||||
struct CharacterVelocity {
|
||||
Ogre::Vector3 gvelocity;
|
||||
Ogre::Vector3 velocity;
|
||||
};
|
||||
struct AnimationControl {
|
||||
enum AnimID {
|
||||
ANIM_IDLE = 0,
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#define COMPONENTS_H_
|
||||
#include <Ogre.h>
|
||||
#include <OgreBullet.h>
|
||||
namespace Ogre
|
||||
{
|
||||
class ImGuiOverlay;
|
||||
}
|
||||
namespace OgreBites
|
||||
{
|
||||
class ApplicationContextSDL;
|
||||
@@ -18,6 +22,8 @@ struct EngineData {
|
||||
Ogre::Bullet::DynamicsWorld *mWorld;
|
||||
float delta;
|
||||
float startupDelay;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
struct Vector3 {
|
||||
float x;
|
||||
@@ -58,10 +64,13 @@ struct RenderWindow {
|
||||
float dpi;
|
||||
};
|
||||
struct App {
|
||||
OgreBites::ApplicationContextSDL *app;
|
||||
Ogre::ImGuiOverlay *mGuiOverlay;
|
||||
OgreBites::InputListenerChain *mInput;
|
||||
std::vector<OgreBites::InputListener *> listeners;
|
||||
};
|
||||
struct InWater {};
|
||||
struct TerrainReady {};
|
||||
struct WaterReady {};
|
||||
struct GroundCheckReady {};
|
||||
}
|
||||
#endif
|
||||
@@ -144,6 +144,27 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
{
|
||||
int i;
|
||||
Ogre::ImGuiOverlay::NewFrame();
|
||||
if (ECS::get().get<EngineData>().startupDelay > 0.0f) {
|
||||
ImVec2 size = ImGui::GetMainViewport()->Size;
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(size.x, size.y),
|
||||
ImGuiCond_Always);
|
||||
ImGui::Begin(
|
||||
"StartupScreen", nullptr,
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoDecoration |
|
||||
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoFocusOnAppearing |
|
||||
ImGuiWindowFlags_NoInputs);
|
||||
// if (ECS::get().get<GUI>().enabled)
|
||||
// ECS::get().get<App>().app->setWindowGrab(true);
|
||||
ImGui::Text(
|
||||
"This game does not autosave. Please use save function to keep your state");
|
||||
ImGui::End();
|
||||
}
|
||||
if (ECS::get().get<GUI>().enabled) {
|
||||
buttons_panel();
|
||||
buildings_editor();
|
||||
@@ -258,9 +279,21 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
|
||||
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.component<GUI>()
|
||||
.on_add([](GUI &gui) {
|
||||
gui.enabled = false;
|
||||
gui.grab = false;
|
||||
gui.grabChanged = false;
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
ecs.component<GUIData>()
|
||||
.on_add([](GUIData &priv) {
|
||||
priv.glb_names.clear();
|
||||
priv.mGUIListener = nullptr;
|
||||
priv.mGuiOverlay = nullptr;
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
ecs.set<GUI>({ false, true, false });
|
||||
ecs.set<GUIData>({ nullptr, {}, nullptr });
|
||||
ui_wait =
|
||||
ecs.system<const RenderWindow, App, GUIData>("SetupGUI")
|
||||
@@ -275,8 +308,9 @@ GUIModule::GUIModule(flecs::world &ecs)
|
||||
Ogre::OverlayManager::getSingleton()
|
||||
.setPixelRatio(vpScale);
|
||||
std::cout << "GUI configure\n";
|
||||
gui.mGuiOverlay =
|
||||
app.app->initialiseImGui();
|
||||
OgreAssert(app.mGuiOverlay,
|
||||
"No ImGUI overlay");
|
||||
gui.mGuiOverlay = app.mGuiOverlay;
|
||||
gui.mGuiOverlay->setZOrder(300);
|
||||
gui.mGuiOverlay->show();
|
||||
gui.mGUIListener = new GUIListener();
|
||||
@@ -299,10 +333,6 @@ GUIModule::GUIModule(flecs::world &ecs)
|
||||
names.begin(),
|
||||
names.end());
|
||||
}
|
||||
ECS::get_mut<ECS::GUI>()
|
||||
.mGuiInpitListener =
|
||||
new OgreBites::
|
||||
ImGuiInputListener();
|
||||
ECS::modified<ECS::GUI>();
|
||||
std::cout << "GUI configure finished\n";
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <flecs.h>
|
||||
namespace OgreBites
|
||||
{
|
||||
class InputListener;
|
||||
}
|
||||
namespace ECS
|
||||
{
|
||||
@@ -11,7 +10,6 @@ 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>();
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace ECS
|
||||
{
|
||||
static flecs::world ecs;
|
||||
void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
|
||||
Ogre::SceneNode *cameraNode, Ogre::Camera *camera)
|
||||
Ogre::SceneNode *cameraNode, Ogre::Camera *camera,
|
||||
Ogre::RenderWindow *window)
|
||||
{
|
||||
std::cout << "Setup GameData\n";
|
||||
ecs.component<EngineData>().add(flecs::Singleton);
|
||||
@@ -20,23 +21,60 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
|
||||
ecs.component<Input>().add(flecs::Singleton);
|
||||
ecs.component<Camera>().add(flecs::Singleton);
|
||||
ecs.component<InWater>();
|
||||
ecs.component<App>().add(flecs::Singleton);
|
||||
ecs.component<WaterReady>().add(flecs::Singleton);
|
||||
ecs.component<GroundCheckReady>().add(flecs::Singleton);
|
||||
ecs.component<App>()
|
||||
.on_add([](App &app) {
|
||||
app.mInput = nullptr;
|
||||
app.mGuiOverlay = nullptr;
|
||||
app.listeners.clear();
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
/* lots of things depend on it */
|
||||
ecs.component<TerrainReady>().add(flecs::Singleton);
|
||||
ecs.import <WaterModule>();
|
||||
ecs.import <CharacterModule>();
|
||||
ecs.import <SunModule>();
|
||||
ecs.import <TerrainModule>();
|
||||
ecs.import <SunModule>();
|
||||
ecs.import <GUIModule>();
|
||||
ecs.system<EngineData>("UpdateDelta")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](EngineData &eng) {
|
||||
eng.delta = ECS::get().delta_time();
|
||||
});
|
||||
ecs.set<EngineData>({ scnMgr, world, 0.0f, 0.0f });
|
||||
ecs.system<EngineData>("UpdateDelay")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.with<GroundCheckReady>()
|
||||
.each([](EngineData &eng) {
|
||||
if (eng.startupDelay >= 0.0f)
|
||||
eng.startupDelay -= eng.delta;
|
||||
#ifdef VDEBUG
|
||||
if (ECS::get().has<GroundCheckReady>())
|
||||
std::cout << "ground check ready\n";
|
||||
#endif
|
||||
});
|
||||
ecs.system<EngineData>("CheckStatus")
|
||||
.kind(flecs::OnUpdate)
|
||||
.run([](flecs::iter &it) {
|
||||
#ifdef VDEBUG
|
||||
if (ECS::get().has<WaterReady>())
|
||||
std::cout << "water ready\n";
|
||||
if (ECS::get().has<TerrainReady>())
|
||||
std::cout << "terrain ready\n";
|
||||
if (ECS::get().has<GroundCheckReady>())
|
||||
std::cout << "ground check ready\n";
|
||||
#endif
|
||||
});
|
||||
ecs.set<EngineData>({ scnMgr, world, 0.0f, 5.0f,
|
||||
(int)window->getWidth(),
|
||||
(int)window->getHeight() });
|
||||
ecs.set<Camera>({ cameraNode, camera, false });
|
||||
ecs.add<GameData>();
|
||||
ecs.add<Input>();
|
||||
ecs.set<WaterSurface>({ nullptr, nullptr, nullptr, nullptr, nullptr });
|
||||
ecs.set<WaterBody>({ nullptr });
|
||||
ecs.add<WaterSurface>();
|
||||
ecs.set<Sun>({ nullptr, nullptr, nullptr, nullptr });
|
||||
ecs.set<Terrain>({ nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
namespace ECS
|
||||
{
|
||||
void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
|
||||
Ogre::SceneNode *cameraNode, Ogre::Camera *camera);
|
||||
Ogre::SceneNode *cameraNode, Ogre::Camera *camera,
|
||||
Ogre::RenderWindow *window);
|
||||
void update(float delta);
|
||||
flecs::world get();
|
||||
template <class T> const T &get()
|
||||
|
||||
@@ -7,7 +7,6 @@ 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) {
|
||||
|
||||
@@ -237,11 +237,14 @@ public:
|
||||
float maxH = terrain->getMaxHeight();
|
||||
int size = terrain->getSize();
|
||||
float worldSize = terrain->getWorldSize();
|
||||
if (!created || true) {
|
||||
if (true) {
|
||||
btRigidBody *body =
|
||||
mWorld->addTerrainRigidBody(
|
||||
group, x, y, 2,
|
||||
0x7ffffffd & (~16));
|
||||
OgreAssert(
|
||||
body,
|
||||
"Could not create RigidBody");
|
||||
Ogre::LogManager::getSingleton().logError(
|
||||
"created rigid body " +
|
||||
Ogre::StringConverter::toString(
|
||||
@@ -278,6 +281,11 @@ public:
|
||||
output.push_back(collider_queue.front());
|
||||
collider_queue.pop_front();
|
||||
}
|
||||
if (collider_queue.empty() &&
|
||||
!ECS::get<Terrain>().mTerrainReady) {
|
||||
ECS::get_mut<Terrain>().mTerrainReady = true;
|
||||
ECS::modified<Terrain>();
|
||||
}
|
||||
}
|
||||
collider_queue = output;
|
||||
}
|
||||
@@ -328,7 +336,7 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
.each([](const EngineData &eng, const Camera &camera,
|
||||
const Sun &sun, Terrain &terrain,
|
||||
TerrainPrivate &priv) {
|
||||
if (!terrain.mTerrainGroup) {
|
||||
if (!terrain.mTerrainGroup && sun.mSun && eng.mScnMgr) {
|
||||
std::cout << "Terrain setup\n";
|
||||
if (!priv.mDummyPageProvider)
|
||||
priv.mDummyPageProvider =
|
||||
@@ -338,6 +346,9 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
terrain.mTerrainGlobals =
|
||||
OGRE_NEW Ogre::TerrainGlobalOptions();
|
||||
|
||||
OgreAssert(terrain.mTerrainGlobals,
|
||||
"Failed to allocate global options");
|
||||
|
||||
Ogre::LogManager::getSingleton().setMinLogLevel(
|
||||
Ogre::LML_TRIVIAL);
|
||||
|
||||
@@ -423,47 +434,14 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
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());
|
||||
if (sun.mSun &&
|
||||
priv.mSunUpdate.getMilliseconds() > 1000) {
|
||||
terrain.mTerrainGlobals->setCompositeMapAmbient(
|
||||
eng.mScnMgr->getAmbientLight());
|
||||
terrain.mTerrainGlobals->setCompositeMapDiffuse(
|
||||
sun.mSun->getDiffuseColour());
|
||||
terrain.mTerrainGlobals->setLightMapDirection(
|
||||
sun.mSun->getDerivedDirection());
|
||||
std::cout << "sun pitch: "
|
||||
<< sun.mSunNode->getOrientation()
|
||||
.getPitch()
|
||||
@@ -471,5 +449,24 @@ TerrainModule::TerrainModule(flecs::world &ecs)
|
||||
priv.mSunUpdate.reset();
|
||||
}
|
||||
});
|
||||
ecs.system<const CharacterBase, const Terrain>("UpdateTerrainStatus")
|
||||
.kind(flecs::OnUpdate)
|
||||
.without<TerrainReady>()
|
||||
.each([](const CharacterBase &ch, const Terrain &terrain) {
|
||||
std::cout << "mTerrainReady: " << terrain.mTerrainReady
|
||||
<< "\n";
|
||||
std::cout << "mBodyNode: " << ch.mBodyNode << "\n";
|
||||
if (ch.mBodyNode && terrain.mTerrainReady) {
|
||||
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())
|
||||
ECS::get().add<TerrainReady>();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,14 +38,19 @@ struct WaterSurface {
|
||||
Ogre::Viewport *mViewports[4];
|
||||
};
|
||||
struct WaterBody {
|
||||
std::vector<btCollisionShape *> mChildShapes;
|
||||
btCollisionShape *mWaterShape;
|
||||
btPairCachingGhostObject *mWaterBody;
|
||||
std::set<btCollisionObject *> mInWater;
|
||||
std::unordered_map<btCollisionObject *, float> mSurface;
|
||||
btManifoldArray mManifoldArray;
|
||||
btVector3 mShapeAabbMin, mShapeAabbMax;
|
||||
int count;
|
||||
btActionInterface *action;
|
||||
bool isInWater(const btCollisionObject *body) const;
|
||||
};
|
||||
struct WaterModule {
|
||||
btPairCachingGhostObject *mGhostObject;
|
||||
WaterModule(flecs::world &ecs);
|
||||
void createWaterShape(WaterBody *water);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
830
terrain.cpp
830
terrain.cpp
File diff suppressed because it is too large
Load Diff
8
tests/CMakeLists.txt
Normal file
8
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
project(tests)
|
||||
find_package(OGRE REQUIRED COMPONENTS Bullet CONFIG)
|
||||
find_package(Bullet REQUIRED)
|
||||
add_executable(compound_shapes compound_shapes.cpp)
|
||||
target_link_libraries(compound_shapes OgreBullet ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY})
|
||||
include_directories(${BULLET_INCLUDE_DIRS})
|
||||
|
||||
add_custom_target(tests ALL DEPENDS compound_shapes)
|
||||
290
tests/compound_shapes.cpp
Normal file
290
tests/compound_shapes.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
#include <iostream>
|
||||
#include <OgreBullet.h>
|
||||
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
||||
#include <btBulletCollisionCommon.h>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
|
||||
struct objects {
|
||||
btDynamicsWorld *world;
|
||||
btRigidBody *groundBody;
|
||||
btPairCachingGhostObject *characterBody;
|
||||
btPairCachingGhostObject *waterBody;
|
||||
};
|
||||
void setupGround(btDynamicsWorld *world, struct objects *objects)
|
||||
{
|
||||
// Static ground
|
||||
btCollisionShape *groundShape =
|
||||
new btBoxShape(btVector3(1000, 1, 1000));
|
||||
btDefaultMotionState *groundMotionState = new btDefaultMotionState(
|
||||
btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, -10, 0)));
|
||||
btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(
|
||||
0, groundMotionState, groundShape, btVector3(0, 0, 0));
|
||||
btRigidBody *groundRigidBody = new btRigidBody(groundRigidBodyCI);
|
||||
world->addRigidBody(groundRigidBody, 2, 0x7fffffff & ~16);
|
||||
objects->groundBody = groundRigidBody;
|
||||
}
|
||||
void setupCharacter(btDynamicsWorld *world, struct objects *objects)
|
||||
{
|
||||
btCompoundShape *shape = new btCompoundShape();
|
||||
btCapsuleShape *subshape = new btCapsuleShape(0.2f, 1.5f);
|
||||
btTransform shapePos;
|
||||
shapePos.setIdentity();
|
||||
shapePos.setOrigin(btVector3(0, 0.75f, 0));
|
||||
shape->addChildShape(shapePos, subshape);
|
||||
btPairCachingGhostObject *characterBody =
|
||||
new btPairCachingGhostObject();
|
||||
characterBody->setCollisionFlags(
|
||||
characterBody->getCollisionFlags() |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE |
|
||||
btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
btTransform bodyPos;
|
||||
bodyPos.setIdentity();
|
||||
bodyPos.setOrigin(btVector3(0, 0.4f, 0));
|
||||
characterBody->setWorldTransform(bodyPos);
|
||||
characterBody->setCollisionShape(shape);
|
||||
world->addCollisionObject(characterBody, 1, 0x7fffffff);
|
||||
objects->characterBody = characterBody;
|
||||
}
|
||||
void setupWater(btDynamicsWorld *world, struct objects *objects)
|
||||
{
|
||||
btCompoundShape *shape = new btCompoundShape();
|
||||
btBoxShape *subshape =
|
||||
new btBoxShape(btVector3(1000.0f, 100.0f, 1000.0f));
|
||||
btTransform shapePos;
|
||||
shapePos.setIdentity();
|
||||
shapePos.setOrigin(btVector3(0, -100, 0));
|
||||
shape->addChildShape(shapePos, subshape);
|
||||
btPairCachingGhostObject *waterBody = new btPairCachingGhostObject();
|
||||
waterBody->setCollisionFlags(waterBody->getCollisionFlags() |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE |
|
||||
btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
btTransform bodyPos;
|
||||
bodyPos.setIdentity();
|
||||
waterBody->setWorldTransform(bodyPos);
|
||||
waterBody->setCollisionShape(shape);
|
||||
world->addCollisionObject(waterBody, 16, 0x7fffffff & ~2);
|
||||
objects->waterBody = waterBody;
|
||||
}
|
||||
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)
|
||||
{
|
||||
std::cout
|
||||
<< "contact: " << Ogre::Bullet::convert(pointInWorldOnB)
|
||||
<< " " << Ogre::Bullet::convert(normalOnBInWorld)
|
||||
<< "\n";
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
void dumpCompoundShape(const char *what, const btCollisionObject *body)
|
||||
{
|
||||
if (body->getCollisionShape()->isCompound()) {
|
||||
const btCompoundShape *shape =
|
||||
static_cast<const btCompoundShape *>(
|
||||
body->getCollisionShape());
|
||||
int i;
|
||||
for (i = 0; i < shape->getNumChildShapes(); i++) {
|
||||
btTransform transform = body->getWorldTransform() *
|
||||
shape->getChildTransform(i);
|
||||
std::cout << what << ": " << " shape: " << i << ": "
|
||||
<< transform.getOrigin().getX() << ", ";
|
||||
std::cout << transform.getOrigin().getY() << ", ";
|
||||
std::cout << transform.getOrigin().getZ();
|
||||
std::cout << " convex: "
|
||||
<< shape->getChildShape(i)->isConvex();
|
||||
std::cout << " shape name: "
|
||||
<< shape->getChildShape(i)->getName();
|
||||
switch (shape->getChildShape(i)->getShapeType()) {
|
||||
case 0: {
|
||||
const btBoxShape *box =
|
||||
static_cast<const btBoxShape *>(
|
||||
shape->getChildShape(i));
|
||||
btVector3 hextents =
|
||||
box->getHalfExtentsWithoutMargin();
|
||||
std::cout << " box: " << hextents.getX() << ", "
|
||||
<< hextents.getY() << ", "
|
||||
<< hextents.getZ();
|
||||
} break;
|
||||
case 10: {
|
||||
const btCapsuleShape *capsule =
|
||||
static_cast<const btCapsuleShape *>(
|
||||
shape->getChildShape(i));
|
||||
float hh = capsule->getHalfHeight();
|
||||
float r = capsule->getRadius();
|
||||
std::cout << " capsule: " << hh << ", " << r;
|
||||
} break;
|
||||
default:
|
||||
std::cout << " shape type: "
|
||||
<< shape->getChildShape(i)
|
||||
->getShapeType();
|
||||
break;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
void showContacts(btCollisionWorld *world, struct objects *objects)
|
||||
{
|
||||
int numManifolds = world->getDispatcher()->getNumManifolds();
|
||||
if (numManifolds == 0)
|
||||
std::cout << "No contacts in world\n";
|
||||
for (int i = 0; i < numManifolds; i++) {
|
||||
btPersistentManifold *contactManifold =
|
||||
world->getDispatcher()->getManifoldByIndexInternal(i);
|
||||
const btCollisionObject *obA = contactManifold->getBody0();
|
||||
const btCollisionObject *obB = contactManifold->getBody1();
|
||||
|
||||
int numContacts = contactManifold->getNumContacts();
|
||||
for (int j = 0; j < numContacts; j++) {
|
||||
btManifoldPoint &pt =
|
||||
contactManifold->getContactPoint(j);
|
||||
if (pt.getDistance() < 0.f) {
|
||||
const btVector3 &ptA = pt.getPositionWorldOnA();
|
||||
const btVector3 &ptB = pt.getPositionWorldOnB();
|
||||
const btVector3 &normalOnB =
|
||||
pt.m_normalWorldOnB;
|
||||
std::cout << "contact: " << i << " " << j << " "
|
||||
<< ptA.getX() << ", " << ptA.getY()
|
||||
<< ", " << ptA.getZ() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int main()
|
||||
{
|
||||
struct objects objects;
|
||||
btDefaultCollisionConfiguration collisionConfig;
|
||||
btCollisionDispatcher dispatcher(&collisionConfig);
|
||||
btCollisionDispatcher *dispatch = &dispatcher;
|
||||
btDbvtBroadphase broadphase;
|
||||
btSequentialImpulseConstraintSolver solver;
|
||||
btDiscreteDynamicsWorld world(&dispatcher, &broadphase, &solver,
|
||||
&collisionConfig);
|
||||
world.setGravity(btVector3(0, -9.81, 0));
|
||||
setupGround(&world, &objects);
|
||||
setupCharacter(&world, &objects);
|
||||
setupWater(&world, &objects);
|
||||
|
||||
#if 0
|
||||
btCompoundShape *compoundShape = new btCompoundShape();
|
||||
|
||||
// Add shapes to the compound shape
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
btBoxShape *box = new btBoxShape(btVector3(1, 1, 1));
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
transform.setOrigin(btVector3(0, 1 - i, 0));
|
||||
compoundShape->addChildShape(transform, box);
|
||||
}
|
||||
|
||||
btDefaultMotionState *compoundMotionState = new btDefaultMotionState(
|
||||
btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 10, 0)));
|
||||
btScalar mass = 5.0;
|
||||
btVector3 inertia(0, 0, 0);
|
||||
compoundShape->calculateLocalInertia(mass, inertia);
|
||||
btRigidBody::btRigidBodyConstructionInfo compoundRigidBodyCI(
|
||||
mass, compoundMotionState, compoundShape, inertia);
|
||||
btRigidBody *compoundRigidBody = new btRigidBody(compoundRigidBodyCI);
|
||||
world.addRigidBody(compoundRigidBody);
|
||||
#endif
|
||||
|
||||
// Simulation
|
||||
btVector3 velocity(0, 0, 0);
|
||||
for (int i = 0; i < 300; i++) {
|
||||
world.stepSimulation(1.f / 60.f, 10);
|
||||
showContacts(&world, &objects);
|
||||
|
||||
#if 0
|
||||
btTransform transform;
|
||||
compoundRigidBody->getMotionState()->getWorldTransform(
|
||||
transform);
|
||||
std::cout << "Step " << i
|
||||
<< ": Position = " << transform.getOrigin().getX()
|
||||
<< ", " << transform.getOrigin().getY() << ", "
|
||||
<< transform.getOrigin().getZ() << std::endl;
|
||||
std::cout << "water overlaps:"
|
||||
<< objects.waterBody->getOverlappingPairCache()
|
||||
->getNumOverlappingPairs()
|
||||
<< "\n";
|
||||
#endif
|
||||
btTransform transform;
|
||||
transform = objects.characterBody->getWorldTransform();
|
||||
std::cout << "Step " << i << " ";
|
||||
std::cout << "Character: "
|
||||
<< "Position = " << transform.getOrigin().getX()
|
||||
<< ", " << transform.getOrigin().getY() << ", "
|
||||
<< transform.getOrigin().getZ() << std::endl;
|
||||
transform = objects.waterBody->getWorldTransform();
|
||||
std::cout << "Water: "
|
||||
<< "Position = " << transform.getOrigin().getX()
|
||||
<< ", " << transform.getOrigin().getY() << ", "
|
||||
<< transform.getOrigin().getZ() << std::endl;
|
||||
std::cout << "water overlaps:"
|
||||
<< objects.waterBody->getOverlappingPairCache()
|
||||
->getNumOverlappingPairs()
|
||||
<< "\n";
|
||||
dumpCompoundShape("Character", objects.characterBody);
|
||||
dumpCompoundShape("Water", objects.waterBody);
|
||||
btCollisionObjectWrapper obA(
|
||||
NULL, objects.waterBody->getCollisionShape(),
|
||||
objects.waterBody,
|
||||
objects.waterBody->getWorldTransform(), -1, 0);
|
||||
btCollisionObjectWrapper obB(
|
||||
NULL, objects.characterBody->getCollisionShape(),
|
||||
objects.characterBody,
|
||||
objects.characterBody->getWorldTransform(), -1, 0);
|
||||
std::cout << __func__ << ": call findAlgorithm: ";
|
||||
btCollisionAlgorithm *algorithm = dispatch->findAlgorithm(
|
||||
&obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS);
|
||||
std::cout << "found algorithm: " << algorithm << "\n";
|
||||
if (!algorithm)
|
||||
continue;
|
||||
std::cout << "algorithm: " << algorithm << "\n";
|
||||
DeepPenetrationContactResultCallback contactPointResult(&obA,
|
||||
&obB);
|
||||
std::cout << "process collision\n";
|
||||
algorithm->processCollision(&obA, &obB, world.getDispatchInfo(),
|
||||
&contactPointResult);
|
||||
algorithm->~btCollisionAlgorithm();
|
||||
dispatch->freeCollisionAlgorithm(algorithm);
|
||||
if (contactPointResult.hasHit()) {
|
||||
std::cout << "InWater!!1\n";
|
||||
}
|
||||
velocity += btVector3(0, -9.8, 0) * 1.0f / 16.0f;
|
||||
objects.characterBody->getWorldTransform().getOrigin() += velocity * 1.0f / 16.0f;
|
||||
std::cout << "process collision done\n";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user