Graphics: Rework tilemap class (and fix its AABB)
This commit is contained in:
parent
830eee78a8
commit
3c86b84e13
|
|
@ -11,9 +11,9 @@
|
||||||
#include <Nazara/Core/Color.hpp>
|
#include <Nazara/Core/Color.hpp>
|
||||||
#include <Nazara/Graphics/Config.hpp>
|
#include <Nazara/Graphics/Config.hpp>
|
||||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||||
|
#include <Nazara/Utils/Bitset.hpp>
|
||||||
#include <Nazara/Utility/VertexStruct.hpp>
|
#include <Nazara/Utility/VertexStruct.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
|
@ -71,12 +71,14 @@ namespace Nz
|
||||||
private:
|
private:
|
||||||
Vector3ui GetTextureSize(std::size_t matIndex) const;
|
Vector3ui GetTextureSize(std::size_t matIndex) const;
|
||||||
inline void InvalidateVertices();
|
inline void InvalidateVertices();
|
||||||
|
void UpdateAABB();
|
||||||
void UpdateVertices() const;
|
void UpdateVertices() const;
|
||||||
|
|
||||||
struct Layer
|
struct Layer
|
||||||
{
|
{
|
||||||
std::set<std::size_t> tiles;
|
|
||||||
std::shared_ptr<MaterialInstance> material;
|
std::shared_ptr<MaterialInstance> material;
|
||||||
|
Bitset<UInt64> enabledTiles;
|
||||||
|
std::size_t enabledTileCount = 0; //< cached bitset popcount
|
||||||
};
|
};
|
||||||
|
|
||||||
mutable std::vector<VertexStruct_XYZ_Color_UV> m_vertices;
|
mutable std::vector<VertexStruct_XYZ_Color_UV> m_vertices;
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,14 @@ namespace Nz
|
||||||
|
|
||||||
std::size_t tileIndex = tilePos.y * m_mapSize.x + tilePos.x;
|
std::size_t tileIndex = tilePos.y * m_mapSize.x + tilePos.x;
|
||||||
Tile& tile = m_tiles[tileIndex];
|
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();
|
InvalidateVertices();
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +41,10 @@ namespace Nz
|
||||||
tile.enabled = false;
|
tile.enabled = false;
|
||||||
|
|
||||||
for (Layer& layer : m_layers)
|
for (Layer& layer : m_layers)
|
||||||
layer.tiles.clear();
|
{
|
||||||
|
layer.enabledTiles.Reset();
|
||||||
|
layer.enabledTileCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
InvalidateVertices();
|
InvalidateVertices();
|
||||||
}
|
}
|
||||||
|
|
@ -57,23 +65,27 @@ namespace Nz
|
||||||
{
|
{
|
||||||
NazaraAssert(tilesPos || tileCount == 0, "Invalid tile position array with a non-zero tileCount");
|
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)
|
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");
|
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;
|
std::size_t tileIndex = tilesPos->y * m_mapSize.x + tilesPos->x;
|
||||||
Tile& tile = m_tiles[tileIndex];
|
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++;
|
tilesPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Layer& layer : m_layers)
|
||||||
|
layer.enabledTileCount = layer.enabledTiles.Count();
|
||||||
|
|
||||||
if (tileCount > 0)
|
if (tileCount > 0)
|
||||||
InvalidateVertices();
|
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(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");
|
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
||||||
|
|
||||||
UInt32 invalidatedLayers = 1U << materialIndex;
|
|
||||||
|
|
||||||
std::size_t tileIndex = tilePos.y * m_mapSize.x + tilePos.x;
|
std::size_t tileIndex = tilePos.y * m_mapSize.x + tilePos.x;
|
||||||
Tile& tile = m_tiles[tilePos.y * m_mapSize.x + tilePos.x];
|
Tile& tile = m_tiles[tilePos.y * m_mapSize.x + tilePos.x];
|
||||||
|
|
||||||
if (!tile.enabled)
|
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)
|
else if (materialIndex != tile.layerIndex)
|
||||||
{
|
{
|
||||||
m_layers[tile.layerIndex].tiles.erase(tileIndex);
|
Layer& oldLayer = m_layers[tile.layerIndex];
|
||||||
m_layers[materialIndex].tiles.insert(tileIndex);
|
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;
|
tile.enabled = true;
|
||||||
|
|
@ -180,7 +198,7 @@ namespace Nz
|
||||||
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
||||||
|
|
||||||
for (Layer& layer : m_layers)
|
for (Layer& layer : m_layers)
|
||||||
layer.tiles.clear();
|
layer.enabledTiles.Reset();
|
||||||
|
|
||||||
std::size_t tileIndex = 0;
|
std::size_t tileIndex = 0;
|
||||||
for (Tile& tile : m_tiles)
|
for (Tile& tile : m_tiles)
|
||||||
|
|
@ -190,9 +208,11 @@ namespace Nz
|
||||||
tile.textureCoords = coords;
|
tile.textureCoords = coords;
|
||||||
tile.layerIndex = materialIndex;
|
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();
|
InvalidateVertices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,8 +260,6 @@ namespace Nz
|
||||||
NazaraAssert(tilesPos || tileCount == 0, "Invalid tile position array with a non-zero tileCount");
|
NazaraAssert(tilesPos || tileCount == 0, "Invalid tile position array with a non-zero tileCount");
|
||||||
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
||||||
|
|
||||||
UInt32 invalidatedLayers = 1U << materialIndex;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < tileCount; ++i)
|
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");
|
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];
|
Tile& tile = m_tiles[tileIndex];
|
||||||
|
|
||||||
if (!tile.enabled)
|
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)
|
else if (materialIndex != tile.layerIndex)
|
||||||
{
|
{
|
||||||
m_layers[tile.layerIndex].tiles.erase(tileIndex);
|
Layer& oldLayer = m_layers[tile.layerIndex];
|
||||||
m_layers[materialIndex].tiles.insert(tileIndex);
|
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;
|
tile.enabled = true;
|
||||||
|
|
@ -266,6 +292,9 @@ namespace Nz
|
||||||
tilesPos++;
|
tilesPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Layer& layer : m_layers)
|
||||||
|
layer.enabledTileCount = layer.enabledTiles.Count();
|
||||||
|
|
||||||
if (tileCount > 0)
|
if (tileCount > 0)
|
||||||
InvalidateVertices();
|
InvalidateVertices();
|
||||||
}
|
}
|
||||||
|
|
@ -373,6 +402,7 @@ namespace Nz
|
||||||
m_origin = origin;
|
m_origin = origin;
|
||||||
|
|
||||||
InvalidateVertices();
|
InvalidateVertices();
|
||||||
|
UpdateAABB();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Tilemap::InvalidateVertices()
|
inline void Tilemap::InvalidateVertices()
|
||||||
|
|
@ -380,6 +410,12 @@ namespace Nz
|
||||||
m_shouldRebuildVertices = true;
|
m_shouldRebuildVertices = true;
|
||||||
OnElementInvalidated(this);
|
OnElementInvalidated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Tilemap::UpdateAABB()
|
||||||
|
{
|
||||||
|
Vector2f size = GetSize();
|
||||||
|
InstancedRenderable::UpdateAABB(Rectf(-m_origin * size, size));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Nazara/Graphics/DebugOff.hpp>
|
#include <Nazara/Graphics/DebugOff.hpp>
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ namespace Nz
|
||||||
std::shared_ptr<MaterialInstance> defaultMaterialInstance = Graphics::Instance()->GetDefaultMaterials().basicDefault;
|
std::shared_ptr<MaterialInstance> defaultMaterialInstance = Graphics::Instance()->GetDefaultMaterials().basicDefault;
|
||||||
for (auto& layer : m_layers)
|
for (auto& layer : m_layers)
|
||||||
layer.material = defaultMaterialInstance;
|
layer.material = defaultMaterialInstance;
|
||||||
|
|
||||||
|
UpdateAABB();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tilemap::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
|
void Tilemap::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
|
||||||
|
|
@ -58,7 +60,7 @@ namespace Nz
|
||||||
for (std::size_t layerIndex = 0; layerIndex < m_layers.size(); ++layerIndex)
|
for (std::size_t layerIndex = 0; layerIndex < m_layers.size(); ++layerIndex)
|
||||||
{
|
{
|
||||||
const auto& layer = m_layers[layerIndex];
|
const auto& layer = m_layers[layerIndex];
|
||||||
if (layer.tiles.empty())
|
if (!layer.enabledTiles.TestAny())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto& materialPipeline = layer.material->GetPipeline(passIndex);
|
const auto& materialPipeline = layer.material->GetPipeline(passIndex);
|
||||||
|
|
@ -69,7 +71,7 @@ namespace Nz
|
||||||
|
|
||||||
const auto& renderPipeline = materialPipeline->GetRenderPipeline(&vertexBufferData, 1);
|
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<RenderSpriteChain>(GetRenderLayer(), layer.material, passFlags, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, spriteCount, vertices, *elementData.scissorBox));
|
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), layer.material, passFlags, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, spriteCount, vertices, *elementData.scissorBox));
|
||||||
|
|
||||||
vertices += 4 * spriteCount;
|
vertices += 4 * spriteCount;
|
||||||
|
|
@ -114,22 +116,27 @@ namespace Nz
|
||||||
|
|
||||||
void Tilemap::UpdateVertices() const
|
void Tilemap::UpdateVertices() const
|
||||||
{
|
{
|
||||||
|
std::array<Vector2f, RectCornerCount> 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;
|
std::size_t spriteCount = 0;
|
||||||
for (const Layer& layer : m_layers)
|
for (const Layer& layer : m_layers)
|
||||||
spriteCount += layer.tiles.size();
|
spriteCount += layer.enabledTileCount;
|
||||||
|
|
||||||
m_vertices.resize(spriteCount * 4);
|
m_vertices.resize(spriteCount * 4);
|
||||||
VertexStruct_XYZ_Color_UV* vertexPtr = reinterpret_cast<VertexStruct_XYZ_Color_UV*>(m_vertices.data());
|
VertexStruct_XYZ_Color_UV* vertexPtr = m_vertices.data();
|
||||||
|
|
||||||
float topCorner = m_tileSize.y * (m_mapSize.y - 1);
|
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 (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];
|
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 x = tileIndex % m_mapSize.x;
|
||||||
std::size_t y = tileIndex / m_mapSize.x;
|
std::size_t y = tileIndex / m_mapSize.x;
|
||||||
|
|
@ -140,17 +147,12 @@ namespace Nz
|
||||||
else
|
else
|
||||||
tileLeftBottom.Set(x * m_tileSize.x, topCorner - y * m_tileSize.y, 0.f);
|
tileLeftBottom.Set(x * m_tileSize.x, topCorner - y * m_tileSize.y, 0.f);
|
||||||
|
|
||||||
std::array<Vector2f, RectCornerCount> 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 })
|
for (RectCorner corner : { RectCorner::LeftBottom, RectCorner::RightBottom, RectCorner::LeftTop, RectCorner::RightTop })
|
||||||
{
|
{
|
||||||
vertexPtr->color = tile.color;
|
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->uv = tile.textureCoords.GetCorner(corner);
|
||||||
|
|
||||||
++vertexPtr;
|
++vertexPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue