Files
ogre-prototype/src/gamedata/StaticGeometryModule.cpp
2026-02-21 00:55:39 +03:00

841 lines
29 KiB
C++

#include <iostream>
#include <algorithm>
#include <nlohmann/json.hpp>
#include <OgreTerrainGroup.h>
#include <OgreFileSystemLayer.h>
#include <OgreRTShaderSystem.h>
#include <OgreStaticGeometry.h>
#include <OgreMeshLodGenerator.h>
#include <OgreWorkQueue.h>
#include <Procedural.h>
#include "Components.h"
#include "GameData.h"
#include "TerrainModule.h"
#include "physics.h"
#include "PhysicsModule.h"
#include "CharacterManagerModule.h"
#include "items.h"
#include "StaticGeometryModule.h"
#include "CharacterAIModule.h"
#include <tracy/Tracy.hpp>
namespace ECS
{
static bool itemsLoaded = false;
static bool furnitureLoaded = false;
static bool templatesLoaded = false;
static std::list<std::pair<long, long> > addQueue;
StaticGeometryModule::StaticGeometryModule(flecs::world &ecs)
{
ZoneScoped;
ecs.module<StaticGeometryModule>();
ecs.import <CharacterManagerModule>();
ecs.import <CharacterAIModule>();
ecs.component<TerrainSlotParent>();
ecs.component<TerrainItem>();
ecs.component<FurnitureItem>();
ecs.component<FurnitureInstance>()
.on_remove([](flecs::entity e, FurnitureInstance &instance) {
ZoneScoped;
if (instance.furniture) {
instance.furniture
->destroyAllChildrenAndObjects();
instance.furniture->getCreator()
->destroySceneNode(instance.furniture);
instance.furniture = nullptr;
}
})
.on_set([](flecs::entity e, FurnitureInstance &instance) {
ZoneScoped;
if (instance.furniture !=
e.get<FurnitureInstance>().furniture) {
FurnitureInstance &f =
e.get_mut<FurnitureInstance>();
if (f.furniture) {
f.furniture
->destroyAllChildrenAndObjects();
f.furniture->getCreator()
->destroySceneNode(f.furniture);
}
}
})
.on_add([](flecs::entity e, FurnitureInstance &instance) {
ZoneScoped;
instance.furniture = nullptr;
});
ecs.component<TerrainItemNode>().on_remove([](flecs::entity e,
TerrainItemNode &item) {
ZoneScoped;
if (item.itemNode) {
item.itemNode->destroyAllChildrenAndObjects();
item.itemNode->getCreator()->destroySceneNode(
item.itemNode);
item.itemNode = nullptr;
}
if (item.geo) {
ECS::get<EngineData>().mScnMgr->destroyStaticGeometry(
item.geo);
item.geo = nullptr;
}
});
ecs.component<TerrainItemMeshNode>();
ecs.component<GeometryUpdateItem>();
ecs.import <TerrainModule>();
ecs.observer<const Terrain>("LoadTerrainItems")
.event(flecs::OnSet)
.each([&](const Terrain &terrain) {
ZoneScopedN("LoadTerrainItems");
if (terrain.mTerrainGroup && !itemsLoaded) {
loadItems();
itemsLoaded = true;
}
});
if (!Ogre::MeshLodGenerator::getSingletonPtr())
new Ogre::MeshLodGenerator();
ecs.system<TerrainItem>("SetupTowns")
.kind(flecs::OnUpdate)
.without<TownNPCs>()
.without<TownAI>()
.each([&](flecs::entity e, TerrainItem &item) {
Ogre::String props = item.properties;
nlohmann::json jp = nlohmann::json::parse(props);
if (jp.find("type") == jp.end())
return;
Ogre::String itemType = jp["type"].get<Ogre::String>();
if (itemType == "town")
Geometry::registerTownItem(e);
});
ecs.system("AddGeometryQueue").kind(flecs::OnUpdate).run([&](flecs::iter &it) {
ZoneScopedN("AddGeometryQueue");
std::list<flecs::entity> items;
if (!ECS::get().has<Terrain>())
return;
if (!ECS::get<Terrain>().mTerrainGroup)
return;
if (!itemsLoaded) {
loadItems();
itemsLoaded = true;
return;
}
if (!furnitureLoaded) {
loadFurniture();
furnitureLoaded = true;
}
if (!templatesLoaded) {
loadTemplates();
templatesLoaded = true;
}
std::list<std::pair<long, long> > output;
while (!addQueue.empty()) {
std::pair<long, long> item = addQueue.front();
std::pair<long, long> slot = { item.first,
item.second };
flecs::entity parent =
ECS::get()
.query_builder<const TerrainSlotParent>()
.build()
.find([&slot](const TerrainSlotParent
&parent) {
return parent.slot == slot;
});
if (parent.is_valid()) {
items.clear();
ECS::get()
.query_builder<const TerrainItem>()
.with(flecs::ChildOf, parent)
.without<TerrainItemNode>()
.write<TerrainItemNode>()
.build()
.each([&](flecs::entity e,
const TerrainItem &item) {
items.push_back(e);
});
for (auto e : items)
createItemGeometry(e);
addQueue.pop_front();
} else {
output.push_back(item);
addQueue.pop_front();
}
}
OgreAssert(addQueue.empty(), "queue is not empty");
if (!output.empty())
addQueue = output;
});
}
void StaticGeometryModule::addGeometryForSlot(long x, long y)
{
ZoneScoped;
addQueue.push_back({ x, y });
}
void StaticGeometryModule::removeGeometryForSlot(long x, long y)
{
ZoneScoped;
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)
{
ZoneScoped;
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)
{
ZoneScoped;
OgreAssert(id.is_valid(), "bad id");
id.get_mut<TerrainItem>().properties = properties;
id.modified<TerrainItem>();
}
const Ogre::String &StaticGeometryModule::getItemProperties(flecs::entity id)
{
ZoneScoped;
OgreAssert(id.is_valid(), "bad id");
return id.get<TerrainItem>().properties;
}
nlohmann::json templates;
void StaticGeometryModule::loadTemplates()
{
ZoneScoped;
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
"templates.list"))
return;
Ogre::String group =
Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource("templates.list");
Ogre::DataStreamPtr stream =
Ogre::ResourceGroupManager::getSingleton().openResource(
"templates.list", group);
Ogre::String json = stream->getAsString();
nlohmann::json jtemplates = nlohmann::json::parse(json);
templates = jtemplates;
}
void StaticGeometryModule::saveTemplates()
{
ZoneScoped;
Ogre::String path = "resources/buildings/templates.list";
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
"templates.list")) {
Ogre::String group =
Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource("templates.list");
Ogre::FileInfoListPtr fileInfoList(
Ogre::ResourceGroupManager::getSingleton()
.findResourceFileInfo(group, "templates.list"));
OgreAssert(fileInfoList->size() == 1,
"templates.list should be there and only once");
path = fileInfoList->at(0).archive->getName() + "/" +
"templates.list";
Ogre::FileSystemLayer::removeFile(path);
}
std::fstream fout(path.c_str(), std::ios::out);
fout << templates.dump();
fout.close();
}
void StaticGeometryModule::saveItems()
{
ZoneScoped;
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);
jitem["objects"] = nlohmann::json::array();
ECS::get()
.query_builder<const TerrainItem>()
.with(flecs::ChildOf, e)
.build()
.each([&](flecs::entity obje,
const TerrainItem &objItem) {
nlohmann::json jobjitem;
to_json(jobjitem["position"],
objItem.position);
to_json(jobjitem["orientation"],
objItem.orientation);
to_json(jobjitem["properties"],
objItem.properties);
jitem["objects"].push_back(jobjitem);
});
jitemlist.push_back(jitem);
});
fout << jitemlist.dump();
fout.close();
}
void StaticGeometryModule::loadItems()
{
ZoneScoped;
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>();
std::cout << v.dump(4) << std::endl;
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 });
OgreAssert(slot.is_valid(), "Failed to create slot");
flecs::entity item =
ECS::get().entity().child_of(slot).set<TerrainItem>(
{ position, orientation, properties });
if (v.find("objects") != v.end()) {
for (auto &obj : v["objects"]) {
Ogre::Vector3 objposition;
Ogre::Quaternion objorientation;
Ogre::String objproperties;
from_json(obj["position"], objposition);
from_json(obj["orientation"], objorientation);
objproperties =
obj["properties"].get<Ogre::String>();
flecs::entity itemObj =
ECS::get()
.entity()
.child_of(item)
.set<TerrainItem>(
{ objposition,
objorientation,
objproperties });
}
}
std::cout << "createItem: " << x << " " << y << " " << item.id()
<< std::endl;
std::cout << "position: " << item.id() << " " << position
<< std::endl;
}
}
void StaticGeometryModule::saveFurniture()
{
/* No saving - furniture is generated by blender */
}
void StaticGeometryModule::loadFurniture()
{
ZoneScoped;
ECS::get().delete_with<FurnitureItem>();
static std::vector<Ogre::String> glb_names;
const std::vector<Ogre::String> &groups =
Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
if (glb_names.size() == 0) {
int i;
for (i = 0; i < groups.size(); i++) {
std::vector<Ogre::String> names =
*Ogre::ResourceGroupManager::getSingleton()
.findResourceNames(
groups[i],
"furniture-*.glb.json");
glb_names.insert(glb_names.end(), names.begin(),
names.end());
}
}
for (auto &g : glb_names) {
Ogre::String group = Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource(g);
Ogre::DataStreamPtr stream =
Ogre::ResourceGroupManager::getSingleton().openResource(
g, group);
Ogre::String json = stream->getAsString();
nlohmann::json jdata = nlohmann::json::parse(json);
std::vector<Ogre::String> tags;
for (auto &tag : jdata["tags"]) {
Ogre::String stag = tag.get<Ogre::String>();
tags.push_back(stag);
}
Ogre::String meshName = jdata["mesh"].get<Ogre::String>();
Ogre::MeshPtr mesh =
Ogre::MeshManager::getSingleton().getByName(meshName);
if (mesh) {
Ogre::LodConfig meshconf(mesh);
Geometry::setupLods(meshconf);
}
ECS::get().entity().set<FurnitureItem>({ json, tags });
std::cout << "path: " << g << std::endl;
}
}
void StaticGeometryModule::getItemPositionPerSlot(
long x, long y, std::list<Ogre::Vector3> *positions)
{
ZoneScoped;
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)
{
ZoneScoped;
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)
{
ZoneScoped;
position = e.get<TerrainItem>().position;
orientation = e.get<TerrainItem>().orientation;
}
void StaticGeometryModule::getItemsProperties(
std::list<std::pair<flecs::entity, Ogre::String> > *items)
{
ZoneScoped;
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)
{
ZoneScoped;
Geometry::createItemGeometry(e);
}
void StaticGeometryModule::destroyItemGeometry(flecs::entity e)
{
ZoneScoped;
Geometry::destroyItemGeometry(e);
}
nlohmann::json &StaticGeometryModule::getTemplates()
{
return templates;
}
void StaticGeometryModule::updateItemGeometry(flecs::entity e)
{
ZoneScoped;
// We add this as task to reduce UI load
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([e]() {
ZoneScopedN("updateItemGeometry");
if (e.has<GeometryUpdateItem>())
return;
e.add<GeometryUpdateItem>();
Geometry::updateItemGeometry(e);
e.remove<GeometryUpdateItem>();
});
}
void StaticGeometryModule::addTriangleBufferWork(
const Ogre::String &meshName, Ogre::StaticGeometry *geo,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
const Procedural::TriangleBuffer &tb)
{
ZoneScoped;
struct WorkData {
Ogre::String meshName;
Ogre::StaticGeometry *geo;
Ogre::Vector3 position;
Ogre::Quaternion rotation;
Procedural::TriangleBuffer tb;
};
WorkData data = { meshName, geo, position, rotation, tb };
// We add this as task to reduce UI load
Ogre::Root::getSingleton().getWorkQueue()->addMainThreadTask([data]() {
ZoneScopedN("addTriangleBufferWork");
Ogre::MeshPtr mesh = data.tb.transformToMesh(data.meshName);
Ogre::Entity *ent =
ECS::get<EngineData>().mScnMgr->createEntity(mesh);
data.geo->addEntity(ent, data.position, data.rotation);
ECS::get<EngineData>().mScnMgr->destroyEntity(ent);
});
}
struct TiledMeshes {
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));
}
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()),
{} };
}
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);
config.createGeneratedLodLevel(15, 0.49f);
config.createGeneratedLodLevel(150, 0.75f);
config.advanced.useBackgroundQueue = false;
Ogre::MeshLodGenerator::getSingleton().generateLodLevels(
config);
return settings.mesh;
}
void removeTile(const Ogre::String &name)
{
tiles.erase(name);
}
TiledMeshes()
{
}
};
}