#include #include #include #include #include #include #include #include #include "Components.h" #include "GameData.h" #include "TerrainModule.h" #include "StaticGeometryModule.h" namespace ECS { StaticGeometryModule::StaticGeometryModule(flecs::world &ecs) { ecs.module(); ecs.component(); ecs.component(); ecs.component().on_remove( [](flecs::entity e, TerrainItemNode &item) { if (item.itemNode) { item.itemNode->destroyAllChildrenAndObjects(); item.itemNode->getCreator()->destroySceneNode( item.itemNode); item.itemNode = nullptr; } }); ecs.import (); ecs.observer("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 slot = { x, y }; flecs::entity parent = ECS::get().query_builder().build().find( [&slot](const TerrainSlotParent &parent) { return parent.slot == slot; }); std::cout << "addGeometryForSlot: " << x << " " << y << std::endl; std::list items; if (parent.is_valid()) { ECS::get() .query_builder() .with(flecs::ChildOf, parent) .without() .write() .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 slot = { x, y }; flecs::entity parent = ECS::get().query_builder().build().find( [&slot](const TerrainSlotParent &parent) { return parent.slot == slot; }); if (parent.is_valid()) { ECS::get() .query_builder() .with(flecs::ChildOf, parent) .without() .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().mTerrainGroup->convertWorldPositionToTerrainSlot( position, &x, &y); std::pair pos{ x, y }; flecs::entity slot = ECS::get().query_builder().build().find( [&](const TerrainSlotParent &slot) -> bool { return slot.slot == pos; }); if (!slot.is_valid()) slot = ECS::get().entity().set({ pos }); flecs::entity item = ECS::get().entity().child_of(slot); nlohmann::json jproperties; jproperties["type"] = type; item.set({ 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().properties = properties; id.modified(); } const Ogre::String &StaticGeometryModule::getItemProperties(flecs::entity id) { OgreAssert(id.is_valid(), "bad id"); return id.get().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(); position.y = j["y"].get(); position.z = j["z"].get(); } static void from_json(const nlohmann::json &j, Ogre::Quaternion &orientation) { orientation.w = j["w"].get(); orientation.x = j["x"].get(); orientation.y = j["y"].get(); orientation.z = j["z"].get(); } 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().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(); ECS::get().delete_with(); 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(); long x, y; ECS::get() .mTerrainGroup->convertWorldPositionToTerrainSlot( position, &x, &y); std::pair pos{ x, y }; flecs::entity slot = ECS::get() .query_builder() .build() .find([&](const TerrainSlotParent &slot) -> bool { return slot.slot == pos; }); if (!slot.is_valid()) slot = ECS::get().entity().set( { pos }); flecs::entity item = ECS::get().entity().child_of(slot); item.set({ 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 *positions) { std::pair pos{ x, y }; if (!positions) return; flecs::entity slot = ECS::get().query_builder().build().find( [&](const TerrainSlotParent &slot) -> bool { return slot.slot == pos; }); if (!slot.is_valid()) return; ECS::get() .query_builder() .with(flecs::ChildOf, slot) .build() .each([&](flecs::entity e, const TerrainItem &item) { positions->push_back(item.position); }); } void StaticGeometryModule::getItemPositions(std::list *positions) { ECS::get().query_builder().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().position; orientation = e.get().orientation; } void StaticGeometryModule::getItemsProperties( std::list > *items) { ECS::get().query_builder().build().each( [&](flecs::entity e, const TerrainItem &item) { items->push_back({ e, item.properties }); }); } void StaticGeometryModule::createItemGeometry(flecs::entity e) { OgreAssert(!e.has(), "Geometry already created"); Ogre::String props = e.get().properties; nlohmann::json jp = nlohmann::json::parse(props); Ogre::SceneNode *itemNode = ECS::get() .mScnMgr->getRootSceneNode() ->createChildSceneNode(); itemNode->_setDerivedPosition(e.get().position); itemNode->_setDerivedOrientation(e.get().orientation); if (jp.find("staticMesh") != jp.end()) { Ogre::String meshName = jp["staticMesh"].get(); Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().getByName(meshName); if (mesh) { Ogre::Entity *ent = ECS::get().mScnMgr->createEntity( mesh); itemNode->attachObject(ent); } } else if (jp.find("type") != jp.end()) { Ogre::String itemType = jp["type"].get(); std::cout << "type: " << itemType << std::endl; std::cout << "props: " << props << std::endl; if (itemType == "harbour") { createHarbour(e, itemNode); e.set({ 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().mScnMgr->createEntity( "Plank" + Ogre::StringConverter::toString(e.id()), "pier-plank.glb"); beam = ECS::get().mScnMgr->createEntity( "Beam" + Ogre::StringConverter::toString(e.id()), "pier-beam.glb"); pillar = ECS::get().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 vertexData; std::shared_ptr indexData; std::set positions; }; std::map 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(vertexData), std::shared_ptr( submesh->indexData->clone()), {} }; #if 0 std::vector vertices; std::vector 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 srcIndexData = tile.indexData; int srcIndexCount = srcIndexData->indexCount; std::shared_ptr 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(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( 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(srcPtr); float *dstPositionData = reinterpret_cast(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(srcPtr); float *dstNormalData = reinterpret_cast(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 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 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(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(vertexLock.pData); unsigned int *dstIndices = static_cast(indexLock.pData); for (const auto &tile : tiles) { std::shared_ptr srcIndexData = tile.second.indexData; int srcIndexCount = srcIndexData->indexCount; std::shared_ptr 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().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().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(); if (jp.find("pierLength") != jp.end()) pierLength = jp["pierLength"].get(); if (jp.find("pierDepth") != jp.end()) pierDepth = jp["pierDepth"].get(); if (jp.find("pierHeight") != jp.end()) pierHeight = jp["pierHeight"].get(); 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().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 } }