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

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