Intagrated Tracy, debugged animations
This commit is contained in:
@@ -29,6 +29,7 @@ find_package(assimp REQUIRED CONFIG)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
find_package(pugixml REQUIRED CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
find_package(Tracy REQUIRED CONFIG)
|
||||
|
||||
add_library(fix::assimp INTERFACE IMPORTED)
|
||||
set_target_properties(fix::assimp PROPERTIES
|
||||
@@ -81,11 +82,12 @@ add_executable(Game Game.cpp ${WATER_SRC})
|
||||
target_include_directories(Game PRIVATE src/gamedata)
|
||||
target_link_libraries(Game OgreBites OgrePaging OgreTerrain OgreMeshLodGenerator
|
||||
OgreProcedural::OgreProcedural
|
||||
OgreCrowd
|
||||
GameData
|
||||
sound
|
||||
sceneloader physics
|
||||
OgreCrowd
|
||||
sceneloader physics lua
|
||||
flecs::flecs_static
|
||||
Tracy::TracyClient
|
||||
-Wl,--as-needed
|
||||
)
|
||||
if(OGRE_STATIC)
|
||||
|
||||
92
Game.cpp
92
Game.cpp
@@ -21,6 +21,7 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "physics.h"
|
||||
#include "sound.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
class App;
|
||||
class SkyRenderer : public Ogre::SceneManager::Listener {
|
||||
protected:
|
||||
@@ -477,6 +478,7 @@ public:
|
||||
}
|
||||
void updateWorld(float delta)
|
||||
{
|
||||
ZoneScoped;
|
||||
if (!ECS::get().has<ECS::GUI>())
|
||||
goto end;
|
||||
{
|
||||
@@ -738,40 +740,50 @@ end:
|
||||
};
|
||||
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();
|
||||
}
|
||||
if (!isGuiEnabled() ||
|
||||
(isGuiEnabled() && ECS::get<ECS::GUI>().narrationBox)) {
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
}
|
||||
{
|
||||
ZoneScopedN("frameRendered");
|
||||
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();
|
||||
}
|
||||
if (!isGuiEnabled() ||
|
||||
(isGuiEnabled() && ECS::get<ECS::GUI>().narrationBox)) {
|
||||
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;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
}
|
||||
}
|
||||
#ifdef USE_RENDER_LOOP
|
||||
FrameMark;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -784,7 +796,23 @@ int main()
|
||||
// KeyHandler keyHandler;
|
||||
// ctx.addInputListener(&keyHandler);
|
||||
ctx.enableDbgDraw(false);
|
||||
#ifdef USE_RENDER_LOOP
|
||||
ctx.getRoot()->startRendering();
|
||||
#else
|
||||
auto renderSystem = Ogre::Root::getSingleton().getRenderSystem();
|
||||
OgreAssert(renderSystem, "no RenderSystem");
|
||||
renderSystem->_initRenderTargets();
|
||||
Ogre::Root::getSingleton().clearEventTimes();
|
||||
Ogre::Root::getSingleton().queueEndRendering(false);
|
||||
while (!Ogre::Root::getSingleton().endRenderingQueued()) {
|
||||
{
|
||||
ZoneScopedN("render");
|
||||
if (!Ogre::Root::getSingleton().renderOneFrame())
|
||||
break;
|
||||
}
|
||||
FrameMark;
|
||||
}
|
||||
#endif
|
||||
ctx.setWindowGrab(false);
|
||||
ctx.closeApp();
|
||||
return 0;
|
||||
|
||||
@@ -49,6 +49,7 @@ target_link_libraries(Editor PRIVATE
|
||||
physics
|
||||
lua
|
||||
flecs::flecs_static
|
||||
Tracy::TracyClient
|
||||
)
|
||||
if(OGRE_STATIC)
|
||||
target_link_options(Editor PRIVATE -static-libstdc++ -static-libgcc)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "physics.h"
|
||||
#include "sound.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
class App;
|
||||
class SkyRenderer : public Ogre::SceneManager::Listener {
|
||||
@@ -683,52 +684,60 @@ public:
|
||||
};
|
||||
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();
|
||||
}
|
||||
/* for editor we always update world */
|
||||
/* TODO: implement pause */
|
||||
mApp->updateWorld(evt.timeSinceLastFrame);
|
||||
if (mInitDelay >= 0.0f)
|
||||
mInitDelay -= evt.timeSinceLastFrame;
|
||||
{
|
||||
ZoneScopedN("frameRendered");
|
||||
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();
|
||||
}
|
||||
/* for editor we always update world */
|
||||
/* TODO: implement pause */
|
||||
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;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
} else {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
if (!isGuiEnabled() && ECS::get().has<ECS::Input>()) {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
} else {
|
||||
ECS::Input &input = ECS::get().get_mut<ECS::Input>();
|
||||
input.control = control;
|
||||
input.mouse = mouse;
|
||||
input.mouse_abs = mouse_abs;
|
||||
mouse.x = 0;
|
||||
mouse.y = 0;
|
||||
input.wheel_y = wheel_y;
|
||||
wheel_y = 0;
|
||||
input.mouse_moved = mouse_moved;
|
||||
input.wheel_moved = wheel_moved;
|
||||
ECS::modified<ECS::Input>();
|
||||
}
|
||||
}
|
||||
FrameMark;
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
68
src/gamedata/AnimationSystem.cpp
Normal file
68
src/gamedata/AnimationSystem.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <iostream>
|
||||
#include "AnimationSystem.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace AnimationSystem
|
||||
{
|
||||
|
||||
bool AnimationSystem::addTime(float time)
|
||||
{
|
||||
int i;
|
||||
ZoneScopedN("AnimationSystem::addTime");
|
||||
preUpdateTriggers();
|
||||
bool ret = m_builder.animation_nodes[0]->addTime(time);
|
||||
for (i = 0; i < m_builder.animationNodeList.size(); i++) {
|
||||
ZoneScoped;
|
||||
AnimationNodeAnimation *anim = m_builder.animationNodeList[i];
|
||||
OgreAssert(anim->mAnimation, "No animation");
|
||||
float weight = anim->getWeight();
|
||||
anim->mAnimation->increaseAccWeight(weight);
|
||||
#ifdef VDEBUG
|
||||
if (debug)
|
||||
std::cout << i
|
||||
<< " node: " << anim->mAnimation->getName()
|
||||
<< " " << weight << std::endl;
|
||||
#endif
|
||||
if (anim->getWeight() > 0.01f) {
|
||||
ZoneScoped;
|
||||
ZoneText("builder", strlen("builder"));
|
||||
ZoneText(anim->mAnimation->getName().c_str(),
|
||||
anim->mAnimation->getName().length());
|
||||
ZoneValue(anim->getWeight() * 100.0f);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < vanimation_list.size(); i++) {
|
||||
ZoneScoped;
|
||||
float weight = vanimation_list[i]->getAccWeight();
|
||||
vanimation_list[i]->setWeight(weight);
|
||||
vanimation_list[i]->resetAccWeight();
|
||||
// #define VDEBUG
|
||||
#ifdef VDEBUG
|
||||
if (debug && vanimation_list[i]->getEnabled())
|
||||
std::cout << i << " animation: "
|
||||
<< vanimation_list[i]->getName() << " "
|
||||
<< weight << std::endl;
|
||||
#endif
|
||||
#undef VDEBUG
|
||||
if (vanimation_list[i]->mAnimationState->getEnabled()) {
|
||||
ZoneScoped;
|
||||
ZoneText("animation", strlen("animation"));
|
||||
ZoneText(vanimation_list[i]->getName().c_str(),
|
||||
vanimation_list[i]->getName().length());
|
||||
ZoneValue(vanimation_list[i]->getWeight() * 100.0f);
|
||||
}
|
||||
}
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
Ogre::Vector3 AnimationSystem::getRootMotionDelta()
|
||||
{
|
||||
ZoneScopedN("AnimationSystem::getRootMotionDelta");
|
||||
Ogre::Vector3 motionDelta(0, 0, 0);
|
||||
int i;
|
||||
for (i = 0; i < vanimation_list.size(); i++)
|
||||
motionDelta += vanimation_list[i]->getRootMotionDelta();
|
||||
return motionDelta;
|
||||
}
|
||||
|
||||
}
|
||||
900
src/gamedata/AnimationSystem.h
Normal file
900
src/gamedata/AnimationSystem.h
Normal file
@@ -0,0 +1,900 @@
|
||||
#ifndef ANIMATIONSYSTEM_H
|
||||
#define ANIMATIONSYSTEM_H
|
||||
|
||||
#include <iostream>
|
||||
#include <Ogre.h>
|
||||
#include <flecs.h>
|
||||
#include <tracy/Tracy.hpp>
|
||||
#include "GameData.h"
|
||||
#include "EventModule.h"
|
||||
|
||||
namespace AnimationSystem
|
||||
{
|
||||
struct AnimationTrigger;
|
||||
struct AnimationTriggerSubscriber {
|
||||
virtual void operator()(const AnimationTrigger *trigger) = 0;
|
||||
};
|
||||
class RootMotionListener : public Ogre::NodeAnimationTrack::Listener {
|
||||
public:
|
||||
RootMotionListener()
|
||||
: Ogre::NodeAnimationTrack::Listener()
|
||||
{
|
||||
}
|
||||
bool getInterpolatedKeyFrame(const Ogre::AnimationTrack *t,
|
||||
const Ogre::TimeIndex &timeIndex,
|
||||
Ogre::KeyFrame *kf) override
|
||||
{
|
||||
#if 0
|
||||
Ogre::TransformKeyFrame *vkf =
|
||||
static_cast<Ogre::TransformKeyFrame *>(kf);
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
Ogre::TransformKeyFrame *k1, *k2;
|
||||
unsigned short firstKeyIndex;
|
||||
float tm = t->getKeyFramesAtTime(timeIndex, &kf1, &kf2,
|
||||
&firstKeyIndex);
|
||||
k1 = static_cast<Ogre::TransformKeyFrame *>(kf1);
|
||||
k2 = static_cast<Ogre::TransformKeyFrame *>(kf2);
|
||||
Ogre::Vector3 translation;
|
||||
Ogre::Quaternion rotation;
|
||||
Ogre::Vector3 deltaMotion;
|
||||
Ogre::Vector3 prevMotion;
|
||||
if (tm == 0.0f) {
|
||||
rotation = k1->getRotation();
|
||||
translation = k1->getTranslate();
|
||||
deltaMotion = translation;
|
||||
} else {
|
||||
rotation = Ogre::Quaternion::nlerp(
|
||||
tm, k1->getRotation(), k2->getRotation(), true);
|
||||
translation =
|
||||
k1->getTranslate() +
|
||||
(k2->getTranslate() - k1->getTranslate()) * tm;
|
||||
deltaMotion = translation - prevTranslation;
|
||||
if (deltaMotion.squaredLength() >
|
||||
translation.squaredLength())
|
||||
deltaMotion = translation;
|
||||
}
|
||||
vkf->setTranslate(deltaMotion);
|
||||
vkf->setRotation(rotation);
|
||||
vkf->setScale(Ogre::Vector3(1, 1, 1));
|
||||
prevTranslation = translation;
|
||||
e.get_mut<CharacterBase>().mBoneMotion = deltaMotion;
|
||||
e.get_mut<CharacterBase>().mBonePrevMotion = prevTranslation;
|
||||
e.modified<CharacterBase>();
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
};
|
||||
struct AnimationTrigger {
|
||||
Ogre::String name;
|
||||
float time;
|
||||
float weight;
|
||||
std::vector<AnimationTriggerSubscriber *> subscriber_list;
|
||||
float getTriggerTime() const
|
||||
{
|
||||
return time;
|
||||
}
|
||||
float getMinWeight() const
|
||||
{
|
||||
return weight;
|
||||
}
|
||||
const Ogre::String &getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
void notify(float weight)
|
||||
{
|
||||
int i;
|
||||
if (weight < this->weight)
|
||||
return;
|
||||
for (i = 0; i < subscriber_list.size(); i++)
|
||||
(*subscriber_list[i])(this);
|
||||
}
|
||||
void addSubscriber(AnimationTriggerSubscriber *sub)
|
||||
{
|
||||
if (std::find(subscriber_list.begin(), subscriber_list.end(),
|
||||
sub) != subscriber_list.end())
|
||||
return;
|
||||
subscriber_list.push_back(sub);
|
||||
}
|
||||
void removeSubscriber(AnimationTriggerSubscriber *sub)
|
||||
{
|
||||
auto it = std::find(subscriber_list.begin(),
|
||||
subscriber_list.end(), sub);
|
||||
if (it != subscriber_list.end())
|
||||
subscriber_list.erase(it);
|
||||
}
|
||||
void clearSubscribers()
|
||||
{
|
||||
subscriber_list.clear();
|
||||
}
|
||||
AnimationTrigger(const Ogre::String name, float time, float weight)
|
||||
: name(name)
|
||||
, time(time)
|
||||
, weight(weight)
|
||||
{
|
||||
}
|
||||
};
|
||||
struct Animation {
|
||||
struct SetupTracks {
|
||||
Ogre::NodeAnimationTrack *mHipsTrack;
|
||||
Ogre::NodeAnimationTrack *mRootTrack;
|
||||
RootMotionListener *mListener;
|
||||
Ogre::Vector3 mRootTranslation;
|
||||
SetupTracks(Ogre::Skeleton *skeleton,
|
||||
Ogre::Animation *animation)
|
||||
: mListener(OGRE_NEW RootMotionListener())
|
||||
{
|
||||
mHipsTrack = nullptr;
|
||||
mRootTrack = nullptr;
|
||||
for (const auto &it : animation->_getNodeTrackList()) {
|
||||
Ogre::NodeAnimationTrack *track = it.second;
|
||||
Ogre::String trackName =
|
||||
track->getAssociatedNode()->getName();
|
||||
if (trackName == "mixamorig:Hips") {
|
||||
mHipsTrack = track;
|
||||
} else if (trackName == "Root") {
|
||||
mRootTrack = track;
|
||||
}
|
||||
}
|
||||
if (!mRootTrack) {
|
||||
Ogre::Bone *bone = skeleton->getBone("Root");
|
||||
mRootTrack = animation->createNodeTrack(
|
||||
bone->getHandle(), bone);
|
||||
Ogre::TransformKeyFrame *kf =
|
||||
mRootTrack->createNodeKeyFrame(0.0f);
|
||||
kf->setTranslate(Ogre::Vector3::ZERO);
|
||||
kf->setRotation(Ogre::Quaternion::IDENTITY);
|
||||
}
|
||||
Ogre::TransformKeyFrame *tkfBeg =
|
||||
(Ogre::TransformKeyFrame *)
|
||||
mRootTrack->getKeyFrame(0);
|
||||
Ogre::TransformKeyFrame *tkfEnd =
|
||||
(Ogre::TransformKeyFrame *)
|
||||
mRootTrack->getKeyFrame(
|
||||
mRootTrack->getNumKeyFrames() -
|
||||
1);
|
||||
mRootTranslation =
|
||||
tkfEnd->getTranslate() - tkfBeg->getTranslate();
|
||||
}
|
||||
};
|
||||
Ogre::AnimationState *mAnimationState;
|
||||
Ogre::Animation *mSkelAnimation;
|
||||
SetupTracks *mTracks;
|
||||
float m_weight;
|
||||
float m_accWeight;
|
||||
Ogre::Skeleton *mSkeleton;
|
||||
Animation(Ogre::Skeleton *skeleton, Ogre::AnimationState *animState,
|
||||
Ogre::Animation *skelAnimation)
|
||||
: mTracks(OGRE_NEW SetupTracks(skeleton, skelAnimation))
|
||||
, mAnimationState(animState)
|
||||
, mSkelAnimation(skelAnimation)
|
||||
, m_weight(0)
|
||||
, m_accWeight(0)
|
||||
, mSkeleton(skeleton)
|
||||
{
|
||||
}
|
||||
Ogre::String getName()
|
||||
{
|
||||
return mAnimationState->getAnimationName();
|
||||
}
|
||||
void setLoop(bool loop)
|
||||
{
|
||||
mAnimationState->setLoop(loop);
|
||||
}
|
||||
bool getLoop() const
|
||||
{
|
||||
return mAnimationState->getLoop();
|
||||
}
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
mAnimationState->setEnabled(enabled);
|
||||
}
|
||||
bool getEnabled() const
|
||||
{
|
||||
return mAnimationState->getEnabled();
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
bool enabled = weight > 0.001f;
|
||||
setEnabled(enabled);
|
||||
mAnimationState->setWeight(weight);
|
||||
m_weight = weight;
|
||||
}
|
||||
float getWeight() const
|
||||
{
|
||||
return m_weight;
|
||||
}
|
||||
Ogre::Vector3 rootMotion;
|
||||
Ogre::Vector3 getRootMotionDelta()
|
||||
{
|
||||
if (mAnimationState->getEnabled())
|
||||
return rootMotion * mAnimationState->getWeight();
|
||||
else
|
||||
return Ogre::Vector3(0, 0, 0);
|
||||
}
|
||||
void getKeyframeIndices(Ogre::Real timePos, unsigned short *pindex)
|
||||
{
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(timePos);
|
||||
Ogre::KeyFrame *kf1, *kf2;
|
||||
mTracks->mRootTrack->getKeyFramesAtTime(index, &kf1, &kf2,
|
||||
pindex);
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool result = mAnimationState->getEnabled();
|
||||
if (!result)
|
||||
return result;
|
||||
unsigned short prev_index, next_index;
|
||||
Ogre::TimeIndex index = mSkelAnimation->_getTimeIndex(
|
||||
mAnimationState->getTimePosition());
|
||||
getKeyframeIndices(mAnimationState->getTimePosition(),
|
||||
&prev_index);
|
||||
unsigned int previous_frame = index.getKeyIndex();
|
||||
float lastTime = mAnimationState->getTimePosition();
|
||||
mAnimationState->addTime(time);
|
||||
float thisTime = mAnimationState->getTimePosition();
|
||||
float length = mAnimationState->getLength();
|
||||
bool loop = mAnimationState->getLoop();
|
||||
int loops =
|
||||
loop ? (int)std::round((lastTime + time - thisTime) /
|
||||
length) :
|
||||
0;
|
||||
Ogre::TransformKeyFrame tkf(0, 0);
|
||||
mTracks->mRootTrack->getInterpolatedKeyFrame(lastTime, &tkf);
|
||||
Ogre::Vector3 lastRootPos = tkf.getTranslate();
|
||||
mTracks->mRootTrack->getInterpolatedKeyFrame(thisTime, &tkf);
|
||||
Ogre::Vector3 thisRootPos = tkf.getTranslate();
|
||||
rootMotion = (thisRootPos - lastRootPos) +
|
||||
(loops * mTracks->mRootTranslation);
|
||||
|
||||
getKeyframeIndices(mAnimationState->getTimePosition(),
|
||||
&next_index);
|
||||
// updateRootMotion(mAnimationState->getTimePosition());
|
||||
return prev_index != next_index;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
mAnimationState->setTimePosition(0);
|
||||
}
|
||||
void resetAccWeight()
|
||||
{
|
||||
m_accWeight = 0;
|
||||
}
|
||||
void increaseAccWeight(float weight)
|
||||
{
|
||||
m_accWeight += weight;
|
||||
}
|
||||
float getAccWeight() const
|
||||
{
|
||||
return m_accWeight;
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return mAnimationState->getLength();
|
||||
if (getEnabled())
|
||||
return mAnimationState->getLength();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return mAnimationState->getTimePosition();
|
||||
if (getEnabled())
|
||||
return mAnimationState->getTimePosition();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
struct AnimationNode {
|
||||
std::vector<AnimationNode *> children;
|
||||
float m_weight;
|
||||
Ogre::String m_name;
|
||||
std::multimap<float, AnimationTrigger *> trigger_list;
|
||||
AnimationNode()
|
||||
: m_weight(0)
|
||||
{
|
||||
}
|
||||
virtual bool addTime(float time) = 0;
|
||||
virtual void setWeight(float weight) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual float getLength() const = 0;
|
||||
virtual float getTimePosition() const = 0;
|
||||
float getWeight()
|
||||
{
|
||||
return m_weight;
|
||||
}
|
||||
const Ogre::String &getName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
void setName(const Ogre::String &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
virtual float getTime() const
|
||||
{
|
||||
float l = getLength();
|
||||
if (l > 0.0f)
|
||||
return getTimePosition() / l;
|
||||
return 0.0f;
|
||||
}
|
||||
void addTrigger(AnimationTrigger *trigger)
|
||||
{
|
||||
trigger_list.insert(std::pair<float, AnimationTrigger *>(
|
||||
trigger->getTriggerTime(), trigger));
|
||||
}
|
||||
void clearTriggers()
|
||||
{
|
||||
auto it = trigger_list.begin();
|
||||
while (it != trigger_list.end()) {
|
||||
delete it->second;
|
||||
it++;
|
||||
}
|
||||
trigger_list.clear();
|
||||
}
|
||||
float mpreUpdateTime;
|
||||
void preUpdateTriggers()
|
||||
{
|
||||
mpreUpdateTime = getTime();
|
||||
}
|
||||
void postUpdateTriggers(float delta)
|
||||
{
|
||||
float postUpdateTime = getTime();
|
||||
bool positive = delta >= 0.0f;
|
||||
if (positive)
|
||||
updateTriggers(mpreUpdateTime, postUpdateTime);
|
||||
else
|
||||
updateTriggers(postUpdateTime, mpreUpdateTime);
|
||||
}
|
||||
void updateTriggers(float currentTime, float nextTime)
|
||||
{
|
||||
int i;
|
||||
float weight = getWeight();
|
||||
if (currentTime <= nextTime) {
|
||||
auto it = trigger_list.lower_bound(currentTime);
|
||||
while (it != trigger_list.end()) {
|
||||
if (nextTime <=
|
||||
it->second->getTriggerTime()) // in future, sorrted by time
|
||||
return;
|
||||
it->second->notify(weight);
|
||||
it++;
|
||||
}
|
||||
} else {
|
||||
updateTriggers(currentTime, 1);
|
||||
updateTriggers(0, nextTime);
|
||||
}
|
||||
}
|
||||
};
|
||||
struct AnimationNodeAnimation : AnimationNode {
|
||||
Animation *mAnimation;
|
||||
bool enabled;
|
||||
AnimationNodeAnimation(Animation *animation)
|
||||
: AnimationNode()
|
||||
, mAnimation(animation)
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = mAnimation->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
enabled = weight > 0.001f;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
mAnimation->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return mAnimation->getLength();
|
||||
if (enabled)
|
||||
return mAnimation->getLength();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return mAnimation->getTimePosition();
|
||||
if (enabled)
|
||||
return mAnimation->getTimePosition();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
struct AnimationNodeStateMachineState : AnimationNode {
|
||||
AnimationNodeStateMachineState()
|
||||
: AnimationNode()
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
bool enabled = weight > 0.001f;
|
||||
children[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
children[0]->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return children[0]->getLength();
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return children[0]->getTimePosition();
|
||||
}
|
||||
};
|
||||
struct AnimationNodeSpeed : AnimationNode {
|
||||
float m_speed;
|
||||
bool enabled;
|
||||
AnimationNodeSpeed(float speed)
|
||||
: AnimationNode()
|
||||
, m_speed(speed)
|
||||
, enabled(false)
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time * m_speed);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
children[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
children[0]->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
if (m_speed > 0.0f || m_speed < 0.0f)
|
||||
return children[0]->getLength() / m_speed;
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
if (m_speed > 0.0f || m_speed < 0.0f)
|
||||
return children[0]->getTimePosition() / m_speed;
|
||||
return 0.0f;
|
||||
}
|
||||
float getTime() const override
|
||||
{
|
||||
float l = children[0]->getLength();
|
||||
if (l > 0.0f)
|
||||
return children[0]->getTimePosition() / l;
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
struct AnimationNodeStateMachine : AnimationNode {
|
||||
std::map<Ogre::String, AnimationNode *> stateMap;
|
||||
std::set<AnimationNode *> fade_in, fade_out;
|
||||
AnimationNode *currentAnim, *nextAnim;
|
||||
float fade_speed;
|
||||
Ogre::String mCurrentStateName;
|
||||
bool configured;
|
||||
bool debug;
|
||||
AnimationNodeStateMachine(float fade_speed, bool debug = false)
|
||||
: AnimationNode()
|
||||
, currentAnim(nullptr)
|
||||
, nextAnim(nullptr)
|
||||
, fade_speed(fade_speed)
|
||||
, mCurrentStateName("")
|
||||
, configured(false)
|
||||
, debug(debug)
|
||||
{
|
||||
m_weight = 1.0f;
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
int i;
|
||||
preUpdateTriggers();
|
||||
if (!configured) {
|
||||
configure();
|
||||
configured = true;
|
||||
}
|
||||
#ifdef VDEBUG
|
||||
if (debug) {
|
||||
std::cout << "state machine addTime" << std::endl;
|
||||
std::cout
|
||||
<< "state machine children: " << children.size()
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < children.size(); i++) {
|
||||
#ifdef VDEBUG
|
||||
if (debug)
|
||||
std::cout << "child weight: " << i << " "
|
||||
<< children[i]->getWeight()
|
||||
<< std::endl;
|
||||
#endif
|
||||
AnimationNode *child = children[i];
|
||||
if (fade_in.find(child) != fade_in.end()) {
|
||||
Ogre::Real newWeight =
|
||||
child->getWeight() + time * fade_speed;
|
||||
child->setWeight(Ogre::Math::Clamp<Ogre::Real>(
|
||||
newWeight * m_weight, 0, m_weight));
|
||||
#ifdef VDEBUG
|
||||
if (debug) {
|
||||
std::cout << "fade in: " << newWeight
|
||||
<< std::endl;
|
||||
std::cout << "m_weight: " << m_weight
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
if (newWeight >= 1)
|
||||
fade_in.erase(child);
|
||||
}
|
||||
if (fade_out.find(child) != fade_out.end()) {
|
||||
Ogre::Real newWeight =
|
||||
child->getWeight() - time * fade_speed;
|
||||
child->setWeight(Ogre::Math::Clamp<Ogre::Real>(
|
||||
newWeight * m_weight, 0, 1));
|
||||
if (newWeight <= 0)
|
||||
fade_out.erase(child);
|
||||
}
|
||||
}
|
||||
OgreAssert(currentAnim, "bad current anim");
|
||||
bool ret = false;
|
||||
if (currentAnim)
|
||||
ret = currentAnim->addTime(time);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
int i;
|
||||
if (weight > m_weight && currentAnim)
|
||||
fade_in.insert(currentAnim);
|
||||
if (weight < m_weight && currentAnim &&
|
||||
currentAnim->getWeight() > weight)
|
||||
currentAnim->setWeight(weight);
|
||||
m_weight = weight;
|
||||
bool enabled = weight > 0.001f;
|
||||
/* do not update child state yet */
|
||||
}
|
||||
void addState(AnimationNode *state)
|
||||
{
|
||||
const Ogre::String &name = state->getName();
|
||||
stateMap[name] = state;
|
||||
state->setWeight(0);
|
||||
fade_in.erase(state);
|
||||
fade_out.erase(state);
|
||||
std::cout << "registered state: " << name << std::endl;
|
||||
}
|
||||
void configure()
|
||||
{
|
||||
int i;
|
||||
if (debug)
|
||||
std::cout << "children: " << children.size()
|
||||
<< std::endl;
|
||||
for (i = 0; i < children.size(); i++)
|
||||
addState(children[i]);
|
||||
if (debug)
|
||||
std::cout << "configure called" << std::endl;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < children.size(); i++)
|
||||
children[i]->reset();
|
||||
}
|
||||
void setAnimation(const Ogre::String &anim_state, bool reset = false)
|
||||
{
|
||||
if (!configured) {
|
||||
configure();
|
||||
configured = true;
|
||||
}
|
||||
OgreAssert(stateMap.find(anim_state) != stateMap.end(),
|
||||
"Bad animation state: " + anim_state);
|
||||
nextAnim = stateMap[anim_state];
|
||||
if (nextAnim == currentAnim)
|
||||
return;
|
||||
if (currentAnim != nullptr) {
|
||||
fade_out.insert(currentAnim);
|
||||
fade_in.erase(currentAnim);
|
||||
}
|
||||
fade_out.erase(nextAnim);
|
||||
fade_in.insert(nextAnim);
|
||||
nextAnim->setWeight(0);
|
||||
if (reset)
|
||||
nextAnim->reset();
|
||||
currentAnim = nextAnim;
|
||||
mCurrentStateName = anim_state;
|
||||
}
|
||||
const Ogre::String &getCurrentState() const
|
||||
{
|
||||
return mCurrentStateName;
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
if (currentAnim)
|
||||
return currentAnim->getLength();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
if (currentAnim)
|
||||
return currentAnim->getTimePosition();
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
struct AnimationSystem : AnimationNode {
|
||||
bool debug;
|
||||
|
||||
#define ANIM_FADE_SPEED \
|
||||
7.5f // animation crossfade speed in % of full weight per second
|
||||
|
||||
struct AnimationNodeOutput : AnimationNode {
|
||||
float m_weight;
|
||||
float m_speed;
|
||||
AnimationNodeOutput()
|
||||
: AnimationNode()
|
||||
, m_weight(1.0f)
|
||||
, m_speed(1.0f)
|
||||
{
|
||||
}
|
||||
bool addTime(float time)
|
||||
{
|
||||
bool ret;
|
||||
preUpdateTriggers();
|
||||
ret = children[0]->addTime(time * m_speed);
|
||||
postUpdateTriggers(time);
|
||||
return ret;
|
||||
}
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_weight = weight;
|
||||
bool enabled = weight > 0.001f;
|
||||
children[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
children[0]->reset();
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return children[0]->getLength();
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return children[0]->getTimePosition();
|
||||
}
|
||||
};
|
||||
|
||||
AnimationSystem(bool debug = false)
|
||||
: debug(debug)
|
||||
, m_builder(this, debug)
|
||||
{
|
||||
}
|
||||
std::unordered_map<Ogre::String, Animation *> animation_list;
|
||||
std::vector<Animation *> vanimation_list;
|
||||
void add_animation(const Ogre::String &name, Animation *animation)
|
||||
{
|
||||
OgreAssert(animation, "No animation " + name);
|
||||
animation_list[name] = animation;
|
||||
vanimation_list.push_back(animation);
|
||||
}
|
||||
void clear_animations()
|
||||
{
|
||||
animation_list.clear();
|
||||
vanimation_list.clear();
|
||||
}
|
||||
struct AnimationSystemBuilder {
|
||||
AnimationSystem *mAnimationSystem;
|
||||
std::vector<AnimationNode *> animation_nodes;
|
||||
AnimationNode *parent;
|
||||
std::list<AnimationNode *> parent_stack;
|
||||
std::unordered_map<Ogre::String, AnimationNode *> nodeMap;
|
||||
std::vector<AnimationNodeAnimation *> animationNodeList;
|
||||
bool debug;
|
||||
AnimationSystemBuilder(AnimationSystem *animationSystem,
|
||||
bool debug = false)
|
||||
: mAnimationSystem(animationSystem)
|
||||
, debug(debug)
|
||||
{
|
||||
}
|
||||
AnimationSystemBuilder *output()
|
||||
{
|
||||
AnimationNodeOutput *onode = new AnimationNodeOutput();
|
||||
animation_nodes.push_back(onode);
|
||||
parent = onode;
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *
|
||||
animation(const Ogre::String &animation_name)
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
Animation *animation =
|
||||
mAnimationSystem->animation_list[animation_name];
|
||||
OgreAssert(animation,
|
||||
"bad animation " + animation_name);
|
||||
AnimationNodeAnimation *onode =
|
||||
new AnimationNodeAnimation(animation);
|
||||
OgreAssert(onode, "bad animation");
|
||||
OgreAssert(onode->mAnimation, "bad animation");
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
animationNodeList.push_back(onode);
|
||||
return this;
|
||||
}
|
||||
/* FIXME: need to remove flecs dependency */
|
||||
AnimationSystemBuilder *
|
||||
trigger_entity(flecs::entity e, const Ogre::String &name,
|
||||
float time, const Ogre::String &event)
|
||||
{
|
||||
struct EntityEventSubscriber
|
||||
: AnimationTriggerSubscriber {
|
||||
Ogre::String event;
|
||||
flecs::entity ent;
|
||||
void operator()(const AnimationTrigger *trigger)
|
||||
{
|
||||
ent.get_mut<ECS::EventData>().add(
|
||||
ent, event, ent, ent);
|
||||
}
|
||||
EntityEventSubscriber(flecs::entity e,
|
||||
const Ogre::String &event)
|
||||
: event(event)
|
||||
, ent(e)
|
||||
{
|
||||
}
|
||||
};
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationTrigger *trigger =
|
||||
new AnimationTrigger(name, time, 0.1f);
|
||||
EntityEventSubscriber *sub =
|
||||
new EntityEventSubscriber(e, event);
|
||||
trigger->addSubscriber(sub);
|
||||
parent->addTrigger(trigger);
|
||||
return this;
|
||||
} // leaf too...
|
||||
AnimationSystemBuilder *
|
||||
transition_end(const Ogre::String &state_from,
|
||||
const Ogre::String &state_to)
|
||||
{
|
||||
struct EndTransitionSubscriber
|
||||
: AnimationTriggerSubscriber {
|
||||
AnimationNodeStateMachine *sm;
|
||||
Ogre::String next_state;
|
||||
bool reset;
|
||||
void operator()(const AnimationTrigger *trigger)
|
||||
{
|
||||
sm->setAnimation(next_state, reset);
|
||||
}
|
||||
EndTransitionSubscriber(
|
||||
AnimationNodeStateMachine *sm,
|
||||
const Ogre::String &next_state,
|
||||
bool reset = true)
|
||||
: sm(sm)
|
||||
, next_state(next_state)
|
||||
, reset(reset)
|
||||
{
|
||||
}
|
||||
};
|
||||
OgreAssert(parent, "no parent");
|
||||
AnimationNodeStateMachine *sm =
|
||||
static_cast<AnimationNodeStateMachine *>(
|
||||
parent);
|
||||
OgreAssert(sm, "no state machine");
|
||||
AnimationTrigger *trigger = new AnimationTrigger(
|
||||
"transition:" + state_from + "_" + state_to,
|
||||
0.99f, 0.1f);
|
||||
EndTransitionSubscriber *sub =
|
||||
new EndTransitionSubscriber(sm, state_to);
|
||||
int i;
|
||||
bool ok = false;
|
||||
for (i = 0; i < sm->children.size(); i++) {
|
||||
if (sm->children[i]->getName() == state_from) {
|
||||
trigger->addSubscriber(sub);
|
||||
sm->children[i]->addTrigger(trigger);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OgreAssert(ok, "Failed to set transition");
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *speed(float speed,
|
||||
const Ogre::String &anchor = "")
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationNodeSpeed *onode =
|
||||
new AnimationNodeSpeed(speed);
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
parent_stack.push_back(parent);
|
||||
parent = onode;
|
||||
if (anchor.length() > 0)
|
||||
nodeMap[anchor] = onode;
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *
|
||||
state_machine(float fade_time = ANIM_FADE_SPEED,
|
||||
const Ogre::String &anchor = "")
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationNodeStateMachine *onode =
|
||||
new AnimationNodeStateMachine(fade_time, debug);
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
parent_stack.push_back(parent);
|
||||
parent = onode;
|
||||
if (anchor.length() > 0)
|
||||
nodeMap[anchor] = onode;
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *state(const Ogre::String &state_name)
|
||||
{
|
||||
OgreAssert(parent, "bad parent");
|
||||
AnimationNodeStateMachineState *onode =
|
||||
new AnimationNodeStateMachineState;
|
||||
animation_nodes.push_back(onode);
|
||||
parent->children.push_back(onode);
|
||||
parent_stack.push_back(parent);
|
||||
parent = onode;
|
||||
onode->setName(state_name);
|
||||
return this;
|
||||
}
|
||||
AnimationSystemBuilder *end()
|
||||
{
|
||||
parent = parent_stack.back();
|
||||
parent_stack.pop_back();
|
||||
return this;
|
||||
}
|
||||
};
|
||||
AnimationSystemBuilder m_builder;
|
||||
Ogre::Vector3 getRootMotionDelta();
|
||||
bool addTime(float time);
|
||||
void setWeight(float weight)
|
||||
{
|
||||
m_builder.animation_nodes[0]->setWeight(weight);
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
m_builder.animation_nodes[0]->reset();
|
||||
}
|
||||
AnimationSystemBuilder *builder()
|
||||
{
|
||||
m_builder.animation_nodes.reserve(8);
|
||||
m_builder.parent = nullptr;
|
||||
return &m_builder;
|
||||
}
|
||||
template <class T> T *get(const Ogre::String &name)
|
||||
{
|
||||
return static_cast<T *>(m_builder.nodeMap[name]);
|
||||
}
|
||||
float getLength() const
|
||||
{
|
||||
return m_builder.animation_nodes[0]->getLength();
|
||||
}
|
||||
float getTimePosition() const
|
||||
{
|
||||
return m_builder.animation_nodes[0]->getTimePosition();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ANIMATIONSYSTEM_H
|
||||
@@ -4,19 +4,22 @@ find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG
|
||||
find_package(Bullet REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
find_package(Tracy REQUIRED CONFIG)
|
||||
add_subdirectory(items)
|
||||
add_subdirectory(LuaModule)
|
||||
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp
|
||||
GUIModule.cpp EditorGUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp
|
||||
GUIModule.cpp EditorGUIModule.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp
|
||||
CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp CharacterManagerModule.cpp
|
||||
VehicleManagerModule.cpp AppModule.cpp StaticGeometryModule.cpp SmartObject.cpp SlotsModule.cpp QuestModule.cpp
|
||||
PlayerActionModule.cpp CharacterAIModule.cpp goap.cpp)
|
||||
PlayerActionModule.cpp CharacterAIModule.cpp goap.cpp AnimationSystem.cpp)
|
||||
target_link_libraries(GameData PUBLIC
|
||||
lua
|
||||
items luamodule
|
||||
flecs::flecs_static
|
||||
nlohmann_json::nlohmann_json
|
||||
OgreMain
|
||||
OgreBites
|
||||
OgrePaging OgreTerrain OgreOverlay OgreProcedural::OgreProcedural items
|
||||
PRIVATE sceneloader world-build physics editor)
|
||||
target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${BULLET_INCLUDE_DIR} ../luaaa ../aitoolkit/include)
|
||||
target_compile_definitions(GameData PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION)
|
||||
OgrePaging OgreTerrain OgreOverlay OgreProcedural::OgreProcedural
|
||||
PRIVATE sceneloader world-build physics editor Tracy::TracyClient
|
||||
)
|
||||
target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${BULLET_INCLUDE_DIR})
|
||||
target_compile_definitions(GameData PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION PUBLIC TRACY_ENABLE)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "CharacterModule.h"
|
||||
#include "items.h"
|
||||
#include "CharacterAIModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
struct ActionExec {
|
||||
@@ -231,7 +232,6 @@ public:
|
||||
Ogre::Vector3 direction =
|
||||
(targetPosition - npc.position).normalisedCopy();
|
||||
targetPosition -= direction * radius;
|
||||
std::cout << action->get_name();
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -245,21 +245,20 @@ public:
|
||||
private:
|
||||
int update(float delta) override
|
||||
{
|
||||
OgreAssert(false, "update");
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
OgreAssert(false, "finish");
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
const ActionNodeActions::RunActionNode *runaction =
|
||||
static_cast<const ActionNodeActions::RunActionNode
|
||||
*>(action);
|
||||
if (runaction)
|
||||
std::cout << "Is Run" << std::endl;
|
||||
OgreAssert(false, "activate");
|
||||
}
|
||||
|
||||
@@ -329,14 +328,32 @@ public:
|
||||
jactionPrereq["is_seated"] = 0;
|
||||
jactionEffect["is_seated"] = 1;
|
||||
} else if (action == "use") {
|
||||
if (props["tags"].find("toilet") !=
|
||||
props["tags"].end()) {
|
||||
std::cout << "toilet" << std::endl;
|
||||
OgreAssert(false, "props: " + props.dump(4));
|
||||
OgreAssert(props["tags"].is_array(), "bad formed tags");
|
||||
const nlohmann::json &tags = props["tags"];
|
||||
if (tags.size() == 1 &&
|
||||
tags[0].get<Ogre::String>() == "") {
|
||||
} else {
|
||||
std::cout << "use: " << props.dump(4)
|
||||
<< std::endl;
|
||||
// OgreAssert(false, "props: " + props.dump(4));
|
||||
bool have_bits = false;
|
||||
if (std::find(tags.begin(), tags.end(),
|
||||
"dance-pole") != tags.end()) {
|
||||
jactionPrereq["is_pole_dancing"] = 0;
|
||||
jactionEffect["is_pole_dancing"] = 1;
|
||||
have_bits = true;
|
||||
}
|
||||
if (std::find(tags.begin(), tags.end(),
|
||||
"toilet") != tags.end()) {
|
||||
jactionPrereq["toilet"] = 1;
|
||||
jactionEffect["toilet"] = 0;
|
||||
have_bits = true;
|
||||
}
|
||||
if (!have_bits) {
|
||||
std::cout << "use: " << props.dump(4)
|
||||
<< std::endl;
|
||||
// OgreAssert(false, "props: " + props.dump(4));
|
||||
OgreAssert(tags.size() == 0,
|
||||
"Some tags: " +
|
||||
props.dump(4));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OgreAssert(false, "props: " + props.dump(4));
|
||||
@@ -363,27 +380,32 @@ public:
|
||||
};
|
||||
struct ActionExecCommon : ActionExec {
|
||||
private:
|
||||
float delay;
|
||||
int update(float delta) override
|
||||
{
|
||||
std::cout << "running: " << action->get_name() << std::endl;
|
||||
return OK;
|
||||
delay -= delta;
|
||||
if (delay > 0.0f)
|
||||
return BUSY;
|
||||
else
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
std::cout << "finish: " << action->get_name() << std::endl;
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
std::cout << "!";
|
||||
delay = 1.0f;
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecCommon(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
, delay(0.0f)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -439,20 +461,30 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
{ "thirsty", 1 } } },
|
||||
{ { { "thirsty", 0 } } },
|
||||
10 },
|
||||
#if 0
|
||||
{ "DrinkWater",
|
||||
{ { { "have_water", 1 }, { "thirsty", 1 } } },
|
||||
{ { { "have_water", 1 },
|
||||
{ "thirsty", 1 },
|
||||
{ "is_seated", 0 } } },
|
||||
{ { { "thirsty", 0 } } },
|
||||
2000 },
|
||||
#endif
|
||||
{ "EatMedicine",
|
||||
{ { { "have_medicine", 1 }, { "healthy", 0 } } },
|
||||
{ "EatMedicineSeated",
|
||||
{ { { "have_medicine", 1 },
|
||||
{ "healthy", 0 },
|
||||
{ "is_seated", 1 } } },
|
||||
{ { { "healthy", 1 } } },
|
||||
100 },
|
||||
{ "EatMedicine",
|
||||
{ { { "have_medicine", 1 },
|
||||
{ "healthy", 0 },
|
||||
{ "is_seated", 0 } } },
|
||||
{ { { "healthy", 1 } } },
|
||||
10000 },
|
||||
#if 0
|
||||
{ "UseToilet",
|
||||
{ { { "toilet", 1 } } },
|
||||
{ { { "toilet", 0 } } },
|
||||
100 },
|
||||
#endif
|
||||
{ "GetFood",
|
||||
{ { { "have_food", 0 } } },
|
||||
{ { { "have_food", 1 } } },
|
||||
@@ -478,25 +510,15 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity town, TownAI &ai,
|
||||
const TownNPCs &npcs) {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask(
|
||||
[this, town, npcs, &ai]() {
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town,
|
||||
npcs,
|
||||
&ai]() {
|
||||
std::lock_guard<
|
||||
std::mutex>
|
||||
lock(ecs_mutex);
|
||||
createBlackboards(
|
||||
town, npcs, ai);
|
||||
});
|
||||
});
|
||||
ZoneScopedN("CreateBlackboards");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
createBlackboards(town, npcs, ai);
|
||||
});
|
||||
ecs.system<ActionNodeList, TownAI, TownNPCs>("UpdateDynamicActions")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, ActionNodeList &alist, TownAI &ai,
|
||||
TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateDynamicActions");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
if (ai.nodeActions.size() > 0)
|
||||
return;
|
||||
@@ -527,12 +549,31 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
.interval(0.1f)
|
||||
.each([this](flecs::entity town, ActionNodeList &alist,
|
||||
TownAI &ai, TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateDynamicNodes");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
ECS::get_mut<ActionNodeList>().updateDynamicNodes();
|
||||
});
|
||||
struct MeasureTime {
|
||||
std::chrono::system_clock::time_point start;
|
||||
std::string what;
|
||||
MeasureTime(const std::string &s)
|
||||
: start(std::chrono::high_resolution_clock::now())
|
||||
, what(s)
|
||||
{
|
||||
}
|
||||
~MeasureTime()
|
||||
{
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<float, std::milli> elapsed =
|
||||
end - start;
|
||||
std::cout << what << " " << elapsed.count()
|
||||
<< std::endl;
|
||||
}
|
||||
};
|
||||
ecs.system<TownNPCs>("UpdateNPCPositions")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([](flecs::entity e, TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateNPCPositions");
|
||||
for (auto it = npcs.npcs.begin(); it != npcs.npcs.end();
|
||||
it++) {
|
||||
auto &npc = npcs.npcs.at(it->first);
|
||||
@@ -549,49 +590,62 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
.interval(0.1f)
|
||||
.each([this](flecs::entity town, ActionNodeList &alist,
|
||||
TownAI &ai, const TownNPCs &npcs) {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask(
|
||||
[this, town, &alist, npcs, &ai]() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(
|
||||
ecs_mutex);
|
||||
ZoneScopedN("UpdateBlackboards");
|
||||
|
||||
updateBlackboards(town, alist,
|
||||
npcs, ai);
|
||||
}
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town,
|
||||
&alist]() {
|
||||
town.modified<TownAI>();
|
||||
town.modified<TownNPCs>();
|
||||
ECS::modified<
|
||||
ActionNodeList>();
|
||||
});
|
||||
});
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([this,
|
||||
town,
|
||||
&alist,
|
||||
npcs,
|
||||
&ai]() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(
|
||||
ecs_mutex);
|
||||
ZoneScopedN(
|
||||
"UpdateBlackboards::Thread");
|
||||
|
||||
updateBlackboards(town, alist, npcs,
|
||||
ai);
|
||||
}
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town,
|
||||
&alist]() {
|
||||
ZoneScopedN(
|
||||
"UpdateBlackboards::MainThread");
|
||||
town.modified<TownAI>();
|
||||
town.modified<TownNPCs>();
|
||||
ECS::modified<ActionNodeList>();
|
||||
});
|
||||
});
|
||||
});
|
||||
ecs.system<TownAI, TownNPCs>("PlanAI")
|
||||
.kind(flecs::OnUpdate)
|
||||
.interval(0.5f)
|
||||
.each([&](flecs::entity town, TownAI &ai,
|
||||
const TownNPCs &npcs) {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask(
|
||||
[this, town, npcs, &ai]() {
|
||||
std::lock_guard<std::mutex> lock(
|
||||
ecs_mutex);
|
||||
buildPlans(town, npcs, ai);
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this,
|
||||
town]() {
|
||||
town.modified<TownAI>();
|
||||
});
|
||||
});
|
||||
ZoneScopedN("PlanAI");
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([this,
|
||||
town,
|
||||
npcs,
|
||||
&ai]() {
|
||||
ZoneScopedN("PlanAI::Thread");
|
||||
std::lock_guard<std::mutex> lock(ecs_mutex);
|
||||
buildPlans(town, npcs, ai);
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([this, town]() {
|
||||
ZoneScopedN(
|
||||
"PlanAI::MainThread");
|
||||
town.modified<TownAI>();
|
||||
});
|
||||
});
|
||||
});
|
||||
static std::unordered_map<int, struct PlanExec> plan_exec;
|
||||
ecs.system<const EngineData, TownNPCs, TownAI>("RunPLAN")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([&](flecs::entity town, const EngineData &eng,
|
||||
TownNPCs &npcs, TownAI &ai) {
|
||||
ZoneScopedN("RunPLAN");
|
||||
for (const auto &plans : ai.plans) {
|
||||
if (plan_exec.find(plans.first) !=
|
||||
plan_exec.end()) {
|
||||
@@ -758,6 +812,7 @@ void CharacterAIModule::buildPlans(flecs::entity town, const TownNPCs &npcs,
|
||||
void CharacterAIModule::createBlackboards(flecs::entity town,
|
||||
const TownNPCs &npcs, TownAI &ai)
|
||||
{
|
||||
ZoneScopedN("createBlackboards");
|
||||
OgreAssert(town.is_valid(), "Bad town entity");
|
||||
std::lock_guard<std::mutex> lock(*ai.mutex);
|
||||
for (auto it = npcs.npcs.begin(); it != npcs.npcs.end(); it++) {
|
||||
@@ -871,6 +926,7 @@ void CharacterAIModule::updateBlackboards(flecs::entity town,
|
||||
ActionNodeList &alist,
|
||||
const TownNPCs &npcs, TownAI &ai)
|
||||
{
|
||||
ZoneScopedN("updateBlackboards");
|
||||
std::lock_guard<std::mutex> lock(*ai.mutex);
|
||||
OgreAssert(town.is_valid(), "Bad town entity");
|
||||
alist.build();
|
||||
@@ -1124,7 +1180,8 @@ void Blackboard::query_ai()
|
||||
const TownNPCs &npcs = town.get<TownNPCs>();
|
||||
const float distance = 10000.0f;
|
||||
Ogre::Vector3 position(0, 0, 0);
|
||||
if (npcs.npcs.at(index).e.is_valid())
|
||||
if (npcs.npcs.at(index).e.is_valid() &&
|
||||
npcs.npcs.at(index).e.has<CharacterBase>())
|
||||
position = npcs.npcs.at(index)
|
||||
.e.get<CharacterBase>()
|
||||
.mBodyNode->_getDerivedPosition();
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "TerrainModule.h"
|
||||
#include "WaterModule.h"
|
||||
#include "world-build.h"
|
||||
#include "AnimationSystem.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
@@ -21,7 +23,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
ecs.system<const CharacterBase, AnimationControl>("HandleAnimations")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](flecs::entity e, const CharacterBase &ch,
|
||||
AnimationControl &anim) {
|
||||
AnimationControl &anim) {
|
||||
ZoneScopedN("HandleAnimations");
|
||||
if (!anim.configured) {
|
||||
int i, j;
|
||||
e.set<EventData>({});
|
||||
@@ -32,19 +35,22 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
const Ogre::AnimationStateMap &animMap =
|
||||
animStateSet->getAnimationStates();
|
||||
anim.mAnimationSystem =
|
||||
new AnimationSystem(false);
|
||||
new AnimationSystem::AnimationSystem(
|
||||
false);
|
||||
ch.mBodyEnt->getSkeleton()
|
||||
->getBone("Root")
|
||||
->removeAllChildren();
|
||||
for (auto it = animMap.begin();
|
||||
it != animMap.end(); it++) {
|
||||
Animation *animation = new Animation(
|
||||
ch.mBodyEnt->getSkeleton(),
|
||||
it->second,
|
||||
ch.mBodyEnt->getSkeleton()
|
||||
->getAnimation(
|
||||
it->first),
|
||||
e);
|
||||
AnimationSystem::Animation *animation =
|
||||
new AnimationSystem::Animation(
|
||||
ch.mBodyEnt
|
||||
->getSkeleton(),
|
||||
it->second,
|
||||
ch.mBodyEnt
|
||||
->getSkeleton()
|
||||
->getAnimation(
|
||||
it->first));
|
||||
#ifdef VDEBUG
|
||||
std::cout
|
||||
<< "animation: " << animNames[i]
|
||||
@@ -93,18 +99,18 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
->end()
|
||||
->state("swimming-edge-climb")
|
||||
->animation("swimming-edge-climb")
|
||||
->trigger(e, "end_of_climb", 0.99f, "animation:swimming-edge-climb:end")
|
||||
->trigger_entity(e, "end_of_climb", 0.99f, "animation:swimming-edge-climb:end")
|
||||
->end()
|
||||
->state("hanging-climb")
|
||||
->animation("hanging-climb")
|
||||
->trigger(e, "end_of_climb2", 0.99f, "animation:hanging-climb:end")
|
||||
->trigger_entity(e, "end_of_climb2", 0.99f, "animation:hanging-climb:end")
|
||||
->end()
|
||||
->state("idle")
|
||||
->animation("idle-act")
|
||||
->end()
|
||||
->state("pass-character")
|
||||
->animation("pass-character")
|
||||
->trigger(e, "pass-character", 0.99f, "animation:pass-character:end")
|
||||
->trigger_entity(e, "pass-character", 0.99f, "animation:pass-character:end")
|
||||
->end()
|
||||
->state("character-talk")
|
||||
->animation("character-talk")
|
||||
@@ -127,10 +133,13 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
/* clang-format on */
|
||||
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>("main")
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"main")
|
||||
->setAnimation("locomotion", true);
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"locomotion-state")
|
||||
->setAnimation("idle", true);
|
||||
anim.configured = true;
|
||||
@@ -152,69 +161,21 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
// ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
#if 0
|
||||
ch.mBodyEnt->getSkeleton()->getBone("Root")->reset();
|
||||
ch.mBodyEnt->getSkeleton()->getBone("Root")->setPosition(
|
||||
Ogre::Vector3::ZERO);
|
||||
#endif
|
||||
ZoneScopedN("HandleAnimations1");
|
||||
bool result = anim.mAnimationSystem->addTime(delta);
|
||||
Ogre::Vector3 rootMotion =
|
||||
anim.mAnimationSystem->getRootMotionDelta();
|
||||
ch.mBonePrevMotion = ch.mBoneMotion;
|
||||
ch.mBoneMotion = rootMotion;
|
||||
ch.mBodyEnt->_updateAnimation();
|
||||
#if 0
|
||||
{
|
||||
ZoneScopedN("Ogre::Entity::_updateAnimation");
|
||||
ch.mBodyEnt->_updateAnimation();
|
||||
}
|
||||
ch.mBodyEnt->getSkeleton()->getBone("Root")->setPosition(
|
||||
Ogre::Vector3::ZERO);
|
||||
#if 0
|
||||
Ogre::Vector3 deltaMotion;
|
||||
ch.mBodyEnt->_updateAnimation();
|
||||
std::cout << "motion: " << ch.mBoneMotion << " "
|
||||
<< rootMotion << " " << ch.mBonePrevMotion
|
||||
<< std::endl;
|
||||
rootMotion = ch.mBodyEnt->getSkeleton()
|
||||
->getBone("Root")
|
||||
->getPosition();
|
||||
if (rootMotion.squaredLength() <
|
||||
ch.mBoneMotion.squaredLength())
|
||||
deltaMotion = rootMotion;
|
||||
else
|
||||
deltaMotion = rootMotion - ch.mBoneMotion;
|
||||
ch.mBonePrevMotion = ch.mBoneMotion;
|
||||
ch.mBoneMotion = deltaMotion;
|
||||
#endif
|
||||
// The value we get is interpolated value. When result is true it is new step
|
||||
#if 0
|
||||
Ogre::Vector3 offset = ch.mRootBone->getPosition();
|
||||
ch.mBoneMotion = static_cast<RootMotionListener *>(
|
||||
anim.mListener)
|
||||
->getDeltaMotion();
|
||||
ch.mRootBone->setPosition(Ogre::Vector3::ZERO);
|
||||
Ogre::Vector3 d = offset - ch.mBonePrevMotion;
|
||||
ch.mBonePrevMotion = offset;
|
||||
|
||||
std::cout << "length: " << d.length() << std::endl;
|
||||
if (d.squaredLength() > 0.02f * 0.02f)
|
||||
d = offset;
|
||||
if (d.squaredLength() > 0.02f * 0.02f)
|
||||
d = Ogre::Vector3::ZERO;
|
||||
std::cout << "length2: " << d.length() << std::endl;
|
||||
OgreAssert(d.length() < 0.5f, "bad offset");
|
||||
ch.mBoneMotion = d;
|
||||
#endif
|
||||
#if 0
|
||||
if (result) {
|
||||
if (d.squaredLength() > 0.0f)
|
||||
ch.mBoneMotion =
|
||||
ch.mRootBone->getPosition() -
|
||||
ch.mBoneMotion;
|
||||
else
|
||||
ch.mBoneMotion =
|
||||
ch.mRootBone->getPosition();
|
||||
} else {
|
||||
ch.mBoneMotion = ch.mRootBone->getPosition() -
|
||||
ch.mBoneMotion;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef VDEBUG
|
||||
#ifdef VDEBUG
|
||||
@@ -224,10 +185,6 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
<< " result: " << result << std::endl;
|
||||
#endif
|
||||
#undef VDEBUG
|
||||
#if 0
|
||||
// ch.mRootBone->setPosition(Ogre::Vector3::ZERO);
|
||||
ch.mBonePrevMotion = offset;
|
||||
#endif
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, CharacterVelocity>(
|
||||
"HandleRootMotionVelocity")
|
||||
@@ -240,7 +197,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
return;
|
||||
if (!ch.mBodyNode)
|
||||
return;
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
ZoneScopedN("HandleRootMotionVelocity");
|
||||
Ogre::Quaternion rot = ch.mBodyNode->getOrientation();
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
Ogre::Vector3 boneMotion = ch.mBoneMotion;
|
||||
v.velocity = Ogre::Vector3::ZERO;
|
||||
@@ -273,33 +231,9 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
#if 0
|
||||
v.velocity.y = 0.0f;
|
||||
#endif
|
||||
OgreAssert(v.velocity.squaredLength() < 1000.0f,
|
||||
"Bad velocity setting");
|
||||
});
|
||||
#if 0
|
||||
ecs.system<const EngineData, const AnimationControl,
|
||||
const CharacterBase, CharacterVelocity>("HandleSwimming")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.with<InWater>()
|
||||
.with<CharacterBuoyancy>()
|
||||
.without<CharacterDisablePhysics>()
|
||||
.without<CharacterInActuator>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const AnimationControl &anim,
|
||||
const CharacterBase &ch, CharacterVelocity &gr) {
|
||||
if (anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
"locomotion-state")
|
||||
->getCurrentState() == "swimming") {
|
||||
float h = Ogre::Math::Clamp(
|
||||
0.0f - ch.mBodyNode->getPosition().y,
|
||||
0.0f, 2000.0f);
|
||||
if (h > 0.05 && h < 2.0f)
|
||||
gr.gvelocity.y += 0.1f * (h + 1.0f) *
|
||||
h * eng.delta;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
ecs.system<const EngineData, CharacterBase, AnimationControl,
|
||||
CharacterVelocity>("HandleRootMotion")
|
||||
.kind(flecs::OnUpdate)
|
||||
@@ -328,19 +262,28 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
return;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
AnimationNodeStateMachine *state_machine =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
ZoneScopedNC("HandleNPCAnimations", 0xFF2020);
|
||||
AnimationSystem::AnimationNodeStateMachine
|
||||
*state_machine = anim.mAnimationSystem->get<
|
||||
AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
Ogre::String current_state =
|
||||
state_machine->getCurrentState();
|
||||
Ogre::String next_state = "idle";
|
||||
if (current_state != "treading_water" &&
|
||||
ch.is_submerged)
|
||||
e.has<InWater>())
|
||||
next_state = "treading_water";
|
||||
if (current_state != "idle" && !ch.is_submerged)
|
||||
if (current_state != "idle" && !e.has<InWater>())
|
||||
next_state = "idle";
|
||||
state_machine->setAnimation(next_state);
|
||||
{
|
||||
ZoneScoped;
|
||||
ZoneTextF("animation: next_state: %s %d %d",
|
||||
next_state.c_str(),
|
||||
(int)ch.is_submerged,
|
||||
(int)e.has<InWater>());
|
||||
}
|
||||
});
|
||||
ecs.system<const CharacterBase, const CharacterInActuator,
|
||||
AnimationControl>("HandlePlayerAnimationsActuator")
|
||||
@@ -349,15 +292,18 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.each([](flecs::entity e, const CharacterBase &ch,
|
||||
const CharacterInActuator &inact,
|
||||
AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
ZoneScopedN("HandlePlayerAnimationsActuator");
|
||||
if (!anim.configured)
|
||||
return;
|
||||
AnimationNodeStateMachine *main_sm =
|
||||
AnimationSystem::AnimationNodeStateMachine *main_sm =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"main");
|
||||
AnimationNodeStateMachine *actuator_sm =
|
||||
AnimationSystem::AnimationNodeStateMachine *actuator_sm =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"actuator-state");
|
||||
Ogre::String current_state = main_sm->getCurrentState();
|
||||
if (current_state != "actuator")
|
||||
@@ -372,13 +318,15 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.without<CharacterControlDisable>()
|
||||
.each([](flecs::entity e, const CharacterBase &ch,
|
||||
AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
ZoneScopedN("HandlePlayerAnimationsNoActuator");
|
||||
if (!anim.configured)
|
||||
return;
|
||||
if (!anim.mAnimationSystem)
|
||||
return;
|
||||
AnimationNodeStateMachine *main_sm =
|
||||
AnimationSystem::AnimationNodeStateMachine *main_sm =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
->get<AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"main");
|
||||
Ogre::String current_state = main_sm->getCurrentState();
|
||||
if (current_state != "locomotion")
|
||||
@@ -395,10 +343,12 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
const CharacterBase &ch, AnimationControl &anim) {
|
||||
if (!anim.configured)
|
||||
return;
|
||||
AnimationNodeStateMachine *state_machine =
|
||||
anim.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
ZoneScopedN("HandlePlayerAnimations");
|
||||
AnimationSystem::AnimationNodeStateMachine
|
||||
*state_machine = anim.mAnimationSystem->get<
|
||||
AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
"locomotion-state");
|
||||
Ogre::String current_state =
|
||||
state_machine->getCurrentState();
|
||||
bool controls_idle = input.motion.zeroLength();
|
||||
@@ -474,6 +424,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const CharacterBase &ch, AnimationControl &anim,
|
||||
CharacterInActuator &act) {
|
||||
ZoneScopedN("HandlePlayerAnimations2");
|
||||
bool controls_idle = input.motion.zeroLength();
|
||||
if (!controls_idle) {
|
||||
std::cout << "motion.z: "
|
||||
@@ -547,7 +498,8 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.each([](flecs::entity e, EventData &evt) {
|
||||
for (auto ev : evt.events) {
|
||||
ZoneScopedN("HandleEvents");
|
||||
for (auto ev : evt.events) {
|
||||
std::cout << "character event: " << ev.event
|
||||
<< std::endl;
|
||||
/* parse character events */
|
||||
@@ -600,10 +552,11 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
true) {
|
||||
const AnimationControl &control =
|
||||
param_e->get().get<AnimationControl>();
|
||||
AnimationNodeStateMachine *sm =
|
||||
control.mAnimationSystem
|
||||
->get<AnimationNodeStateMachine>(
|
||||
param_node->get());
|
||||
AnimationSystem::AnimationNodeStateMachine *sm =
|
||||
control.mAnimationSystem->get<
|
||||
AnimationSystem::
|
||||
AnimationNodeStateMachine>(
|
||||
param_node->get());
|
||||
bool reset = false;
|
||||
if (args.size() == 4) {
|
||||
GameWorld::ValueParameter<bool>
|
||||
@@ -622,6 +575,7 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs)
|
||||
}
|
||||
};
|
||||
ECS::get_mut<GameWorld>().add_command<AnimationSetCommand>(
|
||||
"set_animation_state");
|
||||
"set_animation_state");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
#include "PlayerActionModule.h"
|
||||
#include "items.h"
|
||||
#include "CharacterManagerModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
@@ -102,76 +103,64 @@ CharacterManagerModule::CharacterManagerModule(flecs::world &ecs)
|
||||
.write<LivesIn>()
|
||||
.each([this](flecs::entity town, TerrainItem &item,
|
||||
TownNPCs &npcs) {
|
||||
ZoneScopedN("UpdateCharacters");
|
||||
if (!player.is_valid())
|
||||
return;
|
||||
if (!player.has<CharacterBase>())
|
||||
return;
|
||||
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([this,
|
||||
town]() {
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>()
|
||||
.getPlayer();
|
||||
if (!player.is_valid())
|
||||
return;
|
||||
if (!player.has<CharacterBase>())
|
||||
return;
|
||||
TownNPCs &npcs = town.get_mut<TownNPCs>();
|
||||
Ogre::Vector3 cameraPos =
|
||||
player.get<CharacterBase>()
|
||||
.mBodyNode
|
||||
->_getDerivedPosition();
|
||||
for (auto &npc : npcs.npcs) {
|
||||
int index = npc.first;
|
||||
TownNPCs::NPCData &data = npc.second;
|
||||
Ogre::Vector3 npcPosition =
|
||||
data.position;
|
||||
Ogre::Quaternion npcOrientation =
|
||||
data.orientation;
|
||||
if (cameraPos.squaredDistance(
|
||||
npcPosition) < 10000.0f) {
|
||||
if (!data.e.is_valid()) {
|
||||
data.e = createCharacterData(
|
||||
data.model,
|
||||
data.position,
|
||||
data.orientation);
|
||||
data.e.add<LivesIn>(
|
||||
town);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cameraPos.squaredDistance(
|
||||
npcPosition) > 22500.0f) {
|
||||
if (data.e.is_valid()) {
|
||||
data.e.destruct();
|
||||
data.e =
|
||||
flecs::entity();
|
||||
break;
|
||||
}
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>().getPlayer();
|
||||
if (!player.is_valid())
|
||||
return;
|
||||
if (!player.has<CharacterBase>())
|
||||
return;
|
||||
Ogre::Vector3 cameraPos =
|
||||
player.get<CharacterBase>()
|
||||
.mBodyNode->_getDerivedPosition();
|
||||
for (auto &npc : npcs.npcs) {
|
||||
int index = npc.first;
|
||||
TownNPCs::NPCData &data = npc.second;
|
||||
Ogre::Vector3 npcPosition = data.position;
|
||||
Ogre::Quaternion npcOrientation =
|
||||
data.orientation;
|
||||
if (cameraPos.squaredDistance(npcPosition) <
|
||||
10000.0f) {
|
||||
if (!data.e.is_valid()) {
|
||||
data.e = createCharacterData(
|
||||
data.model,
|
||||
data.position,
|
||||
data.orientation);
|
||||
data.e.add<LivesIn>(town);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (auto &npc : npcs.npcs) {
|
||||
int index = npc.first;
|
||||
TownNPCs::NPCData &data = npc.second;
|
||||
Ogre::Vector3 npcPosition =
|
||||
data.position;
|
||||
Ogre::Quaternion npcOrientation =
|
||||
data.orientation;
|
||||
if (cameraPos.squaredDistance(
|
||||
npcPosition) < 10000.0f) {
|
||||
if (data.e.is_valid()) {
|
||||
if (data.e.has<
|
||||
CharacterBase>() &&
|
||||
data.e.has<LivesIn>(
|
||||
town))
|
||||
createNPCActionNodes(
|
||||
town,
|
||||
index);
|
||||
}
|
||||
if (cameraPos.squaredDistance(npcPosition) >
|
||||
22500.0f) {
|
||||
if (data.e.is_valid()) {
|
||||
data.e.destruct();
|
||||
data.e = flecs::entity();
|
||||
break;
|
||||
}
|
||||
}
|
||||
town.modified<TownNPCs>();
|
||||
});
|
||||
}
|
||||
for (auto &npc : npcs.npcs) {
|
||||
int index = npc.first;
|
||||
TownNPCs::NPCData &data = npc.second;
|
||||
Ogre::Vector3 npcPosition = data.position;
|
||||
Ogre::Quaternion npcOrientation =
|
||||
data.orientation;
|
||||
if (cameraPos.squaredDistance(npcPosition) <
|
||||
10000.0f) {
|
||||
if (data.e.is_valid()) {
|
||||
if (data.e.has<CharacterBase>() &&
|
||||
data.e.has<LivesIn>(town))
|
||||
createNPCActionNodes(
|
||||
town, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
town.modified<TownNPCs>();
|
||||
});
|
||||
}
|
||||
flecs::entity
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "CharacterAnimationModule.h"
|
||||
#include "CharacterManagerModule.h"
|
||||
#include "CharacterModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
@@ -78,11 +79,13 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
ecs.system<EngineData, CharacterBase>("UpdateTimer")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](EngineData &eng, CharacterBase &ch) {
|
||||
ch.mTimer += eng.delta;
|
||||
ZoneScopedN("UpdateTimer");
|
||||
ch.mTimer += eng.delta;
|
||||
});
|
||||
ecs.system<Input, Camera>("HandleInput")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](Input &input, Camera &camera) {
|
||||
ZoneScopedN("HandleInput");
|
||||
flecs::entity player =
|
||||
ECS::get<CharacterManagerModule>().getPlayer();
|
||||
if (!player.is_valid())
|
||||
@@ -157,24 +160,6 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
}
|
||||
ECS::get().modified<ECS::Input>();
|
||||
});
|
||||
ecs.system<CharacterBase>()
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, CharacterBase &ch) {
|
||||
float full_subm = 2.0f;
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
float current_subm = -Ogre::Math::Clamp(
|
||||
pos.y + Ogre::Math::Sin(ch.mTimer * 0.13f +
|
||||
130.0f) *
|
||||
0.07f,
|
||||
-full_subm, 0.0f);
|
||||
if (current_subm > 0.9f)
|
||||
ch.is_submerged = true;
|
||||
else if (current_subm < 0.8f)
|
||||
ch.is_submerged = false;
|
||||
});
|
||||
#define TURN_SPEED 500.0f // character turning in degrees per second
|
||||
ecs.system<const Input, const Camera, CharacterBase>("UpdateBody")
|
||||
.kind(flecs::OnUpdate)
|
||||
@@ -184,7 +169,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.without<CharacterControlDisable>()
|
||||
.each([](flecs::entity e, const Input &input,
|
||||
const Camera &camera, CharacterBase &ch) {
|
||||
ch.mGoalDirection = Ogre::Vector3::ZERO;
|
||||
ZoneScopedN("UpdateBody");
|
||||
ch.mGoalDirection = Ogre::Vector3::ZERO;
|
||||
float delta = e.world().delta_time();
|
||||
if (!input.motion.zeroLength()) {
|
||||
// calculate actually goal direction in world based on player's key directions
|
||||
@@ -253,85 +239,6 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
anim.configured = false;
|
||||
});
|
||||
|
||||
#if 0
|
||||
ecs.system<const EngineData, const CharacterLocation,
|
||||
const CharacterConf, Body2Entity>("SetupCharacter")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<Character>()
|
||||
.without<CharacterBase>()
|
||||
.without<CharacterBody>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterLocation &loc,
|
||||
const CharacterConf &conf, Body2Entity &b2e) {
|
||||
CharacterBase &ch = e.ensure<CharacterBase>();
|
||||
CharacterBody &body = e.ensure<CharacterBody>();
|
||||
AnimationControl &anim = e.ensure<AnimationControl>();
|
||||
ch.mBodyEnt = eng.mScnMgr->createEntity(conf.type);
|
||||
ch.mBodyNode = eng.mScnMgr->getRootSceneNode()
|
||||
->createChildSceneNode();
|
||||
ch.mBodyNode->setOrientation(loc.orientation);
|
||||
ch.mBodyNode->setPosition(loc.position);
|
||||
ch.mBodyNode->attachObject(ch.mBodyEnt);
|
||||
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
|
||||
OgreAssert(ch.mBodyEnt->getSkeleton()->hasBone("Root"),
|
||||
"No root bone");
|
||||
OgreAssert(ch.mSkeleton->hasBone("Root"),
|
||||
"No root bone");
|
||||
ch.mRootBone = ch.mSkeleton->getBone("Root");
|
||||
OgreAssert(ch.mRootBone, "No root bone");
|
||||
// body.mController = nullptr;
|
||||
ch.mBoneMotion = Ogre::Vector3::ZERO;
|
||||
ch.mBonePrevMotion = Ogre::Vector3::ZERO;
|
||||
e.set<CharacterVelocity>(
|
||||
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } });
|
||||
body.checkGround = false;
|
||||
body.checkGroundResult = false;
|
||||
#if 0
|
||||
body.mCollisionShape = nullptr;
|
||||
body.mGhostObject = nullptr;
|
||||
body.mController = nullptr;
|
||||
body.mGhostObject = new btPairCachingGhostObject();
|
||||
b2e.entities[body.mGhostObject] = e;
|
||||
body.mCollisionShape = new btCompoundShape(false);
|
||||
body.mGhostObject->setCollisionShape(
|
||||
body.mCollisionShape);
|
||||
{
|
||||
btVector3 inertia(0, 0, 0);
|
||||
// mCollisionShape = new btCompoundShape();
|
||||
btScalar height = 1.0f;
|
||||
btScalar radius = 0.3f;
|
||||
btCapsuleShape *shape = new btCapsuleShape(
|
||||
radius, 2 * height - 2 * radius);
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
transform.setOrigin(btVector3(0, 1, 0));
|
||||
static_cast<btCompoundShape *>(
|
||||
body.mCollisionShape)
|
||||
->addChildShape(transform, shape);
|
||||
btScalar masses[1] = { 0 };
|
||||
btTransform principal;
|
||||
static_cast<btCompoundShape *>(
|
||||
body.mCollisionShape)
|
||||
->calculatePrincipalAxisTransform(
|
||||
masses, principal, inertia);
|
||||
}
|
||||
body.mGhostObject->setCollisionFlags(body.mGhostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT
|
||||
/*btCollisionObject::CF_KINEMATIC_OBJECT |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE */);
|
||||
body.mGhostObject->setActivationState(
|
||||
DISABLE_DEACTIVATION);
|
||||
eng.mWorld->attachCollisionObject(
|
||||
body.mGhostObject, ch.mBodyEnt, 1, 0x7FFFFFFF);
|
||||
OgreAssert(body.mGhostObject, "Need GhostObject");
|
||||
OgreAssert(body.mCollisionShape, "No collision shape");
|
||||
#endif
|
||||
e.add<CharacterGravity>();
|
||||
e.add<CharacterBuoyancy>();
|
||||
anim.configured = false;
|
||||
// OgreAssert(body.mGhostObject->hasContactResponse(),
|
||||
// "need contact response");
|
||||
});
|
||||
#endif
|
||||
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
|
||||
ecs.system<const EngineData, Camera, const CharacterBase>(
|
||||
"UpdateCamera")
|
||||
@@ -340,7 +247,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.with<GroundCheckReady>()
|
||||
.each([](const EngineData &eng, Camera &camera,
|
||||
const CharacterBase &ch) {
|
||||
float delta = eng.delta;
|
||||
ZoneScopedN("UpdateCamera");
|
||||
float delta = eng.delta;
|
||||
if (!camera.configured) {
|
||||
// create a pivot at roughly the character's shoulder
|
||||
camera.mCameraPivot =
|
||||
@@ -411,6 +319,7 @@ CharacterModule::CharacterModule(flecs::world &ecs)
|
||||
.with<Player>()
|
||||
.without<GroundCheckReady>()
|
||||
.each([](const EngineData &eng, CharacterBase &ch) {
|
||||
ZoneScopedN("CheckGround");
|
||||
#if 0
|
||||
if (body.mGhostObject) {
|
||||
btVector3 from =
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "QuestModule.h"
|
||||
#include "GUIModule.h"
|
||||
#include "GUIModuleCommon.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
struct GUIListener;
|
||||
@@ -79,7 +80,8 @@ struct GUIListener : public Ogre::RenderTargetListener {
|
||||
void
|
||||
preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override
|
||||
{
|
||||
preview(evt);
|
||||
ZoneScopedN("GUIModule::preViewportUpdate");
|
||||
preview(evt);
|
||||
}
|
||||
void buttons_panel()
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "QuestModule.h"
|
||||
#include "world-build.h"
|
||||
#include "physics.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
@@ -286,7 +287,10 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
|
||||
void update(float delta)
|
||||
{
|
||||
ecs.progress(delta);
|
||||
{
|
||||
ZoneScoped;
|
||||
ecs.progress(delta);
|
||||
}
|
||||
}
|
||||
flecs::world get()
|
||||
{
|
||||
|
||||
13
src/gamedata/LuaModule/CMakeLists.txt
Normal file
13
src/gamedata/LuaModule/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
project(LuaModule)
|
||||
find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
find_package(Tracy REQUIRED CONFIG)
|
||||
|
||||
add_library(luamodule STATIC LuaData.cpp)
|
||||
target_include_directories(luamodule PUBLIC .)
|
||||
target_link_libraries(luamodule PUBLIC
|
||||
lua
|
||||
OgreMain
|
||||
flecs::flecs_static
|
||||
PRIVATE GameData Tracy::TracyClient
|
||||
)
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "lua.hpp"
|
||||
#include <OgreFileSystemLayer.h>
|
||||
#include "GameData.h"
|
||||
#include "Components.h"
|
||||
@@ -10,11 +11,10 @@
|
||||
#include "BoatModule.h"
|
||||
#include "EventTriggerModule.h"
|
||||
#include "SlotsModule.h"
|
||||
#include "world-build.h"
|
||||
#include "PlayerActionModule.h"
|
||||
#include "QuestModule.h"
|
||||
#include "LuaData.h"
|
||||
#include "lua.hpp"
|
||||
#include <tracy/Tracy.hpp>
|
||||
extern "C" {
|
||||
int luaopen_lpeg(lua_State *L);
|
||||
}
|
||||
@@ -25,51 +25,6 @@ struct FooPosition {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
#if 0
|
||||
namespace luaaa
|
||||
{
|
||||
template <> struct LuaStack<FooPosition> {
|
||||
inline static FooPosition get(lua_State *L, int idx)
|
||||
{
|
||||
FooPosition result;
|
||||
if (lua_istable(L, idx)) {
|
||||
lua_pushnil(L);
|
||||
while (0 != lua_next(L, idx)) {
|
||||
const int top = lua_gettop(L);
|
||||
const char *name =
|
||||
LuaStack<const char *>::get(L, top - 1);
|
||||
if (strncmp(name, "x", 1) == 0)
|
||||
result.value.x =
|
||||
LuaStack<float>::get(L, top);
|
||||
else if (strncmp(name, "y", 1) == 0)
|
||||
result.value.y =
|
||||
LuaStack<float>::get(L, top);
|
||||
else if (strncmp(name, "z", 1) == 0)
|
||||
result.value.z =
|
||||
LuaStack<float>::get(L, top);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
inline static void put(lua_State *L, const FooPosition &v)
|
||||
{
|
||||
lua_newtable(L);
|
||||
LuaStack<const char *>::put(L, "x");
|
||||
LuaStack<float>::put(L, v.value.x);
|
||||
lua_rawset(L, -3);
|
||||
LuaStack<const char *>::put(L, "y");
|
||||
LuaStack<float>::put(L, v.value.y);
|
||||
lua_rawset(L, -3);
|
||||
LuaStack<const char *>::put(L, "z");
|
||||
LuaStack<float>::put(L, v.value.z);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
namespace ECS
|
||||
{
|
||||
struct LuaEcsEntity {
|
||||
@@ -635,6 +590,7 @@ LuaData::LuaData()
|
||||
flecs::entity object_e = idmap.get_entity(object);
|
||||
Ogre::String nodeName = lua_tostring(L, 3);
|
||||
Ogre::String stateName = lua_tostring(L, 4);
|
||||
#if 0
|
||||
bool reset = false;
|
||||
if (lua_gettop(L) == 5)
|
||||
reset = lua_toboolean(L, 5);
|
||||
@@ -654,6 +610,8 @@ LuaData::LuaData()
|
||||
{ obj, obj_node,
|
||||
obj_state });
|
||||
ECS::modified<GameWorld>();
|
||||
#endif
|
||||
OgreAssert(false, "Not implemented");
|
||||
|
||||
return 0;
|
||||
} else if (command == "params-set") {
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "EventModule.h"
|
||||
#include "TerrainModule.h"
|
||||
#include "PhysicsModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
struct PhysicsShape {
|
||||
@@ -54,8 +55,18 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ecs.component<PhysicsMeshPtr>();
|
||||
ecs.component<PhysicsHeightfieldData>();
|
||||
|
||||
ecs.component<CharacterBody>();
|
||||
ecs.component<TriggerBody>();
|
||||
ecs.component<CharacterBody>().on_remove([](flecs::entity e,
|
||||
CharacterBody &body) {
|
||||
JPH::Character *ch =
|
||||
static_cast<JPH::Character *>(body.ch.get());
|
||||
if (ch) {
|
||||
if (e.has<JPH::BodyID>())
|
||||
e.remove<JPH::BodyID>();
|
||||
JoltPhysicsWrapper::getSingleton().destroyCharacter(ch);
|
||||
body.ch = nullptr;
|
||||
}
|
||||
});
|
||||
ecs.component<TriggerBody>();
|
||||
ecs.component<CharacterVelocity>();
|
||||
ecs.component<WaterBody>().add(flecs::Singleton);
|
||||
ecs.component<CachedMass>();
|
||||
@@ -64,6 +75,7 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ecs.system<EngineData, Physics>("physics_update")
|
||||
.kind(PhysicsUpdate)
|
||||
.each([&](EngineData &e, Physics &ph) {
|
||||
ZoneScopedN("physics");
|
||||
ph.physics->update(e.delta);
|
||||
});
|
||||
ecs.observer<const EngineData, PhysicsMeshName>(
|
||||
@@ -152,6 +164,9 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
JoltPhysicsWrapper::getSingleton().removeBody(id);
|
||||
if (e.has<CharacterBase>() || e.has<Character>())
|
||||
return;
|
||||
if (JoltPhysicsWrapper::getSingleton().bodyIsCharacter(
|
||||
id))
|
||||
return;
|
||||
JoltPhysicsWrapper::getSingleton().destroyBody(id);
|
||||
std::cout << "body destroyed" << std::endl;
|
||||
});
|
||||
@@ -164,7 +179,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.write<JPH::BodyID>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &base) {
|
||||
CharacterBody &b = e.ensure<CharacterBody>();
|
||||
ZoneScopedN("SetupCharacterPh");
|
||||
CharacterBody &b = e.ensure<CharacterBody>();
|
||||
b.ch.reset(JoltPhysicsWrapper::getSingleton()
|
||||
.createCharacter(base.mBodyNode,
|
||||
1.75f, 0.23f));
|
||||
@@ -267,20 +283,23 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ECS::modified<LuaEvent>();
|
||||
});
|
||||
});
|
||||
// FIXME: convert to normal configure to prevent multiple instances
|
||||
ecs.system<const EngineData>("init_water")
|
||||
.kind(PhysicsPreUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterAlmostReady>()
|
||||
.without<WaterBody>()
|
||||
.each([this](const EngineData &eng) {
|
||||
ECS::get().set<WaterBody>({});
|
||||
ZoneScopedN("init_water");
|
||||
ECS::get().set<WaterBody>({});
|
||||
});
|
||||
ecs.system<const EngineData, WaterBody>("update_water")
|
||||
.kind(PhysicsPostUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterAlmostReady>()
|
||||
.each([this](const EngineData &eng, WaterBody &body) {
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
ZoneScopedN("update_water");
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
body.inWater.clear();
|
||||
JoltPhysicsWrapper::getSingleton().broadphaseQuery(
|
||||
eng.delta,
|
||||
@@ -295,8 +314,11 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, const JPH::BodyID &id,
|
||||
const WaterBody &body) {
|
||||
if (!body.isInWater(id))
|
||||
ZoneScopedN("update_water_status1");
|
||||
if (!body.isInWater(id)) {
|
||||
e.remove<InWater>();
|
||||
ZoneTextF("in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const JPH::BodyID, const WaterBody>("update_water_status2")
|
||||
.kind(PhysicsPostUpdate)
|
||||
@@ -305,8 +327,11 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.without<InWater>()
|
||||
.each([this](flecs::entity e, const JPH::BodyID &id,
|
||||
const WaterBody &body) {
|
||||
if (body.isInWater(id))
|
||||
ZoneScopedN("update_water_status2");
|
||||
if (body.isInWater(id)) {
|
||||
e.add<InWater>();
|
||||
ZoneTextF("not in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const CharacterBody, const WaterBody>(
|
||||
"update_water_character1")
|
||||
@@ -316,10 +341,13 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, const CharacterBody &ch,
|
||||
const WaterBody &body) {
|
||||
JPH::Character *chptr =
|
||||
ZoneScopedN("update_water_character1");
|
||||
JPH::Character *chptr =
|
||||
static_cast<JPH::Character *>(ch.ch.get());
|
||||
if (!body.isInWater(chptr->GetBodyID()))
|
||||
if (!body.isInWater(chptr->GetBodyID())) {
|
||||
e.remove<InWater>();
|
||||
ZoneTextF("not in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const CharacterBody, const WaterBody>(
|
||||
"update_water_character2")
|
||||
@@ -329,10 +357,13 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.without<InWater>()
|
||||
.each([this](flecs::entity e, const CharacterBody &ch,
|
||||
const WaterBody &body) {
|
||||
JPH::Character *chptr =
|
||||
ZoneScopedN("update_water_character2");
|
||||
JPH::Character *chptr =
|
||||
static_cast<JPH::Character *>(ch.ch.get());
|
||||
if (body.isInWater(chptr->GetBodyID()))
|
||||
if (body.isInWater(chptr->GetBodyID())) {
|
||||
e.add<InWater>();
|
||||
ZoneTextF("in water");
|
||||
}
|
||||
});
|
||||
ecs.system<const EngineData, const BoatBase, const WaterBody,
|
||||
const JPH::BodyID>("update_water_boat_enable")
|
||||
@@ -342,7 +373,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const BoatBase &boat, const WaterBody &body,
|
||||
const JPH::BodyID &id) {
|
||||
if (!JoltPhysicsWrapper::getSingleton().isAdded(id))
|
||||
ZoneScopedN("update_water_boat_enable");
|
||||
if (!JoltPhysicsWrapper::getSingleton().isAdded(id))
|
||||
JoltPhysicsWrapper::getSingleton().addBody(
|
||||
id, JPH::EActivation::Activate);
|
||||
});
|
||||
@@ -355,7 +387,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const BoatBase &boat, const WaterBody &body,
|
||||
const JPH::BodyID &id) {
|
||||
if (!JoltPhysicsWrapper::getSingleton().isActive(id))
|
||||
ZoneScopedN("update_water_boat_activation");
|
||||
if (!JoltPhysicsWrapper::getSingleton().isActive(id))
|
||||
JoltPhysicsWrapper::getSingleton().activate(id);
|
||||
});
|
||||
ecs.system<const EngineData, const BoatBase, const WaterBody,
|
||||
@@ -368,7 +401,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const BoatBase &boat, const WaterBody &body,
|
||||
const JPH::BodyID &id, const CachedMass &mass) {
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
ZoneScopedN("update_water_boat_buoyancy");
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
float b = 1.0f, drag = 0.5f, adrag = 0.5f;
|
||||
float level = 0.25f;
|
||||
float my = JoltPhysicsWrapper::getSingleton()
|
||||
@@ -425,7 +459,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.with<CharacterBuoyancy>()
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBody &ch, const WaterBody &body) {
|
||||
JPH::Character *chptr =
|
||||
ZoneScopedN("update_water_character_buoyancy");
|
||||
JPH::Character *chptr =
|
||||
static_cast<JPH::Character *>(ch.ch.get());
|
||||
JPH::BodyID id = chptr->GetBodyID();
|
||||
if (JoltPhysicsWrapper::getSingleton().isActive(id)) {
|
||||
@@ -467,13 +502,15 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
eng.delta);
|
||||
}
|
||||
});
|
||||
ecs.system<const EngineData, const CharacterBody>("UpdatePhysics")
|
||||
ecs.system<const EngineData, const CharacterBody>(
|
||||
"UpdateCharacterPhysicsState")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<CharacterUpdatePhysicsState>()
|
||||
.write<CharacterUpdatePhysicsState>()
|
||||
.each([](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBody &body) {
|
||||
if (e.has<CharacterDisablePhysics>())
|
||||
ZoneScopedN("UpdateCharacterPhysicsState");
|
||||
if (e.has<CharacterDisablePhysics>())
|
||||
PhysicsModule::controlPhysics(e, false);
|
||||
else
|
||||
PhysicsModule::controlPhysics(e, true);
|
||||
@@ -489,7 +526,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
const CharacterBase &chbase,
|
||||
const CharacterBody &body, CharacterVelocity &gr) {
|
||||
if (e.has<InWater>() &&
|
||||
ZoneScopedN("HandleVelocity");
|
||||
if (e.has<InWater>() &&
|
||||
chbase.mBodyNode->_getDerivedPosition().y > -0.5f)
|
||||
e.remove<InWater>();
|
||||
Ogre::Vector3 v = gr.velocity;
|
||||
@@ -519,7 +557,27 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
JoltPhysics::convert<JPH::Vec3>(v));
|
||||
gr.velocity = Ogre::Vector3::ZERO;
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, const CharacterBody,
|
||||
ecs.system<CharacterBase>("HandleSubmerge")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<TerrainReady>()
|
||||
.with<WaterReady>()
|
||||
.with<InWater>()
|
||||
.each([this](flecs::entity e, CharacterBase &ch) {
|
||||
ZoneScopedNC("HandleSubmerge", 0xFF3030);
|
||||
float full_subm = 2.0f;
|
||||
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
|
||||
float current_subm = -Ogre::Math::Clamp(
|
||||
pos.y + Ogre::Math::Sin(ch.mTimer * 0.13f +
|
||||
130.0f) *
|
||||
0.07f,
|
||||
-full_subm, 0.0f);
|
||||
if (current_subm > 0.9f)
|
||||
ch.is_submerged = true;
|
||||
else if (current_subm < 0.8f)
|
||||
ch.is_submerged = false;
|
||||
ZoneTextF("is submerged: %d", (int)ch.is_submerged);
|
||||
});
|
||||
ecs.system<const EngineData, CharacterBase, const CharacterBody,
|
||||
CharacterVelocity>("HandleVelocityNoPhysics")
|
||||
.kind(PhysicsPostUpdate)
|
||||
.with<TerrainReady>()
|
||||
@@ -529,7 +587,8 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
.each([this](flecs::entity e, const EngineData &eng,
|
||||
CharacterBase &ch, const CharacterBody &body,
|
||||
CharacterVelocity &gr) {
|
||||
Ogre::Vector3 v = gr.velocity;
|
||||
ZoneScopedNC("HandleVelocityNoPhysics", 0xFF4040);
|
||||
Ogre::Vector3 v = gr.velocity;
|
||||
// v.y = 0.0f;
|
||||
ch.mBodyNode->_setDerivedPosition(
|
||||
ch.mBodyNode->_getDerivedPosition() +
|
||||
@@ -548,9 +607,12 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ch.mBodyNode->_getDerivedPosition().y > -0.5f) {
|
||||
e.remove<InWater>();
|
||||
ch.is_submerged = false;
|
||||
}
|
||||
if (!e.has<InWater>() && ch.is_submerged)
|
||||
ZoneTextF("remove in water");
|
||||
}
|
||||
if (!e.has<InWater>() && ch.is_submerged) {
|
||||
ch.is_submerged = false;
|
||||
ZoneTextF("not submerged");
|
||||
}
|
||||
});
|
||||
}
|
||||
flecs::entity PhysicsModule::createTerrainChunkBody(Ogre::SceneNode *node,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "LuaData.h"
|
||||
#include "PhysicsModule.h"
|
||||
#include "PlayerActionModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
@@ -297,6 +298,7 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
.each([](ActionNodeList &list) {
|
||||
if (list.isBusy())
|
||||
return;
|
||||
ZoneScopedN("updateNodeList");
|
||||
if (list.nodes.size() > 0) {
|
||||
Ogre::SceneNode *cameraNode =
|
||||
ECS::get<Camera>().mCameraNode;
|
||||
@@ -320,6 +322,7 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](ActionNodeList &list, const Input &input) {
|
||||
std::lock_guard<std::mutex> lock(*list.nodeMutex);
|
||||
ZoneScopedN("ActivateActionNode");
|
||||
if (input.control & 32)
|
||||
std::cout << "act pressed" << std::endl;
|
||||
if (list.isBusy())
|
||||
@@ -365,6 +368,7 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs)
|
||||
ecs.system<const EngineData>("UpdateActivatedWords")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([this](const EngineData &eng) {
|
||||
ZoneScopedN("UpdateActivatedWords");
|
||||
for (auto it = activatedWords.begin();
|
||||
it != activatedWords.end();) {
|
||||
int ret = it->second->_update(eng.delta);
|
||||
@@ -745,6 +749,7 @@ void ActionNodeList::updateDynamicNodes()
|
||||
|
||||
void ActionNodeList::build()
|
||||
{
|
||||
ZoneScoped;
|
||||
std::lock_guard<std::mutex> lock(*nodeMutex);
|
||||
indexObj = std::make_shared<ActionNodeList::indexObject>(dynamicNodes);
|
||||
indexObj->index.buildIndex();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "PhysicsModule.h"
|
||||
#include "items.h"
|
||||
#include "StaticGeometryModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
@@ -461,16 +462,14 @@ nlohmann::json &StaticGeometryModule::getTemplates()
|
||||
|
||||
void StaticGeometryModule::updateItemGeometry(flecs::entity e)
|
||||
{
|
||||
if (e.has<GeometryUpdateItem>())
|
||||
return;
|
||||
e.add<GeometryUpdateItem>();
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([e]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask(
|
||||
[e]() {
|
||||
Geometry::updateItemGeometry(e);
|
||||
e.remove<GeometryUpdateItem>();
|
||||
});
|
||||
// We add this as task to reduce UI load
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([e]() {
|
||||
ZoneScopedN("updateItemGeometry");
|
||||
if (e.has<GeometryUpdateItem>())
|
||||
return;
|
||||
e.add<GeometryUpdateItem>();
|
||||
Geometry::updateItemGeometry(e);
|
||||
e.remove<GeometryUpdateItem>();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -487,22 +486,14 @@ void StaticGeometryModule::addTriangleBufferWork(
|
||||
Procedural::TriangleBuffer tb;
|
||||
};
|
||||
WorkData data = { meshName, geo, position, rotation, tb };
|
||||
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addTask([captData = std::move(
|
||||
data)]() {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask(
|
||||
[captData]() {
|
||||
Ogre::MeshPtr mesh =
|
||||
captData.tb.transformToMesh(
|
||||
captData.meshName);
|
||||
Ogre::Entity *ent =
|
||||
ECS::get<EngineData>()
|
||||
.mScnMgr->createEntity(mesh);
|
||||
captData.geo->addEntity(ent, captData.position,
|
||||
captData.rotation);
|
||||
ECS::get<EngineData>().mScnMgr->destroyEntity(
|
||||
ent);
|
||||
});
|
||||
// We add this as task to reduce UI load
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([data]() {
|
||||
ZoneScopedN("addTriangleBufferWork");
|
||||
Ogre::MeshPtr mesh = data.tb.transformToMesh(data.meshName);
|
||||
Ogre::Entity *ent =
|
||||
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
|
||||
data.geo->addEntity(ent, data.position, data.rotation);
|
||||
ECS::get<EngineData>().mScnMgr->destroyEntity(ent);
|
||||
});
|
||||
}
|
||||
struct TiledMeshes {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "GameData.h"
|
||||
#include "Components.h"
|
||||
#include "WaterModule.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
namespace ECS
|
||||
{
|
||||
#if 0
|
||||
@@ -112,12 +113,6 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
Ogre::Plane(Ogre::Vector3(0.0, -1.0, 0.0), h);
|
||||
water.mRefractionClipPlaneBelow =
|
||||
Ogre::Plane(Ogre::Vector3(0.0, 1.0, 0.0), -h);
|
||||
#if 0
|
||||
if (Ogre::TextureManager::getSingleton()
|
||||
.resourceExists(renderTargetName))
|
||||
Ogre::TextureManager::getSingleton()
|
||||
.remove(renderTargetName);
|
||||
#endif
|
||||
Ogre::TexturePtr reflectionTexture =
|
||||
Ogre::TextureManager::getSingleton().createManual(
|
||||
renderTargetName,
|
||||
@@ -201,64 +196,6 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
Ogre::MANUAL_CULL_NONE);
|
||||
pass->setVertexProgram("Water/water_vp");
|
||||
pass->setFragmentProgram("Water/water_fp");
|
||||
#if 0
|
||||
Ogre::GpuProgramPtr water_vp =
|
||||
Ogre::GpuProgramManager::getSingleton()
|
||||
.getByName(
|
||||
"Water/water_vp",
|
||||
Ogre::RGN_AUTODETECT);
|
||||
OgreAssert(water_vp != nullptr,
|
||||
"VP failed");
|
||||
pass->setGpuProgram(
|
||||
Ogre::GPT_VERTEX_PROGRAM,
|
||||
water_vp);
|
||||
OgreAssert(water_vp->isSupported(),
|
||||
"VP not supported");
|
||||
Ogre::GpuProgramPtr water_fp =
|
||||
Ogre::GpuProgramManager::getSingleton()
|
||||
.getByName(
|
||||
"Water/water_fp",
|
||||
Ogre::RGN_AUTODETECT);
|
||||
OgreAssert(water_vp != nullptr,
|
||||
"FP failed");
|
||||
pass->setGpuProgram(
|
||||
Ogre::GPT_FRAGMENT_PROGRAM,
|
||||
water_fp);
|
||||
OgreAssert(water_fp->isSupported(),
|
||||
"FP not supported");
|
||||
Ogre::GpuProgramParametersSharedPtr paramsVP =
|
||||
water_vp->getDefaultParameters();
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"world",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_WORLD_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"worldViewProj",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_WORLDVIEWPROJ_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"textureProjMatrix",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_TEXTURE_WORLDVIEWPROJ_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"eyePosition",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_CAMERA_POSITION_OBJECT_SPACE);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"normalMatrix",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_NORMAL_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"worldView",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_WORLDVIEW_MATRIX);
|
||||
paramsVP->setNamedAutoConstant(
|
||||
"viewProj",
|
||||
Ogre::GpuProgramParameters::
|
||||
ACT_VIEWPROJ_MATRIX);
|
||||
Ogre::GpuProgramParametersSharedPtr paramsFP =
|
||||
water_fp->getDefaultParameters();
|
||||
#endif
|
||||
Ogre::TextureUnitState *texture_unit =
|
||||
pass->createTextureUnitState();
|
||||
texture_unit->setTextureName(
|
||||
@@ -284,38 +221,7 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
Ogre::FT_MAG, Ogre::FO_LINEAR);
|
||||
texture_unit2->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()
|
||||
->getRenderState(
|
||||
Ogre::MSN_SHADERGEN,
|
||||
*mat,
|
||||
0);
|
||||
|
||||
Ogre::RTShader::SubRenderState *perPixelLightModel =
|
||||
Ogre::RTShader::ShaderGenerator::getSingletonPtr()
|
||||
->createSubRenderState(
|
||||
Ogre::RTShader::
|
||||
SRS_PER_PIXEL_LIGHTING);
|
||||
renderState->addTemplateSubRenderState(
|
||||
perPixelLightModel);
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
mat = Ogre::MaterialManager::getSingleton()
|
||||
.getByName("Water/Above");
|
||||
mat->load();
|
||||
#endif
|
||||
mat->load();
|
||||
mat->setReceiveShadows(false);
|
||||
/*
|
||||
@@ -494,202 +400,37 @@ WaterModule::WaterModule(flecs::world &ecs)
|
||||
"Water/Above");
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
#if 0
|
||||
ecs.component<WaterBody>().add(flecs::Singleton);
|
||||
ecs.component<WaterBody>()
|
||||
.on_add([this](WaterBody &body) {
|
||||
#if 0
|
||||
body.mShapeAabbMax = btVector3(0, 0, 0);
|
||||
body.mShapeAabbMin = btVector3(0, 0, 0);
|
||||
body.mSurface.clear();
|
||||
body.mWaterBody = OGRE_NEW btPairCachingGhostObject();
|
||||
createWaterShape(&body);
|
||||
body.mWaterBody->setCollisionShape(body.mWaterShape);
|
||||
btTransform bodyTransform;
|
||||
bodyTransform.setIdentity();
|
||||
body.mWaterBody->setWorldTransform(bodyTransform);
|
||||
body.mWaterBody->setCollisionFlags(
|
||||
body.mWaterBody->getCollisionFlags() |
|
||||
btCollisionObject::CF_KINEMATIC_OBJECT |
|
||||
btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
body.mWaterBody->setActivationState(
|
||||
DISABLE_DEACTIVATION);
|
||||
const EngineData &eng = ECS::get<EngineData>();
|
||||
const WaterSurface &water = ECS::get<WaterSurface>();
|
||||
|
||||
eng.mWorld->attachCollisionObject(body.mWaterBody,
|
||||
water.mWaterEnt, 16,
|
||||
0x7fffffff & ~2);
|
||||
WaterPhysicsAction *action =
|
||||
OGRE_NEW WaterPhysicsAction(body.mWaterBody);
|
||||
body.action = action;
|
||||
ECS::get()
|
||||
.get<EngineData>()
|
||||
.mWorld->getBtWorld()
|
||||
->addAction(body.action);
|
||||
#endif
|
||||
ECS::get().add<WaterReady>();
|
||||
})
|
||||
.add(flecs::Singleton);
|
||||
#endif
|
||||
ecs.system<const EngineData, const Camera, WaterSurface>("UpdateWater")
|
||||
ecs.system<const EngineData, const Camera, WaterSurface>(
|
||||
"UpdateWaterPosition")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<WaterReady>()
|
||||
.interval(0.3f)
|
||||
.each([](const EngineData &eng, const Camera &camera,
|
||||
WaterSurface &water) {
|
||||
float delta = eng.delta;
|
||||
Ogre::Vector3 mCameraPos =
|
||||
camera.mCameraNode->_getDerivedPosition();
|
||||
Ogre::Vector3 waterPos =
|
||||
water.mWaterNode->_getDerivedPosition();
|
||||
mCameraPos.y = 0;
|
||||
waterPos.y = 0;
|
||||
Ogre::Vector3 d = mCameraPos - waterPos;
|
||||
// Ogre::Vector3 waterPosition = mCameraPos;
|
||||
// mWaterNode->setPosition(waterPosition);
|
||||
if (d.squaredLength() < 100.0f * 100.0f)
|
||||
water.mWaterNode->translate(d * 3.0f * delta);
|
||||
else
|
||||
water.mWaterNode->translate(d);
|
||||
// water.mWaterEnt->setVisible(false);
|
||||
water.mViewports[0]->update();
|
||||
water.mViewports[1]->update();
|
||||
// water.mRenderTargetListener.mInDepth = true;
|
||||
// water.mViewports[2]->update();
|
||||
// water.mViewports[3]->update();
|
||||
// water.mRenderTargetListener.mInDepth = false;
|
||||
// water.mWaterEnt->setVisible(true);
|
||||
ZoneScopedN("UpdateWaterPosition");
|
||||
float delta = eng.delta;
|
||||
Ogre::Vector3 mCameraPos =
|
||||
camera.mCameraNode->_getDerivedPosition();
|
||||
Ogre::Vector3 waterPos =
|
||||
water.mWaterNode->_getDerivedPosition();
|
||||
mCameraPos.y = 0;
|
||||
waterPos.y = 0;
|
||||
Ogre::Vector3 d = mCameraPos - waterPos;
|
||||
if (d.squaredLength() < 100.0f * 100.0f)
|
||||
water.mWaterNode->translate(d * 3.0f * delta);
|
||||
else
|
||||
water.mWaterNode->translate(d);
|
||||
});
|
||||
ecs.system<WaterSurface>("UpdateWater")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<WaterReady>()
|
||||
.each([](WaterSurface &water) {
|
||||
static int updateViewport = 0;
|
||||
ZoneScopedN("UpdateWaterRender");
|
||||
water.mViewports[updateViewport++]->update();
|
||||
if (updateViewport > 1)
|
||||
updateViewport = 0;
|
||||
});
|
||||
#if 0
|
||||
ecs.system<const EngineData, const WaterSurface, WaterBody>(
|
||||
"UpdateWaterBody")
|
||||
.kind(flecs::OnUpdate)
|
||||
.with<WaterReady>()
|
||||
.each([this](const EngineData &eng, const WaterSurface &water,
|
||||
WaterBody &body) {
|
||||
int i;
|
||||
#if 0
|
||||
OgreAssert(body.mWaterBody, "Water not ready");
|
||||
std::set<btCollisionObject *> currentOverlaps;
|
||||
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));
|
||||
#endif
|
||||
#if 0
|
||||
btCompoundShape *mshape =
|
||||
static_cast<btCompoundShape *>(
|
||||
body.mWaterBody->getCollisionShape());
|
||||
btDispatcher *dispatch =
|
||||
eng.mWorld->getBtWorld()->getDispatcher();
|
||||
btHashedOverlappingPairCache *cache =
|
||||
body.mWaterBody->getOverlappingPairCache();
|
||||
btBroadphasePairArray &collisionPairs =
|
||||
cache->getOverlappingPairArray();
|
||||
const int numObjects = collisionPairs.size();
|
||||
std::cout << "numObjects: " << numObjects << "\n";
|
||||
std::cout
|
||||
<< "numObjects: "
|
||||
<< body.mWaterBody->getOverlappingPairs().size()
|
||||
<< "\n";
|
||||
for (int i = 0; i < numObjects; i++) {
|
||||
const btBroadphasePair &collisionPair =
|
||||
collisionPairs[i];
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
body.mShapeAabbMin =
|
||||
body.mWaterBody->getWorldTransform()
|
||||
.getOrigin() +
|
||||
btVector3(-100, -100, -100);
|
||||
body.mShapeAabbMax =
|
||||
body.mWaterBody->getWorldTransform()
|
||||
.getOrigin() +
|
||||
btVector3(100, 100, 100);
|
||||
#if 0
|
||||
body.mWaterShape->getAabb(
|
||||
body.mWaterBody->getWorldTransform(),
|
||||
body.mShapeAabbMin, body.mShapeAabbMax);
|
||||
#endif
|
||||
std::cout << "manifolds: "
|
||||
<< static_cast<WaterPhysicsAction *>(
|
||||
body.action)
|
||||
->mManifoldArray.size()
|
||||
<< "\n";
|
||||
for (int j = 0;
|
||||
j < static_cast<WaterPhysicsAction *>(body.action)
|
||||
->mManifoldArray.size();
|
||||
j++) {
|
||||
btPersistentManifold *manifold =
|
||||
static_cast<WaterPhysicsAction *>(
|
||||
body.action)
|
||||
->mManifoldArray[j];
|
||||
std::cout << "contacts: "
|
||||
<< manifold->getNumContacts() << "\n";
|
||||
if (manifold->getNumContacts() == 0)
|
||||
continue;
|
||||
const btCollisionObject *obj =
|
||||
(manifold->getBody0() ==
|
||||
body.mWaterBody) ?
|
||||
manifold->getBody1() :
|
||||
manifold->getBody0();
|
||||
btCollisionObject *nobj =
|
||||
const_cast<btCollisionObject *>(obj);
|
||||
#if 0
|
||||
if (obj->getCollisionFlags() &
|
||||
btCollisionObject::CF_STATIC_OBJECT)
|
||||
continue;
|
||||
#endif
|
||||
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;
|
||||
body.count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::set<btCollisionObject *>::iterator 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);
|
||||
body.count--;
|
||||
} else
|
||||
it++;
|
||||
}
|
||||
#endif
|
||||
});
|
||||
#endif
|
||||
}
|
||||
struct shapeParams {
|
||||
float offsetX, offsetY, offsetZ;
|
||||
@@ -698,38 +439,6 @@ struct shapeParams {
|
||||
static struct shapeParams childShapes[] = {
|
||||
{ 0.0f, 0.0f, 0.0f, 100.0f, 100.0f, 100.0f },
|
||||
};
|
||||
#if 0
|
||||
void WaterModule::createWaterShape(WaterBody *water)
|
||||
{
|
||||
int i = 0;
|
||||
btCompoundShape *shape = OGRE_NEW btCompoundShape();
|
||||
shape->setMargin(0.2f);
|
||||
{
|
||||
btVector3 inertia(0, 0, 0);
|
||||
std::vector<btScalar> masses;
|
||||
btTransform principal;
|
||||
principal.setIdentity();
|
||||
for (i = 0; i < sizeof(childShapes) / sizeof(childShapes[0]);
|
||||
i++) {
|
||||
btTransform xform;
|
||||
xform.setIdentity();
|
||||
xform.setOrigin(btVector3(childShapes[i].offsetX,
|
||||
childShapes[i].offsetY,
|
||||
childShapes[i].offsetZ));
|
||||
btBoxShape *box = OGRE_NEW btBoxShape(btVector3(
|
||||
childShapes[i].boxX, childShapes[i].boxY,
|
||||
childShapes[i].boxZ));
|
||||
water->mChildShapes.push_back(box);
|
||||
shape->addChildShape(xform, box);
|
||||
masses.push_back(0);
|
||||
}
|
||||
shape->calculatePrincipalAxisTransform(masses.data(), principal,
|
||||
inertia);
|
||||
}
|
||||
shape->recalculateLocalAabb();
|
||||
water->mWaterShape = shape;
|
||||
}
|
||||
#endif
|
||||
void WaterSurface::RenderTextureListener::preRenderTargetUpdate(
|
||||
const Ogre::RenderTargetEvent &evt)
|
||||
{
|
||||
@@ -758,254 +467,4 @@ bool WaterSurface::RenderTextureListener::renderableQueued(
|
||||
*ppTech = mSurface->mDepthTech;
|
||||
return true;
|
||||
}
|
||||
#if 0
|
||||
struct DeepPenetrationContactResultCallback : public btManifoldResult {
|
||||
DeepPenetrationContactResultCallback(
|
||||
const btCollisionObjectWrapper *body0Wrap,
|
||||
const btCollisionObjectWrapper *body1Wrap)
|
||||
: btManifoldResult(body0Wrap, body1Wrap)
|
||||
, mPenetrationDistance(0)
|
||||
, mOtherIndex(0)
|
||||
{
|
||||
}
|
||||
float mPenetrationDistance;
|
||||
int mOtherIndex;
|
||||
btVector3 mNormal, mPoint;
|
||||
void reset()
|
||||
{
|
||||
mPenetrationDistance = 0.0f;
|
||||
}
|
||||
bool hasHit()
|
||||
{
|
||||
return mPenetrationDistance < 0.0f;
|
||||
}
|
||||
virtual void addContactPoint(const btVector3 &normalOnBInWorld,
|
||||
const btVector3 &pointInWorldOnB,
|
||||
btScalar depth)
|
||||
{
|
||||
#ifdef VDEBUG
|
||||
std::cout
|
||||
<< "contact: " << Ogre::Bullet::convert(pointInWorldOnB)
|
||||
<< " " << Ogre::Bullet::convert(normalOnBInWorld)
|
||||
<< "\n";
|
||||
#endif
|
||||
if (mPenetrationDistance > depth) { // Has penetration?
|
||||
|
||||
const bool isSwapped =
|
||||
m_manifoldPtr->getBody0() !=
|
||||
m_body0Wrap->getCollisionObject();
|
||||
mPenetrationDistance = depth;
|
||||
mOtherIndex = isSwapped ? m_index0 : m_index1;
|
||||
mPoint = isSwapped ? (pointInWorldOnB +
|
||||
(normalOnBInWorld * depth)) :
|
||||
pointInWorldOnB;
|
||||
|
||||
mNormal = isSwapped ? normalOnBInWorld * -1 :
|
||||
normalOnBInWorld;
|
||||
}
|
||||
}
|
||||
};
|
||||
void WaterPhysicsAction::updateAction(btCollisionWorld *collisionWorld,
|
||||
btScalar deltaTimeStep)
|
||||
{
|
||||
collisionWorld->updateSingleAabb(mWaterBody);
|
||||
mWaterBody->getCollisionShape()->getAabb(
|
||||
mWaterBody->getWorldTransform(), mShapeAabbMin, mShapeAabbMax);
|
||||
btDispatcher *dispatch = collisionWorld->getDispatcher();
|
||||
btHashedOverlappingPairCache *cache =
|
||||
mWaterBody->getOverlappingPairCache();
|
||||
btBroadphasePairArray &collisionPairs =
|
||||
cache->getOverlappingPairArray();
|
||||
btVector3 a, b;
|
||||
collisionWorld->getBroadphase()->getAabb(
|
||||
mWaterBody->getBroadphaseHandle(), a, b);
|
||||
collisionWorld->getBroadphase()->setAabb(
|
||||
mWaterBody->getBroadphaseHandle(), mShapeAabbMin, mShapeAabbMax,
|
||||
dispatch);
|
||||
btDispatcherInfo &dispatchInfo = collisionWorld->getDispatchInfo();
|
||||
dispatch->dispatchAllCollisionPairs(cache, dispatchInfo, dispatch);
|
||||
std::set<btCollisionObject *> currentOverlaps;
|
||||
std::set<btCollisionObject *>::iterator it;
|
||||
const int numObjects = collisionPairs.size();
|
||||
#ifdef VDEBUG
|
||||
std::cout << "collision pairs: " << numObjects << "\n";
|
||||
std::cout << "MIN: " << Ogre::Bullet::convert(mShapeAabbMin) << "\n";
|
||||
std::cout << "MAX: " << Ogre::Bullet::convert(mShapeAabbMax) << "\n";
|
||||
std::cout << "MIN: " << Ogre::Bullet::convert(a) << "\n";
|
||||
std::cout << "MAX: " << Ogre::Bullet::convert(b) << "\n";
|
||||
#endif
|
||||
std::set<const btCollisionObject *> mCurrentInWater;
|
||||
/* perform narrow phase */
|
||||
for (int i = 0; i < numObjects; i++) {
|
||||
int j;
|
||||
const btBroadphasePair *collisionPairPtr =
|
||||
collisionWorld->getBroadphase()
|
||||
->getOverlappingPairCache()
|
||||
->findPair(collisionPairs[i].m_pProxy0,
|
||||
collisionPairs[i].m_pProxy1);
|
||||
if (!collisionPairPtr)
|
||||
continue;
|
||||
#ifndef USE_MANIFOLD
|
||||
const btBroadphasePair &collisionPair = *collisionPairPtr;
|
||||
const btCollisionObject *objA =
|
||||
static_cast<btCollisionObject *>(
|
||||
collisionPair.m_pProxy0->m_clientObject);
|
||||
const btCollisionObject *objB =
|
||||
static_cast<btCollisionObject *>(
|
||||
collisionPair.m_pProxy1->m_clientObject);
|
||||
#ifdef VDEBUG
|
||||
std::cout << "bodies: " << objA << " " << objB << "\n";
|
||||
std::cout << "bodies: " << objA->getCollisionShape()->getName()
|
||||
<< " " << objB->getCollisionShape()->getName()
|
||||
<< "\n";
|
||||
std::cout << "pair: " << i << " " << collisionPair.m_algorithm
|
||||
<< "\n";
|
||||
#endif
|
||||
const btCollisionObject *me, *other;
|
||||
if (objA == static_cast<btCollisionObject *>(mWaterBody)) {
|
||||
me = objA;
|
||||
other = objB;
|
||||
} else {
|
||||
me = objB;
|
||||
other = objA;
|
||||
}
|
||||
const btCollisionShape *my_shape = me->getCollisionShape();
|
||||
const btCollisionShape *other_shape =
|
||||
other->getCollisionShape();
|
||||
btCollisionObjectWrapper obA(NULL, my_shape, mWaterBody,
|
||||
mWaterBody->getWorldTransform(),
|
||||
-1, j);
|
||||
btCollisionObjectWrapper obB(NULL, other_shape, other,
|
||||
other->getWorldTransform(), -1, 0);
|
||||
btCollisionAlgorithm *algorithm = dispatch->findAlgorithm(
|
||||
&obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS);
|
||||
#else
|
||||
btCollisionAlgorithm *algorithm = collisionPairPtr->m_algorithm;
|
||||
OgreAssert(algorithm, "No algorithm found");
|
||||
#endif
|
||||
#ifdef VDEBUG
|
||||
std::cout << "algorithm: " << algorithm << "\n";
|
||||
#endif
|
||||
#ifndef USE_MANIFOLD
|
||||
DeepPenetrationContactResultCallback contactPointResult(&obA,
|
||||
&obB);
|
||||
#ifdef VDEBUG
|
||||
std::cout << "process collision\n";
|
||||
#endif
|
||||
algorithm->processCollision(&obA, &obB,
|
||||
collisionWorld->getDispatchInfo(),
|
||||
&contactPointResult);
|
||||
algorithm->~btCollisionAlgorithm();
|
||||
dispatch->freeCollisionAlgorithm(algorithm);
|
||||
if (contactPointResult.hasHit()) {
|
||||
mCurrentInWater.insert(other);
|
||||
mInWater.insert(other);
|
||||
}
|
||||
#ifdef VDEBUG
|
||||
std::cout << "process collision done\n";
|
||||
#endif
|
||||
#else
|
||||
if (collisionPairPtr->m_algorithm)
|
||||
collisionPairPtr->m_algorithm->getAllContactManifolds(
|
||||
mManifoldArray);
|
||||
std::cout << "action: manifold: " << mManifoldArray.size()
|
||||
<< "\n";
|
||||
#endif
|
||||
#if 0
|
||||
std::cout << " "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy0->m_aabbMin)
|
||||
<< " -> "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy0->m_aabbMax)
|
||||
<< " VS "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy1->m_aabbMin)
|
||||
<< " -> "
|
||||
<< Ogre::Bullet::convert(
|
||||
collisionPair.m_pProxy1->m_aabbMax)
|
||||
<< "\n";
|
||||
std::cout << "group: 0 " << std::dec
|
||||
<< collisionPair.m_pProxy0->m_collisionFilterGroup
|
||||
<< "mask: " << std::hex
|
||||
<< collisionPair.m_pProxy0->m_collisionFilterMask
|
||||
<< "\n";
|
||||
std::cout << "group: 1 " << std::dec
|
||||
<< collisionPair.m_pProxy1->m_collisionFilterGroup
|
||||
<< "mask: " << std::hex
|
||||
<< collisionPair.m_pProxy1->m_collisionFilterMask
|
||||
<< std::dec << "\n";
|
||||
if (collisionPair.m_algorithm)
|
||||
collisionPair.m_algorithm->getAllContactManifolds(
|
||||
mManifoldArray);
|
||||
std::cout << "action: manifold: " << mManifoldArray.size()
|
||||
<< "\n";
|
||||
#endif
|
||||
#ifdef USE_MANIFOLD
|
||||
for (int j = 0; j < mManifoldArray.size(); j++) {
|
||||
btPersistentManifold *manifold = mManifoldArray[j];
|
||||
std::cout << "contacts: " << manifold->getNumContacts()
|
||||
<< "\n";
|
||||
if (manifold->getNumContacts() == 0)
|
||||
continue;
|
||||
const btCollisionObject *obj =
|
||||
(manifold->getBody0() == mWaterBody) ?
|
||||
manifold->getBody1() :
|
||||
manifold->getBody0();
|
||||
btCollisionObject *nobj =
|
||||
const_cast<btCollisionObject *>(obj);
|
||||
#if 1
|
||||
if (obj->getCollisionFlags() &
|
||||
btCollisionObject::CF_STATIC_OBJECT)
|
||||
continue;
|
||||
#endif
|
||||
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 (mInWater.find(nobj) == mInWater.end()) {
|
||||
/* new body */
|
||||
mInWater.insert(nobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
for (std::set<const btCollisionObject *>::iterator it =
|
||||
mInWater.begin();
|
||||
it != mInWater.end();) {
|
||||
const btCollisionObject *obj = *it;
|
||||
if (mCurrentInWater.find(obj) == mCurrentInWater.end()) {
|
||||
/* remove body */
|
||||
it = mInWater.erase(it);
|
||||
} else
|
||||
it++;
|
||||
}
|
||||
#ifdef VDEBUG
|
||||
std::cout << "water count: " << mInWater.size() << "\n";
|
||||
#endif
|
||||
}
|
||||
void WaterPhysicsAction::debugDraw(btIDebugDraw *debugDrawer)
|
||||
{
|
||||
}
|
||||
void WaterPhysicsAction::setupBody()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
bool WaterBody::isInWater(const btCollisionObject *body) const
|
||||
{
|
||||
return static_cast<WaterPhysicsAction *>(action)->isInWater(body);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -3,6 +3,7 @@ find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG
|
||||
find_package(Bullet REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(OgreProcedural REQUIRED CONFIG)
|
||||
find_package(flecs REQUIRED CONFIG)
|
||||
add_library(items STATIC items.cpp harbour.cpp temple.cpp town.cpp)
|
||||
target_include_directories(items PUBLIC . ${CMAKE_SOURCE_DIR}/src/FastNoiseLite)
|
||||
target_link_libraries(items PRIVATE
|
||||
@@ -13,4 +14,5 @@ target_link_libraries(items PRIVATE
|
||||
OgreBites
|
||||
editor
|
||||
physics
|
||||
Tracy::TracyClient
|
||||
)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "CharacterAIModule.h"
|
||||
#include "items.h"
|
||||
#include "town.h"
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
/*
|
||||
* TODO: Create doors and handle them via script.
|
||||
@@ -3363,6 +3364,7 @@ struct TownPlazza : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScopedN("createTownPlazza");
|
||||
struct QueueData {
|
||||
Procedural::TriangleBuffer tb;
|
||||
Ogre::Vector3 position;
|
||||
@@ -3460,6 +3462,8 @@ struct TownPlazza : TownTask {
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([queueData, localPosition,
|
||||
localRotation]() {
|
||||
ZoneScopedN(
|
||||
"createTownPlazza::MainThread");
|
||||
Ogre::Vector3 worldPlazzaCenter =
|
||||
queueData->position +
|
||||
localPosition;
|
||||
@@ -3504,6 +3508,7 @@ struct TownLots : TownTask {
|
||||
int index, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScopedN("createTownLots");
|
||||
struct QueueData {
|
||||
Procedural::TriangleBuffer tb;
|
||||
Ogre::Vector3 position;
|
||||
@@ -3647,6 +3652,8 @@ struct TownLots : TownTask {
|
||||
Ogre::Root::getSingleton()
|
||||
.getWorkQueue()
|
||||
->addMainThreadTask([promise, radius]() {
|
||||
ZoneScopedN(
|
||||
"createTownLots::MainThread");
|
||||
float distance = radius;
|
||||
for (auto &lot : lots) {
|
||||
std::cout
|
||||
@@ -3877,6 +3884,7 @@ struct TownCells : TownTask {
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([radius,
|
||||
baseHeight,
|
||||
promise]() {
|
||||
ZoneScopedN("createCells::MainThread");
|
||||
int count = 0;
|
||||
for (auto &lot : lots) {
|
||||
float distance = radius;
|
||||
@@ -4803,6 +4811,7 @@ struct TownRoofs : TownTask {
|
||||
}
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([radius,
|
||||
promise]() {
|
||||
ZoneScopedN("createTownRoofs::MainThread");
|
||||
{
|
||||
int count = 0;
|
||||
for (auto lot : lots) {
|
||||
@@ -5862,6 +5871,7 @@ void registerTownNPCs(flecs::entity e)
|
||||
void createTown(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
Ogre::StaticGeometry *geo)
|
||||
{
|
||||
ZoneScopedN("createTown");
|
||||
std::cout << "createTown " << e.id() << std::endl;
|
||||
Ogre::MaterialPtr townMaterial = createTownMaterial(e);
|
||||
static std::vector<TownTask *> townTasks;
|
||||
@@ -5924,6 +5934,7 @@ void createTown(flecs::entity e, Ogre::SceneNode *sceneNode,
|
||||
m->wait();
|
||||
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask(
|
||||
[geo]() {
|
||||
ZoneScopedN("createTown::MainThread");
|
||||
for (auto m : townTasks) {
|
||||
delete m;
|
||||
}
|
||||
|
||||
@@ -1510,6 +1510,19 @@ public:
|
||||
}
|
||||
return hadHit;
|
||||
}
|
||||
bool bodyIsCharacter(JPH::BodyID id) const
|
||||
{
|
||||
return characterBodies.find(id) != characterBodies.end();
|
||||
}
|
||||
void destroyCharacter(JPH::Character *ch)
|
||||
{
|
||||
characterBodies.erase(characterBodies.find(ch->GetBodyID()));
|
||||
characters.erase(ch);
|
||||
Ogre::SceneNode *node = id2node[ch->GetBodyID()];
|
||||
id2node.erase(ch->GetBodyID());
|
||||
node2id.erase(node);
|
||||
OGRE_DELETE ch;
|
||||
}
|
||||
};
|
||||
|
||||
void physics()
|
||||
@@ -1806,5 +1819,15 @@ bool JoltPhysicsWrapper::raycastQuery(Ogre::Vector3 startPoint,
|
||||
{
|
||||
return phys->raycastQuery(startPoint, endPoint, position, id);
|
||||
}
|
||||
|
||||
bool JoltPhysicsWrapper::bodyIsCharacter(JPH::BodyID id) const
|
||||
{
|
||||
return phys->bodyIsCharacter(id);
|
||||
}
|
||||
|
||||
void JoltPhysicsWrapper::destroyCharacter(JPH::Character *ch)
|
||||
{
|
||||
phys->destroyCharacter(ch);
|
||||
}
|
||||
template <>
|
||||
JoltPhysicsWrapper *Ogre::Singleton<JoltPhysicsWrapper>::msSingleton = 0;
|
||||
|
||||
@@ -14,6 +14,7 @@ void physics();
|
||||
namespace JPH
|
||||
{
|
||||
class CharacterBase;
|
||||
class Character;
|
||||
class ContactManifold;
|
||||
class ContactSettings;
|
||||
class SubShapeIDPair;
|
||||
@@ -217,5 +218,7 @@ public:
|
||||
void removeContactListener(const JPH::BodyID &id);
|
||||
bool raycastQuery(Ogre::Vector3 startPoint, Ogre::Vector3 endPoint,
|
||||
Ogre::Vector3 &position, JPH::BodyID &id);
|
||||
bool bodyIsCharacter(JPH::BodyID id) const;
|
||||
void destroyCharacter(JPH::Character *ch);
|
||||
};
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user