This commit is contained in:
2025-09-16 20:38:29 +03:00
parent 1aa002d8ba
commit 190318e5c4
20 changed files with 925 additions and 243 deletions

View File

@@ -1,5 +1,5 @@
project(gamedata)
find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG)
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp GUIModule.cpp)
target_link_libraries(GameData PUBLIC OgreMain OgreBites OgreBullet OgrePaging OgreTerrain OgreOverlay flecs::flecs_static)
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp GUIModule.cpp LuaData.cpp WorldMapModule.cpp)
target_link_libraries(GameData PUBLIC OgreMain OgreBites OgreBullet OgrePaging OgreTerrain OgreOverlay flecs::flecs_static lua)
target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -97,7 +97,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
Ogre::ANIMBLEND_CUMULATIVE);
Ogre::String
animNames[AnimationControl::NUM_ANIMS] = {
"idle", "walking", "running"
"idle", "walking", "running",
"treading_water", "swimming"
};
for (i = 0; i < AnimationControl::NUM_ANIMS;
i++) {
@@ -165,11 +166,11 @@ CharacterModule::CharacterModule(flecs::world &ecs)
if (anim.currentAnim != anim.nextAnim)
setAnimation(anim);
});
ecs.system<EngineData, CharacterBase, AnimationControl>(
"HandleAnimations1")
ecs.system<const EngineData, const Input, CharacterBase,
AnimationControl>("HandleAnimations1")
.kind(flecs::OnUpdate)
.each([this](EngineData &eng, CharacterBase &ch,
AnimationControl &anim) {
.each([this](const EngineData &eng, const Input &input,
CharacterBase &ch, AnimationControl &anim) {
float delta = eng.delta;
Ogre::Real animSpeed = 1;
if (anim.currentAnim != AnimationControl::ANIM_NONE) {
@@ -177,6 +178,11 @@ CharacterModule::CharacterModule(flecs::world &ecs)
AnimationControl::ANIM_WALK)
anim.mAnims[anim.currentAnim]->addTime(
delta * 1.0f);
else if (anim.currentAnim ==
AnimationControl::ANIM_SWIMMING &&
input.fast)
anim.mAnims[anim.currentAnim]->addTime(
delta * 20.0f);
else
anim.mAnims[anim.currentAnim]->addTime(
delta * animSpeed);
@@ -186,6 +192,24 @@ CharacterModule::CharacterModule(flecs::world &ecs)
return;
ch.mBoneMotion = ch.mRootBone->getPosition();
});
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;
});
ecs.system<const EngineData, const CharacterBase, CharacterVelocity>(
"HandleGravity")
.kind(flecs::OnUpdate)
@@ -222,6 +246,24 @@ CharacterModule::CharacterModule(flecs::world &ecs)
}
gr.gvelocity *= 0.99;
});
ecs.system<const EngineData, const AnimationControl,
const CharacterBase, CharacterVelocity>("HandleSwimming")
.kind(flecs::OnUpdate)
.with<TerrainReady>()
.with<WaterReady>()
.each([this](flecs::entity e, const EngineData &eng,
const AnimationControl &anim,
const CharacterBase &ch, CharacterVelocity &gr) {
if (anim.currentAnim ==
AnimationControl::ANIM_SWIMMING) {
float h = Ogre::Math::Clamp(
0.2f - ch.mBodyNode->getPosition().y,
0.0f, 2000.0f);
if (h > 0.2 && h < 2.0f)
gr.gvelocity.y += 1.2 * (h + 1.0f) * h *
eng.delta;
}
});
ecs.system<const EngineData, const CharacterBase, CharacterVelocity>(
"HandleRootMotionVelocity")
.kind(flecs::OnUpdate)
@@ -287,34 +329,72 @@ CharacterModule::CharacterModule(flecs::world &ecs)
}
}
});
ecs.system<const Input, AnimationControl>("HandlePlayerAnimations")
ecs.system<const Input, const CharacterBase, AnimationControl>(
"HandlePlayerAnimations")
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.each([](const Input &input, AnimationControl &anim) {
.each([](flecs::entity e, const Input &input,
const CharacterBase &ch, AnimationControl &anim) {
if (!anim.configured)
return;
bool controls_idle = input.motion.zeroLength();
bool anim_is_idle = anim.currentAnim ==
AnimationControl::ANIM_IDLE;
bool anim_is_idle =
anim.currentAnim ==
AnimationControl::ANIM_IDLE ||
anim.currentAnim ==
AnimationControl::ANIM_TREADING_WATER;
bool anim_is_walking = anim.currentAnim ==
AnimationControl::ANIM_WALK;
bool anim_is_running = anim.currentAnim ==
AnimationControl::ANIM_RUN;
bool anim_is_swimming = anim.currentAnim ==
AnimationControl::ANIM_SWIMMING;
bool anim_is_motion = anim_is_walking ||
anim_is_running;
anim_is_running ||
anim_is_swimming;
if (controls_idle) {
if (anim.currentAnim ==
AnimationControl::ANIM_IDLE &&
ch.is_submerged)
anim.nextAnim = AnimationControl::
ANIM_TREADING_WATER;
else if (anim.currentAnim ==
AnimationControl::
ANIM_TREADING_WATER &&
!ch.is_submerged)
anim.nextAnim =
AnimationControl::ANIM_IDLE;
}
if (!controls_idle && anim_is_idle) {
anim.reset = true;
if (input.fast)
anim.nextAnim =
AnimationControl::ANIM_RUN;
else
anim.nextAnim =
AnimationControl::ANIM_WALK;
if (ch.is_submerged) {
if (input.fast)
anim.nextAnim =
AnimationControl::
ANIM_SWIMMING;
else
anim.nextAnim =
AnimationControl::
ANIM_SWIMMING;
} else {
if (input.fast)
anim.nextAnim =
AnimationControl::ANIM_RUN;
else
anim.nextAnim =
AnimationControl::
ANIM_WALK;
}
} else
anim.reset = false;
if (controls_idle && anim_is_motion)
anim.nextAnim = AnimationControl::ANIM_IDLE;
if (ch.is_submerged)
anim.nextAnim = AnimationControl::
ANIM_TREADING_WATER;
else
anim.nextAnim =
AnimationControl::ANIM_IDLE;
else if (!controls_idle && anim_is_motion) {
if (input.fast && anim_is_walking)
anim.nextAnim =
@@ -322,20 +402,42 @@ CharacterModule::CharacterModule(flecs::world &ecs)
else if (!input.fast && anim_is_running)
anim.nextAnim =
AnimationControl::ANIM_WALK;
if ((anim_is_walking || anim_is_running) &&
ch.is_submerged) {
if (input.fast)
anim.nextAnim =
AnimationControl::
ANIM_SWIMMING;
else
anim.nextAnim =
AnimationControl::
ANIM_SWIMMING;
} else if ((anim_is_swimming) &&
!ch.is_submerged) {
if (input.fast)
anim.nextAnim =
AnimationControl::ANIM_RUN;
else
anim.nextAnim =
AnimationControl::
ANIM_WALK;
}
}
});
ecs.system<const EngineData, CharacterBase, CharacterBody>(
"UpdateCharacterBase")
ecs.system<const EngineData, CharacterLocation, CharacterBase,
CharacterBody>("UpdateCharacterBase")
.kind(flecs::OnUpdate)
.with<Character>()
.each([](const EngineData &eng, CharacterBase &ch,
CharacterBody &body) {
.each([](const EngineData &eng, CharacterLocation &loc,
CharacterBase &ch, CharacterBody &body) {
if (!ch.mBodyNode) {
body.mController = nullptr;
ch.mBodyEnt = eng.mScnMgr->createEntity(
"normal-male.glb");
ch.mBodyNode = eng.mScnMgr->getRootSceneNode()
->createChildSceneNode();
ch.mBodyNode->setOrientation(loc.orientation);
ch.mBodyNode->setPosition(loc.position);
ch.mBodyNode->attachObject(ch.mBodyEnt);
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
body.mGhostObject =
@@ -385,6 +487,11 @@ CharacterModule::CharacterModule(flecs::world &ecs)
"No root bone");
ch.mRootBone = ch.mSkeleton->getBone("Root");
OgreAssert(ch.mRootBone, "No root bone");
} else {
loc.orientation =
ch.mBodyNode->_getDerivedOrientation();
loc.position =
ch.mBodyNode->_getDerivedPosition();
}
});
ecs.system<const EngineData, CharacterBase, CharacterBody>(
@@ -592,16 +699,6 @@ CharacterModule::CharacterModule(flecs::world &ecs)
<< "\n";
});
#endif
/* Create player */
player = ecs.entity("player");
player.set<AnimationControl>({ AnimationControl::ANIM_NONE,
AnimationControl::ANIM_NONE, false,
false });
player.set<CharacterBase>(
{ "normal-male.glb", 0.0f, nullptr, nullptr, nullptr });
player.set<CharacterBody>({ nullptr, nullptr, nullptr, false, false });
player.add<Character>();
player.add<Player>();
}
void CharacterModule::setAnimation(AnimationControl &anim)

View File

@@ -16,6 +16,11 @@ struct CharacterBase {
Ogre::Node *mRootBone;
Ogre::Vector3 mBoneMotion;
Ogre::Vector3 mGoalDirection; // actual intended direction in world-space
bool is_submerged;
};
struct CharacterLocation {
Ogre::Quaternion orientation;
Ogre::Vector3 position;
};
struct CharacterBody {
btPairCachingGhostObject *mGhostObject;
@@ -33,6 +38,8 @@ struct AnimationControl {
ANIM_IDLE = 0,
ANIM_WALK,
ANIM_RUN,
ANIM_TREADING_WATER,
ANIM_SWIMMING,
NUM_ANIMS,
ANIM_NONE = NUM_ANIMS
};
@@ -48,7 +55,6 @@ struct AnimationControl {
Ogre::NodeAnimationTrack *mRootTracks[NUM_ANIMS];
};
struct CharacterModule {
flecs::entity player;
CharacterModule(flecs::world &ecs);
void setAnimation(AnimationControl &anim);
void fadeAnimations(AnimationControl &anim, Ogre::Real deltaTime);

View File

@@ -7,8 +7,10 @@
#include <OgreSceneNode.h>
#include <OgreApplicationContext.h>
#include <OgreImGuiInputListener.h>
#include <OgreFontManager.h>
#include "GameData.h"
#include "Components.h"
#include "LuaData.h"
#include "GUIModule.h"
namespace ECS
{
@@ -20,6 +22,50 @@ struct GUIData {
};
struct GUIListener : public Ogre::RenderTargetListener {
float panel_width;
bool enableEditor;
bool enableMapEditor;
ImFont *smallFont, *midFont, *bigFont;
Ogre::FontPtr _smallFont, _midFont, _bigFont;
GUIListener()
: Ogre::RenderTargetListener()
{
_midFont = createFont("midFont", "General",
"Jupiteroid-Regular.ttf", 18.0f);
_smallFont = createFont("smallFont", "General",
"Jupiteroid-Regular.ttf", 13.0f);
_bigFont = createFont("bigFont", "General", "Kenney Bold.ttf",
32.0f);
smallFont = ECS::get<GUIData>().mGuiOverlay->addFont(
"smallFont", "General");
OgreAssert(smallFont, "Could not load font");
midFont = ECS::get<GUIData>().mGuiOverlay->addFont("midFont",
"General");
OgreAssert(midFont, "Could not load font");
bigFont = ECS::get<GUIData>().mGuiOverlay->addFont("bigFont",
"General");
OgreAssert(bigFont, "Could not load font");
#if 0
Ogre::FontPtr _midFont = createFont("midFont", "General",
"Kenney Bold.ttf", 28.0f);
#endif
#if 0
ImGui::GetIO().Fonts->Build();
#endif
}
Ogre::FontPtr createFont(const Ogre::String &name,
const Ogre::String &group,
const Ogre::String &ttfname, float fontSize)
{
Ogre::FontPtr ret =
Ogre::FontManager::getSingleton().create(name, group);
ret->setType(Ogre::FontType::FT_TRUETYPE);
ret->setSource(ttfname);
ret->setTrueTypeSize(fontSize);
ret->setTrueTypeResolution(75);
ret->addCodePointRange(Ogre::Font::CodePointRange(30, 128));
ret->load();
return ret;
}
void
preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override
{
@@ -36,14 +82,24 @@ struct GUIListener : public Ogre::RenderTargetListener {
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
ImGuiCond_Always);
ImGui::Begin("Dumb and Stupid");
ImGui::Begin("Control");
// if (ECS::get().get<GUI>().enabled)
// ECS::get().get<App>().app->setWindowGrab(true);
if (ImGui::Button("Shitty Quit button"))
if (ImGui::Button("Quit"))
Ogre::Root::getSingleton().queueEndRendering();
if (ImGui::Button("Chick-chick"))
if (ImGui::Button("Return"))
ECS::get().get<GUI>().finish();
ImGui::Text("We do stoopid...");
if (ImGui::Button("Enable/Disable item editor")) {
enableEditor ^= true;
if (enableEditor)
enableMapEditor = false;
}
if (ImGui::Button("Enable/Disable map editor")) {
enableMapEditor ^= true;
if (enableMapEditor)
enableEditor = false;
}
ImGui::Text("Text message...");
ImGui::End();
}
void create_entity_node(const Ogre::String &name, int key)
@@ -140,6 +196,9 @@ struct GUIListener : public Ogre::RenderTargetListener {
ImGui::Text("Name: %s", pname.c_str());
}
}
void map_editor()
{
}
void preview(const Ogre::RenderTargetViewportEvent &evt)
{
int i;
@@ -161,118 +220,214 @@ struct GUIListener : public Ogre::RenderTargetListener {
ImGuiWindowFlags_NoInputs);
// if (ECS::get().get<GUI>().enabled)
// ECS::get().get<App>().app->setWindowGrab(true);
ImGui::Text(
ImGui::PushFont(bigFont);
ImGui::TextWrapped(
"%s",
"This game does not autosave. Please use save function to keep your state");
ImGui::PopFont();
ImGui::End();
}
if (ECS::get().get<GUI>().enabled) {
buttons_panel();
buildings_editor();
ImVec2 size = ImGui::GetMainViewport()->Size;
float window_width = size.x * 0.2f;
if (window_width > panel_width)
window_width = panel_width;
float window_height = size.y * 0.5f - 20;
ImGui::SetNextWindowPos(ImVec2(size.x - window_width,
size.y * 0.5f + 20),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width,
window_height),
ImGuiCond_Always);
// ImGui::Begin("Dumb and Stupid", &mKbd.gui_active);
ImGui::Begin("Panel...");
std::deque<Ogre::SceneNode *> tree_input_queue,
tree_output_queue;
std::vector<Ogre::SceneNode *> tree_list;
tree_input_queue.push_back(
ECS::get()
.get<EngineData>()
.mScnMgr->getRootSceneNode());
tree_input_queue.push_back(nullptr);
std::set<Ogre::SceneNode *> visited;
while (true) {
int new_nodes_count = 0;
while (!tree_input_queue.empty()) {
int child;
Ogre::SceneNode *item =
tree_input_queue.front();
tree_input_queue.pop_front();
if (item &&
visited.find(item) ==
visited.end()) { // new node
new_nodes_count++;
tree_output_queue.push_back(
item);
visited.insert(item);
const Ogre::Node::ChildNodeMap
&children =
item->getChildren();
for (child = 0;
child < children.size();
child++) {
tree_output_queue.push_back(
static_cast<
Ogre::SceneNode
*>(
children[child]));
} else if (ECS::get().get<GUI>().enabled) {
if (ECS::get().get<GUI>().narrationBox) {
ImVec2 size = ImGui::GetMainViewport()->Size;
ImGui::SetNextWindowPos(ImVec2(0,
size.y * 0.75f),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(size.x,
size.y * 0.25f),
ImGuiCond_Always);
ImGui::Begin("Narration...", NULL,
ImGuiWindowFlags_NoTitleBar);
ImGui::PushFont(midFont);
ImVec2 p = ImGui::GetCursorScreenPos();
ImGui::TextWrapped(
"%s", ECS::get()
.get<GUI>()
.narrationText.c_str());
ImGui::SetCursorScreenPos(p);
if (ImGui::InvisibleButton(
"Background",
ImGui::GetWindowSize()))
ECS::get<LuaBase>().mLua->call_handler(
"narration_progress");
ImGui::Spacing();
ImGui::PopFont();
ImGui::End();
} else if (ECS::get().get<GUI>().mainMenu) {
ImVec2 size = ImGui::GetMainViewport()->Size;
ImGui::SetNextWindowPos(ImVec2(0, 0),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(size.x, size.y),
ImGuiCond_Always);
ImGui::Begin(
"MainMenu", nullptr,
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoFocusOnAppearing |
0);
// if (ECS::get().get<GUI>().enabled)
// ECS::get().get<App>().app->setWindowGrab(true);
ImGui::PushFont(bigFont);
ImGui::TextWrapped("%s", "Booo!!!!");
bool pressed = false;
bool new_game = false, cont = false,
load_game = false, opts = false,
quit = false;
ImGui::SetCursorPosY(size.y / 2.0f - 300.0f);
ImGui::SetCursorPosX(size.x / 2.0f - 300.0f);
new_game = ImGui::Button("New Game");
ImGui::SetCursorPosX(size.x / 2.0f - 300.0f);
cont = ImGui::Button("Continue");
ImGui::SetCursorPosX(size.x / 2.0f - 300.0f);
load_game = ImGui::Button("Load Game");
ImGui::SetCursorPosX(size.x / 2.0f - 300.0f);
opts = ImGui::Button("Options");
ImGui::SetCursorPosX(size.x / 2.0f - 300.0f);
quit = ImGui::Button("Quit###quit");
pressed = new_game || cont || load_game ||
opts || quit;
ImGui::PopFont();
ImGui::Spacing();
ImGui::End();
if (quit)
Ogre::Root::getSingleton()
.queueEndRendering();
if (pressed)
ECS::get().get<GUI>().finish();
if (new_game) {
ECS::get<LuaBase>().mLua->call_handler(
"new_game");
}
} else {
buttons_panel();
if (enableEditor)
buildings_editor();
if (enableMapEditor)
map_editor();
ImVec2 size = ImGui::GetMainViewport()->Size;
float window_width = size.x * 0.2f;
if (window_width > panel_width)
window_width = panel_width;
float window_height = size.y * 0.5f - 20;
ImGui::SetNextWindowPos(
ImVec2(size.x - window_width,
size.y * 0.5f + 20),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width,
window_height),
ImGuiCond_Always);
// ImGui::Begin("Dumb and Stupid", &mKbd.gui_active);
ImGui::Begin("Panel...");
std::deque<Ogre::SceneNode *> tree_input_queue,
tree_output_queue;
std::vector<Ogre::SceneNode *> tree_list;
tree_input_queue.push_back(
ECS::get()
.get<EngineData>()
.mScnMgr->getRootSceneNode());
tree_input_queue.push_back(nullptr);
std::set<Ogre::SceneNode *> visited;
while (true) {
int new_nodes_count = 0;
while (!tree_input_queue.empty()) {
int child;
Ogre::SceneNode *item =
tree_input_queue.front();
tree_input_queue.pop_front();
if (item &&
visited.find(item) ==
visited.end()) { // new node
new_nodes_count++;
tree_output_queue
.push_back(
nullptr);
}
} else
tree_output_queue.push_back(
item);
item);
visited.insert(item);
const Ogre::Node::ChildNodeMap
&children =
item->getChildren();
for (child = 0;
child <
children.size();
child++) {
tree_output_queue
.push_back(static_cast<
Ogre::SceneNode
*>(
children[child]));
tree_output_queue
.push_back(
nullptr);
}
} else
tree_output_queue
.push_back(
item);
}
if (new_nodes_count == 0)
break;
tree_input_queue = tree_output_queue;
tree_output_queue.clear();
}
if (new_nodes_count == 0)
break;
tree_input_queue = tree_output_queue;
tree_output_queue.clear();
}
tree_list.insert(tree_list.begin(),
tree_output_queue.begin(),
tree_output_queue.end());
int count = 0;
int depth = 0;
std::vector<int> check_depth;
int max_depth = 0;
check_depth.push_back(0);
for (count = 0; count < tree_list.size(); count++) {
int t;
tree_list.insert(tree_list.begin(),
tree_output_queue.begin(),
tree_output_queue.end());
int count = 0;
int depth = 0;
std::vector<int> check_depth;
int max_depth = 0;
check_depth.push_back(0);
for (count = 0; count < tree_list.size();
count++) {
int t;
Ogre::SceneNode *node = tree_list[count];
if (node && max_depth >= depth) {
Ogre::String name = node->getName();
if (name.length() == 0) {
name = "Node #" +
Ogre::StringConverter::
toString(count);
Ogre::SceneNode *node =
tree_list[count];
if (node && max_depth >= depth) {
Ogre::String name =
node->getName();
if (name.length() == 0) {
name = "Node #" +
Ogre::StringConverter::
toString(
count);
}
if (ImGui::TreeNode(
name.c_str())) {
check_depth.push_back(
max_depth);
max_depth++;
ImGui::Text(
"%s",
(name +
"##caption")
.c_str());
position_editor(node);
ImGui::Separator();
orientation_editor(
node);
ImGui::Separator();
ImGui::Text(
"Attachments");
attachments_editor(
node);
}
} else if (!node &&
max_depth >= depth) {
max_depth = check_depth.back();
check_depth.pop_back();
ImGui::TreePop();
}
if (ImGui::TreeNode(name.c_str())) {
check_depth.push_back(
max_depth);
max_depth++;
ImGui::Text("%s",
(name + "##caption")
.c_str());
position_editor(node);
ImGui::Separator();
orientation_editor(node);
ImGui::Separator();
ImGui::Text("Attachments");
attachments_editor(node);
}
} else if (!node && max_depth >= depth) {
max_depth = check_depth.back();
check_depth.pop_back();
ImGui::TreePop();
if (tree_list[count])
depth++;
else
depth--;
}
if (tree_list[count])
depth++;
else
depth--;
ImGui::Spacing();
ImGui::End();
}
ImGui::Spacing();
ImGui::End();
}
}
};
@@ -293,7 +448,7 @@ GUIModule::GUIModule(flecs::world &ecs)
priv.mGuiOverlay = nullptr;
})
.add(flecs::Singleton);
ecs.set<GUI>({ false, true, false });
ecs.set<GUI>({ false, true, false, false, false });
ecs.set<GUIData>({ nullptr, {}, nullptr });
ui_wait =
ecs.system<const RenderWindow, App, GUIData>("SetupGUI")
@@ -311,9 +466,11 @@ GUIModule::GUIModule(flecs::world &ecs)
OgreAssert(app.mGuiOverlay,
"No ImGUI overlay");
gui.mGuiOverlay = app.mGuiOverlay;
gui.mGUIListener = new GUIListener();
gui.mGuiOverlay->setZOrder(300);
gui.mGuiOverlay->show();
gui.mGUIListener = new GUIListener();
gui.mGUIListener->panel_width = 300.0f;
gui.mGUIListener->enableEditor = false;
window.window->addListener(
gui.mGUIListener);
int i;

View File

@@ -10,6 +10,9 @@ struct GUI {
bool enabled;
bool grab;
bool grabChanged;
bool narrationBox;
bool mainMenu;
Ogre::String narrationText;
static void setWindowGrab(bool g = true)
{
ECS::GUI &gui = ECS::get().get_mut<ECS::GUI>();
@@ -23,6 +26,8 @@ struct GUI {
{
ECS::GUI &gui = ECS::get().get_mut<ECS::GUI>();
gui.enabled = false;
gui.mainMenu = false;
gui.narrationBox = false;
ECS::get().modified<ECS::GUI>();
setWindowGrab(true);
}

View File

@@ -7,10 +7,13 @@
#include "TerrainModule.h"
#include "SunModule.h"
#include "GUIModule.h"
#include "LuaData.h"
#include "WorldMapModule.h"
namespace ECS
{
static flecs::world ecs;
flecs::entity player;
void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
Ogre::SceneNode *cameraNode, Ogre::Camera *camera,
Ogre::RenderWindow *window)
@@ -37,6 +40,9 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
ecs.import <TerrainModule>();
ecs.import <SunModule>();
ecs.import <GUIModule>();
ecs.import <LuaModule>();
ecs.import <WorldMapModule>();
ecs.import <LuaModule>();
ecs.system<EngineData>("UpdateDelta")
.kind(flecs::OnUpdate)
.each([](EngineData &eng) {
@@ -84,6 +90,26 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
false,
{ 0, 0, 0 } });
std::cout << "Setup GameData done\n";
/* Create player */
player = ecs.entity("player");
Ogre::Vector3 playerPos(0, 0, 4);
player.set<CharacterLocation>({ { 0, 0, 0, 1 }, playerPos });
player.set<AnimationControl>({ AnimationControl::ANIM_NONE,
AnimationControl::ANIM_NONE, false,
false });
player.set<CharacterBase>({ "normal-male.glb",
0.0f,
nullptr,
nullptr,
nullptr,
nullptr,
{ 0, 0, 0 },
{ 0, 0, 0 },
false });
player.set<CharacterBody>({ nullptr, nullptr, nullptr, false, false });
player.add<Character>();
player.add<Player>();
}
void update(float delta)
{

View File

@@ -4,6 +4,7 @@
#include <flecs.h>
namespace ECS
{
extern flecs::entity player;
void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
Ogre::SceneNode *cameraNode, Ogre::Camera *camera,
Ogre::RenderWindow *window);

133
src/gamedata/LuaData.cpp Normal file
View File

@@ -0,0 +1,133 @@
#include "GameData.h"
#include "Components.h"
#include "GUIModule.h"
#include "LuaData.h"
namespace ECS
{
int LuaData::setup_handler()
{
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_pushvalue(L, 1);
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
setup_handlers.push_back(ref);
return 0;
}
int LuaData::call_handler(const Ogre::String &event)
{
int i;
for (i = 0; i < setup_handlers.size(); i++) {
lua_rawgeti(L, LUA_REGISTRYINDEX, setup_handlers[i]);
lua_pushstring(L, event.c_str());
lua_pcall(L, 1, 0, 0);
}
return 0;
}
LuaData::LuaData()
: L(luaL_newstate())
{
luaopen_base(L);
luaopen_package(L);
lua_pushcfunction(L, [](lua_State *L) -> int {
OgreAssert(false, "Crash function called");
return 0;
});
lua_setglobal(L, "crash");
lua_pushcfunction(L, [](lua_State *L) -> int {
luaL_checktype(L, 1, LUA_TFUNCTION);
ECS::get<LuaBase>().mLua->setup_handler();
return 0;
});
lua_setglobal(L, "setup_handler");
lua_pushcfunction(L, [](lua_State *L) -> int {
luaL_checktype(L, 1, LUA_TSTRING);
size_t len;
Ogre::String message(luaL_tolstring(L, 1, &len));
if (message.length() == 0 && ECS::get_mut<GUI>().narrationBox) {
ECS::get_mut<GUI>().enabled = false;
ECS::get_mut<GUI>().grab = true;
ECS::get_mut<GUI>().grabChanged = true;
ECS::get_mut<GUI>().narrationText = message;
ECS::get_mut<GUI>().narrationBox = false;
ECS::modified<GUI>();
} else {
std::replace(message.begin(), message.end(), '\n', ' ');
std::replace(message.begin(), message.end(), '\r', ' ');
std::cout << "narrator message: " << message
<< std::endl;
ECS::get_mut<GUI>().enabled = true;
ECS::get_mut<GUI>().grab = false;
ECS::get_mut<GUI>().grabChanged = true;
ECS::get_mut<GUI>().narrationText = message;
ECS::get_mut<GUI>().narrationBox = true;
ECS::modified<GUI>();
}
return 0;
});
lua_setglobal(L, "narrate");
lua_pushcfunction(L, [](lua_State *L) -> int {
// ECS::get_mut<GUI>().mainMenu = true;
ECS::get_mut<GUI>().enabled = true;
ECS::get_mut<GUI>().mainMenu = true;
ECS::get_mut<GUI>().grab = false;
ECS::get_mut<GUI>().grabChanged = true;
ECS::modified<GUI>();
return 0;
});
lua_setglobal(L, "main_menu");
}
LuaData::~LuaData()
{
lua_close(L);
}
void LuaData::lateSetup()
{
Ogre::DataStreamList streams =
Ogre::ResourceGroupManager::getSingleton().openResources(
"*.lua", "LuaScripts");
while (!streams.empty()) {
Ogre::DataStreamPtr s = streams.front();
std::cout << "stream: " << s->getAsString() << "\n";
streams.pop_front();
if (luaL_dostring(L, s->getAsString().c_str()) != LUA_OK) {
std::cout << "error: " << lua_tostring(L, -1) << "\n";
OgreAssert(false, "Script failure");
}
}
const char *lua_code = "\n\
function stuff()\n\
return 4\n\
end\n\
x = stuff()\n\
";
luaL_dostring(L, lua_code);
lua_getglobal(L, "x");
int x = lua_tonumber(L, 1);
std::cout << "lua: " << x << "\n";
}
LuaModule::LuaModule(flecs::world &ecs)
{
ecs.component<LuaBase>().add(flecs::Singleton);
ecs.set<LuaBase>({ OGRE_NEW LuaData, false, false });
ecs.system<const EngineData, LuaBase>("LuaUpdate")
.kind(flecs::OnUpdate)
.each([](const EngineData &eng, LuaBase &lua) {
if (!lua.setup_called) {
lua.mLua->lateSetup();
lua.mLua->call_handler("setup");
lua.setup_called = true;
}
if (!lua.startup_called) {
if (eng.startupDelay <= 0.0f) {
lua.mLua->call_handler("startup");
lua.startup_called = true;
}
}
});
}
}

29
src/gamedata/LuaData.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef LUA_DATA_H
#define LUA_DATA_H
#include "lua.hpp"
#include <iostream>
#include <Ogre.h>
#include <OgreSerializer.h>
#include <flecs.h>
namespace ECS
{
struct LuaData {
lua_State *L;
std::vector<int> setup_handlers;
int setup_handler();
int call_handler(const Ogre::String &event);
LuaData();
virtual ~LuaData();
void lateSetup();
};
struct LuaBase {
LuaData *mLua;
bool setup_called;
bool startup_called;
};
struct LuaModule {
LuaModule(flecs::world &ecs);
};
}
#endif

View File

@@ -31,77 +31,30 @@
namespace ECS
{
class FlatTerrainDefiner
: public Ogre::TerrainPagedWorldSection::TerrainDefiner,
public Ogre::FrameListener {
Ogre::SceneManager *mScnMgr;
Ogre::Bullet::DynamicsWorld *mWorld;
struct gen_collider {
Ogre::TerrainGroup *group;
long x;
long y;
};
std::deque<struct gen_collider> collider_queue;
Ogre::Image img, img_noise, img_brushes;
public:
FlatTerrainDefiner(Ogre::SceneManager *scm,
Ogre::Bullet::DynamicsWorld *world)
: Ogre::TerrainPagedWorldSection::TerrainDefiner()
, Ogre::FrameListener()
, mScnMgr(scm)
, mWorld(world)
#define BRUSH_SIZE 64
struct HeightData {
Ogre::Image img;
Ogre::Image img_brushes;
Ogre::Image img_noise;
static HeightData *singleton;
HeightData()
{
Ogre::Root::getSingleton().addFrameListener(this);
img.load(
"world_map.png",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
img_noise.load(
"terrain.png",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
img_brushes.load(
"brushes.png",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
img_noise.load(
"terrain.png",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
}
private:
float get_noise_height(const Ogre::Vector2 &worldOffset, int x, int y)
static HeightData *get_singleton()
{
int h;
Ogre::Vector2 noisePoint;
struct noise_types {
Ogre::Vector2 noiseOfft;
float noiseMul;
float noiseBias;
float noiseAmp;
};
static struct noise_types noise_pass[] = {
{ { -100.0f, 70.0f }, 10.2f, -0.55f, 5.0f },
{ { -130.0f, 55.0f }, 5.35f, -0.55f, 1.0f }
};
static float noise_values[] = { 0.0f, 0.0f };
for (h = 0; h < (int)sizeof(noise_values) /
(int)sizeof(noise_values[0]);
h++) {
noisePoint = (worldOffset + Ogre::Vector2(x, y) +
noise_pass[h].noiseOfft) *
noise_pass[h].noiseMul;
int noise_x =
(int)(noisePoint.x + img_noise.getWidth() / 2) %
img_noise.getWidth();
int noise_y = (int)(noisePoint.y +
img_noise.getHeight() / 2) %
img_noise.getHeight();
Ogre::ColourValue noise_color =
img_noise.getColourAt(noise_x, noise_y, 0);
noise_values[h] =
(noise_color.r + noise_pass[h].noiseBias) *
noise_pass[h].noiseAmp;
}
return noise_values[0] + noise_values[1];
if (!singleton)
singleton = new HeightData();
return singleton;
}
#define BRUSH_SIZE 64
float get_brush_height(int id, int x, int y)
{
int m = 0;
@@ -149,7 +102,96 @@ private:
out:
return height;
}
float get_noise_height(const Ogre::Vector2 &worldOffset, int x, int y)
{
int h;
Ogre::Vector2 noisePoint;
struct noise_types {
Ogre::Vector2 noiseOfft;
float noiseMul;
float noiseBias;
float noiseAmp;
};
static struct noise_types noise_pass[] = {
{ { -100.0f, 70.0f }, 10.2f, -0.55f, 5.0f },
{ { -130.0f, 55.0f }, 5.35f, -0.55f, 1.0f }
};
static float noise_values[] = { 0.0f, 0.0f };
for (h = 0; h < (int)sizeof(noise_values) /
(int)sizeof(noise_values[0]);
h++) {
noisePoint = (worldOffset + Ogre::Vector2(x, y) +
noise_pass[h].noiseOfft) *
noise_pass[h].noiseMul;
int noise_x =
(int)(noisePoint.x + img_noise.getWidth() / 2) %
img_noise.getWidth();
int noise_y = (int)(noisePoint.y +
img_noise.getHeight() / 2) %
img_noise.getHeight();
Ogre::ColourValue noise_color =
img_noise.getColourAt(noise_x, noise_y, 0);
noise_values[h] =
(noise_color.r + noise_pass[h].noiseBias) *
noise_pass[h].noiseAmp;
}
return noise_values[0] + noise_values[1];
}
float get_height(Ogre::TerrainGroup *terrainGroup, long x, long y,
int j, int i)
{
uint16_t terrainSize = terrainGroup->getTerrainSize();
Ogre::Vector2 worldOffset(Ogre::Real(x * (terrainSize - 1)),
Ogre::Real(y * (terrainSize - 1)));
float brush_height0 =
HeightData::get_singleton()->get_brush_height(
0, j % BRUSH_SIZE, i % BRUSH_SIZE) -
0.55f;
float brush_height1 =
HeightData::get_singleton()->get_brush_height(
1, j % BRUSH_SIZE, i % BRUSH_SIZE) -
0.55f;
float mheight =
Ogre::Math::lerp(
brush_height1, brush_height0,
HeightData::get_singleton()->get_base_height(
worldOffset, j, i)) *
120.0f;
float height = mheight;
if (mheight > 0.5f)
height += 2.0f + get_noise_height(worldOffset, j, i);
else if (mheight < -0.5f)
height -= 2.0f + get_noise_height(worldOffset, j, i);
return height;
}
};
HeightData *HeightData::singleton = nullptr;
class FlatTerrainDefiner
: public Ogre::TerrainPagedWorldSection::TerrainDefiner,
public Ogre::FrameListener {
Ogre::SceneManager *mScnMgr;
Ogre::Bullet::DynamicsWorld *mWorld;
struct gen_collider {
Ogre::TerrainGroup *group;
long x;
long y;
};
std::deque<struct gen_collider> collider_queue;
public:
FlatTerrainDefiner(Ogre::SceneManager *scm,
Ogre::Bullet::DynamicsWorld *world)
: Ogre::TerrainPagedWorldSection::TerrainDefiner()
, Ogre::FrameListener()
, mScnMgr(scm)
, mWorld(world)
{
Ogre::Root::getSingleton().addFrameListener(this);
}
private:
public:
void define(Ogre::TerrainGroup *terrainGroup, long x, long y) override
{
@@ -158,37 +200,15 @@ public:
MEMCATEGORY_GEOMETRY);
// float *heightMapCollider = OGRE_ALLOC_T(
// float, terrainSize *terrainSize, MEMCATEGORY_GEOMETRY);
Ogre::Vector2 worldOffset(Ogre::Real(x * (terrainSize - 1)),
Ogre::Real(y * (terrainSize - 1)));
Ogre::Vector2 worldOrigin =
Ogre::Vector2(img.getWidth(), img.getHeight()) * 0.5f;
// Ogre::Vector2 worldOrigin =
// Ogre::Vector2(img.getWidth(), img.getHeight()) * 0.5f;
float chunk = 128.0f;
Ogre::Vector2 revisedValuePoint;
for (int i = 0; i < terrainSize; i++)
for (int j = 0; j < terrainSize; j++) {
float brush_height0 =
get_brush_height(0, j % BRUSH_SIZE,
i % BRUSH_SIZE) -
0.55f;
float brush_height1 =
get_brush_height(1, j % BRUSH_SIZE,
i % BRUSH_SIZE) -
0.55f;
float mheight =
Ogre::Math::lerp(
brush_height1, brush_height0,
get_base_height(worldOffset, j,
i)) *
120.0f;
float height = mheight;
if (mheight > 0.5f)
height += 2.0f +
get_noise_height(worldOffset,
j, i);
else if (mheight < -0.5f)
height -= 2.0f +
get_noise_height(worldOffset,
j, i);
float height =
HeightData::get_singleton()->get_height(
terrainGroup, x, y, j, i);
// height = -2.0f;
heightMap[i * terrainSize + j] = height;
@@ -277,6 +297,26 @@ public:
created = true;
}
collider_queue.pop_front();
// FIXME: create entities and components instead
Ogre::SceneNode *items =
terrain->_getRootSceneNode()
->createChildSceneNode();
for (int i = 0; i < ECS::get<PlacementObjects>()
.altar_items.size();
i++) {
const struct PlacementObjects::item &item =
ECS::get<PlacementObjects>()
.altar_items[i];
Ogre::Entity *ent =
group->getSceneManager()
->createEntity(
item.entity);
Ogre::SceneNode *what =
items->createChildSceneNode();
what->attachObject(ent);
what->setOrientation(item.rotation);
what->setPosition(item.position);
}
} else {
output.push_back(collider_queue.front());
collider_queue.pop_front();
@@ -433,6 +473,7 @@ TerrainModule::TerrainModule(flecs::world &ecs)
terrain.mTerrainGroup->freeTemporaryResources();
std::cout << "Terrain setup done\n";
ECS::get().set<PlacementObjects>({});
}
if (sun.mSun &&
priv.mSunUpdate.getMilliseconds() > 1000) {
@@ -468,5 +509,113 @@ TerrainModule::TerrainModule(flecs::world &ecs)
ECS::get().add<TerrainReady>();
}
});
ecs.system<const Terrain, PlacementObjects>("UpdatePlacementObjects")
.kind(flecs::OnUpdate)
.each([](const Terrain &terrain, PlacementObjects &placement) {
if (placement.altar_items.size() == 0) {
struct PlacementObjects::item item;
int i, j;
int worldSize = terrain.mTerrainGroup
->getTerrainWorldSize();
uint16_t terrainSize =
terrain.mTerrainGroup->getTerrainSize();
item.entity = "altar.glb";
item.rotation = Ogre::Quaternion(0, 0, 0, 1);
item.position = Ogre::Vector3(0, 0, 0);
float height =
HeightData::get_singleton()->get_height(
terrain.mTerrainGroup, 0, 0, 0,
0);
item.position.y = height;
placement.altar_items.push_back(item);
for (i = -64000; i < 64000; i += 1000)
for (j = -64000; j < 64000; j += 1000) {
if (i == 0 && j == 0)
continue;
Ogre::Vector3 position(i, 0, j);
long xslot, yslot;
terrain.mTerrainGroup
->convertWorldPositionToTerrainSlot(
position,
&xslot, &yslot);
Ogre::Vector3 slotpos;
terrain.mTerrainGroup
->convertTerrainSlotToWorldPosition(
xslot, yslot,
&slotpos);
Ogre::Vector3 offset =
(position - slotpos) *
terrainSize / worldSize;
height =
HeightData::get_singleton()
->get_height(
terrain.mTerrainGroup,
xslot,
yslot,
(int)offset.x +
(terrainSize -
1) / 2,
(int)offset.z +
(terrainSize -
1) / 2);
#if 0
height =
terrain.mTerrainGroup
->getHeightAtWorldPosition(
position);
#endif
if (height > -9.0f)
continue;
std::cout << "worldSize: "
<< worldSize - 1
<< std::endl;
std::cout << "height: " << i
<< " " << j << " "
<< height
<< std::endl;
item.entity = "altar.glb";
item.rotation =
Ogre::Quaternion(0, 0,
0, 1);
position.y = height;
item.position = position;
placement.altar_items.push_back(
item);
}
for (i = 0; i < placement.altar_items.size();
i++) {
std::cout << "placement: " << i << " "
<< placement.altar_items[i]
.position
<< std::endl;
}
}
flecs::entity player = ECS::player;
CharacterLocation &loc =
player.get_mut<CharacterLocation>();
float height =
get_height(terrain.mTerrainGroup, loc.position);
loc.position.y = height + 0.0f;
player.get<CharacterBase>().mBodyNode->setPosition(
loc.position);
player.get<CharacterBase>().mBodyNode->setOrientation(
Ogre::Quaternion());
player.modified<CharacterLocation>();
});
}
float TerrainModule::get_height(Ogre::TerrainGroup *group,
const Ogre::Vector3 &position)
{
int worldSize = group->getTerrainWorldSize();
uint16_t terrainSize = group->getTerrainSize();
long xslot, yslot;
group->convertWorldPositionToTerrainSlot(position, &xslot, &yslot);
Ogre::Vector3 slotpos;
group->convertTerrainSlotToWorldPosition(xslot, yslot, &slotpos);
Ogre::Vector3 offset = (position - slotpos) * terrainSize / worldSize;
float height = HeightData::get_singleton()->get_height(
group, xslot, yslot, (int)offset.x + (terrainSize - 1) / 2,
(int)offset.z + (terrainSize - 1) / 2);
return height;
}
}

View File

@@ -23,8 +23,18 @@ struct Terrain {
Ogre::Vector3 mTerrainPos;
};
struct PlacementObjects {
struct item {
Ogre::String entity;
Ogre::Quaternion rotation;
Ogre::Vector3 position;
};
std::vector<struct item> altar_items;
};
struct TerrainModule {
TerrainModule(flecs::world &ecs);
static float get_height(Ogre::TerrainGroup *group,
const Ogre::Vector3 &position);
};
}
#endif

View File

@@ -0,0 +1,6 @@
#include "WorldMapModule.h"
ECS::WorldMapModule::WorldMapModule(flecs::world &ecs)
{
ecs.component<WorldMap>();
}

View File

@@ -0,0 +1,11 @@
#ifndef WORLD_MAP_MODULE_H
#define WORLD_MAP_MODULE_H
#include <flecs.h>
namespace ECS
{
struct WorldMap {};
struct WorldMapModule {
WorldMapModule(flecs::world &ecs);
};
}
#endif