Files
ogre-prototype/src/gamedata/StaticGeometryModule.cpp
2025-12-14 06:59:12 +03:00

1116 lines
35 KiB
C++

#include <iostream>
#include <nlohmann/json.hpp>
#include <OgreTerrainGroup.h>
#include <OgreFileSystemLayer.h>
#include <OgreRTShaderSystem.h>
#include <OgreStaticGeometry.h>
#include <OgreMeshLodGenerator.h>
#include <Procedural.h>
#include "Components.h"
#include "GameData.h"
#include "TerrainModule.h"
#include "StaticGeometryModule.h"
namespace ECS
{
StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
{
ecs.module<StaticGeometryModule>();
ecs.component<TerrainSlotParent>();
ecs.component<TerrainItem>();
ecs.component<TerrainItemNode>().on_remove(
[](flecs::entity e, TerrainItemNode &item) {
if (item.itemNode) {
item.itemNode->destroyAllChildrenAndObjects();
item.itemNode->getCreator()->destroySceneNode(
item.itemNode);
item.itemNode = nullptr;
}
});
ecs.import <TerrainModule>();
ecs.observer<const Terrain>("LoadTerrainItems")
.event(flecs::OnSet)
.each([](const Terrain &terrain) {
if (terrain.mTerrainGroup)
loadItems();
});
if (!Ogre::MeshLodGenerator::getSingletonPtr())
new Ogre::MeshLodGenerator();
}
void StaticGeometryModule::addGeometryForSlot(long x, long y)
{
std::pair<long, long> slot = { x, y };
flecs::entity parent =
ECS::get().query_builder<const TerrainSlotParent>().build().find(
[&slot](const TerrainSlotParent &parent) {
return parent.slot == slot;
});
std::cout << "addGeometryForSlot: " << x << " " << y << std::endl;
std::list<flecs::entity> items;
if (parent.is_valid()) {
ECS::get()
.query_builder<const TerrainItem>()
.with(flecs::ChildOf, parent)
.without<TerrainItemNode>()
.write<TerrainItemNode>()
.build()
.each([&](flecs::entity e, const TerrainItem &item) {
std::cout << "item: " << e.id() << std::endl;
items.push_back(e);
});
for (auto e : items) {
createItemGeometry(e);
}
}
}
void StaticGeometryModule::removeGeometryForSlot(long x, long y)
{
std::pair<long, long> slot = { x, y };
flecs::entity parent =
ECS::get().query_builder<const TerrainSlotParent>().build().find(
[&slot](const TerrainSlotParent &parent) {
return parent.slot == slot;
});
if (parent.is_valid()) {
ECS::get()
.query_builder<const TerrainItem>()
.with(flecs::ChildOf, parent)
.without<TerrainItemNode>()
.build()
.each([](flecs::entity e, const TerrainItem &item) {
OgreAssert(false, "Implement item geo destroy" +
item.properties);
});
}
}
flecs::entity
StaticGeometryModule::createItem(const Ogre::Vector3 &position,
const Ogre::Quaternion &orientation,
const Ogre::String &type)
{
long x, y;
ECS::get<Terrain>().mTerrainGroup->convertWorldPositionToTerrainSlot(
position, &x, &y);
std::pair<long, long> pos{ x, y };
flecs::entity slot =
ECS::get().query_builder<const TerrainSlotParent>().build().find(
[&](const TerrainSlotParent &slot) -> bool {
return slot.slot == pos;
});
if (!slot.is_valid())
slot = ECS::get().entity().set<TerrainSlotParent>({ pos });
flecs::entity item = ECS::get().entity().child_of(slot);
nlohmann::json jproperties;
jproperties["type"] = type;
item.set<TerrainItem>({ position, orientation, jproperties.dump() });
std::cout << "createItem: " << x << " " << y << " " << item.id()
<< std::endl;
return item;
}
void StaticGeometryModule::setItemProperties(flecs::entity id,
Ogre::String properties)
{
OgreAssert(id.is_valid(), "bad id");
id.get_mut<TerrainItem>().properties = properties;
id.modified<TerrainItem>();
}
const Ogre::String &StaticGeometryModule::getItemProperties(flecs::entity id)
{
OgreAssert(id.is_valid(), "bad id");
return id.get<TerrainItem>().properties;
}
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>();
}
void StaticGeometryModule::saveItems()
{
Ogre::String path = "resources/buildings/items.list";
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
"items.list")) {
Ogre::String group =
Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource("items.list");
Ogre::FileInfoListPtr fileInfoList(
Ogre::ResourceGroupManager::getSingleton()
.findResourceFileInfo(group, "items.list"));
OgreAssert(fileInfoList->size() == 1,
"worpd_map.png should be there and only once");
path = fileInfoList->at(0).archive->getName() + "/" +
"items.list";
Ogre::FileSystemLayer::removeFile(path);
}
std::fstream fout(path.c_str(), std::ios::out);
nlohmann::json jitemlist;
ECS::get().query_builder<const TerrainItem>().build().each(
[&](flecs::entity e, const TerrainItem &item) {
nlohmann::json jitem;
to_json(jitem["position"], item.position);
to_json(jitem["orientation"], item.orientation);
to_json(jitem["properties"], item.properties);
jitemlist.push_back(jitem);
});
fout << jitemlist.dump();
fout.close();
}
void StaticGeometryModule::loadItems()
{
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
"items.list"))
return;
Ogre::String group = Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource("items.list");
Ogre::DataStreamPtr stream =
Ogre::ResourceGroupManager::getSingleton().openResource(
"items.list", group);
Ogre::String json = stream->getAsString();
nlohmann::json jlist = nlohmann::json::parse(json);
ECS::get().delete_with<TerrainItem>();
ECS::get().delete_with<TerrainSlotParent>();
for (const auto &v : jlist) {
Ogre::Vector3 position;
Ogre::Quaternion orientation;
Ogre::String properties;
from_json(v["position"], position);
from_json(v["orientation"], orientation);
properties = v["properties"].get<Ogre::String>();
long x, y;
ECS::get<Terrain>()
.mTerrainGroup->convertWorldPositionToTerrainSlot(
position, &x, &y);
std::pair<long, long> pos{ x, y };
flecs::entity slot =
ECS::get()
.query_builder<const TerrainSlotParent>()
.build()
.find([&](const TerrainSlotParent &slot)
-> bool {
return slot.slot == pos;
});
if (!slot.is_valid())
slot = ECS::get().entity().set<TerrainSlotParent>(
{ pos });
flecs::entity item = ECS::get().entity().child_of(slot);
item.set<TerrainItem>({ position, orientation, properties });
std::cout << "createItem: " << x << " " << y << " " << item.id()
<< std::endl;
std::cout << "position: " << item.id() << " " << position
<< std::endl;
}
}
void StaticGeometryModule::getItemPositionPerSlot(
long x, long y, std::list<Ogre::Vector3> *positions)
{
std::pair<long, long> pos{ x, y };
if (!positions)
return;
flecs::entity slot =
ECS::get().query_builder<const TerrainSlotParent>().build().find(
[&](const TerrainSlotParent &slot) -> bool {
return slot.slot == pos;
});
if (!slot.is_valid())
return;
ECS::get()
.query_builder<const TerrainItem>()
.with(flecs::ChildOf, slot)
.build()
.each([&](flecs::entity e, const TerrainItem &item) {
positions->push_back(item.position);
});
}
void StaticGeometryModule::getItemPositions(std::list<Ogre::Vector3> *positions)
{
ECS::get().query_builder<const TerrainItem>().build().each(
[&](flecs::entity e, const TerrainItem &item) {
positions->push_back(item.position);
});
}
void StaticGeometryModule::getItemPositionAndRotation(
flecs::entity e, Ogre::Vector3 &position, Ogre::Quaternion &orientation)
{
position = e.get<TerrainItem>().position;
orientation = e.get<TerrainItem>().orientation;
}
void StaticGeometryModule::getItemsProperties(
std::list<std::pair<flecs::entity, Ogre::String> > *items)
{
ECS::get().query_builder<const TerrainItem>().build().each(
[&](flecs::entity e, const TerrainItem &item) {
items->push_back({ e, item.properties });
});
}
void StaticGeometryModule::createItemGeometry(flecs::entity e)
{
OgreAssert(!e.has<TerrainItemNode>(), "Geometry already created");
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;
if (itemType == "harbour") {
createHarbour(e, itemNode);
e.set<TerrainItemNode>({ itemNode });
}
} else {
std::cout << "can't build item" << std::endl;
std::cout << "props: " << props << std::endl;
OgreAssert(false, "can't create item");
}
}
struct harbourMaker {
Ogre::Entity *planks, *pillar, *beam;
harbourMaker(flecs::entity e)
{
planks = ECS::get<EngineData>().mScnMgr->createEntity(
"Plank" + Ogre::StringConverter::toString(e.id()),
"pier-plank.glb");
beam = ECS::get<EngineData>().mScnMgr->createEntity(
"Beam" + Ogre::StringConverter::toString(e.id()),
"pier-beam.glb");
pillar = ECS::get<EngineData>().mScnMgr->createEntity(
"Pillar" + Ogre::StringConverter::toString(e.id()),
"pier-pillar.glb");
#if 1
Ogre::Entity *entities[] = { planks, pillar, beam };
for (Ogre::Entity *ent : entities) {
Ogre::MeshPtr mesh = ent->getMesh();
Ogre::LodConfig config(mesh);
config.advanced.useCompression = true;
config.advanced.useVertexNormals = true;
config.advanced.preventPunchingHoles = true;
config.advanced.preventBreakingLines = true;
config.createGeneratedLodLevel(10, 0.15f);
config.createGeneratedLodLevel(30, 0.25f);
#if 0
if (ent == planks)
config.createManualLodLevel(
20, "pier-plank-LOD.glb");
else
#endif
config.createGeneratedLodLevel(60, 0.36f);
config.createGeneratedLodLevel(150, 0.65f);
// config.createGeneratedLodLevel(20, 0.95);
config.advanced.useBackgroundQueue = false;
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(
config);
}
#endif
}
};
struct TiledMeshes {
struct Tile {
Ogre::String materialName;
std::shared_ptr<Ogre::VertexData> vertexData;
std::shared_ptr<Ogre::IndexData> indexData;
std::set<uint32_t> positions;
};
std::map<Ogre::String, Tile> tiles;
uint32_t packKey(const Ogre::Vector3i &position)
{
uint32_t key = 0;
key |= (uint32_t)(position[2] + 512) << 20;
key |= (uint32_t)(position[1] + 512) << 10;
key |= (uint32_t)(position[0] + 512) << 0;
return key;
}
void unpackKey(uint32_t key, Ogre::Vector3i &position)
{
uint32_t mask = 0x3ff;
position[0] = (int)(key & mask) - 512;
position[1] = (int)((key >> 10) & mask) - 512;
position[2] = (int)((key >> 20) & mask) - 512;
}
void setTile(const Ogre::String &name, const Ogre::Vector3i &position)
{
if (tiles.find(name) == tiles.end())
return;
tiles[name].positions.insert(packKey(position));
}
void clearTile(const Ogre::String &name, const Ogre::Vector3i &position)
{
if (tiles.find(name) == tiles.end())
return;
tiles[name].positions.erase(packKey(position));
#if 0
auto pos = std::find(tiles[name].positions.begin(),
tiles[name].positions.end(),
packKey(position));
if (pos != tiles[name].positions.end())
tiles[name].positions.erase(pos);
#endif
}
void addTile(const Ogre::String &name, Ogre::MeshPtr mesh)
{
if (mesh->getSubMeshes().size() != 1)
return;
Ogre::SubMesh *submesh = mesh->getSubMesh(0);
Ogre::VertexData *vertexData;
if (submesh->useSharedVertices)
vertexData = mesh->sharedVertexData->clone();
else
vertexData = submesh->vertexData->clone();
tiles[name] = { submesh->getMaterialName(),
std::shared_ptr<Ogre::VertexData>(vertexData),
std::shared_ptr<Ogre::IndexData>(
submesh->indexData->clone()),
{} };
#if 0
std::vector<Ogre::Vector3> vertices;
std::vector<uint32_t> indices;
int count = mesh->getNumSubMeshes();
int i, j;
int indexCount = 0;
int vertexCount = 0;
int sharedVertexOffset = 0;
for (i = 0; i < count; i++) {
Ogre::SubMesh *submesh = mesh->getSubMesh(i);
indexCount += submesh->indexData->indexCount;
if (submesh->useSharedVertices)
vertexCount +=
mesh->sharedVertexData->vertexCount;
else
vertexCount += submesh->vertexData->vertexCount;
}
indices.reserve(indexCount);
vertices.reserve(vertexCount);
size_t currentVertexOffset = 0;
bool added_shared = false;
for (i = 0; i < count; i++) {
Ogre::SubMesh *submesh = mesh->getSubMesh(i);
Ogre::VertexData *vertex_data =
submesh->useSharedVertices ?
mesh->sharedVertexData :
submesh->vertexData;
bool add_vertices =
(submesh->useSharedVertices && !added_shared) ||
!submesh->useSharedVertices;
if (add_vertices) {
if (submesh->useSharedVertices)
sharedVertexOffset = vertices.size();
const Ogre::VertexDeclaration *decl =
vertex_data->vertexDeclaration;
const Ogre::VertexBufferBinding *bind =
vertex_data->vertexBufferBinding;
const Ogre::VertexElement *position_element =
decl->findElementBySemantic(
Ogre::VES_POSITION);
if (!position_element)
continue;
Ogre::HardwareVertexBufferSharedPtr vbuf =
bind->getBuffer(
position_element->getSource());
unsigned char *vertex_buffer = static_cast<
unsigned char *>(vbuf->lock(
Ogre::HardwareBuffer::HBL_READ_ONLY));
int vertexSize = vbuf->getVertexSize();
for (j = 0; j < vertex_data->vertexCount; j++) {
float *position_data;
position_element
->baseVertexPointerToElement(
vertex_buffer,
&position_data);
vertices.push_back(
{ position_data[0],
position_data[1],
position_data[2] });
vertex_buffer += vertexSize;
}
if (submesh->useSharedVertices)
added_shared = true;
vbuf->unlock();
}
Ogre::HardwareIndexBufferSharedPtr ibuf =
submesh->indexData->indexBuffer;
size_t numIndices = submesh->indexData->indexCount;
size_t vertexOffset = submesh->useSharedVertices ?
sharedVertexOffset :
currentVertexOffset;
if (ibuf->getType() ==
Ogre::HardwareIndexBuffer::IT_32BIT) {
unsigned int *pIndices = static_cast<
unsigned int *>(ibuf->lock(
Ogre::HardwareBuffer::HBL_READ_ONLY));
for (j = 0; j < numIndices; j++) {
indices.push_back(
(uint32_t)pIndices[j] +
vertexOffset);
}
ibuf->unlock();
} else {
unsigned short *pIndices = static_cast<
unsigned short *>(ibuf->lock(
Ogre::HardwareBuffer::HBL_READ_ONLY));
for (j = 0; j < numIndices; j++) {
indices.push_back(
(uint32_t)pIndices[j] +
vertexOffset);
}
ibuf->unlock();
}
currentVertexOffset = vertices.size();
}
#endif
}
struct buildSettings {
Ogre::String meshName;
Ogre::String materialName;
Ogre::MeshPtr mesh;
Ogre::SubMesh *sm;
int vertexCount, vertexOffset;
int indexCount, indexOffset;
Ogre::VertexDeclaration *vdecl;
Ogre::HardwareVertexBufferSharedPtr vbuf;
Ogre::AxisAlignedBox bounds;
bool setBounds;
};
void configureSettings(struct buildSettings &settings)
{
settings.mesh = Ogre::MeshManager::getSingleton().createManual(
settings.meshName,
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
settings.mesh->createVertexData();
settings.sm = settings.mesh->createSubMesh();
settings.vertexCount = 0;
settings.indexCount = 0;
settings.vdecl = nullptr;
for (const auto &tile : tiles) {
settings.vertexCount +=
tile.second.vertexData->vertexCount *
tile.second.positions.size();
settings.indexCount +=
tile.second.indexData->indexCount *
tile.second.positions.size();
if (!settings.vdecl) {
settings.vdecl =
tile.second.vertexData
->vertexDeclaration->clone();
settings.materialName =
tile.second.materialName;
}
}
settings.mesh->sharedVertexData->vertexStart = 0;
settings.mesh->sharedVertexData->vertexCount =
settings.vertexCount;
settings.mesh->sharedVertexData->vertexDeclaration =
settings.vdecl;
settings.vbuf =
Ogre::HardwareBufferManager::getSingleton()
.createVertexBuffer(
settings.vdecl->getVertexSize(0),
settings.vertexCount,
Ogre::HBU_GPU_ONLY);
settings.mesh->sharedVertexData->vertexBufferBinding->setBinding(
0, settings.vbuf);
settings.sm->indexData->indexStart = 0;
settings.sm->indexData->indexCount = settings.indexCount;
settings.sm->indexData->indexBuffer =
Ogre::HardwareBufferManager::getSingleton()
.createIndexBuffer(
Ogre::HardwareIndexBuffer::IT_32BIT,
settings.sm->indexData->indexCount * 8,
Ogre::HBU_GPU_ONLY);
settings.sm->setMaterialName(settings.materialName);
settings.setBounds = true;
}
void processIndex(struct buildSettings &settings,
const struct Tile &tile, unsigned int *dstIndices)
{
int j;
std::shared_ptr<Ogre::IndexData> srcIndexData = tile.indexData;
int srcIndexCount = srcIndexData->indexCount;
std::shared_ptr<Ogre::VertexData> srcVertexData =
tile.vertexData;
int srcVertexCount = srcVertexData->vertexCount;
Ogre::HardwareIndexBufferSharedPtr srcIbuf =
srcIndexData->indexBuffer;
Ogre::HardwareBufferLockGuard srcIndexLock(
srcIbuf, Ogre::HardwareBuffer::HBL_READ_ONLY);
if (srcIndexData->indexBuffer->getType() ==
Ogre::HardwareIndexBuffer::IT_32BIT) {
unsigned int *indices =
static_cast<unsigned int *>(srcIndexLock.pData);
for (j = 0; j < srcIndexCount; j++)
dstIndices[settings.indexOffset + j] =
indices[j] + settings.vertexOffset;
} else if (srcIndexData->indexBuffer->getType() ==
Ogre::HardwareIndexBuffer::IT_16BIT) {
unsigned short *indices = static_cast<unsigned short *>(
srcIndexLock.pData);
for (j = 0; j < srcIndexCount; j++)
dstIndices[settings.indexOffset + j] =
indices[j] + settings.vertexOffset;
}
}
void processSingleVertex(
struct buildSettings &settings,
const Ogre::VertexDeclaration::VertexElementList &srcElements,
uint32_t offset, unsigned char *srcData, unsigned char *dstData)
{
for (const auto &srcElement : srcElements) {
unsigned char *srcPtr, *dstPtr;
const Ogre::VertexElement *destElement =
settings.vdecl->findElementBySemantic(
srcElement.getSemantic(),
srcElement.getIndex());
if (!destElement)
goto out;
if (srcElement.getType() != destElement->getType() ||
srcElement.getSize() != destElement->getSize())
goto out;
srcPtr = srcData + srcElement.getOffset();
dstPtr = dstData + destElement->getOffset();
if (destElement->getSemantic() == Ogre::VES_POSITION) {
float *srcPositionData =
reinterpret_cast<float *>(srcPtr);
float *dstPositionData =
reinterpret_cast<float *>(dstPtr);
Ogre::Vector3 position(srcPositionData[0],
srcPositionData[1],
srcPositionData[2]);
Ogre::Vector3i offsetv;
unpackKey(offset, offsetv);
position.x += (float)offsetv[0];
position.y += (float)offsetv[1];
position.z += (float)offsetv[2];
dstPositionData[0] = position.x;
dstPositionData[1] = position.y;
dstPositionData[2] = position.z;
if (settings.setBounds) {
settings.bounds.setMinimum(position);
settings.bounds.setMaximum(position);
settings.setBounds = false;
} else
settings.bounds.merge(position);
} else if (destElement->getSemantic() ==
Ogre::VES_NORMAL) {
float *srcNormalData =
reinterpret_cast<float *>(srcPtr);
float *dstNormalData =
reinterpret_cast<float *>(dstPtr);
Ogre::Vector3 normal(srcNormalData[0],
srcNormalData[1],
srcNormalData[2]);
dstNormalData[0] = normal.x;
dstNormalData[1] = normal.y;
dstNormalData[2] = normal.z;
} else
memcpy(dstPtr, srcPtr, srcElement.getSize());
out:;
}
}
void processTile(struct buildSettings &settings,
const struct Tile &tile, uint32_t position,
unsigned char *dstpData)
{
std::shared_ptr<Ogre::VertexData> srcVertexData =
tile.vertexData;
const Ogre::VertexDeclaration *srcDecl =
srcVertexData->vertexDeclaration;
const Ogre::VertexBufferBinding *srcBind =
srcVertexData->vertexBufferBinding;
int srcVertexCount = srcVertexData->vertexCount;
Ogre::HardwareVertexBufferSharedPtr srcVbuf =
srcBind->getBuffer(0);
std::shared_ptr<Ogre::IndexData> srcIndexData = tile.indexData;
int srcIndexCount = srcIndexData->indexCount;
Ogre::HardwareBufferLockGuard srcVertexLock(
srcVbuf, 0, srcVertexCount * srcDecl->getVertexSize(0),
Ogre::HardwareBuffer::HBL_READ_ONLY);
const Ogre::VertexDeclaration::VertexElementList &srcElements =
srcDecl->getElements();
int j;
unsigned char *srcpData =
static_cast<unsigned char *>(srcVertexLock.pData);
for (j = 0; j < srcVertexCount; j++) {
unsigned char *srcData =
srcpData + j * srcVbuf->getVertexSize();
unsigned char *dstData =
dstpData + (settings.vertexOffset +
j) * settings.vbuf->getVertexSize();
processSingleVertex(settings, srcElements, position,
srcData, dstData);
}
}
Ogre::MeshPtr build(const Ogre::String &meshName)
{
buildSettings settings;
settings.meshName = meshName;
configureSettings(settings);
{
Ogre::HardwareBufferLockGuard vertexLock(
settings.vbuf, 0,
settings.vertexCount *
settings.vdecl->getVertexSize(0),
Ogre::HardwareBuffer::HBL_NO_OVERWRITE);
Ogre::HardwareBufferLockGuard indexLock(
settings.sm->indexData->indexBuffer,
Ogre::HardwareBuffer::HBL_NO_OVERWRITE);
settings.vertexOffset = 0;
settings.indexOffset = 0;
unsigned char *dstpData =
static_cast<unsigned char *>(vertexLock.pData);
unsigned int *dstIndices =
static_cast<unsigned int *>(indexLock.pData);
for (const auto &tile : tiles) {
std::shared_ptr<Ogre::IndexData> srcIndexData =
tile.second.indexData;
int srcIndexCount = srcIndexData->indexCount;
std::shared_ptr<Ogre::VertexData> srcVertexData =
tile.second.vertexData;
int srcVertexCount = srcVertexData->vertexCount;
for (const auto &position :
tile.second.positions) {
processTile(settings, tile.second,
position, dstpData);
processIndex(settings, tile.second,
dstIndices);
settings.vertexOffset += srcVertexCount;
settings.indexOffset += srcIndexCount;
Ogre::Vector3i vposition;
unpackKey(position, vposition);
std::cout << "position: " << position
<< " " << vposition
<< std::endl;
}
}
settings.mesh->_setBounds(settings.bounds);
}
Ogre::LodConfig config(settings.mesh);
// config.advanced.useCompression = false;
// config.advanced.useVertexNormals = true;
config.advanced.preventPunchingHoles = true;
config.advanced.preventBreakingLines = true;
config.createGeneratedLodLevel(2, 0.15f);
config.createGeneratedLodLevel(20, 0.49f);
#if 0
config.createGeneratedLodLevel(15, 0.49f);
config.createGeneratedLodLevel(150, 0.75f);
#endif
config.advanced.useBackgroundQueue = false;
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(
config);
return settings.mesh;
}
void removeTile(const Ogre::String &name)
{
tiles.erase(name);
}
TiledMeshes()
{
}
};
void StaticGeometryModule::createHarbour(flecs::entity e,
Ogre::SceneNode *sceneNode)
{
std::cout << "createHarbour " << e.id() << std::endl;
harbourMaker hm(e);
Ogre::StaticGeometry *geo =
ECS::get<EngineData>().mScnMgr->createStaticGeometry(
"pier_" + Ogre::StringConverter::toString(e.id()));
geo->setRegionDimensions(Ogre::Vector3(140, 140, 140));
Ogre::Vector3 geoposition = sceneNode->_getDerivedPosition();
geoposition.y = 0.0f;
geo->setOrigin(geoposition);
#if 1
Ogre::MaterialPtr pierMaterial;
pierMaterial = Ogre::MaterialManager::getSingleton().getByName(
"proceduralMaterialPier" +
Ogre::StringConverter::toString(e.id()));
if (!pierMaterial) {
Procedural::TextureBuffer wood(128);
Procedural::Colours(&wood)
.setColourBase(Ogre::ColourValue(0.8f, 0.6f, 0, 1))
.setColourPercent(Ogre::ColourValue(0.15f, 0.1f, 0, 1))
.process();
// Procedural::RectangleTexture woodDraw(&wood);
Ogre::TexturePtr pierTexture = wood.createTexture(
"proceduralTexturePier" +
Ogre::StringConverter::toString(e.id()));
pierMaterial = Ogre::MaterialManager::getSingletonPtr()->create(
"proceduralMaterialPier" +
Ogre::StringConverter::toString(e.id()),
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
pierMaterial->getTechnique(0)->getPass(0)->setShininess(0);
pierMaterial->getTechnique(0)->getPass(0)->setDiffuse(
Ogre::ColourValue::White);
pierMaterial->getTechnique(0)->getPass(0)->setSpecular(
Ogre::ColourValue(1.0f, 1.0f, 0.9f));
pierMaterial->getTechnique(0)
->getPass(0)
->createTextureUnitState(
"proceduralTexturePier" +
Ogre::StringConverter::toString(e.id()));
if (Ogre::RTShader::ShaderGenerator::initialize()) {
pierMaterial->prepare();
Ogre::RTShader::ShaderGenerator *mShaderGenerator =
Ogre::RTShader::ShaderGenerator::
getSingletonPtr();
mShaderGenerator->createShaderBasedTechnique(
*pierMaterial,
Ogre::MaterialManager::DEFAULT_SCHEME_NAME,
Ogre::RTShader::ShaderGenerator::
DEFAULT_SCHEME_NAME);
Ogre::RTShader::RenderState *pMainRenderState =
mShaderGenerator->getRenderState(
Ogre::RTShader::ShaderGenerator::
DEFAULT_SCHEME_NAME,
*pierMaterial);
}
}
#endif
Ogre::Vector3 position = sceneNode->_getDerivedPosition();
Ogre::String props = e.get<TerrainItem>().properties;
nlohmann::json jp = nlohmann::json::parse(props);
float pierHeight = 0.0f, pierOffset = 0.0f, pierLength = 6.0f,
pierDepth = 6.0f;
if (jp.find("pierOffset") != jp.end())
pierOffset = jp["pierOffset"].get<float>();
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;
const float beamLength = 6.0f;
const float beamWidth = 5.5f;
if (pierLength < 12.0f)
pierLength = 12.0f;
auto processGrid = [&sceneNode, &geo](float stepLength, float length,
float zoffset, 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);
geo->addEntity(ent, worldPosition + xoffset,
worldOrientation,
Ogre::Vector3(1, 1, 1));
step += stepLength;
}
};
float xofftPlanks;
for (xofftPlanks = -plankWidth; xofftPlanks <= plankWidth;
xofftPlanks += plankWidth)
processGrid(plankLength, pierLength,
pierOffset + plankLength / 2.0f, xofftPlanks,
hm.planks);
{
float step = 0.0f;
while (step < pierLength) {
// pillars
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(pierDepth)
.setSizeZ(0.5f)
.setEnableNormals(true)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(
-5.0f, -pierDepth / 2.0f + 0.5f, step))
.addToTriangleBuffer(tb);
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(pierDepth)
.setSizeZ(0.5f)
.setEnableNormals(true)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(
5.0f, -pierDepth / 2.0f + 0.5f, step))
.addToTriangleBuffer(tb);
step += 6.0f;
}
step = pierLength - 0.5f;
while (step >= 0.0f) {
// bollards
Procedural::CylinderGenerator()
.setHeight(0.8f)
.setRadius(0.3f)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(
-5.3f, 0.4f + 0.5f + 0.1f, step))
.addToTriangleBuffer(tb);
Procedural::CylinderGenerator()
.setHeight(0.8f)
.setRadius(0.3f)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(
5.3f, 0.4f + 0.5f + 0.1f, step))
.addToTriangleBuffer(tb);
step -= 12.0f;
}
// beams
float beamHeight = 0.3f;
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(beamHeight)
.setSizeZ(pierLength)
.setEnableNormals(true)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(-5.0f,
0.2 + beamHeight / 2.0f,
pierLength / 2.0f))
.addToTriangleBuffer(tb);
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(beamHeight)
.setSizeZ(pierLength)
.setEnableNormals(true)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(5.0f,
0.2 + beamHeight / 2.0f,
pierLength / 2.0f))
.addToTriangleBuffer(tb);
}
Ogre::String meshName =
"pier" + Ogre::StringConverter::toString(e.id());
{
Ogre::MeshPtr mesh = tb.transformToMesh(meshName);
Ogre::LodConfig config(mesh);
// 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::Entity *ent =
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
Ogre::SceneNode *pierNode = sceneNode->createChildSceneNode();
float xofft = 0.0f;
Ogre::Vector3 worldPosition =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z * (pierOffset);
worldPosition.y = 0.0f;
Ogre::Quaternion worldOrientation =
sceneNode->_getDerivedOrientation();
Ogre::Vector3 xoffset =
worldOrientation * (Ogre::Vector3::UNIT_X * xofft);
pierNode->_setDerivedPosition(worldPosition + xoffset);
ent->setMaterial(pierMaterial);
//pierNode->attachObject(ent);
geo->addEntity(ent, worldPosition + xoffset, worldOrientation,
Ogre::Vector3(1, 1, 1));
}
geo->build();
std::cout << meshName << std::endl;
#if 0
float step = 0.0f;
float h = Ogre::Math::Sin(step + position.z * 60.0f +
position.x * 60.0f * 60.0f) *
0.1f;
if (pierLength < 12.0f)
pierLength = 12.0f;
if (pierHeight > 0.0f) {
Procedural::BoxGenerator()
.setSizeX(10.0f)
.setSizeY(0.5f)
.setSizeZ(pierHeight)
.setOrientation(Ogre::Quaternion(
Ogre::Degree(-45), Ogre::Vector3(1, 0, 0)))
.setTextureRectangle(
Ogre::RealRect(0.0f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(
0.0f,
pierHeight + 0.5f -
pierHeight *
Ogre::Math::Sin(
Ogre::Degree(45)) /
2.0f,
-pierHeight / 2.0f *
Ogre::Math::Cos(Ogre::Degree(45))))
.addToTriangleBuffer(tb);
}
while (step < pierOffset - 2.0f) {
Procedural::BoxGenerator()
.setSizeX(10.0f)
.setSizeY(0.4f)
.setSizeZ(0.8f)
.setTextureRectangle(
Ogre::RealRect(0.1f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(0.0f, 0.5f + h + pierHeight,
step))
.addToTriangleBuffer(tb);
h = Ogre::Math::Sin(step + position.z * 60.0f +
position.x * 60.0f * 60.0f) *
0.1f;
step += 1.0f;
}
step = 0.0f;
while (step < pierLength) {
h = Ogre::Math::Sin(step + pierOffset + position.z * 60.0f +
position.x * 60.0f * 60.0f) *
0.1f;
// pillars
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(pierDepth)
.setSizeZ(0.5f)
.setEnableNormals(true)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(
-4.0f, -position.y - pierDepth / 2.0f + 0.5f,
step + pierOffset))
.addToTriangleBuffer(tb);
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(pierDepth)
.setSizeZ(0.5f)
.setEnableNormals(true)
.setTextureRectangle(
Ogre::RealRect(0.2f, 0.0f, 0.1f, 0.1f))
.setPosition(Ogre::Vector3(
4.0f, -position.y - pierDepth / 2.0f + 0.5f,
step + pierOffset))
.addToTriangleBuffer(tb);
step += 6.0f;
}
step = 0.0f;
#endif
#if 0
while (step < pierLength) {
h = Ogre::Math::Sin(step + pierOffset + position.z * 60.0f +
position.x * 60.0f * 60.0f) *
0.01f;
Ogre::Vector3 worldPosition =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z *
(step + pierOffset + plankLength / 2.0f);
Ogre::Quaternion worldOrientation =
sceneNode->_getDerivedOrientation();
float xofft;
for (xofft = -plankWidth - plankLength / 2.0f;
xofft <= plankWidth + plankWidth / 2.0f;
xofft += plankWidth) {
Ogre::Vector3 xoffset = worldOrientation *
(Ogre::Vector3::UNIT_X * xofft);
geo->addEntity(planks, worldPosition + xoffset,
worldOrientation,
Ogre::Vector3(1, 1, 1));
}
step += plankLength;
}
#endif
#if 0
float xofftBeam;
for (xofftBeam = -beamWidth; xofftBeam <= beamWidth;
xofftBeam += beamWidth)
processGrid(beamLength, pierLength,
pierOffset + beamLength / 2.0f, xofftBeam, hm.beam);
#endif
#if 0
step = 0.0f;
while (step < pierLength) {
h = Ogre::Math::Sin(step + pierOffset + position.z * 60.0f +
position.x * 60.0f * 60.0f) *
0.01f;
Ogre::Vector3 worldPosition =
sceneNode->_getDerivedPosition() +
sceneNode->_getDerivedOrientation() *
Ogre::Vector3::UNIT_Z *
(step + pierOffset + beamLength / 2.0f);
Ogre::Quaternion worldOrientation =
sceneNode->_getDerivedOrientation();
float xofft;
for (xofft = -beamWidth - beamWidth / 2.0f;
xofft <= beamWidth + beamWidth / 2.0f;
xofft += beamWidth) {
Ogre::Vector3 xoffset = worldOrientation *
(Ogre::Vector3::UNIT_X * xofft);
geo->addEntity(beam, worldPosition + xoffset,
worldOrientation,
Ogre::Vector3(1, 1, 1));
}
step += beamLength;
}
#endif
#if 0
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(0.5f)
.setSizeZ(pierLength)
.setTextureRectangle(Ogre::RealRect(0.4f, 0.0f, 0.1f, 0.1f))
.setEnableNormals(true)
.setPosition(Ogre::Vector3(-4.0f, -position.y + 0.5f,
pierOffset + pierLength / 2.0f))
.addToTriangleBuffer(tb);
Procedural::BoxGenerator()
.setSizeX(0.5f)
.setSizeY(0.5f)
.setSizeZ(pierLength)
.setTextureRectangle(Ogre::RealRect(0.4f, 0.0f, 0.1f, 0.1f))
.setEnableNormals(true)
.setPosition(Ogre::Vector3(4.0f, -position.y + 0.5f,
pierOffset + pierLength / 2.0f))
.addToTriangleBuffer(tb);
#endif
}
}