diff --git a/include/Nazara/Graphics/TextSprite.hpp b/include/Nazara/Graphics/TextSprite.hpp index ae0bd11f7..fe6494560 100644 --- a/include/Nazara/Graphics/TextSprite.hpp +++ b/include/Nazara/Graphics/TextSprite.hpp @@ -9,21 +9,27 @@ #include #include -#include +#include #include #include #include #include #include -class NAZARA_API NzTextSprite : public NzSceneNode +class NzTextSprite; + +using NzTextSpriteConstRef = NzObjectRef; +using NzTextSpriteLibrary = NzObjectLibrary; +using NzTextSpriteRef = NzObjectRef; + +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 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 m_atlases; mutable std::unordered_map m_renderInfos; - mutable std::vector m_localVertices; - mutable std::vector m_vertices; + mutable std::vector m_localVertices; NzColor m_color; NzMaterialRef m_material; NzRectui m_localBounds; mutable bool m_verticesUpdated; + + static NzTextSpriteLibrary::LibraryMap s_library; }; +#include + #endif // NAZARA_TEXTSPRITE_HPP diff --git a/include/Nazara/Graphics/TextSprite.inl b/include/Nazara/Graphics/TextSprite.inl new file mode 100644 index 000000000..85d23d517 --- /dev/null +++ b/include/Nazara/Graphics/TextSprite.inl @@ -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 +#include + +template +NzTextSpriteRef NzTextSprite::New(Args&&... args) +{ + std::unique_ptr object(new NzTextSprite(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +#include diff --git a/include/Nazara/Utility/VertexStruct.hpp b/include/Nazara/Utility/VertexStruct.hpp index 2f4130398..5c2bd313d 100644 --- a/include/Nazara/Utility/VertexStruct.hpp +++ b/include/Nazara/Utility/VertexStruct.hpp @@ -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 diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp index 6bdcbe67d..b4128d7ed 100644 --- a/src/Nazara/Graphics/TextSprite.cpp +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -7,30 +7,24 @@ #include #include #include -#include #include #include #include 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(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 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 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(oldLayer); NzTexture* newTexture = static_cast(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 texCoordPtr(&m_vertices[indices.first].uv, sizeof(NzVertexStruct_XYZ_Color_UV)); + NzSparsePtr 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(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 colorPtr(&m_vertices[0].color, sizeof(NzVertexStruct_XYZ_Color_UV)); - NzSparsePtr posPtr(&m_vertices[0].position, sizeof(NzVertexStruct_XYZ_Color_UV)); + NzSparsePtr colorPtr(&vertices[0].color, sizeof(NzVertexStruct_XYZ_Color_UV)); + NzSparsePtr posPtr(&vertices[0].position, sizeof(NzVertexStruct_XYZ_Color_UV)); + NzSparsePtr 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 color = colorPtr + indices.first*4; NzSparsePtr pos = posPtr + indices.first*4; - NzVertexStruct_XY_Color* localVertex = &m_localVertices[indices.first*4]; + NzSparsePtr 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;