From 3c86b84e132335bd37a7ce8a8dc12d82edd7c71d Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sun, 18 Dec 2022 14:57:40 +0100 Subject: [PATCH] Graphics: Rework tilemap class (and fix its AABB) --- include/Nazara/Graphics/Tilemap.hpp | 6 ++- include/Nazara/Graphics/Tilemap.inl | 80 +++++++++++++++++++++-------- src/Nazara/Graphics/Tilemap.cpp | 30 ++++++----- 3 files changed, 78 insertions(+), 38 deletions(-) diff --git a/include/Nazara/Graphics/Tilemap.hpp b/include/Nazara/Graphics/Tilemap.hpp index 3a4cf3bb7..17f5b9b29 100644 --- a/include/Nazara/Graphics/Tilemap.hpp +++ b/include/Nazara/Graphics/Tilemap.hpp @@ -11,9 +11,9 @@ #include #include #include +#include #include #include -#include namespace Nz { @@ -71,12 +71,14 @@ namespace Nz private: Vector3ui GetTextureSize(std::size_t matIndex) const; inline void InvalidateVertices(); + void UpdateAABB(); void UpdateVertices() const; struct Layer { - std::set tiles; std::shared_ptr material; + Bitset enabledTiles; + std::size_t enabledTileCount = 0; //< cached bitset popcount }; mutable std::vector m_vertices; diff --git a/include/Nazara/Graphics/Tilemap.inl b/include/Nazara/Graphics/Tilemap.inl index 629be65bc..83c1a17f6 100644 --- a/include/Nazara/Graphics/Tilemap.inl +++ b/include/Nazara/Graphics/Tilemap.inl @@ -20,9 +20,14 @@ namespace Nz std::size_t tileIndex = tilePos.y * m_mapSize.x + tilePos.x; Tile& tile = m_tiles[tileIndex]; - tile.enabled = false; + if (tile.enabled) + { + tile.enabled = false; - m_layers[tile.layerIndex].tiles.erase(tileIndex); + Layer& layer = m_layers[tile.layerIndex]; + layer.enabledTiles.Reset(tileIndex); + layer.enabledTileCount = layer.enabledTiles.Count(); + } InvalidateVertices(); } @@ -36,7 +41,10 @@ namespace Nz tile.enabled = false; for (Layer& layer : m_layers) - layer.tiles.clear(); + { + layer.enabledTiles.Reset(); + layer.enabledTileCount = 0; + } InvalidateVertices(); } @@ -57,23 +65,27 @@ namespace Nz { NazaraAssert(tilesPos || tileCount == 0, "Invalid tile position array with a non-zero tileCount"); - UInt32 invalidatedLayers = 0; - for (std::size_t i = 0; i < tileCount; ++i) { NazaraAssert(tilesPos->x < m_mapSize.x&& tilesPos->y < m_mapSize.y, "Tile position is out of bounds"); std::size_t tileIndex = tilesPos->y * m_mapSize.x + tilesPos->x; Tile& tile = m_tiles[tileIndex]; - tile.enabled = false; - m_layers[tile.layerIndex].tiles.erase(tileIndex); + if (tile.enabled) + { + tile.enabled = false; - invalidatedLayers |= 1U << tile.layerIndex; + Layer& layer = m_layers[tile.layerIndex]; + layer.enabledTiles.Reset(tileIndex); + } tilesPos++; } + for (Layer& layer : m_layers) + layer.enabledTileCount = layer.enabledTiles.Count(); + if (tileCount > 0) InvalidateVertices(); } @@ -111,19 +123,25 @@ namespace Nz NazaraAssert(tilePos.x < m_mapSize.x&& tilePos.y < m_mapSize.y, "Tile position is out of bounds"); NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds"); - UInt32 invalidatedLayers = 1U << materialIndex; - std::size_t tileIndex = tilePos.y * m_mapSize.x + tilePos.x; Tile& tile = m_tiles[tilePos.y * m_mapSize.x + tilePos.x]; if (!tile.enabled) - m_layers[materialIndex].tiles.insert(tileIndex); + { + Layer& layer = m_layers[materialIndex]; + layer.enabledTiles.UnboundedSet(tileIndex); + layer.enabledTileCount = layer.enabledTiles.Count(); + } else if (materialIndex != tile.layerIndex) { - m_layers[tile.layerIndex].tiles.erase(tileIndex); - m_layers[materialIndex].tiles.insert(tileIndex); + Layer& oldLayer = m_layers[tile.layerIndex]; + Layer& newLayer = m_layers[tile.layerIndex]; - invalidatedLayers |= 1U << tile.layerIndex; + oldLayer.enabledTiles.Reset(tileIndex); + oldLayer.enabledTileCount = oldLayer.enabledTiles.Count(); + + newLayer.enabledTiles.UnboundedSet(tileIndex); + newLayer.enabledTileCount = newLayer.enabledTiles.Count(); } tile.enabled = true; @@ -180,7 +198,7 @@ namespace Nz NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds"); for (Layer& layer : m_layers) - layer.tiles.clear(); + layer.enabledTiles.Reset(); std::size_t tileIndex = 0; for (Tile& tile : m_tiles) @@ -190,9 +208,11 @@ namespace Nz tile.textureCoords = coords; tile.layerIndex = materialIndex; - m_layers[materialIndex].tiles.insert(tileIndex++); + m_layers[materialIndex].enabledTiles.UnboundedSet(tileIndex++); } + m_layers[materialIndex].enabledTileCount = m_layers[materialIndex].enabledTiles.Count(); + InvalidateVertices(); } @@ -240,8 +260,6 @@ namespace Nz NazaraAssert(tilesPos || tileCount == 0, "Invalid tile position array with a non-zero tileCount"); NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds"); - UInt32 invalidatedLayers = 1U << materialIndex; - for (std::size_t i = 0; i < tileCount; ++i) { NazaraAssert(tilesPos->x < m_mapSize.x&& tilesPos->y < m_mapSize.y, "Tile position is out of bounds"); @@ -250,13 +268,21 @@ namespace Nz Tile& tile = m_tiles[tileIndex]; if (!tile.enabled) - m_layers[materialIndex].tiles.insert(tileIndex); + { + Layer& layer = m_layers[materialIndex]; + layer.enabledTiles.UnboundedSet(tileIndex); + layer.enabledTileCount = layer.enabledTiles.Count(); + } else if (materialIndex != tile.layerIndex) { - m_layers[tile.layerIndex].tiles.erase(tileIndex); - m_layers[materialIndex].tiles.insert(tileIndex); + Layer& oldLayer = m_layers[tile.layerIndex]; + Layer& newLayer = m_layers[tile.layerIndex]; - invalidatedLayers |= 1U << tile.layerIndex; + oldLayer.enabledTiles.Reset(tileIndex); + oldLayer.enabledTileCount = oldLayer.enabledTiles.Count(); + + newLayer.enabledTiles.UnboundedSet(tileIndex); + newLayer.enabledTileCount = newLayer.enabledTiles.Count(); } tile.enabled = true; @@ -266,6 +292,9 @@ namespace Nz tilesPos++; } + for (Layer& layer : m_layers) + layer.enabledTileCount = layer.enabledTiles.Count(); + if (tileCount > 0) InvalidateVertices(); } @@ -373,6 +402,7 @@ namespace Nz m_origin = origin; InvalidateVertices(); + UpdateAABB(); } inline void Tilemap::InvalidateVertices() @@ -380,6 +410,12 @@ namespace Nz m_shouldRebuildVertices = true; OnElementInvalidated(this); } + + inline void Tilemap::UpdateAABB() + { + Vector2f size = GetSize(); + InstancedRenderable::UpdateAABB(Rectf(-m_origin * size, size)); + } } #include diff --git a/src/Nazara/Graphics/Tilemap.cpp b/src/Nazara/Graphics/Tilemap.cpp index a82adaba7..f075c84e7 100644 --- a/src/Nazara/Graphics/Tilemap.cpp +++ b/src/Nazara/Graphics/Tilemap.cpp @@ -38,6 +38,8 @@ namespace Nz std::shared_ptr defaultMaterialInstance = Graphics::Instance()->GetDefaultMaterials().basicDefault; for (auto& layer : m_layers) layer.material = defaultMaterialInstance; + + UpdateAABB(); } void Tilemap::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector& elements) const @@ -58,7 +60,7 @@ namespace Nz for (std::size_t layerIndex = 0; layerIndex < m_layers.size(); ++layerIndex) { const auto& layer = m_layers[layerIndex]; - if (layer.tiles.empty()) + if (!layer.enabledTiles.TestAny()) continue; const auto& materialPipeline = layer.material->GetPipeline(passIndex); @@ -69,7 +71,7 @@ namespace Nz const auto& renderPipeline = materialPipeline->GetRenderPipeline(&vertexBufferData, 1); - std::size_t spriteCount = layer.tiles.size(); + std::size_t spriteCount = layer.enabledTileCount; elements.emplace_back(registry.AllocateElement(GetRenderLayer(), layer.material, passFlags, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, spriteCount, vertices, *elementData.scissorBox)); vertices += 4 * spriteCount; @@ -114,22 +116,27 @@ namespace Nz void Tilemap::UpdateVertices() const { + std::array cornerExtent; + cornerExtent[UnderlyingCast(RectCorner::LeftBottom)] = Vector2f(0.f, 0.f); + cornerExtent[UnderlyingCast(RectCorner::RightBottom)] = Vector2f(1.f, 0.f); + cornerExtent[UnderlyingCast(RectCorner::LeftTop)] = Vector2f(0.f, 1.f); + cornerExtent[UnderlyingCast(RectCorner::RightTop)] = Vector2f(1.f, 1.f); + std::size_t spriteCount = 0; for (const Layer& layer : m_layers) - spriteCount += layer.tiles.size(); + spriteCount += layer.enabledTileCount; m_vertices.resize(spriteCount * 4); - VertexStruct_XYZ_Color_UV* vertexPtr = reinterpret_cast(m_vertices.data()); + VertexStruct_XYZ_Color_UV* vertexPtr = m_vertices.data(); float topCorner = m_tileSize.y * (m_mapSize.y - 1); - Vector3f originShift = m_origin * GetSize(); + Vector2f originShift = m_origin * GetSize(); for (const Layer& layer : m_layers) { - for (std::size_t tileIndex : layer.tiles) + for (std::size_t tileIndex = layer.enabledTiles.FindFirst(); tileIndex != layer.enabledTiles.npos; tileIndex = layer.enabledTiles.FindNext(tileIndex)) { const Tile& tile = m_tiles[tileIndex]; - NazaraAssert(tile.enabled, "Tile specified for rendering is not enabled"); std::size_t x = tileIndex % m_mapSize.x; std::size_t y = tileIndex / m_mapSize.x; @@ -140,17 +147,12 @@ namespace Nz else tileLeftBottom.Set(x * m_tileSize.x, topCorner - y * m_tileSize.y, 0.f); - std::array cornerExtent; - cornerExtent[UnderlyingCast(RectCorner::LeftBottom)] = Vector2f(0.f, 0.f); - cornerExtent[UnderlyingCast(RectCorner::RightBottom)] = Vector2f(1.f, 0.f); - cornerExtent[UnderlyingCast(RectCorner::LeftTop)] = Vector2f(0.f, 1.f); - cornerExtent[UnderlyingCast(RectCorner::RightTop)] = Vector2f(1.f, 1.f); - for (RectCorner corner : { RectCorner::LeftBottom, RectCorner::RightBottom, RectCorner::LeftTop, RectCorner::RightTop }) { vertexPtr->color = tile.color; - vertexPtr->position = tileLeftBottom + Vector3f(m_tileSize * cornerExtent[UnderlyingCast(corner)], 0.f) - originShift; + vertexPtr->position = tileLeftBottom + Vector3f(m_tileSize * cornerExtent[UnderlyingCast(corner)] - originShift, 0.f); vertexPtr->uv = tile.textureCoords.GetCorner(corner); + ++vertexPtr; } }