Graphics/TextSprite: Update to Renderable

Still WIP as it appears to randomly crash


Former-commit-id: 2397ba7e556f7ed72b5fc8752704c3b212fa9fc1
This commit is contained in:
Lynix 2015-06-11 14:14:57 +02:00
parent 35f6e0d376
commit 3b5551ed7a
4 changed files with 81 additions and 105 deletions

View File

@ -9,21 +9,27 @@
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/SceneNode.hpp>
#include <Nazara/Graphics/Renderable.hpp>
#include <Nazara/Utility/AbstractAtlas.hpp>
#include <Nazara/Utility/AbstractTextDrawer.hpp>
#include <Nazara/Utility/VertexStruct.hpp>
#include <memory>
#include <set>
class NAZARA_API NzTextSprite : public NzSceneNode
class NzTextSprite;
using NzTextSpriteConstRef = NzObjectRef<const NzTextSprite>;
using NzTextSpriteLibrary = NzObjectLibrary<NzTextSprite>;
using NzTextSpriteRef = NzObjectRef<NzTextSprite>;
class NAZARA_API NzTextSprite : public NzRenderable
{
public:
NzTextSprite();
NzTextSprite(const NzTextSprite& sprite);
~NzTextSprite() = default;
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override;
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override;
void Clear();
@ -32,7 +38,6 @@ class NAZARA_API NzTextSprite : public NzSceneNode
const NzColor& GetColor() const;
NzMaterial* GetMaterial() const;
nzSceneNodeType GetSceneNodeType() const override;
void InvalidateVertices();
bool IsDrawable() const;
@ -45,14 +50,13 @@ class NAZARA_API NzTextSprite : public NzSceneNode
NzTextSprite& operator=(const NzTextSprite& text);
template<typename... Args> static NzTextSpriteRef New(Args&&... args);
private:
void InvalidateNode() override;
void MakeBoundingVolume() const override;
void OnAtlasInvalidated(const NzAbstractAtlas* atlas);
void OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer);
void Register() override;
void Unregister() override;
void UpdateVertices() const;
void UpdateData(InstanceData* instanceData) const override;
struct RenderIndices
{
@ -69,12 +73,15 @@ class NAZARA_API NzTextSprite : public NzSceneNode
std::unordered_map<const NzAbstractAtlas*, AtlasSlots> m_atlases;
mutable std::unordered_map<NzTexture*, RenderIndices> m_renderInfos;
mutable std::vector<NzVertexStruct_XY_Color> m_localVertices;
mutable std::vector<NzVertexStruct_XYZ_Color_UV> m_vertices;
mutable std::vector<NzVertexStruct_XY_Color_UV> m_localVertices;
NzColor m_color;
NzMaterialRef m_material;
NzRectui m_localBounds;
mutable bool m_verticesUpdated;
static NzTextSpriteLibrary::LibraryMap s_library;
};
#include <Nazara/Graphics/TextSprite.inl>
#endif // NAZARA_TEXTSPRITE_HPP

View File

@ -0,0 +1,17 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <memory>
#include <Nazara/Renderer/Debug.hpp>
template<typename... Args>
NzTextSpriteRef NzTextSprite::New(Args&&... args)
{
std::unique_ptr<NzTextSprite> object(new NzTextSprite(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
#include <Nazara/Renderer/DebugOff.hpp>

View File

@ -28,6 +28,11 @@ struct NzVertexStruct_XY_UV : NzVertexStruct_XY
NzVector2f uv;
};
struct NzVertexStruct_XY_Color_UV : NzVertexStruct_XY_Color
{
NzVector2f uv;
};
/******************************* Structures 3D *******************************/
struct NzVertexStruct_XYZ

View File

@ -7,30 +7,24 @@
#include <Nazara/Core/SparsePtr.hpp>
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/Scene.hpp>
#include <memory>
#include <Nazara/Utility/Font.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzTextSprite::NzTextSprite() :
m_color(NzColor::White),
m_verticesUpdated(false)
m_color(NzColor::White)
{
SetDefaultMaterial();
}
NzTextSprite::NzTextSprite(const NzTextSprite& sprite) :
NzSceneNode(sprite),
NzRenderable(sprite),
m_renderInfos(sprite.m_renderInfos),
m_localVertices(sprite.m_localVertices),
m_vertices(sprite.m_vertices),
m_color(sprite.m_color),
m_material(sprite.m_material),
m_localBounds(sprite.m_localBounds),
m_verticesUpdated(sprite.m_verticesUpdated)
m_localBounds(sprite.m_localBounds)
{
SetParent(sprite.GetParent());
for (auto it = sprite.m_atlases.begin(); it != sprite.m_atlases.end(); ++it)
{
const NzAbstractAtlas* atlas = it->first;
@ -42,18 +36,18 @@ m_verticesUpdated(sprite.m_verticesUpdated)
}
}
void NzTextSprite::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
void NzTextSprite::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{
if (!m_verticesUpdated)
UpdateVertices();
for (auto& pair : m_renderInfos)
{
NzTexture* overlay = pair.first;
RenderIndices& indices = pair.second;
if (indices.count > 0)
renderQueue->AddSprites(m_material, &m_vertices[indices.first*4], indices.count, overlay);
{
const NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<const NzVertexStruct_XYZ_Color_UV*>(instanceData.data.data());
renderQueue->AddSprites(m_material, &vertices[indices.first*4], indices.count, overlay);
}
}
}
@ -63,7 +57,6 @@ void NzTextSprite::Clear()
m_boundingVolume.MakeNull();
m_localVertices.clear();
m_renderInfos.clear();
m_vertices.clear();
}
NzTextSprite* NzTextSprite::Clone() const
@ -86,14 +79,9 @@ NzMaterial* NzTextSprite::GetMaterial() const
return m_material;
}
nzSceneNodeType NzTextSprite::GetSceneNodeType() const
{
return nzSceneNodeType_TextSprite;
}
void NzTextSprite::InvalidateVertices()
{
m_verticesUpdated = false;
OnRenderableInvalidateInstanceData(this, 0);
}
bool NzTextSprite::IsDrawable() const
@ -104,7 +92,8 @@ bool NzTextSprite::IsDrawable() const
void NzTextSprite::SetColor(const NzColor& color)
{
m_color = color;
m_verticesUpdated = false;
InvalidateVertices();
}
void NzTextSprite::SetDefaultMaterial()
@ -161,7 +150,6 @@ void NzTextSprite::Update(const NzAbstractTextDrawer& drawer)
unsigned int glyphCount = drawer.GetGlyphCount();
m_localVertices.resize(glyphCount * 4);
m_vertices.resize(glyphCount * 4);
NzTexture* lastTexture = nullptr;
unsigned int* count = nullptr;
@ -193,8 +181,6 @@ void NzTextSprite::Update(const NzAbstractTextDrawer& drawer)
indices.count = 0; // On réinitialise count à zéro (on va s'en servir comme compteur dans la boucle suivante)
}
NzSparsePtr<NzVector2f> texCoordPtr(&m_vertices[0].uv, sizeof(NzVertexStruct_XYZ_Color_UV));
lastTexture = nullptr;
RenderIndices* indices = nullptr;
for (unsigned int i = 0; i < glyphCount; ++i)
@ -208,15 +194,6 @@ void NzTextSprite::Update(const NzAbstractTextDrawer& drawer)
lastTexture = texture;
}
// Affectation des positions et couleurs (locaux)
for (unsigned int j = 0; j < 4; ++j)
{
m_localVertices[i*4 + j].color = glyph.color;
m_localVertices[i*4 + j].position.Set(glyph.corners[j]);
}
// Calcul des coordonnées de texture (globaux)
// On commence par transformer les coordonnées entières en flottantes:
NzVector2ui size(texture->GetSize());
float invWidth = 1.f/size.x;
@ -228,23 +205,16 @@ void NzTextSprite::Update(const NzAbstractTextDrawer& drawer)
uvRect.width *= invWidth;
uvRect.height *= invHeight;
// Extraction des quatre coins et attribution
NzSparsePtr<NzVector2f> texCoord = texCoordPtr + indices->first*4 + indices->count*4;
if (!glyph.flipped)
static nzRectCorner normalCorners[4] = {nzRectCorner_LeftTop, nzRectCorner_RightTop, nzRectCorner_LeftBottom, nzRectCorner_RightBottom};
static nzRectCorner flippedCorners[4] = {nzRectCorner_LeftBottom, nzRectCorner_LeftTop, nzRectCorner_RightBottom, nzRectCorner_RightTop};
// Affectation des positions, couleurs, coordonnées de textures
for (unsigned int j = 0; j < 4; ++j)
{
// Le glyphe n'est pas retourné, l'ordre des UV suit celui des sommets
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftTop);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightTop);
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftBottom);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightBottom);
}
else
{
// Le glyphe a subit une rotation de 90° (sens antihoraire), on adapte les UV en conséquence
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftBottom);
*texCoord++ = uvRect.GetCorner(nzRectCorner_LeftTop);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightBottom);
*texCoord++ = uvRect.GetCorner(nzRectCorner_RightTop);
// Remember that indices->count is a counter here, not a count value
m_localVertices[indices->count*4 + j].color = glyph.color;
m_localVertices[indices->count*4 + j].position.Set(glyph.corners[j]);
m_localVertices[indices->count*4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j]));
}
// Et on passe au prochain sommet
@ -252,16 +222,15 @@ void NzTextSprite::Update(const NzAbstractTextDrawer& drawer)
}
m_localBounds = drawer.GetBounds();
m_boundingVolume.MakeNull();
m_boundingVolumeUpdated = false;
m_verticesUpdated = false;
InvalidateBoundingVolume();
clearOnFail.Reset();
}
NzTextSprite& NzTextSprite::operator=(const NzTextSprite& text)
{
NzSceneNode::operator=(text);
NzRenderable::operator=(text);
m_atlases.clear();
@ -282,29 +251,19 @@ NzTextSprite& NzTextSprite::operator=(const NzTextSprite& text)
slots.releaseSlot.Connect(atlas->OnAtlasRelease, this, OnAtlasInvalidated);
}
// On ne copie pas les sommets finaux car il est très probable que nos paramètres soient modifiés et qu'ils doivent être régénérés de toute façon
m_verticesUpdated = false;
InvalidateBoundingVolume();
InvalidateVertices();
return *this;
}
void NzTextSprite::InvalidateNode()
{
NzSceneNode::InvalidateNode();
m_verticesUpdated = false;
}
void NzTextSprite::MakeBoundingVolume() const
{
NzVector3f down = (m_scene) ? m_scene->GetDown() : NzVector3f::Down();
NzVector3f right = (m_scene) ? m_scene->GetRight() : NzVector3f::Right();
NzRectf bounds(m_localBounds);
NzVector2f max = bounds.GetMaximum();
NzVector2f min = bounds.GetMinimum();
m_boundingVolume.Set(min.x*right + min.y*down, max.x*right + max.y*down);
m_boundingVolume.Set(min.x*NzVector3f::Right() + min.y*NzVector3f::Down(), max.x*NzVector3f::Right() + max.y*NzVector3f::Down());
}
void NzTextSprite::OnAtlasInvalidated(const NzAbstractAtlas* atlas)
@ -313,7 +272,7 @@ void NzTextSprite::OnAtlasInvalidated(const NzAbstractAtlas* atlas)
if (m_atlases.find(atlas) == m_atlases.end())
{
NazaraInternalError("Not listening to " + NzString::Pointer(atlas));
return false;
return;
}
#endif
@ -329,13 +288,12 @@ void NzTextSprite::OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractIm
if (m_atlases.find(atlas) == m_atlases.end())
{
NazaraInternalError("Not listening to " + NzString::Pointer(atlas));
return false;
return;
}
#endif
// La texture d'un atlas vient d'être recréée (changement de taille)
// nous devons ajuster les coordonnées de textures et la texture du rendu
NzTexture* oldTexture = static_cast<NzTexture*>(oldLayer);
NzTexture* newTexture = static_cast<NzTexture*>(newLayer);
@ -351,11 +309,11 @@ void NzTextSprite::OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractIm
NzVector2f scale = NzVector2f(oldSize)/NzVector2f(newSize); // ratio ancienne et nouvelle taille
// On va maintenant parcourir toutes les coordonnées de texture concernées pour les multiplier par ce ratio
NzSparsePtr<NzVector2f> texCoordPtr(&m_vertices[indices.first].uv, sizeof(NzVertexStruct_XYZ_Color_UV));
NzSparsePtr<NzVector2f> texCoordPtr(&m_localVertices[indices.first].uv, sizeof(NzVertexStruct_XYZ_Color_UV));
for (unsigned int i = 0; i < indices.count; ++i)
{
for (unsigned int j = 0; j < 4; ++j)
texCoordPtr[i*4 + j] *= scale;
m_localVertices[i*4 + j].uv *= scale;
}
// Nous enlevons l'ancienne texture et rajoutons la nouvelle à sa place (pour les mêmes indices)
@ -364,27 +322,14 @@ void NzTextSprite::OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractIm
}
}
void NzTextSprite::Register()
void NzTextSprite::UpdateData(InstanceData* instanceData) const
{
// Le changement de scène peut affecter les sommets
m_verticesUpdated = false;
}
instanceData->data.resize(m_localVertices.size());
NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_Color_UV*>(instanceData->data.data());
void NzTextSprite::Unregister()
{
}
void NzTextSprite::UpdateVertices() const
{
if (!m_transformMatrixUpdated)
UpdateTransformMatrix();
// On récupère le repère de la scène
NzVector3f down = (m_scene) ? m_scene->GetDown() : NzVector3f::Down();
NzVector3f right = (m_scene) ? m_scene->GetRight() : NzVector3f::Right();
NzSparsePtr<NzColor> colorPtr(&m_vertices[0].color, sizeof(NzVertexStruct_XYZ_Color_UV));
NzSparsePtr<NzVector3f> posPtr(&m_vertices[0].position, sizeof(NzVertexStruct_XYZ_Color_UV));
NzSparsePtr<NzColor> colorPtr(&vertices[0].color, sizeof(NzVertexStruct_XYZ_Color_UV));
NzSparsePtr<NzVector3f> posPtr(&vertices[0].position, sizeof(NzVertexStruct_XYZ_Color_UV));
NzSparsePtr<NzVector2f> texCoordPtr(&vertices[0].uv, sizeof(NzVertexStruct_XYZ_Color_UV));
// Nous allons maintenant initialiser les sommets finaux (ceux envoyés à la RenderQueue)
// à l'aide du repère, de la matrice et de notre attribut de couleur
@ -394,18 +339,20 @@ void NzTextSprite::UpdateVertices() const
NzSparsePtr<NzColor> color = colorPtr + indices.first*4;
NzSparsePtr<NzVector3f> pos = posPtr + indices.first*4;
NzVertexStruct_XY_Color* localVertex = &m_localVertices[indices.first*4];
NzSparsePtr<NzVector2f> uv = texCoordPtr + indices.first*4;
NzVertexStruct_XY_Color_UV* localVertex = &m_localVertices[indices.first*4];
for (unsigned int i = 0; i < indices.count; ++i)
{
for (unsigned int j = 0; j < 4; ++j)
{
*pos++ = m_transformMatrix.Transform(localVertex->position.x*right + localVertex->position.y*down);
*pos++ = instanceData->transformMatrix.Transform(localVertex->position.x*NzVector3f::Right() + localVertex->position.y*NzVector3f::Down());
*color++ = m_color * localVertex->color;
*uv++ = localVertex->uv;
localVertex++;
}
}
}
m_verticesUpdated = true;
}
NzTextSpriteLibrary::LibraryMap NzTextSprite::s_library;