Graphics: Add Tilemap
This commit is contained in:
@@ -80,6 +80,7 @@
|
||||
#include <Nazara/Graphics/SubmeshRenderer.hpp>
|
||||
#include <Nazara/Graphics/TextSprite.hpp>
|
||||
#include <Nazara/Graphics/TextureSamplerCache.hpp>
|
||||
#include <Nazara/Graphics/Tilemap.hpp>
|
||||
#include <Nazara/Graphics/TransferInterface.hpp>
|
||||
#include <Nazara/Graphics/UberShader.hpp>
|
||||
#include <Nazara/Graphics/ViewerInstance.hpp>
|
||||
|
||||
94
include/Nazara/Graphics/Tilemap.hpp
Normal file
94
include/Nazara/Graphics/Tilemap.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_GRAPHICS_TILEMAP_HPP
|
||||
#define NAZARA_GRAPHICS_TILEMAP_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/Color.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||
#include <Nazara/Utility/VertexStruct.hpp>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class MaterialInstance;
|
||||
|
||||
class NAZARA_GRAPHICS_API Tilemap : public InstancedRenderable
|
||||
{
|
||||
public:
|
||||
struct Tile;
|
||||
|
||||
Tilemap(const Vector2ui& mapSize, const Vector2f& tileSize, std::size_t materialCount = 1);
|
||||
Tilemap(const Tilemap&) = delete;
|
||||
Tilemap(Tilemap&&) noexcept = default;
|
||||
~Tilemap() = default;
|
||||
|
||||
void BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const override;
|
||||
|
||||
inline void DisableTile(const Vector2ui& tilePos);
|
||||
inline void DisableTiles();
|
||||
inline void DisableTiles(const Vector2ui* tilesPos, std::size_t tileCount);
|
||||
|
||||
inline void EnableIsometricMode(bool isometric);
|
||||
|
||||
inline void EnableTile(const Vector2ui& tilePos, const Rectf& coords, const Color& color = Color::White, std::size_t materialIndex = 0U);
|
||||
inline void EnableTile(const Vector2ui& tilePos, const Rectui& rect, const Color& color = Color::White, std::size_t materialIndex = 0U);
|
||||
inline void EnableTiles(const Rectf& coords, const Color& color = Color::White, std::size_t materialIndex = 0U);
|
||||
inline void EnableTiles(const Rectui& rect, const Color& color = Color::White, std::size_t materialIndex = 0U);
|
||||
inline void EnableTiles(const Vector2ui* tilesPos, std::size_t tileCount, const Rectf& coords, const Color& color = Color::White, std::size_t materialIndex = 0U);
|
||||
inline void EnableTiles(const Vector2ui* tilesPos, std::size_t tileCount, const Rectui& rect, const Color& color = Color::White, std::size_t materialIndex = 0U);
|
||||
|
||||
inline const Vector2ui& GetMapSize() const;
|
||||
const std::shared_ptr<MaterialInstance>& GetMaterial(std::size_t i) const override;
|
||||
std::size_t GetMaterialCount() const override;
|
||||
inline Vector2f GetSize() const;
|
||||
inline const Tile& GetTile(const Vector2ui& tilePos) const;
|
||||
inline const Vector2f& GetTileSize() const;
|
||||
|
||||
inline bool IsIsometricModeEnabled() const;
|
||||
|
||||
void SetMaterial(std::size_t matIndex, std::shared_ptr<MaterialInstance> material);
|
||||
inline void SetOrigin(const Vector3f& origin);
|
||||
|
||||
struct Tile
|
||||
{
|
||||
std::size_t layerIndex = 0U;
|
||||
Color color = Color::White;
|
||||
Rectf textureCoords = Rectf::Zero();
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
Tilemap& operator=(const Tilemap&) = delete;
|
||||
Tilemap& operator=(Tilemap&&) noexcept = default;
|
||||
|
||||
private:
|
||||
Vector3ui GetTextureSize(std::size_t matIndex) const;
|
||||
inline void InvalidateVertices();
|
||||
void UpdateVertices() const;
|
||||
|
||||
struct Layer
|
||||
{
|
||||
std::set<std::size_t> tiles;
|
||||
std::shared_ptr<MaterialInstance> material;
|
||||
};
|
||||
|
||||
mutable std::vector<VertexStruct_XYZ_Color_UV> m_vertices;
|
||||
std::vector<Tile> m_tiles;
|
||||
std::vector<Layer> m_layers;
|
||||
Vector2ui m_mapSize;
|
||||
Vector2f m_tileSize;
|
||||
Vector3f m_origin;
|
||||
bool m_isometricModeEnabled;
|
||||
mutable bool m_shouldRebuildVertices;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/Tilemap.inl>
|
||||
|
||||
#endif // NAZARA_GRAPHICS_TILEMAP_HPP
|
||||
376
include/Nazara/Graphics/Tilemap.inl
Normal file
376
include/Nazara/Graphics/Tilemap.inl
Normal file
@@ -0,0 +1,376 @@
|
||||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/Tilemap.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Disable the tile at position tilePos, disabling rendering at this location
|
||||
*
|
||||
* \param tilePos Position of the tile to disable
|
||||
*
|
||||
* \see DisableTiles
|
||||
*/
|
||||
inline void Tilemap::DisableTile(const Vector2ui& tilePos)
|
||||
{
|
||||
NazaraAssert(tilePos.x < m_mapSize.x&& tilePos.y < m_mapSize.y, "Tile position is out of bounds");
|
||||
|
||||
std::size_t tileIndex = tilePos.y * m_mapSize.x + tilePos.x;
|
||||
Tile& tile = m_tiles[tileIndex];
|
||||
tile.enabled = false;
|
||||
|
||||
m_layers[tile.layerIndex].tiles.erase(tileIndex);
|
||||
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disable all tiles
|
||||
*/
|
||||
inline void Tilemap::DisableTiles()
|
||||
{
|
||||
for (Tile& tile : m_tiles)
|
||||
tile.enabled = false;
|
||||
|
||||
for (Layer& layer : m_layers)
|
||||
layer.tiles.clear();
|
||||
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disable tileCount tiles at positions contained at tilesPos location, disabling rendering at those locations
|
||||
*
|
||||
* This is equivalent to calling tileCount times DisableTile with the positions contained at tilesPos
|
||||
*
|
||||
* \param tilesPos Pointer to a valid array of at least tileCount positions
|
||||
* \param tileCount Number of tiles to disable
|
||||
*
|
||||
* \remark if tileCount is zero, this is a no-op and the value of tilesPos is not used
|
||||
*
|
||||
* \see DisableTile
|
||||
*/
|
||||
inline void Tilemap::DisableTiles(const Vector2ui* tilesPos, std::size_t 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)
|
||||
{
|
||||
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);
|
||||
|
||||
invalidatedLayers |= 1U << tile.layerIndex;
|
||||
|
||||
tilesPos++;
|
||||
}
|
||||
|
||||
if (tileCount > 0)
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable/Disable isometric mode
|
||||
*
|
||||
* If enabled, every odd line will overlap by half the tile size with the upper line
|
||||
*
|
||||
* \param isometric Should the isometric mode be enabled for this Tilemap
|
||||
*
|
||||
* \see IsIsometricModeEnabled
|
||||
*/
|
||||
inline void Tilemap::EnableIsometricMode(bool isometric)
|
||||
{
|
||||
m_isometricModeEnabled = isometric;
|
||||
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable and sets the tile at position tilePos
|
||||
*
|
||||
* Setup the tile at position tilePos using color, normalized coordinates coords and materialIndex
|
||||
*
|
||||
* \param tilePos Position of the tile to enable
|
||||
* \param coords Normalized coordinates ([0..1]) used to specify which region of the material textures will be used
|
||||
* \param color The multiplicative color applied to the tile
|
||||
* \param materialIndex The material which will be used for rendering this tile
|
||||
*
|
||||
* \see EnableTiles
|
||||
*/
|
||||
inline void Tilemap::EnableTile(const Vector2ui& tilePos, const Rectf& coords, const Color& color, std::size_t materialIndex)
|
||||
{
|
||||
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);
|
||||
else if (materialIndex != tile.layerIndex)
|
||||
{
|
||||
m_layers[tile.layerIndex].tiles.erase(tileIndex);
|
||||
m_layers[materialIndex].tiles.insert(tileIndex);
|
||||
|
||||
invalidatedLayers |= 1U << tile.layerIndex;
|
||||
}
|
||||
|
||||
tile.enabled = true;
|
||||
tile.color = color;
|
||||
tile.textureCoords = coords;
|
||||
tile.layerIndex = materialIndex;
|
||||
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable and sets the tile at position tilePos
|
||||
*
|
||||
* Setup the tile at position tilePos using color, unnormalized coordinates rect and materialIndex
|
||||
*
|
||||
* \param tilePos Position of the tile to enable
|
||||
* \param coords Unnormalized coordinates ([0..size]) used to specify which region of the material textures will be used
|
||||
* \param color The multiplicative color applied to the tile
|
||||
* \param materialIndex The material which will be used for rendering this tile
|
||||
*
|
||||
* \remark The material at [materialIndex] must have a valid diffuse map before using this function,
|
||||
* as the size of the material diffuse map is used to compute normalized texture coordinates before returning.
|
||||
*
|
||||
* \see EnableTiles
|
||||
*/
|
||||
inline void Tilemap::EnableTile(const Vector2ui& tilePos, const Rectui& rect, const Color& color, std::size_t materialIndex)
|
||||
{
|
||||
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
||||
|
||||
Vector2ui textureSize(GetTextureSize(materialIndex));
|
||||
float invWidth = 1.f / textureSize.x;
|
||||
float invHeight = 1.f / textureSize.y;
|
||||
|
||||
Rectf unnormalizedCoords(invWidth * rect.x, invHeight * rect.y, invWidth * rect.width, invHeight * rect.height);
|
||||
EnableTile(tilePos, unnormalizedCoords, color, materialIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable and sets all the tiles
|
||||
*
|
||||
* Setup all tiles using color, normalized coordinates coords and materialIndex
|
||||
*
|
||||
* \param coords Normalized coordinates ([0..1]) used to specify which region of the material textures will be used
|
||||
* \param color The multiplicative color applied to the tile
|
||||
* \param materialIndex The material which will be used for rendering this tile
|
||||
*
|
||||
* \remark The material at [materialIndex] must have a valid diffuse map before using this function,
|
||||
* as the size of the material diffuse map is used to compute normalized texture coordinates before returning.
|
||||
*
|
||||
* \see EnableTile
|
||||
*/
|
||||
inline void Tilemap::EnableTiles(const Rectf& coords, const Color& color, std::size_t materialIndex)
|
||||
{
|
||||
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
||||
|
||||
for (Layer& layer : m_layers)
|
||||
layer.tiles.clear();
|
||||
|
||||
std::size_t tileIndex = 0;
|
||||
for (Tile& tile : m_tiles)
|
||||
{
|
||||
tile.enabled = true;
|
||||
tile.color = color;
|
||||
tile.textureCoords = coords;
|
||||
tile.layerIndex = materialIndex;
|
||||
|
||||
m_layers[materialIndex].tiles.insert(tileIndex++);
|
||||
}
|
||||
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable and sets all the tiles
|
||||
*
|
||||
* Setup all tiles using color, unnormalized coordinates coords and materialIndex
|
||||
*
|
||||
* \param coords Unnormalized coordinates ([0..size]) used to specify which region of the material textures will be used
|
||||
* \param color The multiplicative color applied to the tile
|
||||
* \param materialIndex The material which will be used for rendering this tile
|
||||
*
|
||||
* \remark The material at [materialIndex] must have a valid diffuse map before using this function,
|
||||
* as the size of the material diffuse map is used to compute normalized texture coordinates before returning.
|
||||
*
|
||||
* \see EnableTile
|
||||
*/
|
||||
inline void Tilemap::EnableTiles(const Rectui& rect, const Color& color, std::size_t materialIndex)
|
||||
{
|
||||
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
||||
|
||||
Vector2ui textureSize(GetTextureSize(materialIndex));
|
||||
float invWidth = 1.f / textureSize.x;
|
||||
float invHeight = 1.f / textureSize.y;
|
||||
|
||||
Rectf unnormalizedCoords(invWidth * rect.x, invHeight * rect.y, invWidth * rect.width, invHeight * rect.height);
|
||||
EnableTiles(unnormalizedCoords, color, materialIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable and sets tileCount tiles at positions contained at tilesPos location, enabling rendering at those locations
|
||||
*
|
||||
* Setup all tiles using color, normalized coordinates coords and materialIndex
|
||||
*
|
||||
* \param tilesPos Pointer to a valid array of at least tileCount positions
|
||||
* \param tileCount Number of tiles to enable
|
||||
* \param coords Normalized coordinates ([0..1]) used to specify which region of the material textures will be used
|
||||
* \param color The multiplicative color applied to the tile
|
||||
* \param materialIndex The material which will be used for rendering this tile
|
||||
*
|
||||
* \see EnableTile
|
||||
*/
|
||||
inline void Tilemap::EnableTiles(const Vector2ui* tilesPos, std::size_t tileCount, const Rectf& coords, const Color& color, std::size_t materialIndex)
|
||||
{
|
||||
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");
|
||||
|
||||
std::size_t tileIndex = tilesPos->y * m_mapSize.x + tilesPos->x;
|
||||
Tile& tile = m_tiles[tileIndex];
|
||||
|
||||
if (!tile.enabled)
|
||||
m_layers[materialIndex].tiles.insert(tileIndex);
|
||||
else if (materialIndex != tile.layerIndex)
|
||||
{
|
||||
m_layers[tile.layerIndex].tiles.erase(tileIndex);
|
||||
m_layers[materialIndex].tiles.insert(tileIndex);
|
||||
|
||||
invalidatedLayers |= 1U << tile.layerIndex;
|
||||
}
|
||||
|
||||
tile.enabled = true;
|
||||
tile.color = color;
|
||||
tile.textureCoords = coords;
|
||||
tile.layerIndex = materialIndex;
|
||||
tilesPos++;
|
||||
}
|
||||
|
||||
if (tileCount > 0)
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable and sets tileCount tiles at positions contained at tilesPos location, enabling rendering at those locations
|
||||
*
|
||||
* Setup all tiles using color, unnormalized coordinates coords and materialIndex
|
||||
*
|
||||
* \param tilesPos Pointer to a valid array of at least tileCount positions
|
||||
* \param tileCount Number of tiles to enable
|
||||
* \param coords Unnormalized coordinates ([0..size]) used to specify which region of the material textures will be used
|
||||
* \param color The multiplicative color applied to the tile
|
||||
* \param materialIndex The material which will be used for rendering this tile
|
||||
*
|
||||
* \remark The material at [materialIndex] must have a valid diffuse map before using this function,
|
||||
* as the size of the material diffuse map is used to compute normalized texture coordinates before returning.
|
||||
*
|
||||
* \see EnableTile
|
||||
*/
|
||||
inline void Tilemap::EnableTiles(const Vector2ui* tilesPos, std::size_t tileCount, const Rectui& rect, const Color& color, std::size_t materialIndex)
|
||||
{
|
||||
NazaraAssert(materialIndex < m_layers.size(), "Material out of bounds");
|
||||
|
||||
Vector2ui textureSize(GetTextureSize(materialIndex));
|
||||
float invWidth = 1.f / textureSize.x;
|
||||
float invHeight = 1.f / textureSize.y;
|
||||
|
||||
Rectf unnormalizedCoords(invWidth * rect.x, invHeight * rect.y, invWidth * rect.width, invHeight * rect.height);
|
||||
EnableTiles(tilesPos, tileCount, unnormalizedCoords, color, materialIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the tilemap size (i.e. number of tiles in each dimension)
|
||||
* \return Number of tiles in each dimension
|
||||
*
|
||||
* \see GetSize
|
||||
* \see GetTileSize
|
||||
*/
|
||||
inline const Vector2ui& Tilemap::GetMapSize() const
|
||||
{
|
||||
return m_mapSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the size of the tilemap in units (which is equivalent to GetMapSize() * GetTileSize())
|
||||
* \return Maximum size in units occupied by this tilemap
|
||||
*
|
||||
* \see GetMapSize
|
||||
* \see GetTileSize
|
||||
*/
|
||||
inline Vector2f Tilemap::GetSize() const
|
||||
{
|
||||
return Vector2f(m_mapSize) * m_tileSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns informations about a particular tile
|
||||
*
|
||||
* \param tilePos Position of the tile to get (enabled or not)
|
||||
*
|
||||
* \return Maximum size in units occupied by this tilemap
|
||||
*/
|
||||
inline const Tilemap::Tile& Tilemap::GetTile(const Vector2ui& tilePos) const
|
||||
{
|
||||
NazaraAssert(tilePos.x < m_mapSize.x&& tilePos.y < m_mapSize.y, "Tile position is out of bounds");
|
||||
|
||||
return m_tiles[tilePos.y * m_mapSize.x + tilePos.x];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the tile size (i.e. number of units occupied by a tile in each dimension)
|
||||
* \return Tile size in each dimension
|
||||
*
|
||||
* \see GetMapSize
|
||||
* \see GetSize
|
||||
*/
|
||||
inline const Vector2f& Tilemap::GetTileSize() const
|
||||
{
|
||||
return m_tileSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the actual state of the isometric mode
|
||||
* \return True if the isometric mode is enabled
|
||||
*
|
||||
* \see EnableIsometricMode
|
||||
*/
|
||||
inline bool Tilemap::IsIsometricModeEnabled() const
|
||||
{
|
||||
return m_isometricModeEnabled;
|
||||
}
|
||||
|
||||
inline void Tilemap::SetOrigin(const Vector3f& origin)
|
||||
{
|
||||
m_origin = origin;
|
||||
|
||||
InvalidateVertices();
|
||||
}
|
||||
|
||||
inline void Tilemap::InvalidateVertices()
|
||||
{
|
||||
m_shouldRebuildVertices = true;
|
||||
OnElementInvalidated(this);
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
Reference in New Issue
Block a user