Refactoring: split items

This commit is contained in:
2025-12-27 16:05:32 +03:00
parent d3c93c5c18
commit 5bb529bc31
18 changed files with 2474 additions and 2206 deletions

View File

@@ -296,15 +296,71 @@ public:
void frameRendered(const Ogre::FrameEvent &evt) override;
};
class App : public OgreBites::ApplicationContext {
Ogre::SceneNode *mCameraNode, *mCameraPivot, *mCameraGoal;
Ogre::Camera *mCamera;
Ogre::Real mPivotPitch;
struct SceneData {
Ogre::SceneManager *mScnMgr;
Ogre::Camera *mCamera;
Ogre::SceneNode *mCameraNode, *mCameraPivot, *mCameraGoal;
Ogre::Real mPivotPitch;
SceneData()
: mScnMgr(nullptr)
, mCamera(nullptr)
, mCameraNode(nullptr)
, mCameraPivot(nullptr)
, mCameraGoal(nullptr)
{
}
void setup(Ogre::Root *root, Ogre::OverlaySystem *overlaySystem)
{
Ogre::SceneManager *scnMgr = root->createSceneManager();
mScnMgr = scnMgr;
mScnMgr->addRenderQueueListener(overlaySystem);
}
void initCamera(const Ogre::String &cameraName)
{
mCameraNode = mScnMgr->getRootSceneNode()->createChildSceneNode(
cameraName + "CameraNode");
mCameraNode->setPosition(0, 2, 3);
mCameraNode->lookAt(Ogre::Vector3(0, 1, -1),
Ogre::Node::TS_PARENT);
// create the camera
mCamera = mScnMgr->createCamera(cameraName);
mCamera->setNearClipDistance(0.05f);
mCamera->setAutoAspectRatio(true);
mCameraNode->attachObject(mCamera);
mCameraPivot =
mScnMgr->getRootSceneNode()->createChildSceneNode(
cameraName + "FPSCameraPivot");
mCameraGoal = mCameraPivot->createChildSceneNode(
cameraName + "FPSCameraGoal", Ogre::Vector3(0, 2, 3));
mCameraNode->setPosition(mCameraPivot->getPosition() +
mCameraGoal->getPosition());
mCameraPivot->setFixedYawAxis(true);
mCameraGoal->setFixedYawAxis(true);
mCameraNode->setFixedYawAxis(true);
// our model is quite small, so reduce the clipping planes
mCamera->setNearClipDistance(0.1f);
mCamera->setFarClipDistance(800);
mPivotPitch = 0;
}
void setupRTSS()
{
Ogre::RTShader::ShaderGenerator *shadergen =
Ogre::RTShader::ShaderGenerator::getSingletonPtr();
shadergen->addSceneManager(mScnMgr);
}
Ogre::SceneManager *getSceneManager()
{
return mScnMgr;
}
};
class App : public OgreBites::ApplicationContext {
Ogre::Viewport *mViewport;
SkyBoxRenderer *sky;
bool mGrab;
KeyboardListener mKbd;
SceneData mEditorNormalScene, mEditorAltScene;
public:
App()
@@ -316,16 +372,12 @@ public:
virtual ~App()
{
}
void setup()
void setup() override
{
OgreBites::ApplicationContext::setup();
Ogre::Root *root = getRoot();
Ogre::SceneManager *scnMgr = root->createSceneManager();
mScnMgr = scnMgr;
Ogre::OverlaySystem *pOverlaySystem = getOverlaySystem();
mScnMgr->addRenderQueueListener(pOverlaySystem);
// mTrayMgr = new OgreBites::TrayManager("AppTrays",
// getRenderWindow());
mEditorNormalScene.setup(root, getOverlaySystem());
mEditorAltScene.setup(root, getOverlaySystem());
}
bool isWindowGrab()
{
@@ -353,85 +405,41 @@ public:
void initCamera()
{
mCameraNode = mScnMgr->getRootSceneNode()->createChildSceneNode(
"CameraNode");
mCameraNode->setPosition(0, 2, 3);
mCameraNode->lookAt(Ogre::Vector3(0, 1, -1),
Ogre::Node::TS_PARENT);
// create the camera
mCamera = mScnMgr->createCamera("fps_camera");
mCamera->setNearClipDistance(0.05f);
mCamera->setAutoAspectRatio(true);
mCameraNode->attachObject(mCamera);
// and tell it to render into the main window
mViewport = getRenderWindow()->addViewport(mCamera);
mCameraPivot =
mScnMgr->getRootSceneNode()->createChildSceneNode(
"FPSCameraPivot");
mCameraGoal = mCameraPivot->createChildSceneNode(
"FPSCameraGoal", Ogre::Vector3(0, 2, 3));
mCameraNode->setPosition(mCameraPivot->getPosition() +
mCameraGoal->getPosition());
mCameraPivot->setFixedYawAxis(true);
mCameraGoal->setFixedYawAxis(true);
mCameraNode->setFixedYawAxis(true);
// our model is quite small, so reduce the clipping planes
mCamera->setNearClipDistance(0.1f);
mCamera->setFarClipDistance(800);
mPivotPitch = 0;
mEditorNormalScene.initCamera("fps_camera");
mEditorNormalScene.initCamera("alt_camera");
mViewport = getRenderWindow()->addViewport(
mEditorNormalScene.mCamera);
}
void configure()
{
std::cout << "Startup"
<< "\n";
std::cout << "Startup"
<< "\n";
initApp();
std::cout << "Set up RTSS"
<< "\n";
std::cout << "Set up RTSS"
<< "\n";
Ogre::Root *root = getRoot();
Ogre::SceneManager *scnMgr = getSceneManager();
// register our scene with the RTSS
Ogre::RTShader::ShaderGenerator *shadergen =
Ogre::RTShader::ShaderGenerator::getSingletonPtr();
shadergen->addSceneManager(scnMgr);
mEditorNormalScene.setupRTSS();
mEditorAltScene.setupRTSS();
setWindowGrab(false);
std::cout << "Init camera"
<< "\n";
std::cout << "Init camera"
<< "\n";
initCamera();
std::cout << "Set up water"
<< "\n";
std::cout << "Set up cursor"
<< "\n";
Ogre::ResourceGroupManager::getSingleton()
.initialiseAllResourceGroups();
// OgreBites::ApplicationContext::loadResources();
// setupCursor();
std::cout << "Setup input"
<< "\n";
std::cout << "Setup input"
<< "\n";
setupInput();
std::cout << "Create content"
<< "\n";
std::cout << "Create content"
<< "\n";
createContent();
std::cout << "Setup done"
<< "\n";
#if 0
mDbgDraw->setDebugMode(mDbgDraw->getDebugMode() |
btIDebugDraw::DBG_DrawContactPoints);
#endif
}
Ogre::SceneManager *getSceneManager()
{
return mScnMgr;
std::cout << "Setup done"
<< "\n";
}
Ogre::Timer mTerrainUpd;
// TODO: implement rough water level calculation
float getWaterLevel(const Ogre::Vector3 &position)
{
Ogre::Vector3::UNIT_Y;
float etime =
Ogre::ControllerManager::getSingleton().getElapsedTime();
return 0.0f;
}
void updateWorld(float delta)
@@ -447,6 +455,26 @@ public:
ECS::get().modified<ECS::GUI>();
}
ECS::update(delta);
#if 0
if (switchWindow) {
int scene = ECS::get<ECS::EditorSceneSwitch>().scene;
mEditorNormalScene.mScnMgr->removeRenderQueueListener(
getOverlaySystem());
mEditorAltScene.mScnMgr->removeRenderQueueListener(
getOverlaySystem());
mViewport->setOverlaysEnabled(false);
if (scene == 0)
mViewport->setCamera(
mEditorNormalScene.mCamera);
else if (scene == 1)
mViewport->setCamera(mEditorAltScene.mCamera);
mViewport->setOverlaysEnabled(true);
mEditorNormalScene.mScnMgr->addRenderQueueListener(
getOverlaySystem());
mEditorAltScene.mScnMgr->addRenderQueueListener(
getOverlaySystem());
}
#endif
}
class InputListenerChainFlexible : public OgreBites::InputListener {
protected:
@@ -580,10 +608,11 @@ public:
void setupInput()
{
}
bool switchWindow = false;
void createContent()
{
int i;
sky = new SkyBoxRenderer(getSceneManager());
sky = new SkyBoxRenderer(mEditorNormalScene.getSceneManager());
bool drawFirst = true;
uint8_t renderQueue = drawFirst ?
Ogre::RENDER_QUEUE_SKIES_EARLY :
@@ -599,8 +628,14 @@ public:
"Skybox/Dynamic", "General");
OgreAssert(m, "Sky box material not found.");
m->load();
ECS::setupEditor(mScnMgr, /*mDynWorld.get(), */ mCameraNode,
mCamera, getRenderWindow());
ECS::setupEditor(
mEditorNormalScene.mScnMgr,
/*mDynWorld.get(), */ mEditorNormalScene.mCameraNode,
mEditorNormalScene.mCamera, getRenderWindow());
ECS::setupEditorAlt(
mEditorAltScene.mScnMgr,
/*mDynWorld.get(), */ mEditorAltScene.mCameraNode,
mEditorAltScene.mCamera, getRenderWindow());
ECS::get().import <ECS::EditorGizmoModule>();
ECS::get().import <ECS::EditorInputModule>();
ECS::get().set<ECS::RenderWindow>(
@@ -632,11 +667,20 @@ public:
nullptr,
{ getImGuiInputListener(), &mKbd } });
ECS::get().add<ECS::EditorDebugMaterial>();
#if 0
ECS::get()
.observer<ECS::EditorSceneSwitch>("UpdateEditorScene")
.event(flecs::OnSet)
.each([&](ECS::EditorSceneSwitch &sw) {
switchWindow = true;
});
#endif
std::shared_ptr<Ogre::ManualObject> manualObj(
mScnMgr->createManualObject("EditorGizmo"));
mEditorNormalScene.mScnMgr->createManualObject(
"EditorGizmo"));
Ogre::SceneNode *gizmoNode =
mScnMgr->getRootSceneNode()->createChildSceneNode(
"EditorGizmoNode");
mEditorNormalScene.mScnMgr->getRootSceneNode()
->createChildSceneNode("EditorGizmoNode");
gizmoNode->attachObject(manualObj.get());
manualObj->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY);
ECS::get().set<ECS::EditorGizmo>({ manualObj, gizmoNode });
@@ -723,13 +767,9 @@ public:
ECS::get().get_mut<ECS::GUI>().enabled = active;
ECS::get().modified<ECS::GUI>();
}
Ogre::Camera *getCamera()
{
return mCamera;
}
flecs::entity getPlayer() const
{
return ECS::player;
return ECS::player;
}
void enableDbgDraw(bool enable)
{
@@ -795,7 +835,7 @@ int main()
{
App ctx;
ctx.configure();
// ctx.enableDbgDraw(false);
// ctx.enableDbgDraw(false);
ctx.getRoot()->startRendering();
ctx.setWindowGrab(false);
ctx.closeApp();

View File

@@ -4,6 +4,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)
add_subdirectory(items)
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp
GUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp
CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp CharacterManagerModule.cpp
@@ -14,7 +15,7 @@ target_link_libraries(GameData PUBLIC
nlohmann_json::nlohmann_json
OgreMain
OgreBites
OgrePaging OgreTerrain OgreOverlay OgreProcedural::OgreProcedural
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)
target_compile_definitions(GameData PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION)

View File

@@ -75,5 +75,8 @@ struct GroundCheckReady {};
struct Body2Entity {
/* std::unordered_map<btCollisionObject *, flecs::entity> entities; */
};
struct EditorSceneSwitch {
int scene;
};
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@ void setup_minimal()
ecs.component<Body2Entity>().add(flecs::Singleton);
}
void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
Ogre::Camera *camera, Ogre::RenderWindow *window)
Ogre::Camera *camera, Ogre::RenderWindow *window)
{
std::cout << "Setup GameData\n";
setup_minimal();
@@ -112,58 +112,58 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
// ecs.set<Body2Entity>({});
std::cout << "Setup GameData done\n";
ecs.system("SpawnPlayer").kind(flecs::OnUpdate).interval(0.5f).run([&](flecs::iter &it) {
flecs::entity player =
ECS::get<CharacterManagerModule>().getPlayer();
if (!player.is_valid()) {
/* Create player */
Ogre::Vector3 position;
JPH::BodyID id;
long x, y;
Ogre::TerrainGroup *tg =
ECS::get<ECS::Terrain>().mTerrainGroup;
if (tg->isDerivedDataUpdateInProgress())
return;
tg->convertWorldPositionToTerrainSlot(
Ogre::Vector3(0, 0, 4), &x, &y);
Ogre::Terrain *terrain = tg->getTerrain(x, y);
if (terrain && terrain->isLoaded()) {
if (PhysicsModule::raycastQuery(
Ogre::Vector3(0, 500, 4),
Ogre::Vector3(0, -500, 4), position,
id)) {
if (position.y < -10.0f &&
position.y > -50.0f) {
player =
ecs.get_mut<
CharacterManagerModule>()
.createPlayer(
{ position.x,
position.y,
position.z },
Ogre::Quaternion(
Ogre::Radian(
Ogre::Math::
PI),
Ogre::Vector3::
UNIT_Y));
std::cout << position
<< std::endl;
// OgreAssert(false, "spawn");
}
}
}
}
});
ecs.system("SpawnPlayer").kind(flecs::OnUpdate).interval(0.5f).run([&](flecs::iter &it) {
flecs::entity player =
ECS::get<CharacterManagerModule>().getPlayer();
if (!player.is_valid()) {
/* Create player */
Ogre::Vector3 position;
JPH::BodyID id;
long x, y;
Ogre::TerrainGroup *tg =
ECS::get<ECS::Terrain>().mTerrainGroup;
if (tg->isDerivedDataUpdateInProgress())
return;
tg->convertWorldPositionToTerrainSlot(
Ogre::Vector3(0, 0, 4), &x, &y);
Ogre::Terrain *terrain = tg->getTerrain(x, y);
if (terrain && terrain->isLoaded()) {
if (PhysicsModule::raycastQuery(
Ogre::Vector3(0, 500, 4),
Ogre::Vector3(0, -500, 4), position,
id)) {
if (position.y < -10.0f &&
position.y > -50.0f) {
player =
ecs.get_mut<
CharacterManagerModule>()
.createPlayer(
{ position.x,
position.y,
position.z },
Ogre::Quaternion(
Ogre::Radian(
Ogre::Math::
PI),
Ogre::Vector3::
UNIT_Y));
std::cout << position
<< std::endl;
// OgreAssert(false, "spawn");
}
}
}
}
});
}
void setupInteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
Ogre::Camera *camera, Ogre::RenderWindow *window)
Ogre::Camera *camera, Ogre::RenderWindow *window)
{
}
void setupInventoryScene(Ogre::SceneManager *scnMgr,
Ogre::SceneNode *cameraNode, Ogre::Camera *camera,
Ogre::RenderWindow *window)
Ogre::SceneNode *cameraNode, Ogre::Camera *camera,
Ogre::RenderWindow *window)
{
}
@@ -173,6 +173,7 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
std::cout << "Setup Editor\n";
setup_minimal();
ecs.component<RenderWindow>().add(flecs::Singleton);
ecs.component<EditorSceneSwitch>().add(flecs::Singleton);
ecs.import <CharacterModule>();
ecs.import <BoatModule>();
ecs.import <PhysicsModule>();
@@ -218,6 +219,9 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
(int)window->getHeight(), false });
ecs.set<Camera>({ cameraNode, camera, false });
#if 0
ecs.set<EditorSceneSwitch>({ 0 });
#endif
ecs.add<GameData>();
ecs.add<Input>();
ecs.add<WaterSurface>();
@@ -252,11 +256,11 @@ flecs::world get()
bool Vector3::zeroLength() const
{
float l = x * x + y * y + z * z;
return (l < 1e-06 * 1e-06);
return (l < 1e-06 * 1e-06);
}
void setupEditorAlt(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
Ogre::Camera *camera, Ogre::RenderWindow *window)
Ogre::Camera *camera, Ogre::RenderWindow *window)
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,11 @@ struct TerrainItem {
};
struct TerrainItemNode {
Ogre::SceneNode *itemNode;
Ogre::StaticGeometry *geo;
Ogre::StaticGeometry *geo;
};
struct TerrainItemMeshNode {
Ogre::SceneNode *itemNode;
Ogre::StaticGeometry *geo;
};
struct StaticGeometryModule {
@@ -43,16 +47,7 @@ struct StaticGeometryModule {
static void getItemsProperties(
std::list<std::pair<flecs::entity, Ogre::String> > *items);
static void createItemGeometry(flecs::entity e);
static void destroyItemGeometry(flecs::entity e);
static void setupLods(Ogre::LodConfig &config);
static void createPlazza(flecs::entity e, const nlohmann::json &district, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo);
static void createBridge(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
static void createPier(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
static void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo);
static void createBuildings(flecs::entity e, const nlohmann::json &district, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo);
static void createTemple(flecs::entity e, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo);
static void destroyItemGeometry(flecs::entity e);
};
}
#endif

View File

@@ -278,7 +278,7 @@ public:
float worldSize = terrain->getWorldSize();
float scaled = worldSize / (size - 1);
Ogre::Vector3 bodyPosition = terrain->getPosition();
// bodyPosition.y += (maxH + minH) / 2.0f;
// bodyPosition.y += (maxH + minH) / 2.0f;
bodyPosition.x += worldSize / 2.0f;
bodyPosition.z += worldSize / 2.0f;
Ogre::Vector3 offset =
@@ -338,21 +338,22 @@ public:
}
void update()
{
std::lock_guard<std::mutex> guard(mtx);
static bool created = false;
std::lock_guard<std::mutex> guard(mtx);
static bool created = false;
while (!collider_queue.empty()) {
Ogre::TerrainGroup *group =
Ogre::TerrainGroup *group =
collider_queue.front().group;
if (group->isDerivedDataUpdateInProgress())
break;
long x = collider_queue.front().x;
if (group->isDerivedDataUpdateInProgress())
break;
long x = collider_queue.front().x;
long y = collider_queue.front().y;
std::cout << x << " " << y << " "
<< collider_queue.size() << std::endl;
std::cout << x << " " << y << " "
<< collider_queue.size() << std::endl;
Ogre::Terrain *terrain = group->getTerrain(x, y);
Ogre::Vector3 worldPos;
group->convertTerrainSlotToWorldPosition(x, y,
&worldPos);
#if 0
std::cout << "terrain: " << terrain;
if (terrain)
std::cout
@@ -360,7 +361,8 @@ public:
<< terrain->isLoaded() << " "
<< terrain->isDerivedDataUpdateInProgress()
<< std::endl;
if (terrain && terrain->getHeightData() &&
#endif
if (terrain && terrain->getHeightData() &&
terrain->isLoaded() &&
!terrain->isDerivedDataUpdateInProgress()) {
Ogre::LogManager::getSingleton().logError(
@@ -368,8 +370,8 @@ public:
Ogre::StringConverter::toString(x) +
" " +
Ogre::StringConverter::toString(y));
// float minH = terrain->getMinHeight();
// float maxH = terrain->getMaxHeight();
// float minH = terrain->getMinHeight();
// float maxH = terrain->getMaxHeight();
int size = terrain->getSize();
float worldSize = terrain->getWorldSize();
{
@@ -440,22 +442,22 @@ public:
#endif
/* Spawn items */
StaticGeometryModule::addGeometryForSlot(x, y);
collider_queue.pop_front();
collider_queue.pop_front();
} else {
/* Terrain data not ready maybe move to next terrain */
gen_collider m = collider_queue.front();
/* Terrain data not ready maybe move to next terrain */
gen_collider m = collider_queue.front();
collider_queue.pop_front();
collider_queue.push_back(m);
break; // allow system to move on
collider_queue.push_back(m);
break; // allow system to move on
}
}
if (collider_queue.empty() &&
!ECS::get<Terrain>().mTerrainReady) {
ECS::get_mut<Terrain>().mTerrainReady = true;
ECS::modified<Terrain>();
}
}
}
if (collider_queue.empty() &&
!ECS::get<Terrain>().mTerrainReady) {
ECS::get_mut<Terrain>().mTerrainReady = true;
ECS::modified<Terrain>();
}
}
};
class DummyPageProvider : public Ogre::PageProvider {
public:

View File

@@ -468,6 +468,31 @@ WaterModule::WaterModule(flecs::world &ecs)
std::cout << "Water setup done\n";
ECS::get().add<WaterAlmostReady>();
})
.on_remove([](flecs::entity e, WaterSurface &water) {
const Ogre::String renderTargetName =
"ReflectionRefractionTexture";
ECS::get<EngineData>()
.mScnMgr->getRenderQueue()
->setRenderableListener(nullptr);
water.mReflectionTexture->removeAllViewports();
ECS::get<EngineData>().mScnMgr->destroyCamera(
water.mRefractionCamera);
ECS::get<EngineData>().mScnMgr->destroyCamera(
water.mRefractionDepthCamera);
ECS::get<EngineData>().mScnMgr->destroyCamera(
water.mReflectionCamera);
ECS::get<EngineData>().mScnMgr->destroyCamera(
water.mReflectionDepthCamera);
Ogre::TextureManager::getSingleton().remove(
renderTargetName);
water.mWaterNode->destroyAllChildrenAndObjects();
ECS::get<EngineData>().mScnMgr->destroySceneNode(
water.mWaterNode);
Ogre::MaterialManager::getSingleton().remove(
"Water/Depth");
Ogre::MaterialManager::getSingleton().remove(
"Water/Above");
})
.add(flecs::Singleton);
#if 0
ecs.component<WaterBody>().add(flecs::Singleton);

View File

@@ -0,0 +1,16 @@
project(items)
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)
add_library(items STATIC items.cpp harbour.cpp temple.cpp town.cpp)
target_include_directories(items PUBLIC .)
target_link_libraries(items PRIVATE
flecs::flecs_static
nlohmann_json::nlohmann_json
GameData
OgreMain
OgreBites
editor
physics
)

View File

@@ -0,0 +1,983 @@
#include <iostream>
#include <Ogre.h>
#include <OgreTerrainGroup.h>
#include <OgreImGuiOverlay.h>
#include <OgreRTShaderSystem.h>
#include <Procedural.h>
#include <nlohmann/json.hpp>
#include "Components.h"
#include "GameData.h"
#include "EditorGizmoModule.h"
#include "TerrainModule.h"
#include "StaticGeometryModule.h"
#include "items.h"
#include "harbour.h"
namespace ECS
{
namespace Items
{
/* This is editor function */
static bool findPierOffset(float &offset)
{
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
float length = 0.0f;
while (length < 250.0f) {
Ogre::Vector3 currentPosition = basePos + direction * length;
float height = ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
if (height < -4.0f) {
offset = length;
break;
}
length += 2.0f;
}
return length < 250.0f;
}
static bool findPierOffsetAndLengthAndDepth(float &offset, float &length,
float &depth)
{
if (!findPierOffset(offset))
return false;
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
length = 0.0f;
depth = 4.0f;
while (length < 60.0f) {
Ogre::Vector3 currentPosition =
basePos + direction * (offset + length);
float height = ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
if (depth < -height)
depth = -height;
if (height > -4.0f)
break;
length += 6.0f;
}
return true;
}
static void findPierHeight(float maxLength, float &height)
{
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
float length = 0.0f;
height = 0.0f;
while (length < 60.0f) {
Ogre::Vector3 currentPosition = basePos + direction * (length);
float dheight =
ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
if (height < dheight)
height = dheight;
length += 1.0f;
}
}
static void findPierPath(float pathLength, std::vector<Ogre::Vector3> &path)
{
float minHeight = 0.2f;
int i;
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
float length = 0.0f;
while (length < pathLength) {
Ogre::Vector3 currentPosition = basePos + direction * (length);
float dheight =
ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
if (dheight < minHeight)
dheight = minHeight;
Ogre::Vector3 localOffset = Ogre::Vector3(0, 0, 1) * length;
Ogre::Vector3 localFromWorld =
ECS::get<EditorGizmo>()
.sceneNode->convertWorldToLocalPosition(
{ currentPosition.x, dheight,
currentPosition.z });
path.push_back(
{ localOffset.x, localFromWorld.y, localOffset.z });
length += 2.0f;
}
if (path.size() == 0) {
path.push_back(Ogre::Vector3(0, 0, 0));
path.push_back(Ogre::Vector3(0, 0, pathLength));
}
std::vector<Ogre::Vector3> tmppath = path;
path.clear();
for (auto &pt : tmppath) {
if (path.size() == 0)
path.push_back(pt);
else {
if (path.back().z + 0.5f >= pt.z)
continue;
else
path.push_back(pt);
}
}
Ogre::Vector3 lastp = path.back();
for (i = 1; i < path.size(); i++) {
Ogre::Vector3 &prev = path[i - 1];
if (path[i].y > prev.y)
continue;
else if (path[i].y < prev.y) {
float d = prev.y - path[i].y;
if (d > 0.15f)
path[i].y = prev.y - 0.15f;
}
}
float dy = path.back().y - lastp.y;
if (dy > 0)
path.push_back({ lastp.x, lastp.y, path.back().z + dy * 3.0f });
path.push_back({ path.back().x, path.back().y, path.back().z + 2.0f });
}
bool editHarbourDistrict(nlohmann::json &jitem)
{
float plazzaRadius = 5.0f;
float plazzaHeight = 0.2f;
float plazzaElevation = 0.0f;
float centerOffset = 0.0f;
bool plazza = false;
bool changed = false;
struct LotData {
float distance;
float angle;
float width;
float depth;
float elevation;
bool valid;
Ogre::String type;
Ogre::String properties;
};
std::vector<LotData> centerBuildings;
nlohmann::json &j = jitem;
if (j.find("centerOffset") != j.end())
centerOffset = j["centerOffset"].get<float>();
if (j.find("plazza") != j.end())
plazza = j["plazza"].get<bool>();
if (j.find("plazzaRadius") != j.end())
plazzaRadius = j["plazzaRadius"].get<float>();
if (j.find("plazzaHeight") != j.end())
plazzaHeight = j["plazzaHeight"].get<float>();
if (j.find("plazzaElevation") != j.end())
plazzaElevation = j["plazzaElevation"].get<float>();
if (j.find("centerBuildings") != j.end()) {
for (auto &jb : j["centerBuildings"]) {
LotData data;
data.distance = 100.0f;
data.angle = 0;
data.width = 50.0f;
data.depth = 50.0f;
data.elevation = 0.0f;
data.type = "base";
data.properties = "{}";
data.valid = true;
if (jb.find("distance") != jb.end())
data.distance = jb["distance"].get<float>();
if (jb.find("angle") != jb.end())
data.angle = jb["angle"].get<float>();
if (jb.find("width") != jb.end())
data.width = jb["width"].get<float>();
if (jb.find("depth") != jb.end())
data.depth = jb["depth"].get<float>();
if (jb.find("elevation") != jb.end())
data.elevation = jb["elevation"].get<float>();
if (jb.find("type") != jb.end())
data.type = jb["type"].get<Ogre::String>();
if (jb.find("properties") != jb.end())
data.properties =
jb["properties"].get<Ogre::String>();
centerBuildings.push_back(data);
}
}
if (ImGui::SliderFloat("Center Offset", &centerOffset, 0.0f, 100.0f))
changed = true;
if (ImGui::Checkbox("Plazza", &plazza))
changed = true;
if (plazza) {
if (ImGui::SliderFloat("Plazza Radius", &plazzaRadius, 5.0f,
100.0f))
changed = true;
if (ImGui::SliderFloat("Plazza Height", &plazzaHeight, 0.2f,
1.0f))
changed = true;
if (ImGui::SliderFloat("Plazza Elevation", &plazzaElevation,
-5.0f, 5.0f))
changed = true;
}
int count = 0;
for (auto &b : centerBuildings) {
ImGui::Text("Lot %d", count);
Ogre::String ms = "##" + Ogre::StringConverter::toString(count);
if (ImGui::SliderFloat(("Lot distance" + ms).c_str(),
&b.distance, 0.0f, 100.0f))
changed = true;
if (ImGui::SliderFloat(("Lot angle" + ms).c_str(), &b.angle,
0.0f, 360.0f))
changed = true;
if (ImGui::SliderFloat(("Width" + ms).c_str(), &b.width, 10.0f,
200.0f))
changed = true;
if (ImGui::SliderFloat(("Depth" + ms).c_str(), &b.depth, 10.0f,
200.0f))
changed = true;
if (ImGui::SliderFloat(("Elevation" + ms).c_str(), &b.elevation,
-10.0f, 10.0f))
changed = true;
if (ImGui::SmallButton(("Delete" + ms).c_str()))
b.valid = false;
count++;
}
if (ImGui::SmallButton("Add building")) {
changed = true;
LotData data;
data.distance = 100.0f;
data.angle = 0;
data.width = 50.0f;
data.depth = 50.0f;
data.elevation = 0.0f;
data.type = "base";
data.properties = "{}";
data.valid = true;
centerBuildings.push_back(data);
}
if (changed) {
j["centerOffset"] = centerOffset;
j["plazza"] = plazza;
j["plazzaRadius"] = plazzaRadius;
j["plazzaHeight"] = plazzaHeight;
j["plazzaElevation"] = plazzaElevation;
nlohmann::json lots = nlohmann::json::array();
for (const auto &d : centerBuildings) {
nlohmann::json jdata;
if (!d.valid)
continue;
jdata["distance"] = d.distance;
jdata["angle"] = d.angle;
jdata["width"] = d.width;
jdata["depth"] = d.depth;
jdata["elevation"] = d.elevation;
jdata["type"] = d.type;
jdata["properties"] = d.properties;
lots.push_back(jdata);
}
j["centerBuildings"] = lots;
}
return changed;
}
void createHarbourPopup(const std::pair<flecs::entity, Ogre::String> item)
{
bool lighthouse = false;
float lighthouseDistance = 0.0f;
float lighthouseAngle = 0.0f;
float centerOffset = 0.0f;
bool changed = false;
Ogre::String prop = StaticGeometryModule::getItemProperties(item.first);
nlohmann::json j = nlohmann::json::parse(prop);
nlohmann::json jcenter = nlohmann::json::object();
if (j.find("lighthouse") != j.end())
lighthouse = j["lighthouse"].get<bool>();
if (j.find("lighthouseDistance") != j.end())
lighthouseDistance = j["lighthouseDistance"].get<float>();
if (j.find("lighthouseAngle") != j.end())
lighthouseAngle = j["lighthouseAngle"].get<float>();
if (j.find("centerOffset") != j.end())
centerOffset = j["centerOffset"].get<float>();
if (j.find("center") != j.end())
jcenter = j["center"];
if (ImGui::Checkbox("Lighthouse", &lighthouse))
changed = true;
if (lighthouse) {
if (ImGui::SliderFloat("Lighthouse Distance",
&lighthouseDistance, 0.0f, 100.0f))
changed = true;
if (ImGui::SliderFloat("Lighthouse Angle", &lighthouseAngle,
-90.0f, 90.0f))
changed = true;
}
if (ImGui::SliderFloat("Center Offset Global", &centerOffset, 0.0f,
100.0f))
changed = true;
changed = changed || editHarbourDistrict(jcenter);
if (changed) {
j["lighthouse"] = lighthouse;
j["lighthouseDistance"] = lighthouseDistance;
j["lighthouseAngle"] = lighthouseAngle;
j["center"] = jcenter;
j["centerOffset"] = centerOffset;
StaticGeometryModule::setItemProperties(item.first, j.dump());
StaticGeometryModule::saveItems();
StaticGeometryModule::destroyItemGeometry(item.first);
StaticGeometryModule::createItemGeometry(item.first);
}
ImGui::Text("%s", j.dump(4).c_str());
}
void createHarbourItem()
{
Ogre::Vector3 itemPosition =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion itemOrientation =
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
float pierLength, pierDepth;
float pierOffset;
float pierHeight;
if (!findPierOffsetAndLengthAndDepth(pierOffset, pierLength, pierDepth))
return;
findPierHeight(pierOffset + pierLength, pierHeight);
std::vector<Ogre::Vector3> pierPath;
findPierPath(pierOffset + 2.0f, pierPath);
flecs::entity e = StaticGeometryModule::createItem(
itemPosition, itemOrientation, "harbour");
Ogre::String prop = StaticGeometryModule::getItemProperties(e);
nlohmann::json j = nlohmann::json::parse(prop);
j["pierOffset"] = pierOffset;
j["pierLength"] = pierLength;
j["pierDepth"] = pierDepth;
j["pierHeight"] = pierHeight;
nlohmann::json p = nlohmann::json::array();
for (const auto &pt : pierPath) {
nlohmann::json pj;
to_json(pj, pt);
p.push_back(pj);
}
j["pierPath"] = p;
StaticGeometryModule::setItemProperties(e, j.dump());
// setHarbourSurface();
StaticGeometryModule::saveItems();
// updateWorldTexture();
// updateHeightmap();
// TerrainModule::save_heightmap();
}
void createHarbourMenu()
{
if (ImGui::MenuItem("Create"))
createHarbourItem();
}
}
namespace Geometry
{
void createBridge(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo)
{
int i;
Procedural::TriangleBuffer tb;
Ogre::MaterialPtr harbourMaterial;
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
"proceduralMaterialHarbour" +
Ogre::StringConverter::toString(e.id()));
float stepWidth = 12.0f;
float stepHeight = 0.15f;
float stepDepth = 0.25f;
float stairsHeight = 0.0f;
float stairsOffset = 0.0f;
std::vector<Ogre::Vector3> pierPath;
Ogre::String props = e.get<TerrainItem>().properties;
nlohmann::json jp = nlohmann::json::parse(props);
if (jp.find("stairsHeight") != jp.end())
stairsHeight = jp["stairsHeight"].get<float>();
if (jp.find("stairsOffset") != jp.end())
stairsOffset = jp["stairsOffset"].get<float>();
if (jp.find("stepHeight") != jp.end())
stepHeight = jp["stepHeight"].get<float>();
if (jp.find("stepDepth") != jp.end())
stepDepth = jp["stepDepth"].get<float>();
if (jp.find("pierPath") != jp.end()) {
pierPath.reserve(jp["pierPath"].size());
for (auto &jpt : jp["pierPath"]) {
Ogre::Vector3 pt;
from_json(jpt, pt);
pierPath.push_back(pt);
}
}
#if 1
Procedural::Shape *pierShape = new Procedural::Shape();
pierShape->addPoint(8.f, -0.7f);
pierShape->addPoint(6.f, 0.7f);
pierShape->addPoint(6.05f, 0.65f);
pierShape->addPoint(0.f, 0.6f);
pierShape->addPoint(-6.05f, 0.65f);
pierShape->addPoint(-6.0f, 0.7f);
pierShape->addPoint(-8.f, -0.7f);
pierShape->close();
Procedural::CubicHermiteSpline3 *pierCurve;
Procedural::Path pierCurvePath;
if (jp.find("pierPath") != jp.end()) {
pierPath.reserve(jp["pierPath"].size());
pierCurve = new Procedural::CubicHermiteSpline3();
// pierCurve = new Procedural::RoundedCornerSpline3();
#if 0
{
int i;
for (i = 0; i < 5; i++) {
Ogre::Vector3 pt;
from_json(jp["pierPath"][i], pt);
pierPath.push_back(pt);
pierCurve->addPoint(
pt, pt - Ogre::Vector3(0, 0, -1),
pt + Ogre::Vector3(0, 0, 1));
}
Ogre::Vector3 pt2;
from_json(jp["pierPath"].back(), pt2);
pierPath.push_back(pt2);
pierCurve->addPoint(pt2);
for (const auto &m : pierPath) {
std::cout << m << std::endl;
}
}
#endif
#if 1
for (auto &jpt : jp["pierPath"]) {
Ogre::Vector3 pt;
from_json(jpt, pt);
pierPath.push_back(pt);
pierCurve->addPoint(pt, Ogre::Vector3(0, 0, 1));
// pierCurve->addPoint(pt);
}
#endif
OgreAssert(pierPath.size() > 0, "empty path");
// pierCurve->setNumSeg(8);
pierCurvePath = pierCurve->realizePath();
// V
Procedural::Track shapeTextureTrack =
Procedural::Track(Procedural::Track::AM_POINT)
.addKeyFrame(0, 0.0f)
.addKeyFrame(6, 0.1f);
// U
Procedural::Track pathTextureTrack =
Procedural::Track(Procedural::Track::AM_POINT)
.addKeyFrame(0, 0.45f)
.addKeyFrame(6, 0.9f);
Procedural::Extruder extruder;
extruder.setShapeTextureTrack(&shapeTextureTrack)
.setPathTextureTrack(&pathTextureTrack)
.setShapeToExtrude(pierShape)
.setExtrusionPath(&pierCurvePath)
.setEnableNormals(true)
.setUTile(1.0f)
.setVTile(1.0f)
.addToTriangleBuffer(tb);
for (auto &v : tb.getVertices()) {
v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.41f, 0.9f);
v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f);
}
#if 0
for (const auto &v : tb.getVertices()) {
std::cout << "UV: " << v.mUV << std::endl;
}
OgreAssert(false, "uvs");
#endif
#if 0
Ogre::LodConfig config(extrudedMesh);
setupLods(config);
Ogre::Entity *pathEnt =
ECS::get<EngineData>().mScnMgr->createEntity(
extrudedMesh);
pathEnt->setMaterial(harbourMaterial);
float xofft = 0.0f;
Ogre::Vector3 worldPosition =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z * 0.0f;
Ogre::Quaternion worldOrientation =
sceneNode->_getDerivedOrientation();
Ogre::Vector3 xoffset =
worldOrientation * (Ogre::Vector3::UNIT_X * xofft);
geo->addEntity(pathEnt, worldPosition + xoffset,
worldOrientation, Ogre::Vector3(1, 1, 1));
#endif
}
#else
for (i = 0; i < pierPath.size(); i++) {
if (i == 0)
continue;
Ogre::Vector3 lvec = pierPath[i] - pierPath[i - 1];
Ogre::Vector3 xvec = Ogre::Vector3::UNIT_Y.crossProduct(lvec);
Ogre::Vector3 n = lvec.crossProduct(xvec).normalisedCopy();
Ogre::Vector3 pos = (pierPath[i] + pierPath[i - 1]) * 0.5f;
Procedural::PlaneGenerator()
.setNormal(n)
.setNumSegX(2)
.setNumSegY(2)
.setSizeX(1)
.setSizeY(1)
.setPosition(pos)
.addToTriangleBuffer(tb);
}
#endif
Ogre::String meshName =
"pierPathMesh" + Ogre::StringConverter::toString(e.id());
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().getByName(meshName);
if (mesh)
Ogre::MeshManager::getSingleton().remove(mesh);
mesh = tb.transformToMesh(meshName);
Ogre::LodConfig config(mesh);
setupLods(config);
Ogre::Entity *pathEnt =
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
pathEnt->setMaterial(harbourMaterial);
float xofft = 0.0f;
Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z * 0.0f;
Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation();
Ogre::Vector3 xoffset =
worldOrientation * (Ogre::Vector3::UNIT_X * xofft);
geo->addEntity(pathEnt, worldPosition + xoffset, worldOrientation,
Ogre::Vector3(1, 1, 1));
ECS::get<EngineData>().mScnMgr->destroyEntity(pathEnt);
}
void createPier(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo)
{
Ogre::MaterialPtr harbourMaterial;
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
"proceduralMaterialHarbour" +
Ogre::StringConverter::toString(e.id()));
harbourMaker hm(e);
Ogre::Vector3 position = sceneNode->_getDerivedPosition();
Ogre::String props = e.get<TerrainItem>().properties;
nlohmann::json jp = nlohmann::json::parse(props);
float pierHeight = 0.0f, pierLength = 6.0f, pierDepth = 6.0f;
if (jp.find("pierLength") != jp.end())
pierLength = jp["pierLength"].get<float>();
if (jp.find("pierDepth") != jp.end())
pierDepth = jp["pierDepth"].get<float>();
if (jp.find("pierHeight") != jp.end())
pierHeight = jp["pierHeight"].get<float>();
Procedural::TriangleBuffer tb;
float plankLength = 2.0f;
float plankWidth = 4.01f;
float plankHeight = 0.3f;
const float beamLength = 6.0f;
const float beamWidth = 5.5f;
float beamHeight = 0.3f;
if (pierLength < 12.0f)
pierLength = 12.0f;
auto processGrid = [&sceneNode, &geo](float stepLength, float length,
float zoffset, float yofft,
float xofft, Ogre::Entity *ent) {
float step = 0.0f;
while (step < length) {
Ogre::Vector3 worldPosition =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z *
(step + zoffset);
Ogre::Quaternion worldOrientation =
sceneNode->_getDerivedOrientation();
Ogre::Vector3 xoffset = worldOrientation *
(Ogre::Vector3::UNIT_X * xofft);
Ogre::Vector3 yoffset = worldOrientation *
(Ogre::Vector3::UNIT_Y * yofft);
geo->addEntity(ent, worldPosition + xoffset + yoffset,
worldOrientation,
Ogre::Vector3(1, 1, 1));
step += stepLength;
}
};
float xofftPlanks;
for (xofftPlanks = -plankWidth; xofftPlanks <= plankWidth;
xofftPlanks += plankWidth)
processGrid(plankLength, pierLength, plankLength / 2.0f,
plankHeight / 2.0f + beamHeight / 2.0f, xofftPlanks,
hm.planks);
{
Procedural::TriangleBuffer tbPillars, tbBollards;
float step = 0.0f;
while (step < pierLength) {
// pillars
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(pierDepth)
.setSizeZ(0.5f)
.setEnableNormals(true)
.setPosition(Ogre::Vector3(
-5.0f, -pierDepth / 2.0f + 0.5f, step))
.addToTriangleBuffer(tbPillars);
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(pierDepth)
.setSizeZ(0.5f)
.setEnableNormals(true)
.setPosition(Ogre::Vector3(
5.0f, -pierDepth / 2.0f + 0.5f, step))
.addToTriangleBuffer(tbPillars);
step += 6.0f;
}
step = pierLength - 0.5f;
while (step >= 0.0f) {
// bollards
Procedural::CylinderGenerator()
.setHeight(0.8f)
.setRadius(0.3f)
.setPosition(Ogre::Vector3(
-5.3f, 0.4f + 0.5f + 0.1f, step))
.addToTriangleBuffer(tbBollards);
Procedural::CylinderGenerator()
.setHeight(0.8f)
.setRadius(0.3f)
.setPosition(Ogre::Vector3(
5.3f, 0.4f + 0.5f + 0.1f, step))
.addToTriangleBuffer(tbBollards);
step -= 12.0f;
}
// beams
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(beamHeight)
.setSizeZ(pierLength)
.setEnableNormals(true)
.setPosition(Ogre::Vector3(-5.0f,
0.2 + beamHeight / 2.0f,
pierLength / 2.0f))
.addToTriangleBuffer(tbPillars);
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(beamHeight)
.setSizeZ(pierLength)
.setEnableNormals(true)
.setPosition(Ogre::Vector3(5.0f,
0.2 + beamHeight / 2.0f,
pierLength / 2.0f))
.addToTriangleBuffer(tbPillars);
for (auto &v : tbPillars.getVertices()) {
v.mUV *= 0.08f;
v.mUV += Ogre::Vector2(0.01f, 0.01f);
v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.0f, 0.1f);
v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f);
}
for (auto &v : tbBollards.getVertices()) {
v.mUV *= 0.08f;
v.mUV.x += 0.21f;
v.mUV.y += 0.01f;
v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.2f, 0.3f);
v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f);
}
tb.append(tbPillars);
tb.append(tbBollards);
}
Ogre::String meshName =
"pier" + Ogre::StringConverter::toString(e.id());
{
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().getByName(meshName);
if (mesh)
Ogre::MeshManager::getSingleton().remove(mesh);
mesh = tb.transformToMesh(meshName);
Ogre::LodConfig config(mesh);
// config.advanced.useCompression = false;
// config.advanced.useVertexNormals = true;
setupLods(config);
Ogre::Entity *ent =
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
ent->setMaterial(harbourMaterial);
float xofft = 0.0f;
Ogre::Vector3 worldPosition =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z * 0.0f;
Ogre::Quaternion worldOrientation =
sceneNode->_getDerivedOrientation();
Ogre::Vector3 xoffset =
worldOrientation * (Ogre::Vector3::UNIT_X * xofft);
geo->addEntity(ent, worldPosition + xoffset, worldOrientation,
Ogre::Vector3(1, 1, 1));
}
std::cout << meshName << std::endl;
}
void createPlazza(flecs::entity e, const nlohmann::json &district,
Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo)
{
Ogre::MaterialPtr harbourMaterial;
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
"proceduralMaterialHarbour" +
Ogre::StringConverter::toString(e.id()));
Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition();
Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation();
const nlohmann::json &jp = district;
Procedural::TriangleBuffer tb;
float centerOffset = 0.0f;
float plazzaRadius = 5.0f;
float plazzaHeight = 0.2f;
float plazzaElevation = 0.0f;
if (jp.find("centerOffset") != jp.end())
centerOffset = jp["centerOffset"].get<float>();
if (jp.find("plazzaRadius") != jp.end())
plazzaRadius = jp["plazzaRadius"].get<float>();
if (jp.find("plazzaHeight") != jp.end())
plazzaHeight = jp["plazzaHeight"].get<float>();
if (jp.find("plazzaElevation") != jp.end())
plazzaElevation = jp["plazzaElevation"].get<float>();
if (plazzaHeight < 0.1f)
plazzaHeight = 0.1f;
if (plazzaRadius < 5.0f)
plazzaRadius = 5.0f;
Ogre::Vector3 worldPlazzaCenter = worldPosition;
#if 0
Procedural::CylinderGenerator()
.setHeight(plazzaHeight)
.setRadius(plazzaRadius)
.setEnableNormals(true)
.setPosition(Ogre::Vector3(
0.0f, plazzaHeight / 2.0f + plazzaElevation, 0.0f))
.addToTriangleBuffer(tb);
#endif
float mh = 4.0f;
Procedural::Shape *plazzaShape = new Procedural::Shape();
plazzaShape->addPoint(0, -plazzaHeight - mh - mh);
plazzaShape->addPoint(plazzaRadius * 0.5f + mh,
-plazzaHeight - mh - mh);
plazzaShape->addPoint(plazzaRadius + mh, -plazzaHeight - mh);
plazzaShape->addPoint(plazzaRadius, -plazzaHeight);
plazzaShape->addPoint(plazzaRadius, 0.0f);
plazzaShape->addPoint(plazzaRadius - 0.1f, 0.1f);
plazzaShape->addPoint(plazzaRadius - mh + 0.1f, plazzaHeight);
plazzaShape->addPoint(plazzaRadius - mh, plazzaHeight + 0.1f);
plazzaShape->addPoint(plazzaRadius * 0.5f + mh, plazzaHeight);
plazzaShape->addPoint(0, plazzaHeight);
Procedural::Lathe()
.setShapeToExtrude(plazzaShape)
.setEnableNormals(true)
.setPosition(Ogre::Vector3(
0.0f, plazzaHeight / 2.0f + plazzaElevation, 0.0f))
.setNumSeg(24)
.addToTriangleBuffer(tb);
for (auto &v : tb.getVertices()) {
v.mUV *= 0.08f;
v.mUV.x += 0.41f;
v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.4f, 0.5f);
v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f);
}
Ogre::String meshName =
"plazzaMesh" + Ogre::StringConverter::toString(e.id());
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().getByName(meshName);
if (mesh)
Ogre::MeshManager::getSingleton().remove(mesh);
mesh = tb.transformToMesh(meshName);
Ogre::LodConfig config(mesh);
setupLods(config);
Ogre::Entity *pathEnt =
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
pathEnt->setMaterial(harbourMaterial);
geo->addEntity(pathEnt, worldPlazzaCenter, worldOrientation,
Ogre::Vector3(1, 1, 1));
}
void createBuildings(flecs::entity e, const nlohmann::json &district,
Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo)
{
Ogre::MaterialPtr harbourMaterial;
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
"proceduralMaterialHarbour" +
Ogre::StringConverter::toString(e.id()));
nlohmann::json jbuildings = nlohmann::json::array();
if (district.find("centerBuildings") != district.end())
jbuildings = district["centerBuildings"];
Ogre::Vector3 centerPosition = sceneNode->_getDerivedPosition();
Ogre::Quaternion centerOrientation =
sceneNode->_getDerivedOrientation();
int count = 0;
float baseHeight = 4.0f;
for (const auto &jb : jbuildings) {
Procedural::TriangleBuffer tb;
float angle = 0.0f;
float depth = 50.0f;
float width = 100.0f;
float distance = 100.0f;
float elevation = 0.0f;
std::cout << jb.dump() << std::endl;
if (jb.find("angle") != jb.end())
angle = jb["angle"].get<float>();
if (jb.find("depth") != jb.end())
depth = jb["depth"].get<float>();
if (jb.find("width") != jb.end())
width = jb["width"].get<float>();
if (jb.find("distance") != jb.end())
distance = jb["distance"].get<float>();
if (jb.find("elevation") != jb.end())
elevation = jb["elevation"].get<float>();
OgreAssert(width > 1 && depth > 1 && baseHeight > 1,
"Bad stuff happen");
Ogre::Quaternion rotation = Ogre::Quaternion(
Ogre::Degree(angle), Ogre::Vector3::UNIT_Y);
Ogre::Vector3 offset = centerOrientation * rotation *
(Ogre::Vector3::UNIT_Z * distance);
Procedural::BoxGenerator()
.setSizeX(width)
.setSizeY(baseHeight)
.setSizeZ(depth)
.setEnableNormals(true)
.setPosition(Ogre::Vector3(
0.0f, -baseHeight / 2.0f + elevation, 0.0f))
.addToTriangleBuffer(tb);
OgreAssert(tb.getVertices().size() > 8, "bad box");
for (auto &v : tb.getVertices()) {
float c = 1.0 + 1.0 / (v.mPosition.y + baseHeight +
elevation);
v.mPosition.x *= c;
v.mPosition.z *= c;
v.mUV *= 0.08f;
v.mUV.x += 0.41f;
v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.4f, 0.5f);
v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f);
}
Ogre::String meshName =
"lotbase" + Ogre::StringConverter::toString(count) +
"_" + Ogre::StringConverter::toString(e.id());
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().getByName(meshName);
if (mesh)
Ogre::MeshManager::getSingleton().remove(mesh);
mesh = tb.transformToMesh(meshName);
Ogre::LodConfig config(mesh);
setupLods(config);
Ogre::Entity *ent =
ECS::get<EngineData>().mScnMgr->createEntity(
"Ent" + meshName, mesh);
ent->setMaterial(harbourMaterial);
geo->addEntity(ent, centerPosition + offset, rotation,
Ogre::Vector3::UNIT_SCALE);
ECS::get<EngineData>().mScnMgr->destroyEntity(ent);
count++;
}
}
void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo)
{
std::cout << "createHarbour " << e.id() << std::endl;
Ogre::MaterialPtr harbourMaterial;
harbourMaterial = Ogre::MaterialManager::getSingleton().getByName(
"proceduralMaterialHarbour" +
Ogre::StringConverter::toString(e.id()));
if (!harbourMaterial) {
Procedural::TextureBuffer colorAtlas(1024);
Procedural::RectangleTexture drawAtlas(&colorAtlas);
Ogre::ColourValue normalYellow(0.8f, 0.6f, 0, 1);
Ogre::ColourValue roadBrown(0.4f, 0.3f, 0.3f, 1);
Ogre::ColourValue bollardGrey(0.2f, 0.2f, 0.2f, 1);
drawAtlas.setRectangle(Ogre::RealRect(0.0f, 0.0f, 0.4f, 1.0f))
.setColour(normalYellow)
.process();
drawAtlas.setRectangle(Ogre::RealRect(0.2f, 0.0f, 0.3f, 1.0f))
.setColour(bollardGrey)
.process();
drawAtlas.setRectangle(Ogre::RealRect(0.4f, 0.0f, 1.0f, 1.0f))
.setColour(roadBrown)
.process();
Ogre::TexturePtr pierTexture = colorAtlas.createTexture(
"proceduralTextureHarbour" +
Ogre::StringConverter::toString(e.id()));
colorAtlas.saveImage("tmp.png");
harbourMaterial =
Ogre::MaterialManager::getSingletonPtr()->create(
"proceduralMaterialHarbour" +
Ogre::StringConverter::toString(e.id()),
Ogre::ResourceGroupManager::
DEFAULT_RESOURCE_GROUP_NAME);
harbourMaterial->getTechnique(0)->getPass(0)->setShininess(0);
harbourMaterial->getTechnique(0)->getPass(0)->setDiffuse(
Ogre::ColourValue::White);
harbourMaterial->getTechnique(0)->getPass(0)->setSpecular(
Ogre::ColourValue(1.0f, 1.0f, 0.9f));
harbourMaterial->getTechnique(0)
->getPass(0)
->createTextureUnitState(
"proceduralTextureHarbour" +
Ogre::StringConverter::toString(e.id()));
if (Ogre::RTShader::ShaderGenerator::initialize()) {
harbourMaterial->prepare();
Ogre::RTShader::ShaderGenerator *mShaderGenerator =
Ogre::RTShader::ShaderGenerator::
getSingletonPtr();
mShaderGenerator->createShaderBasedTechnique(
*harbourMaterial,
Ogre::MaterialManager::DEFAULT_SCHEME_NAME,
Ogre::RTShader::ShaderGenerator::
DEFAULT_SCHEME_NAME);
Ogre::RTShader::RenderState *pMainRenderState =
mShaderGenerator->getRenderState(
Ogre::RTShader::ShaderGenerator::
DEFAULT_SCHEME_NAME,
*harbourMaterial);
}
}
{
Ogre::String props = e.get<TerrainItem>().properties;
nlohmann::json jp = nlohmann::json::parse(props);
float pierOffset = 0.0f;
float centerOffset = 0.0f;
float plazzaRadius = 5.0f;
bool plazza = false;
nlohmann::json jcenter = nlohmann::json::object();
if (jp.find("center") != jp.end())
jcenter = jp["center"];
if (jcenter.find("plazzaRadius") != jcenter.end())
plazzaRadius = jcenter["plazzaRadius"];
if (jp.find("pierOffset") != jp.end())
pierOffset = jp["pierOffset"].get<float>();
if (jp.find("plazza") != jp.end())
plazza = jp["plazza"].get<bool>();
if (jp.find("centerOffset") != jp.end())
centerOffset = jp["centerOffset"].get<float>();
Ogre::Vector3 worldPosition =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z * (pierOffset);
float xofft = 0.0f;
float stairLengthZ = worldPosition.y;
float stairsOffset = 0.0f;
stairsOffset = stairLengthZ;
jp["stairsHeight"] = worldPosition.y;
jp["stairsOffset"] = stairsOffset;
e.get_mut<TerrainItem>().properties = jp.dump();
e.modified<TerrainItem>();
worldPosition.y = 0.0f;
Ogre::Quaternion worldOrientation =
sceneNode->_getDerivedOrientation();
Ogre::Vector3 xoffset =
worldOrientation * (Ogre::Vector3::UNIT_X * xofft);
Ogre::Vector3 zoffset =
worldOrientation *
(Ogre::Vector3::UNIT_Z * (stairsOffset - 1));
Ogre::SceneNode *elevatorNode =
sceneNode->createChildSceneNode();
Ogre::SceneNode *pierNode = sceneNode->createChildSceneNode();
pierNode->_setDerivedPosition(worldPosition + zoffset +
xoffset);
Ogre::Vector3 worldPlazzaCenter =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z *
(-centerOffset - plazzaRadius + 2.0f);
Ogre::SceneNode *centerNode = sceneNode->createChildSceneNode();
centerNode->_setDerivedPosition(worldPlazzaCenter);
createBridge(e, elevatorNode, geo);
createPier(e, pierNode, geo);
createPlazza(e, jcenter, centerNode, geo);
createBuildings(e, jcenter, centerNode, geo);
}
geo->build();
}
}
}

View File

@@ -0,0 +1,25 @@
#ifndef __HARBOUR_H__
#define __HARBOUR_H__
#include <flecs.h>
namespace ECS
{
namespace Items
{
void createHarbourPopup(const std::pair<flecs::entity, Ogre::String> item);
void createHarbourMenu();
}
namespace Geometry
{
void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
void createBridge(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
void createPier(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
void createPlazza(flecs::entity e, const nlohmann::json &district,
Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo);
void createBuildings(flecs::entity e, const nlohmann::json &district,
Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo);
}
}
#endif

View File

@@ -0,0 +1,223 @@
#include <iostream>
#include <Ogre.h>
#include <OgreImGuiOverlay.h>
#include <OgreTerrainGroup.h>
#include <OgreRTShaderSystem.h>
#include <OgreMeshLodGenerator.h>
#include <Procedural.h>
#include <nlohmann/json.hpp>
#include "Components.h"
#include "GameData.h"
#include "StaticGeometryModule.h"
#include "EditorGizmoModule.h"
#include "TerrainModule.h"
#include "physics.h"
#include "PhysicsModule.h"
#include "harbour.h"
#include "temple.h"
#include "town.h"
#include "items.h"
namespace ECS
{
namespace Items
{
void showItemPopup(const std::pair<flecs::entity, Ogre::String> &item)
{
Ogre::String popupLabel =
"EditPopup" + Ogre::StringConverter::toString(item.first.id());
if (ImGui::BeginPopup(popupLabel.c_str())) {
Ogre::String prop =
StaticGeometryModule::getItemProperties(item.first);
nlohmann::json j = nlohmann::json::parse(prop);
Ogre::String itemType = j["type"].get<Ogre::String>();
if (itemType == "harbour")
createHarbourPopup(item);
else if (itemType == "temple")
createTemplePopup(item);
else if (itemType == "town")
createTownPopup(item);
ImGui::EndPopup();
}
}
void showItemButtons(const std::pair<flecs::entity, Ogre::String> &item)
{
ImGui::SameLine();
Ogre::String upd_label =
"Update Height##" +
Ogre::StringConverter::toString(item.first.id());
if (ImGui::SmallButton(upd_label.c_str())) {
TerrainItem &uitem = item.first.get_mut<TerrainItem>();
uitem.position.y =
ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
uitem.position);
StaticGeometryModule::saveItems();
}
ImGui::SameLine();
Ogre::String edit_label =
"Edit##" + Ogre::StringConverter::toString(item.first.id());
Ogre::String popupLabel =
"EditPopup" + Ogre::StringConverter::toString(item.first.id());
if (ImGui::SmallButton(edit_label.c_str()))
ImGui::OpenPopup(popupLabel.c_str());
ImGui::SameLine();
Ogre::String del_label =
"delete##" + Ogre::StringConverter::toString(item.first.id());
if (ImGui::SmallButton(del_label.c_str())) {
item.first.destruct();
StaticGeometryModule::saveItems();
}
ImGui::Spacing();
}
void createItemsMenu()
{
if (ImGui::BeginMenu("Harbour")) {
Items::createHarbourMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Temple")) {
Items::createTempleMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Town")) {
Items::createTownMenu();
ImGui::EndMenu();
}
}
}
namespace Geometry
{
void setupLods(Ogre::LodConfig &config)
{
// config.advanced.useCompression = false;
// config.advanced.useVertexNormals = true;
config.advanced.preventPunchingHoles = true;
config.advanced.preventBreakingLines = true;
config.createGeneratedLodLevel(10, 0.15f);
config.createGeneratedLodLevel(30, 0.25f);
config.createGeneratedLodLevel(60, 0.36f);
config.createGeneratedLodLevel(150, 0.65f);
config.advanced.useBackgroundQueue = false;
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(config);
}
Ogre::StaticGeometry *createStaticGeometry(flecs::entity e)
{
Ogre::String props = e.get<TerrainItem>().properties;
nlohmann::json jp = nlohmann::json::parse(props);
if (jp.find("type") != jp.end()) {
Ogre::String itemType = jp["type"].get<Ogre::String>();
Ogre::String geoName = itemType + "_" +
Ogre::StringConverter::toString(e.id());
OgreAssert((ECS::get<EngineData>().mScnMgr->hasStaticGeometry(
geoName)) == false,
"" + geoName + " already exists for some reason");
Ogre::StaticGeometry *geo =
ECS::get<EngineData>().mScnMgr->createStaticGeometry(
geoName);
return geo;
}
return nullptr;
}
void createItemGeometry(flecs::entity e)
{
OgreAssert(!e.has<TerrainItemNode>(), "Geometry already created");
std::cout << "creating geometry for item: " << e.id() << std::endl;
Ogre::String props = e.get<TerrainItem>().properties;
nlohmann::json jp = nlohmann::json::parse(props);
Ogre::SceneNode *itemNode = ECS::get<EngineData>()
.mScnMgr->getRootSceneNode()
->createChildSceneNode();
itemNode->_setDerivedPosition(e.get<TerrainItem>().position);
itemNode->_setDerivedOrientation(e.get<TerrainItem>().orientation);
if (jp.find("staticMesh") != jp.end()) {
Ogre::String meshName = jp["staticMesh"].get<Ogre::String>();
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().getByName(meshName);
if (mesh) {
Ogre::Entity *ent =
ECS::get<EngineData>().mScnMgr->createEntity(
mesh);
itemNode->attachObject(ent);
}
} else if (jp.find("type") != jp.end()) {
Ogre::String itemType = jp["type"].get<Ogre::String>();
std::cout << "type: " << itemType << std::endl;
std::cout << "props: " << props << std::endl;
Ogre::StaticGeometry *geo = createStaticGeometry(e);
if (geo) {
geo->setRegionDimensions(Ogre::Vector3(140, 140, 140));
Ogre::Vector3 geoposition =
itemNode->_getDerivedPosition();
geoposition.y = 0.0f;
geo->setOrigin(geoposition);
}
if (itemType == "harbour") {
OgreAssert(geo, "Can't create static geometry");
Geometry::createHarbour(e, itemNode, geo);
e.set<TerrainItemNode>({ itemNode, geo });
} else if (itemType == "temple") {
OgreAssert(geo, "Can't create static geometry");
createTemple(e, itemNode, geo);
e.set<TerrainItemNode>({ itemNode, geo });
} else if (itemType == "town") {
OgreAssert(geo, "Can't create static geometry");
createTown(e, itemNode, geo);
e.set<TerrainItemNode>({ itemNode, geo });
std::cout << " town created: " << e.id() << std::endl;
} else {
OgreAssert(geo, "Can't create static geometry");
e.set<TerrainItemNode>({ itemNode, geo });
OgreAssert(false, "Unknown item type: " + itemType);
}
} else {
std::cout << "can't build item" << std::endl;
std::cout << "props: " << props << std::endl;
OgreAssert(false, "can't create item");
}
}
void destroyItemGeometry(flecs::entity e)
{
OgreAssert(e.has<TerrainItemNode>(), "No geometry created");
#if 0
ECS::get<EngineData>().mScnMgr->destroyStaticGeometry()
e.get<TerrainItemNode>().geo->destroy();
e.get_mut<TerrainItemNode>().geo = nullptr;
e.modified<TerrainItemNode>();
#endif
e.remove<TerrainItemNode>();
}
flecs::entity createMeshGeometry(const Ogre::String &meshName,
flecs::entity parente,
Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo)
{
Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().load(
meshName,
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
OgreAssert(mesh, "mesh " + meshName + " not found");
Ogre::LodConfig config(mesh);
setupLods(config);
Ogre::Entity *ent = ECS::get<EngineData>().mScnMgr->createEntity(
"Ent" + meshName, mesh);
geo->addEntity(ent, sceneNode->_getDerivedPosition(),
sceneNode->_getDerivedOrientation());
ECS::get<EngineData>().mScnMgr->destroyEntity(ent);
JPH::ShapeRefC shape =
JoltPhysicsWrapper::getSingleton().createMeshShape(mesh);
JPH::BodyID id = JoltPhysicsWrapper::getSingleton().createBody(
shape.GetPtr(), 0, sceneNode, JPH::EMotionType::Static,
Layers::NON_MOVING);
flecs::entity e = ECS::get()
.entity()
.child_of(parente)
.set<JPH::BodyID>(id)
.set<TerrainItemMeshNode>({ sceneNode, geo });
JoltPhysicsWrapper::getSingleton().addBody(id,
JPH::EActivation::Activate);
return e;
}
}
}

View File

@@ -0,0 +1,89 @@
#ifndef __ITEMS_H__
#define __ITEMS_H__
#include <OgreMeshLodGenerator.h>
#include <flecs.h>
namespace ECS
{
namespace Items
{
void showItemPopup(const std::pair<flecs::entity, Ogre::String> &item);
void showItemButtons(const std::pair<flecs::entity, Ogre::String> &item);
void createItemsMenu();
}
namespace Geometry
{
void setupLods(Ogre::LodConfig &config);
struct harbourMaker {
Ogre::Entity *planks, *pillar, *beam;
Ogre::String makeName(const Ogre::String &base, flecs::entity e)
{
return base + Ogre::StringConverter::toString(e.id());
}
harbourMaker(flecs::entity e)
{
Ogre::String planksName = makeName("Plank", e);
Ogre::String beamName = makeName("Beam", e);
Ogre::String pillarName = makeName("Pillar", e);
std::pair<Ogre::String, Ogre::Entity **> sets[] = {
{ planksName, &planks },
{ beamName, &beam },
{ pillarName, &pillar }
};
std::map<Ogre::String, Ogre::String> meshes = {
{ planksName, "pier-plank.glb" },
{ beamName, "pier-beam.glb" },
{ pillarName, "pier-pillar.glb" },
};
for (auto &p : sets) {
if (ECS::get<EngineData>().mScnMgr->hasEntity(p.first))
*p.second =
ECS::get<EngineData>()
.mScnMgr->getEntity(p.first);
else {
*p.second = ECS::get<EngineData>()
.mScnMgr->createEntity(
p.first,
meshes.at(p.first));
Ogre::MeshPtr mesh = (*p.second)->getMesh();
Ogre::LodConfig config(mesh);
setupLods(config);
}
}
}
};
void createItemGeometry(flecs::entity e);
void destroyItemGeometry(flecs::entity e);
flecs::entity createMeshGeometry(const Ogre::String &meshName,
flecs::entity parente,
Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
}
static void to_json(nlohmann::json &j, const Ogre::Vector3 &position)
{
j["x"] = position.x;
j["y"] = position.y;
j["z"] = position.z;
}
static void to_json(nlohmann::json &j, const Ogre::Quaternion &orientation)
{
j["w"] = orientation.w;
j["x"] = orientation.x;
j["y"] = orientation.y;
j["z"] = orientation.z;
}
static void from_json(const nlohmann::json &j, Ogre::Vector3 &position)
{
position.x = j["x"].get<float>();
position.y = j["y"].get<float>();
position.z = j["z"].get<float>();
}
static void from_json(const nlohmann::json &j, Ogre::Quaternion &orientation)
{
orientation.w = j["w"].get<float>();
orientation.x = j["x"].get<float>();
orientation.y = j["y"].get<float>();
orientation.z = j["z"].get<float>();
}
}
#endif

View File

@@ -0,0 +1,240 @@
#include <iostream>
#include <Ogre.h>
#include <OgreTerrainGroup.h>
#include <OgreImGuiOverlay.h>
#include <OgreRTShaderSystem.h>
#include <Procedural.h>
#include <nlohmann/json.hpp>
#include "Components.h"
#include "GameData.h"
#include "EditorGizmoModule.h"
#include "TerrainModule.h"
#include "StaticGeometryModule.h"
#include "physics.h"
#include "PhysicsModule.h"
#include "items.h"
#include "temple.h"
namespace ECS
{
namespace Items
{
void createTempleItem()
{
Ogre::Vector3 itemPosition =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion itemOrientation =
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
flecs::entity e = StaticGeometryModule::createItem(
itemPosition, itemOrientation, "temple");
Ogre::String prop = StaticGeometryModule::getItemProperties(e);
nlohmann::json j = nlohmann::json::parse(prop);
j["size"] = 40.0f;
j["form"] = "rect";
j["pillarHeight"] = 16.0f;
j["pillarRadius"] = 0.5f;
j["pillarCount"] = 20;
StaticGeometryModule::setItemProperties(e, j.dump());
StaticGeometryModule::saveItems();
}
void createTempleMenu()
{
if (ImGui::MenuItem("Create"))
createTempleItem();
}
void createTemplePopup(const std::pair<flecs::entity, Ogre::String> item)
{
float size = 40.0f;
float pillarRadius = 0.5f;
float pillarHeight = 16.0f;
int pillarCount = 20;
Ogre::String form;
Ogre::String prop = StaticGeometryModule::getItemProperties(item.first);
nlohmann::json j = nlohmann::json::parse(prop);
bool changed = false;
if (j.find("size") != j.end())
size = j["size"].get<float>();
if (j.find("pillarRadius") != j.end())
pillarRadius = j["pillarRadius"].get<float>();
if (j.find("pillarHeight") != j.end())
pillarHeight = j["pillarHeight"].get<float>();
if (j.find("pillarCount") != j.end())
pillarCount = j["pillarCount"].get<int>();
if (ImGui::SliderFloat("Temple Size", &size, 40.0f, 100.0f))
changed = true;
if (ImGui::SliderFloat("Temple Pillar Radius", &pillarRadius, 0.5f,
2.0f))
changed = true;
if (ImGui::SliderFloat("Temple Pillar Height", &pillarHeight, 16.0f,
60.0f))
changed = true;
if (ImGui::SliderInt("Pillar Count", &pillarCount, 1, 200))
changed = true;
if (changed) {
j["size"] = size;
j["pillarRadius"] = pillarRadius;
j["pillarHeight"] = pillarHeight;
j["pillarCount"] = pillarCount;
StaticGeometryModule::setItemProperties(item.first, j.dump());
StaticGeometryModule::saveItems();
StaticGeometryModule::destroyItemGeometry(item.first);
StaticGeometryModule::createItemGeometry(item.first);
}
ImGui::Text("%s", j.dump(4).c_str());
}
}
namespace Geometry
{
void createTemple(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo)
{
Ogre::String props = e.get<TerrainItem>().properties;
nlohmann::json jp = nlohmann::json::parse(props);
float size = 20.0f;
int pillarCount = 4;
float pillarRadius = 0.5f, pillarHeight = 10.0f;
if (jp.find("size") != jp.end())
size = jp["size"].get<float>();
if (jp.find("pillarCount") != jp.end())
pillarCount = jp["pillarCount"].get<int>();
if (jp.find("pillarHeight") != jp.end())
pillarHeight = jp["pillarHeight"].get<float>();
if (jp.find("pillarCount") != jp.end())
size = jp["size"].get<float>();
Procedural::TriangleBuffer tb, colliderTb;
float elevation = 0.0f;
Ogre::MaterialPtr templeMaterial;
templeMaterial = Ogre::MaterialManager::getSingleton().getByName(
"proceduralMaterialTemple" +
Ogre::StringConverter::toString(e.id()));
if (!templeMaterial) {
Procedural::TextureBuffer colorAtlas(1024);
Procedural::RectangleTexture drawAtlas(&colorAtlas);
Ogre::ColourValue normalGreen(0.6f, 0.8f, 0.5f, 1);
drawAtlas.setRectangle(Ogre::RealRect(0.0f, 0.0f, 0.4f, 1.0f))
.setColour(normalGreen)
.process();
Ogre::TexturePtr pierTexture = colorAtlas.createTexture(
"proceduralTextureTemple" +
Ogre::StringConverter::toString(e.id()));
colorAtlas.saveImage("tmp2.png");
templeMaterial = Ogre::MaterialManager::getSingletonPtr()->create(
"proceduralMaterialTemple" +
Ogre::StringConverter::toString(e.id()),
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
templeMaterial->getTechnique(0)->getPass(0)->setShininess(0);
templeMaterial->getTechnique(0)->getPass(0)->setDiffuse(
Ogre::ColourValue::White);
templeMaterial->getTechnique(0)->getPass(0)->setSpecular(
Ogre::ColourValue(1.0f, 1.0f, 0.9f));
templeMaterial->getTechnique(0)
->getPass(0)
->createTextureUnitState(
"proceduralTextureTemple" +
Ogre::StringConverter::toString(e.id()));
if (Ogre::RTShader::ShaderGenerator::initialize()) {
templeMaterial->prepare();
Ogre::RTShader::ShaderGenerator *mShaderGenerator =
Ogre::RTShader::ShaderGenerator::
getSingletonPtr();
mShaderGenerator->createShaderBasedTechnique(
*templeMaterial,
Ogre::MaterialManager::DEFAULT_SCHEME_NAME,
Ogre::RTShader::ShaderGenerator::
DEFAULT_SCHEME_NAME);
Ogre::RTShader::RenderState *pMainRenderState =
mShaderGenerator->getRenderState(
Ogre::RTShader::ShaderGenerator::
DEFAULT_SCHEME_NAME,
*templeMaterial);
}
}
Ogre::Vector3 worldPosition = sceneNode->_getDerivedPosition();
Ogre::Quaternion worldOrientation = sceneNode->_getDerivedOrientation();
Procedural::BoxGenerator()
.setSizeX(size)
.setSizeY(20)
.setSizeZ(size)
.setEnableNormals(true)
.setPosition(
Ogre::Vector3(0.0f, -20.0f / 2.0f + elevation, 0.0f))
.addToTriangleBuffer(tb);
float pillarStep = 0.0f;
float pillarStepSize = size * 4.0f / (float)pillarCount;
int pcount = pillarCount;
while (pillarStep < size - pillarRadius * 2.0f && pcount > 0) {
float s = pillarStep - size / 2.0f + pillarStepSize / 2.0f;
Procedural::CylinderGenerator()
.setHeight(pillarHeight)
.setRadius(pillarRadius)
.setNumSegBase(8)
.setPosition(s, 0.0f, -size / 2.0f + pillarRadius)
.addToTriangleBuffer(tb);
Procedural::CylinderGenerator()
.setHeight(pillarHeight)
.setRadius(pillarRadius)
.setNumSegBase(8)
.setPosition(s, 0.0f, size / 2.0f - pillarRadius)
.addToTriangleBuffer(tb);
Procedural::CylinderGenerator()
.setHeight(pillarHeight)
.setRadius(pillarRadius)
.setNumSegBase(8)
.setPosition(-size / 2.0f + pillarRadius, 0.0f, s)
.addToTriangleBuffer(tb);
Procedural::CylinderGenerator()
.setHeight(pillarHeight)
.setRadius(pillarRadius)
.setNumSegBase(8)
.setPosition(size / 2.0f - pillarRadius, 0.0f, s)
.addToTriangleBuffer(tb);
pillarStep += pillarStepSize;
pcount--;
pcount--;
pcount--;
pcount--;
}
OgreAssert(tb.getVertices().size() > 8, "bad box");
for (auto &v : tb.getVertices()) {
#if 0
float c = 1.0 + 1.0 / (v.mPosition.y + baseHeight +
elevation);
v.mPosition.x *= c;
v.mPosition.z *= c;
#endif
v.mUV *= 0.08f;
v.mUV.x += 0.01f;
v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.0f, 0.4f);
v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f);
}
Ogre::String meshName =
"Temple" + Ogre::StringConverter::toString(e.id());
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().getByName(meshName);
if (mesh)
Ogre::MeshManager::getSingleton().remove(mesh);
mesh = tb.transformToMesh(meshName);
Ogre::LodConfig config(mesh);
Geometry::setupLods(config);
Ogre::Entity *ent = ECS::get<EngineData>().mScnMgr->createEntity(
"Ent" + meshName, mesh);
ent->setMaterial(templeMaterial);
geo->addEntity(ent, worldPosition, worldOrientation,
Ogre::Vector3::UNIT_SCALE);
ECS::get<EngineData>().mScnMgr->destroyEntity(ent);
// TODO set altar position
createMeshGeometry("altar.glb", e, sceneNode->createChildSceneNode(),
geo);
geo->build();
JPH::ShapeRefC shape =
JoltPhysicsWrapper::getSingleton().createMeshShape(mesh);
JPH::BodyID id = JoltPhysicsWrapper::getSingleton().createBody(
shape.GetPtr(), 0, sceneNode, JPH::EMotionType::Static,
Layers::NON_MOVING);
e.set<JPH::BodyID>(id);
JoltPhysicsWrapper::getSingleton().addBody(id,
JPH::EActivation::Activate);
}
}
}

View File

@@ -0,0 +1,20 @@
#ifndef __TEMPLE_H__
#define __TEMPLE_H__
#include <OgreMeshLodGenerator.h>
#include <flecs.h>
namespace ECS
{
namespace Items
{
void createTempleItem();
void createTempleMenu();
void createTemplePopup(const std::pair<flecs::entity, Ogre::String> item);
}
namespace Geometry
{
void createTemple(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
}
}
#endif

View File

@@ -0,0 +1,71 @@
#include <iostream>
#include <Ogre.h>
#include <OgreTerrainGroup.h>
#include <OgreImGuiOverlay.h>
#include <OgreRTShaderSystem.h>
#include <Procedural.h>
#include <nlohmann/json.hpp>
#include "Components.h"
#include "GameData.h"
#include "EditorGizmoModule.h"
#include "TerrainModule.h"
#include "StaticGeometryModule.h"
#include "physics.h"
#include "PhysicsModule.h"
#include "items.h"
#include "town.h"
namespace ECS
{
namespace Items
{
void createTownItem()
{
Ogre::Vector3 itemPosition =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion itemOrientation =
ECS::get<EditorGizmo>().sceneNode->_getDerivedOrientation();
flecs::entity e = StaticGeometryModule::createItem(
itemPosition, itemOrientation, "town");
Ogre::String prop = StaticGeometryModule::getItemProperties(e);
nlohmann::json j = nlohmann::json::parse(prop);
j["districts"] = nlohmann::json::array();
StaticGeometryModule::setItemProperties(e, j.dump());
// setHarbourSurface();
StaticGeometryModule::saveItems();
// updateWorldTexture();
// updateHeightmap();
// TerrainModule::save_heightmap();
}
void createTownMenu()
{
if (ImGui::MenuItem("Create"))
createTownItem();
}
void createTownPopup(const std::pair<flecs::entity, Ogre::String> item)
{
Ogre::String prop = StaticGeometryModule::getItemProperties(item.first);
nlohmann::json j = nlohmann::json::parse(prop);
bool changed = false;
if (ImGui::SmallButton("Add district")) {
nlohmann::json d;
d["radius"] = 50.0f;
d["lots"] = nlohmann::json::array();
j["districts"].push_back(d);
changed = true;
}
if (changed) {
StaticGeometryModule::setItemProperties(item.first, j.dump());
StaticGeometryModule::saveItems();
StaticGeometryModule::destroyItemGeometry(item.first);
StaticGeometryModule::createItemGeometry(item.first);
}
}
}
namespace Geometry
{
void createTown(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo)
{
}
}
}

19
src/gamedata/items/town.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef __TOWN_H__
#define __TOWN_H__
#include <OgreMeshLodGenerator.h>
#include <flecs.h>
namespace ECS
{
namespace Items
{
void createTownItem();
void createTownMenu();
void createTownPopup(const std::pair<flecs::entity, Ogre::String> item);
}
namespace Geometry
{
void createTown(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
}
}
#endif