diff --git a/include/Nazara/Core/CallOnExit.hpp b/include/Nazara/Core/CallOnExit.hpp index 3f8fc1f2f..45ea2622d 100644 --- a/include/Nazara/Core/CallOnExit.hpp +++ b/include/Nazara/Core/CallOnExit.hpp @@ -19,6 +19,7 @@ class NzCallOnExit : NzNonCopyable NzCallOnExit(Func func = nullptr); ~NzCallOnExit(); + void CallAndReset(Func func = nullptr); void Reset(Func func = nullptr); private: diff --git a/include/Nazara/Core/CallOnExit.inl b/include/Nazara/Core/CallOnExit.inl index 00960f3ac..fd7f4de80 100644 --- a/include/Nazara/Core/CallOnExit.inl +++ b/include/Nazara/Core/CallOnExit.inl @@ -2,6 +2,7 @@ // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include inline NzCallOnExit::NzCallOnExit(Func func) : @@ -15,6 +16,14 @@ inline NzCallOnExit::~NzCallOnExit() m_func(); } +inline void NzCallOnExit::CallAndReset(Func func) +{ + if (m_func) + m_func(); + + Reset(func); +} + inline void NzCallOnExit::Reset(Func func) { m_func = func; diff --git a/include/Nazara/Core/GuillotineBinPack.hpp b/include/Nazara/Core/GuillotineBinPack.hpp new file mode 100644 index 000000000..fecac3d00 --- /dev/null +++ b/include/Nazara/Core/GuillotineBinPack.hpp @@ -0,0 +1,85 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// Implémentation originale de Jukka Jylänki (Merci de sa contribution au domaine public) +// http://clb.demon.fi/projects/even-more-rectangle-bin-packing + +#pragma once + +#ifndef NAZARA_GUILLOTINEBINPACK_HPP +#define NAZARA_GUILLOTINEBINPACK_HPP + +#include +#include +#include +#include + +class NAZARA_API NzGuillotineBinPack +{ + public: + enum FreeRectChoiceHeuristic + { + RectBestAreaFit, + RectBestLongSideFit, + RectBestShortSideFit, + RectWorstAreaFit, + RectWorstLongSideFit, + RectWorstShortSideFit + }; + + enum GuillotineSplitHeuristic + { + SplitLongerAxis, + SplitLongerLeftoverAxis, + SplitMaximizeArea, + SplitMinimizeArea, + SplitShorterAxis, + SplitShorterLeftoverAxis + }; + + NzGuillotineBinPack(); + NzGuillotineBinPack(unsigned int width, unsigned int height); + NzGuillotineBinPack(const NzVector2ui& size); + NzGuillotineBinPack(const NzGuillotineBinPack&) = default; + NzGuillotineBinPack(NzGuillotineBinPack&&) = default; + ~NzGuillotineBinPack() = default; + + void Clear(); + + void Expand(unsigned int newWidth, unsigned newHeight); + void Expand(const NzVector2ui& newSize); + + void FreeRectangle(const NzRectui& rect); + + unsigned int GetHeight() const; + float GetOccupancy() const; + NzVector2ui GetSize() const; + unsigned int GetWidth() const; + + bool Insert(NzRectui* rects, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + bool Insert(NzRectui* rects, bool* flipped, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + bool Insert(NzRectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod); + + bool MergeFreeRectangles(); + + void Reset(); + void Reset(unsigned int width, unsigned int height); + void Reset(const NzVector2ui& size); + + NzGuillotineBinPack& operator=(const NzGuillotineBinPack&) = default; + NzGuillotineBinPack& operator=(NzGuillotineBinPack&&) = default; + + private: + void SplitFreeRectAlongAxis(const NzRectui& freeRect, const NzRectui& placedRect, bool splitHorizontal); + void SplitFreeRectByHeuristic(const NzRectui& freeRect, const NzRectui& placedRect, GuillotineSplitHeuristic method); + + static int ScoreByHeuristic(int width, int height, const NzRectui& freeRect, FreeRectChoiceHeuristic rectChoice); + + std::vector m_freeRectangles; + unsigned int m_height; + unsigned int m_usedArea; + unsigned int m_width; +}; + +#endif // NAZARA_GUILLOTINEBINPACK_HPP diff --git a/include/Nazara/Core/Resource.hpp b/include/Nazara/Core/Resource.hpp index adf0eace2..2bc392734 100644 --- a/include/Nazara/Core/Resource.hpp +++ b/include/Nazara/Core/Resource.hpp @@ -23,6 +23,8 @@ class NAZARA_API NzResource { public: NzResource(bool persistent = true); + NzResource(const NzResource& resource) = delete; + NzResource(NzResource&& resource) = delete; virtual ~NzResource(); void AddResourceListener(NzResourceListener* listener, int index = 0) const; @@ -37,6 +39,9 @@ class NAZARA_API NzResource bool SetPersistent(bool persistent = true, bool checkReferenceCount = false); + NzResource& operator=(const NzResource& resource) = delete; + NzResource& operator=(NzResource&& resource) = delete; + protected: void NotifyCreated(); void NotifyDestroy(); diff --git a/include/Nazara/Core/SparsePtr.hpp b/include/Nazara/Core/SparsePtr.hpp index 8d104827c..b077b6d56 100644 --- a/include/Nazara/Core/SparsePtr.hpp +++ b/include/Nazara/Core/SparsePtr.hpp @@ -46,7 +46,9 @@ class NzSparsePtr T& operator[](int index) const; NzSparsePtr operator+(int count) const; + NzSparsePtr operator+(unsigned int count) const; NzSparsePtr operator-(int count) const; + NzSparsePtr operator-(unsigned int count) const; std::ptrdiff_t operator-(const NzSparsePtr& ptr) const; NzSparsePtr& operator+=(int count); diff --git a/include/Nazara/Core/SparsePtr.inl b/include/Nazara/Core/SparsePtr.inl index eb6c988ae..188996d4b 100644 --- a/include/Nazara/Core/SparsePtr.inl +++ b/include/Nazara/Core/SparsePtr.inl @@ -127,12 +127,24 @@ NzSparsePtr NzSparsePtr::operator+(int count) const return NzSparsePtr(m_ptr + count*m_stride, m_stride); } +template +NzSparsePtr NzSparsePtr::operator+(unsigned int count) const +{ + return NzSparsePtr(m_ptr + count*m_stride, m_stride); +} + template NzSparsePtr NzSparsePtr::operator-(int count) const { return NzSparsePtr(m_ptr - count*m_stride, m_stride); } +template +NzSparsePtr NzSparsePtr::operator-(unsigned int count) const +{ + return NzSparsePtr(m_ptr - count*m_stride, m_stride); +} + template std::ptrdiff_t NzSparsePtr::operator-(const NzSparsePtr& ptr) const { diff --git a/include/Nazara/Graphics/AbstractRenderQueue.hpp b/include/Nazara/Graphics/AbstractRenderQueue.hpp index c3a9de2e4..d10685882 100644 --- a/include/Nazara/Graphics/AbstractRenderQueue.hpp +++ b/include/Nazara/Graphics/AbstractRenderQueue.hpp @@ -12,11 +12,13 @@ #include #include #include +#include class NzDrawable; class NzLight; class NzMaterial; class NzSprite; +class NzTexture; struct NzMeshData; class NAZARA_API NzAbstractRenderQueue : NzNonCopyable @@ -28,7 +30,7 @@ class NAZARA_API NzAbstractRenderQueue : NzNonCopyable virtual void AddDrawable(const NzDrawable* drawable) = 0; virtual void AddLight(const NzLight* light) = 0; virtual void AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix) = 0; - virtual void AddSprite(const NzSprite* sprite) = 0; + virtual void AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay = nullptr) = 0; virtual void Clear(bool fully) = 0; }; diff --git a/include/Nazara/Graphics/AbstractViewer.hpp b/include/Nazara/Graphics/AbstractViewer.hpp index 7e0306689..d6c3d5f3f 100644 --- a/include/Nazara/Graphics/AbstractViewer.hpp +++ b/include/Nazara/Graphics/AbstractViewer.hpp @@ -28,6 +28,9 @@ class NAZARA_API NzAbstractViewer virtual NzVector3f GetEyePosition() const = 0; virtual NzVector3f GetForward() const = 0; virtual const NzFrustumf& GetFrustum() const = 0; + virtual NzVector3f GetGlobalForward() const = 0; + virtual NzVector3f GetGlobalRight() const = 0; + virtual NzVector3f GetGlobalUp() const = 0; virtual const NzMatrix4f& GetProjectionMatrix() const = 0; virtual const NzRenderTarget* GetTarget() const = 0; virtual const NzMatrix4f& GetViewMatrix() const = 0; diff --git a/include/Nazara/Graphics/Camera.hpp b/include/Nazara/Graphics/Camera.hpp index 534f48df7..3cdb0eb41 100644 --- a/include/Nazara/Graphics/Camera.hpp +++ b/include/Nazara/Graphics/Camera.hpp @@ -32,6 +32,9 @@ class NAZARA_API NzCamera : public NzAbstractViewer, public NzNode, NzRenderTarg NzVector3f GetForward() const; float GetFOV() const; const NzFrustumf& GetFrustum() const; + NzVector3f GetGlobalForward() const; + NzVector3f GetGlobalRight() const; + NzVector3f GetGlobalUp() const; const NzMatrix4f& GetProjectionMatrix() const; const NzRenderTarget* GetTarget() const; const NzRectf& GetTargetRegion() const; diff --git a/include/Nazara/Graphics/DeferredRenderQueue.hpp b/include/Nazara/Graphics/DeferredRenderQueue.hpp index 8cec0ecea..8ad147042 100644 --- a/include/Nazara/Graphics/DeferredRenderQueue.hpp +++ b/include/Nazara/Graphics/DeferredRenderQueue.hpp @@ -31,7 +31,7 @@ class NAZARA_API NzDeferredRenderQueue : public NzAbstractRenderQueue, NzResourc void AddDrawable(const NzDrawable* drawable) override; void AddLight(const NzLight* light) override; void AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix) override; - void AddSprite(const NzSprite* sprite) override; + void AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay = nullptr) override; void Clear(bool fully); diff --git a/include/Nazara/Graphics/Enums.hpp b/include/Nazara/Graphics/Enums.hpp index 59a8104c4..257928a66 100644 --- a/include/Nazara/Graphics/Enums.hpp +++ b/include/Nazara/Graphics/Enums.hpp @@ -71,10 +71,11 @@ enum nzRenderTechniqueType enum nzSceneNodeType { - nzSceneNodeType_Light, // NzLight - nzSceneNodeType_Model, // NzModel - nzSceneNodeType_Root, // NzSceneRoot - nzSceneNodeType_Sprite, // NzSprite + nzSceneNodeType_Light, // NzLight + nzSceneNodeType_Model, // NzModel + nzSceneNodeType_Root, // NzSceneRoot + nzSceneNodeType_Sprite, // NzSprite + nzSceneNodeType_TextSprite, // NzTextSprite nzSceneNodeType_User, nzSceneNodeType_Max = nzSceneNodeType_User @@ -85,10 +86,12 @@ enum nzShaderFlags { nzShaderFlags_None = 0, - nzShaderFlags_Deferred = 0x1, - nzShaderFlags_Instancing = 0x2, + nzShaderFlags_Deferred = 0x1, + nzShaderFlags_Instancing = 0x2, + nzShaderFlags_TextureOverlay = 0x4, + nzShaderFlags_VertexColor = 0x8, - nzShaderFlags_Max = nzShaderFlags_Instancing*2-1 + nzShaderFlags_Max = nzShaderFlags_VertexColor*2-1 }; #endif // NAZARA_ENUMS_GRAPHICS_HPP diff --git a/include/Nazara/Graphics/ForwardRenderQueue.hpp b/include/Nazara/Graphics/ForwardRenderQueue.hpp index 85710cd0d..a7571a848 100644 --- a/include/Nazara/Graphics/ForwardRenderQueue.hpp +++ b/include/Nazara/Graphics/ForwardRenderQueue.hpp @@ -33,7 +33,7 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource void AddDrawable(const NzDrawable* drawable) override; void AddLight(const NzLight* light) override; void AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix) override; - void AddSprite(const NzSprite* sprite) override; + void AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay = nullptr) override; void Clear(bool fully); @@ -43,6 +43,12 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource bool OnResourceDestroy(const NzResource* resource, int index) override; void OnResourceReleased(const NzResource* resource, int index) override; + struct SpriteChain_XYZ_Color_UV + { + const NzVertexStruct_XYZ_Color_UV* vertices; + unsigned int spriteCount; + }; + struct TransparentModelData { NzMatrix4f transformMatrix; @@ -68,12 +74,13 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource typedef std::map>, MeshDataComparator> MeshInstanceContainer; typedef std::map, BatchedModelMaterialComparator> ModelBatches; - typedef std::map> BatchedSpriteContainer; + typedef std::map> BasicSpriteOverlayContainer; + typedef std::map BasicSpriteBatches; typedef std::vector LightContainer; typedef std::vector TransparentModelContainer; + BasicSpriteBatches basicSprites; ModelBatches opaqueModels; - BatchedSpriteContainer sprites; TransparentModelContainer transparentModels; std::vector transparentModelData; std::vector otherDrawables; diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.hpp b/include/Nazara/Graphics/ForwardRenderTechnique.hpp index 9050cda20..6aa2da571 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.hpp +++ b/include/Nazara/Graphics/ForwardRenderTechnique.hpp @@ -32,23 +32,27 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique, Nz void SetMaxLightPassPerObject(unsigned int passCount); private: - struct LightUniforms; + struct ShaderUniforms; + void DrawBasicSprites(const NzScene* scene) const; void DrawOpaqueModels(const NzScene* scene) const; - void DrawSprites(const NzScene* scene) const; void DrawTransparentModels(const NzScene* scene) const; - const LightUniforms* GetLightUniforms(const NzShader* shader) const; + const ShaderUniforms* GetShaderUniforms(const NzShader* shader) const; - struct LightUniforms + struct ShaderUniforms { - NzLightUniforms uniforms; - bool exists; - int offset; // "Distance" entre Lights[0].type et Lights[1].type + NzLightUniforms lightUniforms; + bool hasLightUniforms; + /// Moins coûteux en mémoire que de stocker un NzLightUniforms par index de lumière, /// à voir si ça fonctionne chez tout le monde + int lightOffset; // "Distance" entre Lights[0].type et Lights[1].type + + // Autre uniformes + int textureOverlay; }; - mutable std::unordered_map m_lightUniforms; + mutable std::unordered_map m_shaderUniforms; mutable NzForwardRenderQueue m_renderQueue; NzIndexBufferRef m_indexBuffer; mutable NzLightManager m_directionalLights; diff --git a/include/Nazara/Graphics/GuillotineTextureAtlas.hpp b/include/Nazara/Graphics/GuillotineTextureAtlas.hpp new file mode 100644 index 000000000..04197a41b --- /dev/null +++ b/include/Nazara/Graphics/GuillotineTextureAtlas.hpp @@ -0,0 +1,23 @@ +// 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 + +#pragma once + +#ifndef NAZARA_GUILLOTINETEXTUREATLAS_HPP +#define NAZARA_GUILLOTINETEXTUREATLAS_HPP + +#include +#include + +class NAZARA_API NzGuillotineTextureAtlas : public NzGuillotineImageAtlas +{ + public: + NzGuillotineTextureAtlas() = default; + ~NzGuillotineTextureAtlas() = default; + + private: + NzAbstractImage* ResizeImage(NzAbstractImage* oldImage, const NzVector2ui& size) const override; +}; + +#endif // NAZARA_GUILLOTINETEXTUREATLAS_HPP diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp index 0f41e0f39..ffe7f8217 100644 --- a/include/Nazara/Graphics/Material.hpp +++ b/include/Nazara/Graphics/Material.hpp @@ -46,7 +46,6 @@ class NAZARA_API NzMaterial : public NzResource public: NzMaterial(); NzMaterial(const NzMaterial& material); - NzMaterial(NzMaterial&& material); ~NzMaterial(); const NzShader* Apply(nzUInt32 shaderFlags = 0, nzUInt8 textureUnit = 0, nzUInt8* lastUsedUnit = nullptr) const; @@ -127,7 +126,6 @@ class NAZARA_API NzMaterial : public NzResource void SetSrcBlend(nzBlendFunc func); NzMaterial& operator=(const NzMaterial& material); - NzMaterial& operator=(NzMaterial&& material); static NzMaterial* GetDefault(); @@ -140,6 +138,7 @@ class NAZARA_API NzMaterial : public NzResource }; void Copy(const NzMaterial& material); + void Move(NzMaterial&& material); void GenerateShader(nzUInt32 flags) const; void InvalidateShaders(); diff --git a/include/Nazara/Graphics/Model.hpp b/include/Nazara/Graphics/Model.hpp index ea5b937ba..3249cdd48 100644 --- a/include/Nazara/Graphics/Model.hpp +++ b/include/Nazara/Graphics/Model.hpp @@ -36,7 +36,6 @@ class NAZARA_API NzModel : public NzSceneNode public: NzModel(); NzModel(const NzModel& model); - NzModel(NzModel&& model); virtual ~NzModel(); void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override; @@ -83,7 +82,6 @@ class NAZARA_API NzModel : public NzSceneNode void SetSkinCount(unsigned int skinCount); NzModel& operator=(const NzModel& node); - NzModel& operator=(NzModel&& node); protected: void InvalidateNode() override; diff --git a/include/Nazara/Graphics/Scene.hpp b/include/Nazara/Graphics/Scene.hpp index d286c4c19..8a9b1b89c 100644 --- a/include/Nazara/Graphics/Scene.hpp +++ b/include/Nazara/Graphics/Scene.hpp @@ -41,9 +41,15 @@ class NAZARA_API NzScene NzColor GetAmbientColor() const; NzAbstractBackground* GetBackground() const; + NzVector3f GetBackward() const; + NzVector3f GetDown() const; + NzVector3f GetForward() const; + NzVector3f GetLeft() const; NzAbstractRenderTechnique* GetRenderTechnique() const; + NzVector3f GetRight() const; NzSceneNode& GetRoot() const; NzAbstractViewer* GetViewer() const; + NzVector3f GetUp() const; float GetUpdateTime() const; unsigned int GetUpdatePerSecond() const; diff --git a/include/Nazara/Graphics/SceneNode.hpp b/include/Nazara/Graphics/SceneNode.hpp index 09aa1fab3..edfdf56e2 100644 --- a/include/Nazara/Graphics/SceneNode.hpp +++ b/include/Nazara/Graphics/SceneNode.hpp @@ -21,23 +21,30 @@ class NAZARA_API NzSceneNode : public NzNode public: NzSceneNode(); NzSceneNode(const NzSceneNode& sceneNode); + NzSceneNode(NzSceneNode& sceneNode) = delete; virtual ~NzSceneNode(); virtual void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const = 0; void EnableDrawing(bool drawingEnabled); + NzVector3f GetBackward() const; virtual const NzBoundingVolumef& GetBoundingVolume() const = 0; + NzVector3f GetDown() const; + NzVector3f GetForward() const; + NzVector3f GetLeft() const; nzNodeType GetNodeType() const final; + NzVector3f GetRight() const; NzScene* GetScene() const; virtual nzSceneNodeType GetSceneNodeType() const = 0; + NzVector3f GetUp() const; virtual bool IsDrawable() const = 0; bool IsDrawingEnabled() const; bool IsVisible() const; NzSceneNode& operator=(const NzSceneNode& sceneNode); - NzSceneNode& operator=(NzSceneNode&& sceneNode); + NzSceneNode& operator=(NzSceneNode&& sceneNode) = delete; protected: virtual bool FrustumCull(const NzFrustumf& frustum) const; diff --git a/include/Nazara/Graphics/Sprite.hpp b/include/Nazara/Graphics/Sprite.hpp index b383f1e44..b3739cb07 100644 --- a/include/Nazara/Graphics/Sprite.hpp +++ b/include/Nazara/Graphics/Sprite.hpp @@ -10,6 +10,7 @@ #include #include #include +#include class NAZARA_API NzSprite : public NzSceneNode { @@ -17,12 +18,12 @@ class NAZARA_API NzSprite : public NzSceneNode NzSprite(); NzSprite(NzTexture* texture); NzSprite(const NzSprite& sprite); - NzSprite(NzSprite&& sprite); - ~NzSprite(); + ~NzSprite() = default; void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override; const NzBoundingVolumef& GetBoundingVolume() const override; + const NzColor& GetColor() const; NzMaterial* GetMaterial() const; nzSceneNodeType GetSceneNodeType() const override; const NzVector2f& GetSize() const; @@ -30,6 +31,8 @@ class NAZARA_API NzSprite : public NzSceneNode bool IsDrawable() const; + void SetColor(const NzColor& color); + void SetDefaultMaterial(); void SetMaterial(NzMaterial* material, bool resizeSprite = true); void SetSize(const NzVector2f& size); void SetSize(float sizeX, float sizeY); @@ -37,17 +40,23 @@ class NAZARA_API NzSprite : public NzSceneNode void SetTextureCoords(const NzRectf& coords); void SetTextureRect(const NzRectui& rect); + NzSprite& operator=(const NzSprite& sprite); + private: void InvalidateNode() override; void Register() override; void Unregister() override; void UpdateBoundingVolume() const; + void UpdateVertices() const; mutable NzBoundingVolumef m_boundingVolume; + NzColor m_color; NzMaterialRef m_material; NzRectf m_textureCoords; NzVector2f m_size; + mutable NzVertexStruct_XYZ_Color_UV m_vertices[4]; mutable bool m_boundingVolumeUpdated; + mutable bool m_verticesUpdated; }; #endif // NAZARA_SPRITE_HPP diff --git a/include/Nazara/Graphics/TextSprite.hpp b/include/Nazara/Graphics/TextSprite.hpp new file mode 100644 index 000000000..be8df8b69 --- /dev/null +++ b/include/Nazara/Graphics/TextSprite.hpp @@ -0,0 +1,75 @@ +// Copyright (C) 2014 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 + +#pragma once + +#ifndef NAZARA_TEXTSPRITE_HPP +#define NAZARA_TEXTSPRITE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class NAZARA_API NzTextSprite : public NzSceneNode, NzAbstractAtlas::Listener +{ + public: + NzTextSprite(); + NzTextSprite(const NzTextSprite& sprite); + ~NzTextSprite(); + + void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override; + + void Clear(); + + const NzBoundingVolumef& GetBoundingVolume() const override; + const NzColor& GetColor() const; + NzMaterial* GetMaterial() const; + nzSceneNodeType GetSceneNodeType() const override; + + void InvalidateVertices(); + bool IsDrawable() const; + + void SetColor(const NzColor& color); + void SetDefaultMaterial(); + void SetMaterial(NzMaterial* material); + void SetText(const NzAbstractTextDrawer& drawer); + + NzTextSprite& operator=(const NzTextSprite& text); + + private: + void ClearAtlases(); + void InvalidateNode() override; + bool OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata) override; + bool OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata) override; + void OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata) override; + void Register() override; + void Unregister() override; + void UpdateBoundingVolume() const; + void UpdateVertices() const; + + struct RenderIndices + { + unsigned int first; + unsigned int count; + }; + + std::set m_atlases; + mutable std::unordered_map m_renderInfos; + mutable std::vector m_localVertices; + mutable std::vector m_vertices; + mutable NzBoundingVolumef m_boundingVolume; + NzColor m_color; + NzMaterialRef m_material; + NzRectui m_localBounds; + mutable bool m_boundingVolumeUpdated; + mutable bool m_verticesUpdated; +}; + +#endif // NAZARA_TEXTSPRITE_HPP diff --git a/include/Nazara/Graphics/View.hpp b/include/Nazara/Graphics/View.hpp index bc048aeb6..b7f016afc 100644 --- a/include/Nazara/Graphics/View.hpp +++ b/include/Nazara/Graphics/View.hpp @@ -32,6 +32,9 @@ class NAZARA_API NzView : public NzAbstractViewer, public NzNode, NzRenderTarget NzVector3f GetEyePosition() const; NzVector3f GetForward() const; const NzFrustumf& GetFrustum() const; + NzVector3f GetGlobalForward() const; + NzVector3f GetGlobalRight() const; + NzVector3f GetGlobalUp() const; const NzMatrix4f& GetProjectionMatrix() const; const NzVector2f& GetSize() const; const NzRenderTarget* GetTarget() const; @@ -42,6 +45,7 @@ class NAZARA_API NzView : public NzAbstractViewer, public NzNode, NzRenderTarget float GetZNear() const; void SetSize(const NzVector2f& size); + void SetSize(float width, float height); void SetTarget(const NzRenderTarget* renderTarget); void SetTarget(const NzRenderTarget& renderTarget); void SetTargetRegion(const NzRectf& region); diff --git a/include/Nazara/Math/Box.hpp b/include/Nazara/Math/Box.hpp index 0409caffc..1705f25df 100644 --- a/include/Nazara/Math/Box.hpp +++ b/include/Nazara/Math/Box.hpp @@ -38,7 +38,7 @@ class NzBox NzBox& ExtendTo(const NzVector3& point); NzSphere GetBoundingSphere() const; - NzVector3 GetCorner(nzCorner corner) const; + NzVector3 GetCorner(nzBoxCorner corner) const; NzVector3 GetCenter() const; NzVector3 GetLengths() const; NzVector3 GetMaximum() const; diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index 651a6de13..11578f605 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -117,32 +117,32 @@ NzBox& NzBox::ExtendTo(const NzVector3& point) } template -NzVector3 NzBox::GetCorner(nzCorner corner) const +NzVector3 NzBox::GetCorner(nzBoxCorner corner) const { switch (corner) { - case nzCorner_FarLeftBottom: + case nzBoxCorner_FarLeftBottom: return NzVector3(x, y, z); - case nzCorner_FarLeftTop: + case nzBoxCorner_FarLeftTop: return NzVector3(x, y + height, z); - case nzCorner_FarRightBottom: + case nzBoxCorner_FarRightBottom: return NzVector3(x + width, y, z); - case nzCorner_FarRightTop: + case nzBoxCorner_FarRightTop: return NzVector3(x + width, y + height, z); - case nzCorner_NearLeftBottom: + case nzBoxCorner_NearLeftBottom: return NzVector3(x, y, z + depth); - case nzCorner_NearLeftTop: + case nzBoxCorner_NearLeftTop: return NzVector3(x, y + height, z + depth); - case nzCorner_NearRightBottom: + case nzBoxCorner_NearRightBottom: return NzVector3(x + width, y, z + depth); - case nzCorner_NearRightTop: + case nzBoxCorner_NearRightTop: return NzVector3(x + width, y + height, z + depth); } diff --git a/include/Nazara/Math/Enums.hpp b/include/Nazara/Math/Enums.hpp index efa249643..214c9958c 100644 --- a/include/Nazara/Math/Enums.hpp +++ b/include/Nazara/Math/Enums.hpp @@ -7,18 +7,18 @@ #ifndef NAZARA_ENUMS_MATH_HPP #define NAZARA_ENUMS_MATH_HPP -enum nzCorner +enum nzBoxCorner { - nzCorner_FarLeftBottom, - nzCorner_FarLeftTop, - nzCorner_FarRightBottom, - nzCorner_FarRightTop, - nzCorner_NearLeftBottom, - nzCorner_NearLeftTop, - nzCorner_NearRightBottom, - nzCorner_NearRightTop, + nzBoxCorner_FarLeftBottom, + nzBoxCorner_FarLeftTop, + nzBoxCorner_FarRightBottom, + nzBoxCorner_FarRightTop, + nzBoxCorner_NearLeftBottom, + nzBoxCorner_NearLeftTop, + nzBoxCorner_NearRightBottom, + nzBoxCorner_NearRightTop, - nzCorner_Max = nzCorner_NearRightTop + nzBoxCorner_Max = nzBoxCorner_NearRightTop }; enum nzExtend @@ -51,4 +51,14 @@ enum nzIntersectionSide nzIntersectionSide_Max = nzIntersectionSide_Outside }; +enum nzRectCorner +{ + nzRectCorner_LeftBottom, + nzRectCorner_LeftTop, + nzRectCorner_RightBottom, + nzRectCorner_RightTop, + + nzRectCorner_Max = nzRectCorner_RightTop +}; + #endif // NAZARA_ENUMS_MATH_HPP diff --git a/include/Nazara/Math/Frustum.hpp b/include/Nazara/Math/Frustum.hpp index e5de19b50..f94c229b0 100644 --- a/include/Nazara/Math/Frustum.hpp +++ b/include/Nazara/Math/Frustum.hpp @@ -37,7 +37,7 @@ class NzFrustum NzFrustum& Extract(const NzMatrix4& clipMatrix); NzFrustum& Extract(const NzMatrix4& view, const NzMatrix4& projection); - const NzVector3& GetCorner(nzCorner corner) const; + const NzVector3& GetCorner(nzBoxCorner corner) const; const NzPlane& GetPlane(nzFrustumPlane plane) const; nzIntersectionSide Intersect(const NzBoundingVolume& volume) const; @@ -52,7 +52,7 @@ class NzFrustum NzString ToString() const; private: - NzVector3 m_corners[nzCorner_Max+1]; + NzVector3 m_corners[nzBoxCorner_Max+1]; NzPlane m_planes[nzFrustumPlane_Max+1]; }; diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index 0a7b02215..336f5ad0a 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -44,23 +44,23 @@ NzFrustum& NzFrustum::Build(T angle, T ratio, T zNear, T zFar, const NzVec NzVector3 fc = eye + f * zFar; // Calcul du frustum - m_corners[nzCorner_FarLeftBottom] = fc - u*farH - s*farW; - m_corners[nzCorner_FarLeftTop] = fc + u*farH - s*farW; - m_corners[nzCorner_FarRightTop] = fc + u*farH + s*farW; - m_corners[nzCorner_FarRightBottom] = fc - u*farH + s*farW; + m_corners[nzBoxCorner_FarLeftBottom] = fc - u*farH - s*farW; + m_corners[nzBoxCorner_FarLeftTop] = fc + u*farH - s*farW; + m_corners[nzBoxCorner_FarRightTop] = fc + u*farH + s*farW; + m_corners[nzBoxCorner_FarRightBottom] = fc - u*farH + s*farW; - m_corners[nzCorner_NearLeftBottom] = nc - u*nearH - s*nearW; - m_corners[nzCorner_NearLeftTop] = nc + u*nearH - s*nearW; - m_corners[nzCorner_NearRightTop] = nc + u*nearH + s*nearW; - m_corners[nzCorner_NearRightBottom] = nc - u*nearH + s*nearW; + m_corners[nzBoxCorner_NearLeftBottom] = nc - u*nearH - s*nearW; + m_corners[nzBoxCorner_NearLeftTop] = nc + u*nearH - s*nearW; + m_corners[nzBoxCorner_NearRightTop] = nc + u*nearH + s*nearW; + m_corners[nzBoxCorner_NearRightBottom] = nc - u*nearH + s*nearW; // Construction des plans du frustum - m_planes[nzFrustumPlane_Bottom].Set(m_corners[nzCorner_NearLeftBottom], m_corners[nzCorner_NearRightBottom], m_corners[nzCorner_FarRightBottom]); - m_planes[nzFrustumPlane_Far].Set(m_corners[nzCorner_FarRightTop], m_corners[nzCorner_FarLeftTop], m_corners[nzCorner_FarLeftBottom]); - m_planes[nzFrustumPlane_Left].Set(m_corners[nzCorner_NearLeftTop], m_corners[nzCorner_NearLeftBottom], m_corners[nzCorner_FarLeftBottom]); - m_planes[nzFrustumPlane_Near].Set(m_corners[nzCorner_NearLeftTop], m_corners[nzCorner_NearRightTop], m_corners[nzCorner_NearRightBottom]); - m_planes[nzFrustumPlane_Right].Set(m_corners[nzCorner_NearRightBottom], m_corners[nzCorner_NearRightTop], m_corners[nzCorner_FarRightBottom]); - m_planes[nzFrustumPlane_Top].Set(m_corners[nzCorner_NearRightTop], m_corners[nzCorner_NearLeftTop], m_corners[nzCorner_FarLeftTop]); + m_planes[nzFrustumPlane_Bottom].Set(m_corners[nzBoxCorner_NearLeftBottom], m_corners[nzBoxCorner_NearRightBottom], m_corners[nzBoxCorner_FarRightBottom]); + m_planes[nzFrustumPlane_Far].Set(m_corners[nzBoxCorner_FarRightTop], m_corners[nzBoxCorner_FarLeftTop], m_corners[nzBoxCorner_FarLeftBottom]); + m_planes[nzFrustumPlane_Left].Set(m_corners[nzBoxCorner_NearLeftTop], m_corners[nzBoxCorner_NearLeftBottom], m_corners[nzBoxCorner_FarLeftBottom]); + m_planes[nzFrustumPlane_Near].Set(m_corners[nzBoxCorner_NearLeftTop], m_corners[nzBoxCorner_NearRightTop], m_corners[nzBoxCorner_NearRightBottom]); + m_planes[nzFrustumPlane_Right].Set(m_corners[nzBoxCorner_NearRightBottom], m_corners[nzBoxCorner_NearRightTop], m_corners[nzBoxCorner_FarRightBottom]); + m_planes[nzFrustumPlane_Top].Set(m_corners[nzBoxCorner_NearRightTop], m_corners[nzBoxCorner_NearLeftTop], m_corners[nzBoxCorner_FarLeftTop]); return *this; } @@ -272,56 +272,56 @@ NzFrustum& NzFrustum::Extract(const NzMatrix4& clipMatrix) corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_FarLeftBottom] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_FarLeftBottom] = NzVector3(corner.x, corner.y, corner.z); // FarLeftTop corner.Set(F(-1.0), F(1.0), F(1.0)); corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_FarLeftTop] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_FarLeftTop] = NzVector3(corner.x, corner.y, corner.z); // FarRightBottom corner.Set(F(1.0), F(-1.0), F(1.0)); corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_FarRightBottom] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_FarRightBottom] = NzVector3(corner.x, corner.y, corner.z); // FarRightTop corner.Set(F(1.0), F(1.0), F(1.0)); corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_FarRightTop] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_FarRightTop] = NzVector3(corner.x, corner.y, corner.z); // NearLeftBottom corner.Set(F(-1.0), F(-1.0), F(0.0)); corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_NearLeftBottom] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_NearLeftBottom] = NzVector3(corner.x, corner.y, corner.z); // NearLeftTop corner.Set(F(-1.0), F(1.0), F(0.0)); corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_NearLeftTop] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_NearLeftTop] = NzVector3(corner.x, corner.y, corner.z); // NearRightBottom corner.Set(F(1.0), F(-1.0), F(0.0)); corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_NearRightBottom] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_NearRightBottom] = NzVector3(corner.x, corner.y, corner.z); // NearRightTop corner.Set(F(1.0), F(1.0), F(0.0)); corner = invClipMatrix.Transform(corner); corner.Normalize(); - m_corners[nzCorner_NearRightTop] = NzVector3(corner.x, corner.y, corner.z); + m_corners[nzBoxCorner_NearRightTop] = NzVector3(corner.x, corner.y, corner.z); } else NazaraWarning("Clip matrix is not invertible, failed to compute frustum corners"); @@ -339,10 +339,10 @@ NzFrustum& NzFrustum::Extract(const NzMatrix4& view, const NzMatrix4 } template -const NzVector3& NzFrustum::GetCorner(nzCorner corner) const +const NzVector3& NzFrustum::GetCorner(nzBoxCorner corner) const { #ifdef NAZARA_DEBUG - if (corner > nzCorner_Max) + if (corner > nzBoxCorner_Max) { NazaraError("Corner not handled (0x" + NzString::Number(corner, 16) + ')'); @@ -481,7 +481,7 @@ template template NzFrustum& NzFrustum::Set(const NzFrustum& frustum) { - for (unsigned int i = 0; i <= nzCorner_Max; ++i) + for (unsigned int i = 0; i <= nzBoxCorner_Max; ++i) m_corners[i].Set(frustum.m_corners[i]); for (unsigned int i = 0; i <= nzFrustumPlane_Max; ++i) diff --git a/include/Nazara/Math/OrientedBox.hpp b/include/Nazara/Math/OrientedBox.hpp index 9f5b711b6..b6ea75fd7 100644 --- a/include/Nazara/Math/OrientedBox.hpp +++ b/include/Nazara/Math/OrientedBox.hpp @@ -24,7 +24,7 @@ class NzOrientedBox NzOrientedBox(const NzOrientedBox& orientedBox) = default; ~NzOrientedBox() = default; - const NzVector3& GetCorner(nzCorner corner) const; + const NzVector3& GetCorner(nzBoxCorner corner) const; bool IsValid() const; @@ -59,7 +59,7 @@ class NzOrientedBox NzBox localBox; private: - NzVector3 m_corners[nzCorner_Max+1]; // Ne peuvent pas être modifiés directement + NzVector3 m_corners[nzBoxCorner_Max+1]; // Ne peuvent pas être modifiés directement }; template diff --git a/include/Nazara/Math/OrientedBox.inl b/include/Nazara/Math/OrientedBox.inl index 992698bad..8d242d52e 100644 --- a/include/Nazara/Math/OrientedBox.inl +++ b/include/Nazara/Math/OrientedBox.inl @@ -37,10 +37,10 @@ NzOrientedBox::NzOrientedBox(const NzOrientedBox& orientedBox) } template -const NzVector3& NzOrientedBox::GetCorner(nzCorner corner) const +const NzVector3& NzOrientedBox::GetCorner(nzBoxCorner corner) const { #ifdef NAZARA_DEBUG - if (corner > nzCorner_Max) + if (corner > nzBoxCorner_Max) { NazaraError("Corner not handled (0x" + NzString::Number(corner, 16) + ')'); @@ -102,7 +102,7 @@ template template NzOrientedBox& NzOrientedBox::Set(const NzOrientedBox& orientedBox) { - for (unsigned int i = 0; i <= nzCorner_Max; ++i) + for (unsigned int i = 0; i <= nzBoxCorner_Max; ++i) m_corners[i].Set(orientedBox.m_corners[i]); localBox = orientedBox.localBox; @@ -115,21 +115,21 @@ NzString NzOrientedBox::ToString() const { NzStringStream ss; - return ss << "OrientedBox(FLB: " << m_corners[nzCorner_FarLeftBottom].ToString() << "\n" - << " FLT: " << m_corners[nzCorner_FarLeftTop].ToString() << "\n" - << " FRB: " << m_corners[nzCorner_FarRightBottom].ToString() << "\n" - << " FRT: " << m_corners[nzCorner_FarRightTop].ToString() << "\n" - << " NLB: " << m_corners[nzCorner_NearLeftBottom].ToString() << "\n" - << " NLT: " << m_corners[nzCorner_NearLeftTop].ToString() << "\n" - << " NRB: " << m_corners[nzCorner_NearRightBottom].ToString() << "\n" - << " NRT: " << m_corners[nzCorner_NearRightTop].ToString() << ")\n"; + return ss << "OrientedBox(FLB: " << m_corners[nzBoxCorner_FarLeftBottom].ToString() << "\n" + << " FLT: " << m_corners[nzBoxCorner_FarLeftTop].ToString() << "\n" + << " FRB: " << m_corners[nzBoxCorner_FarRightBottom].ToString() << "\n" + << " FRT: " << m_corners[nzBoxCorner_FarRightTop].ToString() << "\n" + << " NLB: " << m_corners[nzBoxCorner_NearLeftBottom].ToString() << "\n" + << " NLT: " << m_corners[nzBoxCorner_NearLeftTop].ToString() << "\n" + << " NRB: " << m_corners[nzBoxCorner_NearRightBottom].ToString() << "\n" + << " NRT: " << m_corners[nzBoxCorner_NearRightTop].ToString() << ")\n"; } template void NzOrientedBox::Update(const NzMatrix4& transformMatrix) { - for (unsigned int i = 0; i <= nzCorner_Max; ++i) - m_corners[i] = transformMatrix.Transform(localBox.GetCorner(static_cast(i))); + for (unsigned int i = 0; i <= nzBoxCorner_Max; ++i) + m_corners[i] = transformMatrix.Transform(localBox.GetCorner(static_cast(i))); } template @@ -148,7 +148,7 @@ template NzVector3& NzOrientedBox::operator()(unsigned int i) { #if NAZARA_MATH_SAFE - if (i > nzCorner_Max) + if (i > nzBoxCorner_Max) { NzStringStream ss; ss << "Index out of range: (" << i << " >= 3)"; @@ -165,7 +165,7 @@ template NzVector3 NzOrientedBox::operator()(unsigned int i) const { #if NAZARA_MATH_SAFE - if (i > nzCorner_Max) + if (i > nzBoxCorner_Max) { NzStringStream ss; ss << "Index out of range: (" << i << " >= 3)"; diff --git a/include/Nazara/Math/Ray.inl b/include/Nazara/Math/Ray.inl index ec4802bca..900ec2bbf 100644 --- a/include/Nazara/Math/Ray.inl +++ b/include/Nazara/Math/Ray.inl @@ -204,9 +204,9 @@ bool NzRay::Intersect(const NzBox& box, const NzMatrix4& transform, T* template bool NzRay::Intersect(const NzOrientedBox& orientedBox, T* closestHit, T* farthestHit) const { - NzVector3 width = (orientedBox.GetCorner(nzCorner_NearLeftBottom) - orientedBox.GetCorner(nzCorner_FarLeftBottom)).Normalize(); - NzVector3 height = (orientedBox.GetCorner(nzCorner_FarLeftTop) - orientedBox.GetCorner(nzCorner_FarLeftBottom)).Normalize(); - NzVector3 depth = (orientedBox.GetCorner(nzCorner_FarRightBottom) - orientedBox.GetCorner(nzCorner_FarLeftBottom)).Normalize(); + NzVector3 width = (orientedBox.GetCorner(nzBoxCorner_NearLeftBottom) - orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)).Normalize(); + NzVector3 height = (orientedBox.GetCorner(nzBoxCorner_FarLeftTop) - orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)).Normalize(); + NzVector3 depth = (orientedBox.GetCorner(nzBoxCorner_FarRightBottom) - orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)).Normalize(); // Construction de la matrice de transformation de l'OBB NzMatrix4 matrix(width.x, height.x, depth.x, F(0.0), diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index a91c7b0e9..424d69079 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -8,6 +8,7 @@ #define NAZARA_RECT_HPP #include +#include #include template @@ -33,6 +34,7 @@ class NzRect NzRect& ExtendTo(const NzRect& rect); NzVector2 GetCenter() const; + NzVector2 GetCorner(nzRectCorner corner) const; NzVector2 GetLengths() const; NzVector2 GetMaximum() const; NzVector2 GetMinimum() const; diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index 3d1908b83..5cee6602d 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -109,6 +109,28 @@ NzVector2 NzRect::GetCenter() const return GetPosition() + GetLengths() / F(2.0); } +template +NzVector2 NzRect::GetCorner(nzRectCorner corner) const +{ + switch (corner) + { + case nzRectCorner_LeftBottom: + return NzVector2(x, y + height); + + case nzRectCorner_LeftTop: + return NzVector2(x, y); + + case nzRectCorner_RightBottom: + return NzVector2(x + width, y + height); + + case nzRectCorner_RightTop: + return NzVector2(x + width, y); + } + + NazaraError("Corner not handled (0x" + NzString::Number(corner, 16) + ')'); + return NzVector2(); +} + template NzVector2 NzRect::GetLengths() const { diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index 357babaa5..53850c631 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -9,6 +9,9 @@ #include +template class NzVector3; +template class NzVector4; + template class NzVector2 { @@ -19,6 +22,8 @@ class NzVector2 NzVector2(const T vec[2]); template explicit NzVector2(const NzVector2& vec); NzVector2(const NzVector2& vec) = default; + explicit NzVector2(const NzVector3& vec); + explicit NzVector2(const NzVector4& vec); ~NzVector2() = default; T AbsDotProduct(const NzVector2& vec) const; @@ -48,6 +53,8 @@ class NzVector2 NzVector2& Set(T scale); NzVector2& Set(const T vec[2]); NzVector2& Set(const NzVector2& vec); + NzVector2& Set(const NzVector3& vec); + NzVector2& Set(const NzVector4& vec); template NzVector2& Set(const NzVector2& vec); T SquaredDistance(const NzVector2& vec) const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index 227d95425..f97786610 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -36,6 +36,18 @@ NzVector2::NzVector2(const NzVector2& vec) Set(vec); } +template +NzVector2::NzVector2(const NzVector3& vec) +{ + Set(vec); +} + +template +NzVector2::NzVector2(const NzVector4& vec) +{ + Set(vec); +} + template T NzVector2::AbsDotProduct(const NzVector2& vec) const { @@ -208,6 +220,24 @@ NzVector2& NzVector2::Set(const NzVector2& vec) return *this; } +template +NzVector2& NzVector2::Set(const NzVector3& vec) +{ + x = vec.x; + y = vec.y; + + return *this; +} + +template +NzVector2& NzVector2::Set(const NzVector4& vec) +{ + x = vec.x; + y = vec.y; + + return *this; +} + template T NzVector2::SquaredDistance(const NzVector2& vec) const { diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 875662270..e8fe8f7d0 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -8,18 +8,23 @@ #define NAZARA_VECTOR3_HPP #include -#include -template class NzVector3 +template class NzVector2; +template class NzVector4; + +template +class NzVector3 { public: NzVector3() = default; NzVector3(T X, T Y, T Z); + NzVector3(T X, const NzVector2& vec); explicit NzVector3(T scale); NzVector3(const T vec[3]); NzVector3(const NzVector2& vec, T Z = 0.0); template explicit NzVector3(const NzVector3& vec); NzVector3(const NzVector3& vec) = default; + explicit NzVector3(const NzVector4& vec); ~NzVector3() = default; T AbsDotProduct(const NzVector3& vec) const; @@ -56,11 +61,13 @@ template class NzVector3 NzVector3& Normalize(T* length = nullptr); NzVector3& Set(T X, T Y, T Z); + NzVector3& Set(T X, const NzVector2& vec); NzVector3& Set(T scale); NzVector3& Set(const T vec[3]); NzVector3& Set(const NzVector2& vec, T Z = 0.0); NzVector3& Set(const NzVector3& vec); template NzVector3& Set(const NzVector3& vec); + NzVector3& Set(const NzVector4& vec); T SquaredDistance(const NzVector3& vec) const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index f300330b8..fb395a748 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -17,6 +17,12 @@ NzVector3::NzVector3(T X, T Y, T Z) Set(X, Y, Z); } +template +NzVector3::NzVector3(T X, const NzVector2& vec) +{ + Set(X, vec); +} + template NzVector3::NzVector3(T scale) { @@ -42,6 +48,12 @@ NzVector3::NzVector3(const NzVector3& vec) Set(vec); } +template +NzVector3::NzVector3(const NzVector4& vec) +{ + Set(vec); +} + template T NzVector3::AbsDotProduct(const NzVector3& vec) const { @@ -255,6 +267,16 @@ NzVector3& NzVector3::Set(T X, T Y, T Z) return *this; } +template +NzVector3& NzVector3::Set(T X, const NzVector2& vec) +{ + x = X; + y = vec.x; + z = vec.y; + + return *this; +} + template NzVector3& NzVector3::Set(T scale) { @@ -302,6 +324,16 @@ NzVector3& NzVector3::Set(const NzVector3& vec) return *this; } +template +NzVector3& NzVector3::Set(const NzVector4& vec) +{ + x = vec.x; + y = vec.y; + z = vec.z; + + return *this; +} + template T NzVector3::SquaredDistance(const NzVector3& vec) const { diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index 5b71081d8..7bad9b918 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -8,16 +8,23 @@ #define NAZARA_VECTOR4_HPP #include -#include -template class NzVector4 +template class NzVector2; +template class NzVector3; + +template +class NzVector4 { public: NzVector4() = default; NzVector4(T X, T Y, T Z, T W = 1.0); + NzVector4(T X, T Y, const NzVector2& vec); + NzVector4(T X, const NzVector2& vec, T W); + NzVector4(T X, const NzVector3& vec); explicit NzVector4(T scale); NzVector4(const T vec[4]); - NzVector4(const NzVector3& vec, T W = 1.0); + NzVector4(const NzVector2& vec, T Z = 0.0, T W = 1.0); + NzVector4(const NzVector3& vec, T W = 0.0); template explicit NzVector4(const NzVector4& vec); NzVector4(const NzVector4& vec) = default; ~NzVector4() = default; @@ -39,8 +46,12 @@ template class NzVector4 NzVector4& Normalize(T* length = nullptr); NzVector4& Set(T X, T Y, T Z, T W = 1.0); + NzVector4& Set(T X, T Y, const NzVector2& vec); + NzVector4& Set(T X, const NzVector2& vec, T W); + NzVector4& Set(T X, const NzVector3& vec); NzVector4& Set(T scale); NzVector4& Set(const T vec[4]); + NzVector4& Set(const NzVector2& vec, T Z = 0.0, T W = 1.0); NzVector4& Set(const NzVector3& vec, T W = 1.0); NzVector4& Set(const NzVector4& vec); template NzVector4& Set(const NzVector4& vec); diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 2f6002fbc..c1d7f4d1c 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -18,6 +18,24 @@ NzVector4::NzVector4(T X, T Y, T Z, T W) Set(X, Y, Z, W); } +template +NzVector4::NzVector4(T X, T Y, const NzVector2& vec) +{ + Set(X, Y, vec); +} + +template +NzVector4::NzVector4(T X, const NzVector2& vec, T W) +{ + Set(X, vec, W); +} + +template +NzVector4::NzVector4(T X, const NzVector3& vec) +{ + Set(X, vec); +} + template NzVector4::NzVector4(T scale) { @@ -30,6 +48,12 @@ NzVector4::NzVector4(const T vec[4]) Set(vec); } +template +NzVector4::NzVector4(const NzVector2& vec, T Z, T W) +{ + Set(vec, Z, W); +} + template NzVector4::NzVector4(const NzVector3& vec, T W) { @@ -155,10 +179,43 @@ NzVector4& NzVector4::Normalize(T* length) template NzVector4& NzVector4::Set(T X, T Y, T Z, T W) { - w = W; x = X; y = Y; z = Z; + w = W; + + return *this; +} + +template +NzVector4& NzVector4::Set(T X, T Y, const NzVector2& vec) +{ + x = X; + y = Y; + z = vec.x; + w = vec.y; + + return *this; +} + +template +NzVector4& NzVector4::Set(T X, const NzVector2& vec, T W) +{ + x = X; + y = vec.x; + z = vec.y; + w = W; + + return *this; +} + +template +NzVector4& NzVector4::Set(T X, const NzVector3& vec) +{ + x = X; + y = vec.x; + z = vec.y; + w = vec.z; return *this; } @@ -166,10 +223,10 @@ NzVector4& NzVector4::Set(T X, T Y, T Z, T W) template NzVector4& NzVector4::Set(T scale) { - w = scale; x = scale; y = scale; z = scale; + w = scale; return *this; } @@ -182,6 +239,17 @@ NzVector4& NzVector4::Set(const T vec[4]) return *this; } +template +NzVector4& NzVector4::Set(const NzVector2& vec, T Z, T W) +{ + x = vec.x; + y = vec.y; + z = Z; + w = W; + + return *this; +} + template NzVector4& NzVector4::Set(const NzVector3& vec, T W) { @@ -205,10 +273,10 @@ template template NzVector4& NzVector4::Set(const NzVector4& vec) { - w = F(vec.w); x = F(vec.x); y = F(vec.y); z = F(vec.z); + w = F(vec.w); return *this; } diff --git a/include/Nazara/Renderer/DebugDrawer.hpp b/include/Nazara/Renderer/DebugDrawer.hpp index fc632765a..1bb055c37 100644 --- a/include/Nazara/Renderer/DebugDrawer.hpp +++ b/include/Nazara/Renderer/DebugDrawer.hpp @@ -27,6 +27,7 @@ class NAZARA_API NzDebugDrawer static void Draw(const NzFrustumf& frustum); static void Draw(const NzOrientedBoxf& orientedBox); static void Draw(const NzSkeleton* skeleton); + static void Draw(const NzVector3f& position, float size = 0.1f); static void DrawBinormals(const NzStaticMesh* subMesh); static void DrawCone(const NzVector3f& origin, const NzQuaternionf& rotation, float angle, float length); static void DrawLine(const NzVector3f& p1, const NzVector3f& p2); diff --git a/include/Nazara/Renderer/Enums.hpp b/include/Nazara/Renderer/Enums.hpp index fa9fc9a3d..0065f55b2 100644 --- a/include/Nazara/Renderer/Enums.hpp +++ b/include/Nazara/Renderer/Enums.hpp @@ -187,6 +187,7 @@ enum nzSamplerWrap enum nzShaderUniform { + ///FIXME: Virer EyePosition, SceneAmbient et TargetSize de l'énumération (ils n'ont rien à faire dans le module de rendu) nzShaderUniform_EyePosition, nzShaderUniform_InvProjMatrix, nzShaderUniform_InvTargetSize, diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index df6c199d7..8aa5a438d 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -69,6 +69,7 @@ class NAZARA_API NzOpenGL GLenum dataFormat; GLenum dataType; GLint internalFormat; + GLint swizzle[4]; }; NzOpenGL() = delete; diff --git a/include/Nazara/Renderer/RenderTarget.hpp b/include/Nazara/Renderer/RenderTarget.hpp index eaec9f2ce..b04edd177 100644 --- a/include/Nazara/Renderer/RenderTarget.hpp +++ b/include/Nazara/Renderer/RenderTarget.hpp @@ -44,7 +44,7 @@ class NAZARA_API NzRenderTarget { public: Listener() = default; - ~Listener(); + virtual ~Listener(); virtual bool OnRenderTargetParametersChange(const NzRenderTarget* renderTarget, void* userdata); virtual void OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata); diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index aff9101fa..42832c661 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -57,6 +57,7 @@ class NAZARA_API NzRenderer static nzUInt8 GetMaxAnisotropyLevel(); static unsigned int GetMaxColorAttachments(); static unsigned int GetMaxRenderTargets(); + static unsigned int GetMaxTextureSize(); static unsigned int GetMaxTextureUnits(); static unsigned int GetMaxVertexAttribs(); static float GetPointSize(); diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index 024216d70..02a1a208f 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include class NzTexture; @@ -23,13 +23,13 @@ using NzTextureRef = NzResourceRef; struct NzTextureImpl; -class NAZARA_API NzTexture : public NzResource, NzNonCopyable +class NAZARA_API NzTexture : public NzAbstractImage, public NzResource, NzNonCopyable { friend class NzRenderer; - friend class NzRenderTexture; public: NzTexture() = default; + NzTexture(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, nzUInt8 levelCount = 1); explicit NzTexture(const NzImage& image); ~NzTexture(); @@ -42,18 +42,20 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable void EnsureMipmapsUpdate() const; - nzUInt8 GetBytesPerPixel() const; - unsigned int GetDepth() const; + unsigned int GetDepth(nzUInt8 level = 0) const; nzPixelFormat GetFormat() const; - unsigned int GetHeight() const; - NzVector2ui GetSize() const; + unsigned int GetHeight(nzUInt8 level = 0) const; + nzUInt8 GetLevelCount() const; + nzUInt8 GetMaxLevel() const; + unsigned int GetMemoryUsage() const; + unsigned int GetMemoryUsage(nzUInt8 level) const; + NzVector3ui GetSize(nzUInt8 level = 0) const; nzImageType GetType() const; - unsigned int GetWidth() const; + unsigned int GetWidth(nzUInt8 level = 0) const; bool HasMipmaps() const; - bool IsCompressed() const; - bool IsCubemap() const; + void InvalidateMipmaps(); bool IsValid() const; // Load @@ -87,10 +89,6 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable bool Update(const nzUInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); bool Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); bool Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); - bool UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 level = 0); - bool UpdateFace(nzCubemapFace face, const NzImage& image, const NzRectui& rect, nzUInt8 level = 0); - bool UpdateFace(nzCubemapFace face, const nzUInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); - bool UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); // Fonctions OpenGL unsigned int GetOpenGLID() const; @@ -101,7 +99,7 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable static bool IsTypeSupported(nzImageType type); private: - void InvalidateMipmaps(); + bool CreateTexture(bool proxy); NzTextureImpl* m_impl = nullptr; }; diff --git a/include/Nazara/Utility/AbstractAtlas.hpp b/include/Nazara/Utility/AbstractAtlas.hpp new file mode 100644 index 000000000..2d290153b --- /dev/null +++ b/include/Nazara/Utility/AbstractAtlas.hpp @@ -0,0 +1,56 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ABSTRACTATLAS_HPP +#define NAZARA_ABSTRACTATLAS_HPP + +#include +#include +#include +#include + +class NzAbstractImage; +class NzImage; + +class NAZARA_API NzAbstractAtlas +{ + public: + class Listener; + + NzAbstractAtlas(); + virtual ~NzAbstractAtlas(); + + void AddListener(Listener* font, void* userdata = nullptr) const; + + virtual void Clear() = 0; + virtual void Free(NzSparsePtr rects, NzSparsePtr layers, unsigned int count) = 0; + virtual NzAbstractImage* GetLayer(unsigned int layerIndex) const = 0; + virtual unsigned int GetLayerCount() const = 0; + virtual bool Insert(const NzImage& image, NzRectui* rect, bool* flipped, unsigned int* layerIndex) = 0; + + void RemoveListener(Listener* font) const; + + class Listener + { + public: + Listener() = default; + virtual ~Listener(); + + virtual bool OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata); + virtual bool OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata); + virtual void OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata); + }; + + protected: + void NotifyCleared(); + void NotifyLayerChange(NzAbstractImage* oldLayer, NzAbstractImage* newLayer); + + private: + mutable std::unordered_map m_listeners; + bool m_listenersLocked; +}; + +#endif // NAZARA_ABSTRACTATLAS_HPP diff --git a/include/Nazara/Utility/AbstractImage.hpp b/include/Nazara/Utility/AbstractImage.hpp new file mode 100644 index 000000000..8697ea813 --- /dev/null +++ b/include/Nazara/Utility/AbstractImage.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ABSTRACTIMAGE_HPP +#define NAZARA_ABSTRACTIMAGE_HPP + +#include +#include +#include +#include +#include + +class NAZARA_API NzAbstractImage +{ + public: + NzAbstractImage() = default; + virtual ~NzAbstractImage(); + + nzUInt8 GetBytesPerPixel() const; + virtual unsigned int GetDepth(nzUInt8 level = 0) const = 0; + virtual nzPixelFormat GetFormat() const = 0; + virtual unsigned int GetHeight(nzUInt8 level = 0) const = 0; + virtual nzUInt8 GetLevelCount() const = 0; + virtual nzUInt8 GetMaxLevel() const = 0; + virtual unsigned int GetMemoryUsage() const = 0; + virtual unsigned int GetMemoryUsage(nzUInt8 level) const = 0; + virtual NzVector3ui GetSize(nzUInt8 level = 0) const = 0; + virtual nzImageType GetType() const = 0; + virtual unsigned int GetWidth(nzUInt8 level = 0) const = 0; + + bool IsCompressed() const; + bool IsCubemap() const; + + virtual bool Update(const nzUInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0) = 0; + virtual bool Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0) = 0; + virtual bool Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0) = 0; +}; + +#endif // NAZARA_IMAGE_HPP diff --git a/include/Nazara/Utility/AbstractTextDrawer.hpp b/include/Nazara/Utility/AbstractTextDrawer.hpp new file mode 100644 index 000000000..76df09a00 --- /dev/null +++ b/include/Nazara/Utility/AbstractTextDrawer.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ABSTRACTTEXTDRAWER_HPP +#define NAZARA_ABSTRACTTEXTDRAWER_HPP + +#include +#include +#include +#include + +class NzAbstractImage; +class NzFont; + +class NAZARA_API NzAbstractTextDrawer +{ + public: + struct Glyph; + + NzAbstractTextDrawer() = default; + virtual ~NzAbstractTextDrawer(); + + virtual const NzRectui& GetBounds() const = 0; + virtual NzFont* GetFont(unsigned int index) const = 0; + virtual unsigned int GetFontCount() const = 0; + virtual const Glyph& GetGlyph(unsigned int index) const = 0; + virtual unsigned int GetGlyphCount() const = 0; + + struct Glyph + { + NzColor color; + NzRectui atlasRect; + NzVector2f corners[4]; + NzAbstractImage* atlas; + bool flipped; + }; +}; + +#endif // NAZARA_ABSTRACTTEXTDRAWER_HPP diff --git a/include/Nazara/Utility/Buffer.hpp b/include/Nazara/Utility/Buffer.hpp index be48b34ad..b7a81e094 100644 --- a/include/Nazara/Utility/Buffer.hpp +++ b/include/Nazara/Utility/Buffer.hpp @@ -25,22 +25,22 @@ class NAZARA_API NzBuffer : public NzResource, NzNonCopyable friend class NzUtility; public: - using BufferFunction = NzAbstractBuffer* (*)(NzBuffer* parent, nzBufferType type); + using BufferFactory = NzAbstractBuffer* (*)(NzBuffer* parent, nzBufferType type); NzBuffer(nzBufferType type); - NzBuffer(nzBufferType type, unsigned int size, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); + NzBuffer(nzBufferType type, unsigned int size, nzUInt32 storage = nzDataStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); ~NzBuffer(); bool CopyContent(const NzBuffer& buffer); - bool Create(unsigned int size, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); + bool Create(unsigned int size, nzUInt32 storage = nzDataStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); void Destroy(); bool Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard = false); NzAbstractBuffer* GetImpl() const; unsigned int GetSize() const; - nzBufferStorage GetStorage() const; + nzUInt32 GetStorage() const; nzBufferType GetType() const; nzBufferUsage GetUsage() const; @@ -50,24 +50,24 @@ class NAZARA_API NzBuffer : public NzResource, NzNonCopyable void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int size = 0); void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int size = 0) const; - bool SetStorage(nzBufferStorage storage); + bool SetStorage(nzUInt32 storage); void Unmap() const; - static bool IsSupported(nzBufferStorage storage); - static void SetBufferFunction(nzBufferStorage storage, BufferFunction func); + static bool IsStorageSupported(nzUInt32 storage); + static void SetBufferFactory(nzUInt32 storage, BufferFactory func); private: static bool Initialize(); static void Uninitialize(); - nzBufferStorage m_storage; nzBufferType m_type; nzBufferUsage m_usage; + nzUInt32 m_storage; NzAbstractBuffer* m_impl; unsigned int m_size; - static BufferFunction s_bufferFunctions[nzBufferStorage_Max+1]; + static BufferFactory s_bufferFactories[nzDataStorage_Max+1]; }; #endif // NAZARA_BUFFER_HPP diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index 25e09c10a..ac056a41b 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -25,15 +25,6 @@ enum nzBufferAccess nzBufferAccess_Max = nzBufferAccess_WriteOnly }; -enum nzBufferStorage -{ - //nzBufferStorage_Both, ///TODO - nzBufferStorage_Hardware, - nzBufferStorage_Software, - - nzBufferStorage_Max = nzBufferStorage_Software -}; - enum nzBufferType { nzBufferType_Index, @@ -84,6 +75,16 @@ enum nzCubemapFace nzCubemapFace_Max = nzCubemapFace_NegativeZ }; +enum nzDataStorageFlags +{ + nzDataStorage_Hardware = 0x1, + nzDataStorage_Software = 0x2, + + nzDataStorage_Both = nzDataStorage_Hardware | nzDataStorage_Software, + + nzDataStorage_Max = nzDataStorage_Software*2-1 +}; + enum nzEventType { nzEventType_GainedFocus, @@ -130,6 +131,7 @@ enum nzPixelFormat { nzPixelFormat_Undefined = -1, + nzPixelFormat_A8, // 1*uint8 nzPixelFormat_BGR8, // 3*uint8 nzPixelFormat_BGRA8, // 4*uint8 nzPixelFormat_DXT1, @@ -217,6 +219,27 @@ enum nzPrimitiveMode nzPrimitiveMode_Max = nzPrimitiveMode_TriangleFan }; +enum nzTextAlign +{ + nzTextAlign_Left, + nzTextAlign_Middle, + nzTextAlign_Right, + + nzTextAlign_Max = nzTextAlign_Right +}; + +enum nzTextStyleFlags +{ + nzTextStyle_Regular = 0x0, + + nzTextStyle_Bold = 0x1, + nzTextStyle_Italic = 0x2, + nzTextStyle_StrikeThrough = 0x4, + nzTextStyle_Underlined = 0x8, + + nzTextStyle_Max = nzTextStyle_Underlined*2-1 +}; + enum nzVertexComponent { nzVertexComponent_Unused = -1, @@ -251,8 +274,11 @@ enum nzVertexLayout { // Déclarations destinées au rendu nzVertexLayout_XY, + nzVertexLayout_XY_Color, nzVertexLayout_XY_UV, nzVertexLayout_XYZ, + nzVertexLayout_XYZ_Color, + nzVertexLayout_XYZ_Color_UV, nzVertexLayout_XYZ_Normal, nzVertexLayout_XYZ_Normal_UV, nzVertexLayout_XYZ_Normal_UV_Tangent, diff --git a/include/Nazara/Utility/Font.hpp b/include/Nazara/Utility/Font.hpp new file mode 100644 index 000000000..80b175f5f --- /dev/null +++ b/include/Nazara/Utility/Font.hpp @@ -0,0 +1,129 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FONT_HPP +#define NAZARA_FONT_HPP + +#include +#include +#include +#include +#include +#include +#include + +struct NAZARA_API NzFontParams +{ + bool IsValid() const; +}; + +class NzFont; +class NzFontData; + +struct NzFontGlyph; + +using NzFontConstRef = NzResourceRef; +using NzFontLoader = NzResourceLoader; +using NzFontRef = NzResourceRef; + +class NAZARA_API NzFont : public NzResource, NzAbstractAtlas::Listener, NzNonCopyable +{ + friend NzFontLoader; + + public: + struct Glyph; + struct SizeInfo; + + NzFont(); + NzFont(NzFont&& font) = default; + ~NzFont(); + + void ClearGlyphCache(); + void ClearKerningCache(); + void ClearSizeInfoCache(); + + bool Create(NzFontData* data); + void Destroy(); + + bool ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt32 style, NzFontGlyph* glyph) const; + + const NzAbstractAtlas* GetAtlas() const; + unsigned int GetCachedGlyphCount(unsigned int characterSize, nzUInt32 style) const; + unsigned int GetCachedGlyphCount() const; + NzString GetFamilyName() const; + int GetKerning(unsigned int characterSize, char32_t first, char32_t second) const; + const Glyph& GetGlyph(unsigned int characterSize, nzUInt32 style, char32_t character) const; + unsigned int GetGlyphBorder() const; + unsigned int GetMinimumStepSize() const; + const SizeInfo& GetSizeInfo(unsigned int characterSize) const; + NzString GetStyleName() const; + + bool IsValid() const; + + bool Precache(unsigned int characterSize, nzUInt32 style, char32_t character) const; + bool Precache(unsigned int characterSize, nzUInt32 style, const NzString& characterSet) const; + + // Open + bool OpenFromFile(const NzString& filePath, const NzFontParams& params = NzFontParams()); + bool OpenFromMemory(const void* data, std::size_t size, const NzFontParams& params = NzFontParams()); + bool OpenFromStream(NzInputStream& stream, const NzFontParams& params = NzFontParams()); + + void SetAtlas(std::shared_ptr atlas); + void SetGlyphBorder(unsigned int borderSize); + void SetMinimumStepSize(unsigned int minimumSizeStep); + + NzFont& operator=(NzFont&& font) = default; + + enum ModicationCode + { + ModificationCode_AtlasChanged, + ModificationCode_AtlasLayerChanged, + ModificationCode_GlyphCacheCleared, + ModificationCode_KerningCacheCleared, + ModificationCode_SizeInfoCacheCleared + }; + + struct Glyph + { + NzRecti aabb; + NzRectui atlasRect; + bool requireFauxBold; + bool requireFauxItalic; + bool flipped; + bool valid; + int advance; + unsigned int layerIndex; + }; + + struct SizeInfo + { + int spaceAdvance; + unsigned int lineHeight; + float underlinePosition; + float underlineThickness; + }; + + private: + using GlyphMap = std::unordered_map; + + nzUInt64 ComputeKey(unsigned int characterSize, nzUInt32 style) const; + bool OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata) override; + bool OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata) override; + void OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata) override; + const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, nzUInt32 style, char32_t character) const; + + std::shared_ptr m_atlas; + std::unique_ptr m_data; + mutable std::unordered_map> m_kerningCache; + mutable std::unordered_map m_glyphes; + mutable std::unordered_map m_sizeInfoCache; + unsigned int m_glyphBorder; + unsigned int m_minimumSizeStep; + + static NzFontLoader::LoaderList s_loaders; +}; + +#endif // NAZARA_FONT_HPP diff --git a/include/Nazara/Utility/FontData.hpp b/include/Nazara/Utility/FontData.hpp new file mode 100644 index 000000000..171735b10 --- /dev/null +++ b/include/Nazara/Utility/FontData.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FONTDATA_HPP +#define NAZARA_FONTDATA_HPP + +#include +#include + +struct NzFontGlyph; + +class NAZARA_API NzFontData +{ + public: + NzFontData() = default; + virtual ~NzFontData(); + + virtual bool ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt32 style, NzFontGlyph* dst) = 0; + + virtual NzString GetFamilyName() const = 0; + virtual NzString GetStyleName() const = 0; + + virtual bool HasKerning() const = 0; + + virtual bool IsScalable() const = 0; + + virtual int QueryKerning(unsigned int characterSize, char32_t first, char32_t second) const = 0; + virtual unsigned int QueryLineHeight(unsigned int characterSize) const = 0; + virtual float QueryUnderlinePosition(unsigned int characterSize) const = 0; + virtual float QueryUnderlineThickness(unsigned int characterSize) const = 0; + + virtual bool SupportsStyle(nzUInt32 style) const = 0; +}; + +#endif // NAZARA_FONTDATA_HPP diff --git a/include/Nazara/Utility/FontGlyph.hpp b/include/Nazara/Utility/FontGlyph.hpp new file mode 100644 index 000000000..11bceb255 --- /dev/null +++ b/include/Nazara/Utility/FontGlyph.hpp @@ -0,0 +1,19 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FONTGLYPH_HPP +#define NAZARA_FONTGLYPH_HPP + +#include + +struct NzFontGlyph +{ + NzImage image; + NzRecti aabb; + int advance; +}; + +#endif // NAZARA_FONTGLYPH_HPP diff --git a/include/Nazara/Utility/GuillotineImageAtlas.hpp b/include/Nazara/Utility/GuillotineImageAtlas.hpp new file mode 100644 index 000000000..22c50fdcb --- /dev/null +++ b/include/Nazara/Utility/GuillotineImageAtlas.hpp @@ -0,0 +1,66 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_GUILLOTINEIMAGEATLAS_HPP +#define NAZARA_GUILLOTINEIMAGEATLAS_HPP + +#include +#include +#include +#include +#include +#include +#include + +class NAZARA_API NzGuillotineImageAtlas : public NzAbstractAtlas +{ + public: + NzGuillotineImageAtlas(); + virtual ~NzGuillotineImageAtlas(); + + void Clear(); + void Free(NzSparsePtr rects, NzSparsePtr layers, unsigned int count); + + NzGuillotineBinPack::FreeRectChoiceHeuristic GetRectChoiceHeuristic() const; + NzGuillotineBinPack::GuillotineSplitHeuristic GetRectSplitHeuristic() const; + NzAbstractImage* GetLayer(unsigned int layerIndex) const; + unsigned int GetLayerCount() const; + + bool Insert(const NzImage& image, NzRectui* rect, bool* flipped, unsigned int* layerIndex); + + void SetRectChoiceHeuristic(NzGuillotineBinPack::FreeRectChoiceHeuristic heuristic); + void SetRectSplitHeuristic(NzGuillotineBinPack::GuillotineSplitHeuristic heuristic); + + protected: + struct Layer; + + virtual NzAbstractImage* ResizeImage(NzAbstractImage* oldImage, const NzVector2ui& size) const; + bool ResizeLayer(Layer& layer, const NzVector2ui& size); + + struct QueuedGlyph + { + NzImage image; + NzRectui rect; + bool flipped; + }; + + struct Layer + { + std::vector queuedGlyphs; + std::unique_ptr image; + NzGuillotineBinPack binPack; + unsigned int freedRectangles = 0; + }; + + private: + void ProcessGlyphQueue(Layer& layer) const; + + mutable std::vector m_layers; + NzGuillotineBinPack::FreeRectChoiceHeuristic m_rectChoiceHeuristic; + NzGuillotineBinPack::GuillotineSplitHeuristic m_rectSplitHeuristic; +}; + +#endif // NAZARA_GUILLOTINEIMAGEATLAS_HPP diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 21cefa6b3..57c188822 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -13,12 +13,8 @@ #include #include #include -#include -#include -#include +#include #include -#include -#include #include ///TODO: Filtres @@ -40,7 +36,7 @@ using NzImageConstRef = NzResourceRef; using NzImageLoader = NzResourceLoader; using NzImageRef = NzResourceRef; -class NAZARA_API NzImage : public NzResource +class NAZARA_API NzImage : public NzAbstractImage, public NzResource { friend NzImageLoader; @@ -50,7 +46,6 @@ class NAZARA_API NzImage : public NzResource NzImage(); NzImage(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, nzUInt8 levelCount = 1); NzImage(const NzImage& image); - NzImage(NzImage&& image) noexcept; NzImage(SharedImage* sharedImage); ~NzImage(); @@ -68,22 +63,20 @@ class NAZARA_API NzImage : public NzResource bool FlipHorizontally(); bool FlipVertically(); - nzUInt8 GetBytesPerPixel() const; const nzUInt8* GetConstPixels(unsigned int x = 0, unsigned int y = 0, unsigned int z = 0, nzUInt8 level = 0) const; unsigned int GetDepth(nzUInt8 level = 0) const; nzPixelFormat GetFormat() const; unsigned int GetHeight(nzUInt8 level = 0) const; nzUInt8 GetLevelCount() const; nzUInt8 GetMaxLevel() const; + unsigned int GetMemoryUsage() const; + unsigned int GetMemoryUsage(nzUInt8 level) const; NzColor GetPixelColor(unsigned int x, unsigned int y = 0, unsigned int z = 0) const; nzUInt8* GetPixels(unsigned int x = 0, unsigned int y = 0, unsigned int z = 0, nzUInt8 level = 0); - unsigned int GetSize() const; - unsigned int GetSize(nzUInt8 level) const; + NzVector3ui GetSize(nzUInt8 level = 0) const; nzImageType GetType() const; unsigned int GetWidth(nzUInt8 level = 0) const; - bool IsCompressed() const; - bool IsCubemap() const; bool IsValid() const; // Load @@ -106,12 +99,11 @@ class NAZARA_API NzImage : public NzResource void SetLevelCount(nzUInt8 levelCount); bool SetPixelColor(const NzColor& color, unsigned int x, unsigned int y = 0, unsigned int z = 0); - void Update(const nzUInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); - void Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); - void Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); + bool Update(const nzUInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); + bool Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); + bool Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, nzUInt8 level = 0); NzImage& operator=(const NzImage& image); - NzImage& operator=(NzImage&& image) noexcept; static void Copy(nzUInt8* destination, const nzUInt8* source, nzUInt8 bpp, unsigned int width, unsigned int height, unsigned int depth = 1, unsigned int dstWidth = 0, unsigned int dstHeight = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0); static nzUInt8 GetMaxLevel(unsigned int width, unsigned int height, unsigned int depth = 1); diff --git a/include/Nazara/Utility/IndexBuffer.hpp b/include/Nazara/Utility/IndexBuffer.hpp index 3088a0fd1..cd1860199 100644 --- a/include/Nazara/Utility/IndexBuffer.hpp +++ b/include/Nazara/Utility/IndexBuffer.hpp @@ -23,7 +23,7 @@ class NAZARA_API NzIndexBuffer : public NzResource NzIndexBuffer() = default; NzIndexBuffer(bool largeIndices, NzBuffer* buffer); NzIndexBuffer(bool largeIndices, NzBuffer* buffer, unsigned int startOffset, unsigned int endOffset); - NzIndexBuffer(bool largeIndices, unsigned int length, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); + NzIndexBuffer(bool largeIndices, unsigned int length, nzUInt32 storage = nzDataStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); NzIndexBuffer(const NzIndexBuffer& indexBuffer); NzIndexBuffer(NzIndexBuffer&& indexBuffer) noexcept; ~NzIndexBuffer(); @@ -54,11 +54,11 @@ class NAZARA_API NzIndexBuffer : public NzResource void Reset(); void Reset(bool largeIndices, NzBuffer* buffer); void Reset(bool largeIndices, NzBuffer* buffer, unsigned int startOffset, unsigned int endOffset); - void Reset(bool largeIndices, unsigned int length, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); + void Reset(bool largeIndices, unsigned int length, nzUInt32 storage = nzDataStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); void Reset(const NzIndexBuffer& indexBuffer); void Reset(NzIndexBuffer&& indexBuffer) noexcept; - bool SetStorage(nzBufferStorage storage); + bool SetStorage(nzUInt32 storage); void Unmap() const; diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index 116bbc3e7..296d72f7c 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -24,12 +24,12 @@ struct NAZARA_API NzMeshParams { NzMeshParams(); // Vérifie que le storage par défaut est supporté (software autrement) - // Si ceci sera le stockage utilisé par les buffers - nzBufferStorage storage = nzBufferStorage_Hardware; - // La mise à l'échelle éventuelle que subira le mesh NzVector3f scale = NzVector3f::Unit(); + // Si ceci sera le stockage utilisé par les buffers + nzUInt32 storage = nzDataStorage_Hardware; + // Charger une version animée du mesh si possible ? bool animated = true; diff --git a/include/Nazara/Utility/Node.hpp b/include/Nazara/Utility/Node.hpp index 4536739a7..11f9d1f15 100644 --- a/include/Nazara/Utility/Node.hpp +++ b/include/Nazara/Utility/Node.hpp @@ -24,26 +24,26 @@ class NAZARA_API NzNode void EnsureDerivedUpdate() const; void EnsureTransformMatrixUpdate() const; - NzVector3f GetBackward() const; + virtual NzVector3f GetBackward() const; const std::vector& GetChilds() const; - NzVector3f GetDown() const; - NzVector3f GetForward() const; + virtual NzVector3f GetDown() const; + virtual NzVector3f GetForward() const; bool GetInheritPosition() const; bool GetInheritRotation() const; bool GetInheritScale() const; NzVector3f GetInitialPosition() const; NzQuaternionf GetInitialRotation() const; NzVector3f GetInitialScale() const; - NzVector3f GetLeft() const; + virtual NzVector3f GetLeft() const; const NzString& GetName() const; virtual nzNodeType GetNodeType() const; const NzNode* GetParent() const; NzVector3f GetPosition(nzCoordSys coordSys = nzCoordSys_Global) const; - NzVector3f GetRight() const; + virtual NzVector3f GetRight() const; NzQuaternionf GetRotation(nzCoordSys coordSys = nzCoordSys_Global) const; NzVector3f GetScale(nzCoordSys coordSys = nzCoordSys_Global) const; const NzMatrix4f& GetTransformMatrix() const; - NzVector3f GetUp() const; + virtual NzVector3f GetUp() const; bool HasChilds() const; @@ -95,7 +95,7 @@ class NAZARA_API NzNode virtual void InvalidateNode(); virtual void OnParenting(const NzNode* parent); void RemoveChild(NzNode* node) const; - void UpdateDerived() const; + virtual void UpdateDerived() const; virtual void UpdateTransformMatrix() const; mutable std::vector m_childs; diff --git a/include/Nazara/Utility/PixelFormat.hpp b/include/Nazara/Utility/PixelFormat.hpp index 9f864e9ad..f4443c22b 100644 --- a/include/Nazara/Utility/PixelFormat.hpp +++ b/include/Nazara/Utility/PixelFormat.hpp @@ -13,6 +13,10 @@ #include #include +///TODO: Permettre la conversion automatique entre les formats via des renseignements de bits et de type pour chaque format. +/// Ce serait plus lent que la conversion spécialisée (qui ne disparaît donc pas) mais ça permettrait au moteur de faire la conversion +/// entre n'importe quel formats non-compressés. + class NzPixelFormat { friend class NzUtility; diff --git a/include/Nazara/Utility/PixelFormat.inl b/include/Nazara/Utility/PixelFormat.inl index c92f8b8c0..2154d2f05 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/include/Nazara/Utility/PixelFormat.inl @@ -168,6 +168,9 @@ inline nzUInt8 NzPixelFormat::GetBitsPerPixel(nzPixelFormat format) { switch (format) { + case nzPixelFormat_A8: + return 8; + case nzPixelFormat_BGR8: return 24; @@ -287,20 +290,14 @@ inline nzUInt8 NzPixelFormat::GetBitsPerPixel(nzPixelFormat format) inline nzUInt8 NzPixelFormat::GetBytesPerPixel(nzPixelFormat format) { - nzUInt8 bytesPerPixel = GetBitsPerPixel(format)/8; - - #if NAZARA_UTILITY_SAFE - if (bytesPerPixel == 0) - NazaraWarning("This format is either invalid or using less than one byte per pixel"); - #endif - - return bytesPerPixel; + return GetBitsPerPixel(format)/8; } inline nzPixelFormatType NzPixelFormat::GetType(nzPixelFormat format) { switch (format) { + case nzPixelFormat_A8: case nzPixelFormat_BGR8: case nzPixelFormat_BGRA8: case nzPixelFormat_DXT1: @@ -372,6 +369,7 @@ inline bool NzPixelFormat::HasAlpha(nzPixelFormat format) { switch (format) { + case nzPixelFormat_A8: case nzPixelFormat_BGRA8: case nzPixelFormat_DXT3: case nzPixelFormat_DXT5: @@ -444,6 +442,7 @@ inline bool NzPixelFormat::IsCompressed(nzPixelFormat format) case nzPixelFormat_DXT5: return true; + case nzPixelFormat_A8: case nzPixelFormat_BGR8: case nzPixelFormat_BGRA8: case nzPixelFormat_L8: @@ -529,6 +528,9 @@ inline NzString NzPixelFormat::ToString(nzPixelFormat format) { switch (format) { + case nzPixelFormat_A8: + return "A8"; + case nzPixelFormat_BGR8: return "BGR8"; diff --git a/include/Nazara/Utility/SimpleTextDrawer.hpp b/include/Nazara/Utility/SimpleTextDrawer.hpp new file mode 100644 index 000000000..ca4b11845 --- /dev/null +++ b/include/Nazara/Utility/SimpleTextDrawer.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SIMPLETEXTDRAWER_HPP +#define NAZARA_SIMPLETEXTDRAWER_HPP + +#include +#include +#include +#include +#include +#include +#include + +class NAZARA_API NzSimpleTextDrawer : public NzAbstractTextDrawer, NzResourceListener +{ + public: + NzSimpleTextDrawer(); + virtual ~NzSimpleTextDrawer(); + + const NzRectui& GetBounds() const; + unsigned int GetCharacterSize() const; + const NzColor& GetColor() const; + NzFont* GetFont() const; + nzUInt32 GetStyle() const; + + void SetCharacterSize(unsigned int characterSize); + void SetColor(const NzColor& color); + void SetFont(NzFont* font); + void SetStyle(nzUInt32 style); + void SetText(const NzString& str); + + static NzSimpleTextDrawer Draw(unsigned int characterSize, const NzString& str, nzUInt32 style = nzTextStyle_Regular, const NzColor& color = NzColor::White); + static NzSimpleTextDrawer Draw(NzFont* font, unsigned int characterSize, const NzString& str, nzUInt32 style = nzTextStyle_Regular, const NzColor& color = NzColor::White); + + private: + NzFont* GetFont(unsigned int index) const override; + unsigned int GetFontCount() const override; + const Glyph& GetGlyph(unsigned int index) const override; + unsigned int GetGlyphCount() const override; + + bool OnResourceModified(const NzResource* resource, int index, unsigned int code) override; + void OnResourceReleased(const NzResource* resource, int index) override; + void UpdateGlyphs() const; + + mutable std::vector m_glyphs; + NzColor m_color; + NzFontRef m_font; + mutable NzRectui m_bounds; + NzString m_text; + nzUInt32 m_style; + mutable bool m_glyphUpdated; + unsigned int m_characterSize; +}; + +#endif // NAZARA_SIMPLETEXTDRAWER_HPP diff --git a/include/Nazara/Utility/VertexBuffer.hpp b/include/Nazara/Utility/VertexBuffer.hpp index 6b009561d..feb09ae16 100644 --- a/include/Nazara/Utility/VertexBuffer.hpp +++ b/include/Nazara/Utility/VertexBuffer.hpp @@ -24,7 +24,7 @@ class NAZARA_API NzVertexBuffer : public NzResource NzVertexBuffer() = default; NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, NzBuffer* buffer); NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, NzBuffer* buffer, unsigned int startOffset, unsigned int endOffset); - NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); + NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzUInt32 storage = nzDataStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); NzVertexBuffer(const NzVertexBuffer& vertexBuffer); NzVertexBuffer(NzVertexBuffer&& vertexBuffer) noexcept; ~NzVertexBuffer(); @@ -50,11 +50,11 @@ class NAZARA_API NzVertexBuffer : public NzResource void Reset(); void Reset(const NzVertexDeclaration* vertexDeclaration, NzBuffer* buffer); void Reset(const NzVertexDeclaration* vertexDeclaration, NzBuffer* buffer, unsigned int startOffset, unsigned int endOffset); - void Reset(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); + void Reset(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzUInt32 storage = nzDataStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); void Reset(const NzVertexBuffer& vertexBuffer); void Reset(NzVertexBuffer&& vertexBuffer) noexcept; - bool SetStorage(nzBufferStorage storage); + bool SetStorage(nzUInt32 storage); void SetVertexDeclaration(const NzVertexDeclaration* vertexDeclaration); void Unmap() const; diff --git a/include/Nazara/Utility/VertexStruct.hpp b/include/Nazara/Utility/VertexStruct.hpp index 62c01c439..9cc365aee 100644 --- a/include/Nazara/Utility/VertexStruct.hpp +++ b/include/Nazara/Utility/VertexStruct.hpp @@ -7,6 +7,7 @@ #ifndef NAZARA_VERTEXSTRUCT_HPP #define NAZARA_VERTEXSTRUCT_HPP +#include #include #include @@ -17,7 +18,12 @@ struct NzVertexStruct_XY NzVector2f position; }; -struct NzVertexStruct_XY_UV : public NzVertexStruct_XY +struct NzVertexStruct_XY_Color : NzVertexStruct_XY +{ + NzColor color; +}; + +struct NzVertexStruct_XY_UV : NzVertexStruct_XY { NzVector2f uv; }; @@ -29,29 +35,39 @@ struct NzVertexStruct_XYZ NzVector3f position; }; -struct NzVertexStruct_XYZ_Normal : public NzVertexStruct_XYZ +struct NzVertexStruct_XYZ_Color : NzVertexStruct_XYZ { - NzVector3f normal; + NzColor color; }; -struct NzVertexStruct_XYZ_Normal_UV : public NzVertexStruct_XYZ_Normal +struct NzVertexStruct_XYZ_Color_UV : NzVertexStruct_XYZ_Color { NzVector2f uv; }; -struct NzVertexStruct_XYZ_Normal_UV_Tangent : public NzVertexStruct_XYZ_Normal_UV +struct NzVertexStruct_XYZ_Normal : NzVertexStruct_XYZ +{ + NzVector3f normal; +}; + +struct NzVertexStruct_XYZ_Normal_UV : NzVertexStruct_XYZ_Normal +{ + NzVector2f uv; +}; + +struct NzVertexStruct_XYZ_Normal_UV_Tangent : NzVertexStruct_XYZ_Normal_UV { NzVector3f tangent; }; -struct NzVertexStruct_XYZ_UV : public NzVertexStruct_XYZ +struct NzVertexStruct_XYZ_UV : NzVertexStruct_XYZ { NzVector2f uv; }; /************************* Structures 3D (+ Skinning) ************************/ -struct NzVertexStruct_XYZ_Normal_UV_Tangent_Skinning : public NzVertexStruct_XYZ_Normal_UV_Tangent +struct NzVertexStruct_XYZ_Normal_UV_Tangent_Skinning : NzVertexStruct_XYZ_Normal_UV_Tangent { nzInt32 weightCount; diff --git a/src/Nazara/Core/GuillotineBinPack.cpp b/src/Nazara/Core/GuillotineBinPack.cpp new file mode 100644 index 000000000..7a32f3ae1 --- /dev/null +++ b/src/Nazara/Core/GuillotineBinPack.cpp @@ -0,0 +1,446 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// Implémentation originale de Jukka Jylänki (Merci de sa contribution au domaine public) +// http://clb.demon.fi/projects/even-more-rectangle-bin-packing +// Je n'ai vraiment fait qu'adapter le code au moteur (Avec quelques améliorations), je n'ai aucun mérite sur le code ci-dessous + +#include +#include +#include +#include +#include +#include + +namespace +{ + int ScoreBestAreaFit(int width, int height, const NzRectui& freeRectSize) + { + return freeRectSize.width * freeRectSize.height - width * height; + } + + int ScoreBestLongSideFit(int width, int height, const NzRectui& freeRectSize) + { + int leftoverHoriz = std::abs(freeRectSize.width - width); + int leftoverVert = std::abs(freeRectSize.height - height); + int leftover = std::max(leftoverHoriz, leftoverVert); + + return leftover; + } + + int ScoreBestShortSideFit(int width, int height, const NzRectui& freeRectSize) + { + int leftoverHoriz = std::abs(freeRectSize.width - width); + int leftoverVert = std::abs(freeRectSize.height - height); + int leftover = std::min(leftoverHoriz, leftoverVert); + + return leftover; + } + + int ScoreWorstAreaFit(int width, int height, const NzRectui& freeRectSize) + { + return -ScoreBestAreaFit(width, height, freeRectSize); + } + + int ScoreWorstLongSideFit(int width, int height, const NzRectui& freeRectSize) + { + return -ScoreBestLongSideFit(width, height, freeRectSize); + } + + int ScoreWorstShortSideFit(int width, int height, const NzRectui& freeRectSize) + { + return -ScoreBestShortSideFit(width, height, freeRectSize); + } +} + +NzGuillotineBinPack::NzGuillotineBinPack() +{ + Reset(); +} + +NzGuillotineBinPack::NzGuillotineBinPack(unsigned int width, unsigned int height) +{ + Reset(width, height); +} + +NzGuillotineBinPack::NzGuillotineBinPack(const NzVector2ui& size) +{ + Reset(size); +} + +void NzGuillotineBinPack::Clear() +{ + m_freeRectangles.clear(); + m_freeRectangles.push_back(NzRectui(0, 0, m_width, m_height)); + + m_usedArea = 0; +} + +void NzGuillotineBinPack::Expand(unsigned int newWidth, unsigned newHeight) +{ + unsigned int oldWidth = m_width; + unsigned int oldHeight = m_height; + + m_width = std::max(newWidth, m_width); + m_height = std::max(newHeight, m_height); + + if (m_width > oldWidth) + m_freeRectangles.push_back(NzRectui(oldWidth, 0, m_width - oldWidth, oldHeight)); + + if (m_height > oldHeight) + m_freeRectangles.push_back(NzRectui(0, oldHeight, m_width, m_height - oldHeight)); + + // On va ensuite fusionner les rectangles tant que possible + while (MergeFreeRectangles()); +} + +void NzGuillotineBinPack::Expand(const NzVector2ui& newSize) +{ + Expand(newSize.x, newSize.y); +} + +void NzGuillotineBinPack::FreeRectangle(const NzRectui& rect) +{ + ///DOC: Cette méthode ne devrait recevoir que des rectangles calculés par la méthode Insert et peut provoquer de la fragmentation + m_freeRectangles.push_back(rect); + + m_usedArea -= rect.width * rect.height; +} + +unsigned int NzGuillotineBinPack::GetHeight() const +{ + return m_height; +} + +float NzGuillotineBinPack::GetOccupancy() const +{ + return static_cast(m_usedArea)/(m_width*m_height); +} + +NzVector2ui NzGuillotineBinPack::GetSize() const +{ + return NzVector2ui(m_width, m_height); +} + +unsigned int NzGuillotineBinPack::GetWidth() const +{ + return m_width; +} + +bool NzGuillotineBinPack::Insert(NzRectui* rects, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) +{ + return Insert(rects, nullptr, nullptr, count, merge, rectChoice, splitMethod); +} + +bool NzGuillotineBinPack::Insert(NzRectui* rects, bool* flipped, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) +{ + return Insert(rects, flipped, nullptr, count, merge, rectChoice, splitMethod); +} + +bool NzGuillotineBinPack::Insert(NzRectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) +{ + std::vector remainingRects(count); // La position du rectangle + for (unsigned int i = 0; i < count; ++i) + remainingRects[i] = &rects[i]; + + // Pack rectangles one at a time until we have cleared the rects array of all rectangles. + while (!remainingRects.empty()) + { + // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better. + bool bestFlipped; + int bestFreeRect; + int bestRect; + int bestScore = std::numeric_limits::max(); + + for (std::size_t i = 0; i < m_freeRectangles.size(); ++i) + { + NzRectui& freeRect = m_freeRectangles[i]; + + for (std::size_t j = 0; j < remainingRects.size(); ++j) + { + NzRectui& rect = *remainingRects[j]; + + // If this rectangle is a perfect match, we pick it instantly. + if (rect.width == freeRect.width && rect.height == freeRect.height) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = false; + bestScore = std::numeric_limits::min(); + i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit. + break; + } + // If flipping this rectangle is a perfect match, pick that then. + else if (rect.height == freeRect.width && rect.width == freeRect.height) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = true; + bestScore = std::numeric_limits::min(); + i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit. + break; + } + // Try if we can fit the rectangle upright. + else if (rect.width <= freeRect.width && rect.height <= freeRect.height) + { + int score = ScoreByHeuristic(rect.width, rect.height, freeRect, rectChoice); + if (score < bestScore) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = false; + bestScore = score; + } + } + // If not, then perhaps flipping sideways will make it fit? + else if (rect.height <= freeRect.width && rect.width <= freeRect.height) + { + int score = ScoreByHeuristic(rect.height, rect.width, freeRect, rectChoice); + if (score < bestScore) + { + bestFreeRect = i; + bestRect = j; + bestFlipped = true; + bestScore = score; + } + } + } + } + + // If we didn't manage to find any rectangle to pack, abort. + if (bestScore == std::numeric_limits::max()) + { + // Si nous le pouvons, on marque les rectangles n'ayant pas pu être insérés + if (inserted) + { + for (NzRectui* rect : remainingRects) + { + unsigned int position = rect - rects; + inserted[position] = false; + } + } + + return false; + } + + // Otherwise, we're good to go and do the actual packing. + unsigned int position = remainingRects[bestRect] - rects; + NzRectui& rect = *remainingRects[bestRect]; + rect.x = m_freeRectangles[bestFreeRect].x; + rect.y = m_freeRectangles[bestFreeRect].y; + + if (bestFlipped) + std::swap(rect.width, rect.height); + + if (flipped) + flipped[position] = bestFlipped; + + if (inserted) + inserted[position] = true; + + // Remove the free space we lost in the bin. + SplitFreeRectByHeuristic(m_freeRectangles[bestFreeRect], rect, splitMethod); + m_freeRectangles.erase(m_freeRectangles.begin() + bestFreeRect); + + // Remove the rectangle we just packed from the input list. + remainingRects.erase(remainingRects.begin() + bestRect); + + // Perform a Rectangle Merge step if desired. + if (merge) + MergeFreeRectangles(); + + m_usedArea += rect.width * rect.height; + } + + return true; +} + +bool NzGuillotineBinPack::MergeFreeRectangles() +{ + ///DOC: Renvoie true s'il y a eu fusion (et donc si une fusion est encore possible) + std::size_t oriSize = m_freeRectangles.size(); + + // Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one. + // Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that) + for (std::size_t i = 0; i < m_freeRectangles.size(); ++i) + { + NzRectui& firstRect = m_freeRectangles[i]; + + for (std::size_t j = i+1; j < m_freeRectangles.size(); ++j) + { + NzRectui& secondRect = m_freeRectangles[j]; + + if (firstRect.width == secondRect.width && firstRect.x == secondRect.x) + { + if (firstRect.y == secondRect.y + secondRect.height) + { + firstRect.y -= secondRect.height; + firstRect.height += secondRect.height; + m_freeRectangles.erase(m_freeRectangles.begin() + j); + --j; + } + else if (firstRect.y + firstRect.height == secondRect.y) + { + firstRect.height += secondRect.height; + m_freeRectangles.erase(m_freeRectangles.begin() + j); + --j; + } + } + else if (firstRect.height == secondRect.height && firstRect.y == secondRect.y) + { + if (firstRect.x == secondRect.x + secondRect.width) + { + firstRect.x -= secondRect.width; + firstRect.width += secondRect.width; + m_freeRectangles.erase(m_freeRectangles.begin() + j); + --j; + } + else if (firstRect.x + firstRect.width == secondRect.x) + { + firstRect.width += secondRect.width; + m_freeRectangles.erase(m_freeRectangles.begin() + j); + --j; + } + } + } + } + + return m_freeRectangles.size() < oriSize; +} + +void NzGuillotineBinPack::Reset() +{ + m_height = 0; + m_width = 0; + + Clear(); +} + +void NzGuillotineBinPack::Reset(unsigned int width, unsigned int height) +{ + m_height = height; + m_width = width; + + Clear(); +} + +void NzGuillotineBinPack::Reset(const NzVector2ui& size) +{ + Reset(size.x, size.y); +} + +void NzGuillotineBinPack::SplitFreeRectAlongAxis(const NzRectui& freeRect, const NzRectui& placedRect, bool splitHorizontal) +{ + // Form the two new rectangles. + NzRectui bottom; + bottom.x = freeRect.x; + bottom.y = freeRect.y + placedRect.height; + bottom.height = freeRect.height - placedRect.height; + + NzRectui right; + right.x = freeRect.x + placedRect.width; + right.y = freeRect.y; + right.width = freeRect.width - placedRect.width; + + if (splitHorizontal) + { + bottom.width = freeRect.width; + right.height = placedRect.height; + } + else // Split vertically + { + bottom.width = placedRect.width; + right.height = freeRect.height; + } + + // Add the new rectangles into the free rectangle pool if they weren't degenerate. + if (bottom.width > 0 && bottom.height > 0) + m_freeRectangles.push_back(bottom); + + if (right.width > 0 && right.height > 0) + m_freeRectangles.push_back(right); +} + +void NzGuillotineBinPack::SplitFreeRectByHeuristic(const NzRectui& freeRect, const NzRectui& placedRect, GuillotineSplitHeuristic method) +{ + // Compute the lengths of the leftover area. + const int w = freeRect.width - placedRect.width; + const int h = freeRect.height - placedRect.height; + + // Placing placedRect into freeRect results in an L-shaped free area, which must be split into + // two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line. + // We have two choices: horizontal or vertical. + + // Use the given heuristic to decide which choice to make. + + bool splitHorizontal; + switch (method) + { + case SplitLongerAxis: + // Split along the longer total axis. + splitHorizontal = (freeRect.width > freeRect.height); + break; + + case SplitLongerLeftoverAxis: + // Split along the longer leftover axis. + splitHorizontal = (w > h); + break; + + case SplitMaximizeArea: + // Maximize the smaller area == minimize the larger area. + // Tries to make the rectangles more even-sized. + splitHorizontal = (placedRect.width * h <= w * placedRect.height); + break; + + case SplitMinimizeArea: + // Maximize the larger area == minimize the smaller area. + // Tries to make the single bigger rectangle. + splitHorizontal = (placedRect.width * h > w * placedRect.height); + break; + + case SplitShorterAxis: + // Split along the shorter total axis. + splitHorizontal = (freeRect.width <= freeRect.height); + break; + + case SplitShorterLeftoverAxis: + // Split along the shorter leftover axis. + splitHorizontal = (w <= h); + break; + + default: + NazaraError("Split heuristic out of enum (0x" + NzString::Number(method, 16) + ')'); + splitHorizontal = true; + } + + // Perform the actual split. + SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal); +} + +int NzGuillotineBinPack::ScoreByHeuristic(int width, int height, const NzRectui& freeRect, FreeRectChoiceHeuristic rectChoice) +{ + switch (rectChoice) + { + case RectBestAreaFit: + return ScoreBestAreaFit(width, height, freeRect); + + case RectBestLongSideFit: + return ScoreBestLongSideFit(width, height, freeRect); + + case RectBestShortSideFit: + return ScoreBestShortSideFit(width, height, freeRect); + + case RectWorstAreaFit: + return ScoreWorstAreaFit(width, height, freeRect); + + case RectWorstLongSideFit: + return ScoreWorstLongSideFit(width, height, freeRect); + + case RectWorstShortSideFit: + return ScoreWorstShortSideFit(width, height, freeRect); + } + + NazaraError("Rect choice heuristic out of enum (0x" + NzString::Number(rectChoice, 16) + ')'); + return std::numeric_limits::max(); +} diff --git a/src/Nazara/Graphics/Camera.cpp b/src/Nazara/Graphics/Camera.cpp index a0eb272a6..570b1f289 100644 --- a/src/Nazara/Graphics/Camera.cpp +++ b/src/Nazara/Graphics/Camera.cpp @@ -80,6 +80,21 @@ const NzFrustumf& NzCamera::GetFrustum() const return m_frustum; } +NzVector3f NzCamera::GetGlobalForward() const +{ + return NzVector3f::Forward(); +} + +NzVector3f NzCamera::GetGlobalRight() const +{ + return NzVector3f::Right(); +} + +NzVector3f NzCamera::GetGlobalUp() const +{ + return NzVector3f::Up(); +} + const NzMatrix4f& NzCamera::GetProjectionMatrix() const { if (!m_projectionMatrixUpdated) diff --git a/src/Nazara/Graphics/DeferredRenderQueue.cpp b/src/Nazara/Graphics/DeferredRenderQueue.cpp index c4e393ec1..821e92d86 100644 --- a/src/Nazara/Graphics/DeferredRenderQueue.cpp +++ b/src/Nazara/Graphics/DeferredRenderQueue.cpp @@ -103,29 +103,15 @@ void NzDeferredRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData } } -void NzDeferredRenderQueue::AddSprite(const NzSprite* sprite) +void NzDeferredRenderQueue::AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay) { - #if NAZARA_GRAPHICS_SAFE - if (!sprite) - { - NazaraError("Invalid sprite"); - return; - } - - if (!sprite->IsDrawable()) - { - NazaraError("Sprite is not drawable"); - return; - } - #endif - /*NzMaterial* material = sprite->GetMaterial(); if (!material->IsLightingEnabled() || material->IsEnabled(nzRendererParameter_Blend)) m_forwardQueue->AddSprite(sprite); else sprites[material].push_back(sprite);*/ - m_forwardQueue->AddSprite(sprite); + m_forwardQueue->AddSprites(material, vertices, spriteCount, overlay); } void NzDeferredRenderQueue::Clear(bool fully) diff --git a/src/Nazara/Graphics/ForwardRenderQueue.cpp b/src/Nazara/Graphics/ForwardRenderQueue.cpp index 90770660d..c148d56f1 100644 --- a/src/Nazara/Graphics/ForwardRenderQueue.cpp +++ b/src/Nazara/Graphics/ForwardRenderQueue.cpp @@ -12,12 +12,15 @@ #include #include +///FIXME: Régler ce problème de dépendance aux ressources + namespace { enum ResourceType { ResourceType_IndexBuffer, ResourceType_Material, + ResourceType_Texture, ResourceType_VertexBuffer }; } @@ -121,23 +124,26 @@ void NzForwardRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData& } } -void NzForwardRenderQueue::AddSprite(const NzSprite* sprite) +void NzForwardRenderQueue::AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay) { - #if NAZARA_GRAPHICS_SAFE - if (!sprite) + auto matIt = basicSprites.find(material); + if (matIt == basicSprites.end()) { - NazaraError("Invalid sprite"); - return; + matIt = basicSprites.insert(std::make_pair(material, BasicSpriteBatches::mapped_type())).first; + material->AddResourceListener(this, ResourceType_Material); } - if (!sprite->IsDrawable()) + auto& overlayMap = matIt->second; + auto overlayIt = overlayMap.find(overlay); + if (overlayIt == overlayMap.end()) { - NazaraError("Sprite is not drawable"); - return; + overlayIt = overlayMap.insert(std::make_pair(overlay, BasicSpriteOverlayContainer::mapped_type())).first; + if (overlay) + overlay->AddResourceListener(this, ResourceType_Texture); } - #endif - sprites[sprite->GetMaterial()].push_back(sprite); + auto& spriteVector = overlayIt->second; + spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount})); } void NzForwardRenderQueue::Clear(bool fully) @@ -150,12 +156,27 @@ void NzForwardRenderQueue::Clear(bool fully) if (fully) { - for (auto& matIt : opaqueModels) + for (auto& matPair : basicSprites) { - const NzMaterial* material = matIt.first; + const NzMaterial* material = matPair.first; material->RemoveResourceListener(this); - MeshInstanceContainer& instances = std::get<2>(matIt.second); + auto& overlayMap = matPair.second; + for (auto& overlayPair : overlayMap) + { + const NzTexture* overlay = overlayPair.first; + if (overlay) + overlay->RemoveResourceListener(this); + } + } + basicSprites.clear(); + + for (auto& matPair : opaqueModels) + { + const NzMaterial* material = matPair.first; + material->RemoveResourceListener(this); + + MeshInstanceContainer& instances = std::get<2>(matPair.second); for (auto& instanceIt : instances) { const NzMeshData& renderData = instanceIt.first; @@ -167,7 +188,6 @@ void NzForwardRenderQueue::Clear(bool fully) } } opaqueModels.clear(); - sprites.clear(); } } @@ -210,6 +230,7 @@ bool NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int ind } case ResourceType_Material: + basicSprites.erase(static_cast(resource)); opaqueModels.erase(static_cast(resource)); break; @@ -260,6 +281,15 @@ void NzForwardRenderQueue::OnResourceReleased(const NzResource* resource, int in case ResourceType_Material: { + for (auto it = basicSprites.begin(); it != basicSprites.end(); ++it) + { + if (it->first == resource) + { + basicSprites.erase(it); + break; + } + } + for (auto it = opaqueModels.begin(); it != opaqueModels.end(); ++it) { if (it->first == resource) @@ -268,6 +298,25 @@ void NzForwardRenderQueue::OnResourceReleased(const NzResource* resource, int in break; } } + + break; + } + + case ResourceType_Texture: + { + for (auto matIt = basicSprites.begin(); matIt != basicSprites.end(); ++matIt) + { + auto& overlayMap = matIt->second; + for (auto overlayIt = overlayMap.begin(); overlayIt != overlayMap.end(); ++overlayIt) + { + if (overlayIt->first == resource) + { + overlayMap.erase(overlayIt); + break; + } + } + } + break; } @@ -299,7 +348,6 @@ bool NzForwardRenderQueue::BatchedModelMaterialComparator::operator()(const NzMa const NzShader* shader1 = mat1->GetShaderInstance()->GetShader(); const NzShader* shader2 = mat2->GetShaderInstance()->GetShader(); - if (shader1 != shader2) return shader1 < shader2; @@ -320,7 +368,6 @@ bool NzForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const NzM const NzShader* shader1 = mat1->GetShaderInstance()->GetShader(); const NzShader* shader2 = mat2->GetShaderInstance()->GetShader(); - if (shader1 != shader2) return shader1 < shader2; diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index 896e7c70a..0a73e8641 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -27,7 +27,7 @@ namespace NzIndexBuffer* BuildIndexBuffer() { - std::unique_ptr indexBuffer(new NzIndexBuffer(false, s_maxSprites*6, nzBufferStorage_Hardware, nzBufferUsage_Static)); + std::unique_ptr indexBuffer(new NzIndexBuffer(false, s_maxSprites*6, nzDataStorage_Hardware, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); NzBufferMapper mapper(indexBuffer.get(), nzBufferAccess_WriteOnly); @@ -49,7 +49,7 @@ namespace } NzForwardRenderTechnique::NzForwardRenderTechnique() : -m_spriteBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_UV), s_maxSprites*4, nzBufferStorage_Hardware, nzBufferUsage_Dynamic), +m_spriteBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Color_UV), s_maxSprites*4, nzDataStorage_Hardware, nzBufferUsage_Dynamic), m_maxLightPassPerObject(3) { if (!s_indexBuffer) @@ -87,8 +87,8 @@ bool NzForwardRenderTechnique::Draw(const NzScene* scene) const if (!m_renderQueue.transparentModels.empty()) DrawTransparentModels(scene); - if (!m_renderQueue.sprites.empty()) - DrawSprites(scene); + if (!m_renderQueue.basicSprites.empty()) + DrawBasicSprites(scene); // Les autres drawables (Exemple: Terrain) for (const NzDrawable* drawable : m_renderQueue.otherDrawables) @@ -162,11 +162,108 @@ void NzForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount) m_maxLightPassPerObject = passCount; } +void NzForwardRenderTechnique::DrawBasicSprites(const NzScene* scene) const +{ + NzAbstractViewer* viewer = scene->GetViewer(); + const NzShader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + + NzRenderer::SetIndexBuffer(m_indexBuffer); + NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity()); + NzRenderer::SetVertexBuffer(&m_spriteBuffer); + + for (auto& matIt : m_renderQueue.basicSprites) + { + const NzMaterial* material = matIt.first; + auto& overlayMap = matIt.second; + + for (auto& overlayIt : overlayMap) + { + const NzTexture* overlay = overlayIt.first; + auto& spriteChainVector = overlayIt.second; + + unsigned int spriteChainCount = spriteChainVector.size(); + if (spriteChainCount > 0) + { + // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + nzUInt32 flags = nzShaderFlags_VertexColor; + if (overlay) + flags |= nzShaderFlags_TextureOverlay; + + nzUInt8 overlayUnit; + const NzShader* shader = material->Apply(flags, 0, &overlayUnit); + + if (overlay) + { + overlayUnit++; + NzRenderer::SetTexture(overlayUnit, overlay); + NzRenderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler()); + } + + // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + if (shader != lastShader) + { + // Index des uniformes dans le shader + shaderUniforms = GetShaderUniforms(shader); + + // Couleur ambiante de la scène + shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor()); + // Overlay + shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit); + // Position de la caméra + shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition()); + + lastShader = shader; + } + + unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous + unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés + + do + { + // On ouvre le buffer en écriture + NzBufferMapper vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite); + NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(vertexMapper.GetPointer()); + + unsigned int spriteCount = 0; + + do + { + NzForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain]; + unsigned int count = std::min(s_maxSprites - spriteCount, currentChain.spriteCount - spriteChainOffset); + + std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(NzVertexStruct_XYZ_Color_UV)); + vertices += count*4; + + spriteCount += count; + spriteChainOffset += count; + + // Avons-nous traité la chaîne entière ? + if (spriteChainOffset == currentChain.spriteCount) + { + spriteChain++; + spriteChainOffset = 0; + } + } + while (spriteCount < s_maxSprites && spriteChain < spriteChainCount); + + vertexMapper.Unmap(); + + NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, spriteCount*6); + } + while (spriteChain < spriteChainCount); + + spriteChainVector.clear(); + } + } + } +} + void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const { NzAbstractViewer* viewer = scene->GetViewer(); - const LightUniforms* lightUniforms = nullptr; const NzShader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; for (auto& matIt : m_renderQueue.opaqueModels) { @@ -191,14 +288,14 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas if (shader != lastShader) { + // Index des uniformes dans le shader + shaderUniforms = GetShaderUniforms(shader); + // Couleur ambiante de la scène shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor()); // Position de la caméra shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition()); - // Index des uniformes d'éclairage dans le shader - lightUniforms = GetLightUniforms(shader); - lastShader = shader; } @@ -250,7 +347,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; for (unsigned int pass = 0; pass < passCount; ++pass) { - if (lightUniforms->exists) + if (shaderUniforms->hasLightUniforms) { unsigned int renderedLightCount = std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); lightCount -= renderedLightCount; @@ -267,15 +364,15 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const } for (unsigned int i = 0; i < renderedLightCount; ++i) - m_directionalLights.GetLight(lightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i); + m_directionalLights.GetLight(lightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i); + NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); } const NzMatrix4f* instanceMatrices = &instances[0]; unsigned int instanceCount = instances.size(); - unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) + unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois while (instanceCount > 0) { @@ -298,7 +395,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const } else { - if (lightUniforms->exists) + if (shaderUniforms->hasLightUniforms) { for (const NzMatrix4f& matrix : instances) { @@ -332,14 +429,14 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const for (unsigned int i = 0; i < renderedLightCount; ++i) { if (directionalLightIndex >= directionalLightCount) - m_lights.GetResult(otherLightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i); + m_lights.GetResult(otherLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); else - m_directionalLights.GetLight(directionalLightIndex++)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i); + m_directionalLights.GetLight(directionalLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); } // On désactive l'éventuel surplus for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i); + NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); // Et on passe à l'affichage DrawFunc(meshData.primitiveMode, 0, indexCount); @@ -351,7 +448,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const } else { - // Sans instancing, on doit effectuer un drawcall pour chaque instance + // Sans instancing, on doit effectuer un draw call pour chaque instance // Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances // À cause du temps de modification du buffer d'instancing for (const NzMatrix4f& matrix : instances) @@ -367,84 +464,8 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const } // Et on remet à zéro les données - renderQueueInstancing = false; used = false; - } - } -} - -void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const -{ - NzAbstractViewer* viewer = scene->GetViewer(); - const NzShader* lastShader = nullptr; - - NzRenderer::SetIndexBuffer(m_indexBuffer); - NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity()); - NzRenderer::SetVertexBuffer(&m_spriteBuffer); - - for (auto& matIt : m_renderQueue.sprites) - { - const NzMaterial* material = matIt.first; - auto& spriteVector = matIt.second; - - unsigned int spriteCount = spriteVector.size(); - if (spriteCount > 0) - { - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) - const NzShader* shader = material->Apply(); - - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas - if (shader != lastShader) - { - // Couleur ambiante de la scène - shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor()); - // Position de la caméra - shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition()); - - lastShader = shader; - } - - const NzSprite** spritePtr = &spriteVector[0]; - do - { - unsigned int renderedSpriteCount = std::min(spriteCount, 64U); - spriteCount -= renderedSpriteCount; - - NzBufferMapper vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedSpriteCount*4); - NzVertexStruct_XYZ_UV* vertices = reinterpret_cast(vertexMapper.GetPointer()); - - for (unsigned int i = 0; i < renderedSpriteCount; ++i) - { - const NzSprite* sprite = *spritePtr++; - const NzRectf& textureCoords = sprite->GetTextureCoords(); - const NzVector2f& halfSize = sprite->GetSize()*0.5f; - NzVector3f center = sprite->GetPosition(); - NzQuaternionf rotation = sprite->GetRotation(); - - vertices->position = center + rotation * NzVector3f(-halfSize.x, halfSize.y, 0.f); - vertices->uv.Set(textureCoords.x, textureCoords.y + textureCoords.height); - vertices++; - - vertices->position = center + rotation * NzVector3f(halfSize.x, halfSize.y, 0.f); - vertices->uv.Set(textureCoords.width, textureCoords.y + textureCoords.height); - vertices++; - - vertices->position = center + rotation * NzVector3f(-halfSize.x, -halfSize.y, 0.f); - vertices->uv.Set(textureCoords.x, textureCoords.y); - vertices++; - - vertices->position = center + rotation * NzVector3f(halfSize.x, -halfSize.y, 0.f); - vertices->uv.Set(textureCoords.width, textureCoords.y); - vertices++; - } - - vertexMapper.Unmap(); - - NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedSpriteCount*6); - } - while (spriteCount > 0); - - spriteVector.clear(); + renderQueueInstancing = false; } } } @@ -452,8 +473,8 @@ void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const { NzAbstractViewer* viewer = scene->GetViewer(); - const LightUniforms* lightUniforms = nullptr; const NzShader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; unsigned int lightCount = 0; for (unsigned int index : m_renderQueue.transparentModels) @@ -469,18 +490,18 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas if (shader != lastShader) { + // Index des uniformes dans le shader + shaderUniforms = GetShaderUniforms(shader); + // Couleur ambiante de la scène shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor()); // Position de la caméra shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition()); - // Index des uniformes d'éclairage dans le shader - lightUniforms = GetLightUniforms(shader); - // On envoie les lumières directionnelles s'il y a (Les mêmes pour tous) lightCount = std::min(m_directionalLights.GetLightCount(), NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); for (unsigned int i = 0; i < lightCount; ++i) - m_directionalLights.GetLight(i)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*i); + m_directionalLights.GetLight(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); lastShader = shader; } @@ -515,45 +536,46 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const { unsigned int count = std::min(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - lightCount, m_lights.ComputeClosestLights(matrix.GetTranslation() + modelData.boundingSphere.GetPosition(), modelData.boundingSphere.radius, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)); for (unsigned int i = 0; i < count; ++i) - m_lights.GetResult(i)->Enable(shader, lightUniforms->uniforms, lightUniforms->offset*(lightCount++)); + m_lights.GetResult(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*(lightCount++)); } for (unsigned int i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - NzLight::Disable(shader, lightUniforms->uniforms, lightUniforms->offset*i); + NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); NzRenderer::SetMatrix(nzMatrixType_World, matrix); DrawFunc(meshData.primitiveMode, 0, indexCount); } } -const NzForwardRenderTechnique::LightUniforms* NzForwardRenderTechnique::GetLightUniforms(const NzShader* shader) const +const NzForwardRenderTechnique::ShaderUniforms* NzForwardRenderTechnique::GetShaderUniforms(const NzShader* shader) const { - auto it = m_lightUniforms.find(shader); - if (it != m_lightUniforms.end()) + auto it = m_shaderUniforms.find(shader); + if (it != m_shaderUniforms.end()) return &(it->second); else { + ShaderUniforms uniforms; + uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay"); + int type0Location = shader->GetUniformLocation("Lights[0].type"); int type1Location = shader->GetUniformLocation("Lights[1].type"); - LightUniforms lightUniforms; - if (type0Location > 0 && type1Location > 0) { - lightUniforms.exists = true; - lightUniforms.offset = type1Location - type0Location; - lightUniforms.uniforms.ubo = false; - lightUniforms.uniforms.locations.type = type0Location; - lightUniforms.uniforms.locations.color = shader->GetUniformLocation("Lights[0].color"); - lightUniforms.uniforms.locations.factors = shader->GetUniformLocation("Lights[0].factors"); - lightUniforms.uniforms.locations.parameters1 = shader->GetUniformLocation("Lights[0].parameters1"); - lightUniforms.uniforms.locations.parameters2 = shader->GetUniformLocation("Lights[0].parameters2"); - lightUniforms.uniforms.locations.parameters3 = shader->GetUniformLocation("Lights[0].parameters3"); + uniforms.hasLightUniforms = true; + uniforms.lightOffset = type1Location - type0Location; + uniforms.lightUniforms.ubo = false; + uniforms.lightUniforms.locations.type = type0Location; + uniforms.lightUniforms.locations.color = shader->GetUniformLocation("Lights[0].color"); + uniforms.lightUniforms.locations.factors = shader->GetUniformLocation("Lights[0].factors"); + uniforms.lightUniforms.locations.parameters1 = shader->GetUniformLocation("Lights[0].parameters1"); + uniforms.lightUniforms.locations.parameters2 = shader->GetUniformLocation("Lights[0].parameters2"); + uniforms.lightUniforms.locations.parameters3 = shader->GetUniformLocation("Lights[0].parameters3"); } else - lightUniforms.exists = false; + uniforms.hasLightUniforms = false; - auto pair = m_lightUniforms.emplace(shader, lightUniforms); + auto pair = m_shaderUniforms.emplace(shader, uniforms); return &(pair.first->second); } } diff --git a/src/Nazara/Graphics/GuillotineTextureAtlas.cpp b/src/Nazara/Graphics/GuillotineTextureAtlas.cpp new file mode 100644 index 000000000..0963eddf3 --- /dev/null +++ b/src/Nazara/Graphics/GuillotineTextureAtlas.cpp @@ -0,0 +1,43 @@ +// 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 +#include +#include + +NzAbstractImage* NzGuillotineTextureAtlas::ResizeImage(NzAbstractImage* oldImage, const NzVector2ui& size) const +{ + std::unique_ptr newTexture(new NzTexture); + if (newTexture->Create(nzImageType_2D, nzPixelFormat_A8, size.x, size.y, 1, 0xFF)) + { + if (oldImage) + { + NzTexture* oldTexture = static_cast(oldImage); + + // Copie des anciennes données + ///TODO: Copie de texture à texture + NzImage image; + if (!oldTexture->Download(&image)) + { + NazaraError("Failed to download old texture"); + return nullptr; + } + + if (!newTexture->Update(image, NzRectui(0, 0, image.GetWidth(), image.GetHeight()))) + { + NazaraError("Failed to update texture"); + return nullptr; + } + } + + return newTexture.release(); + } + else + { + // Si on arrive ici c'est que la taille demandée est trop grande pour la carte graphique + // ou que nous manquons de mémoire + return nullptr; + } +} diff --git a/src/Nazara/Graphics/Light.cpp b/src/Nazara/Graphics/Light.cpp index ff3d5bfdd..e3288adc2 100644 --- a/src/Nazara/Graphics/Light.cpp +++ b/src/Nazara/Graphics/Light.cpp @@ -41,7 +41,7 @@ m_innerAngle(light.m_innerAngle), m_outerAngle(light.m_outerAngle), m_radius(light.m_radius) { - SetParent(light); + SetParent(light.GetParent()); } void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp index 3c9861acc..8a6ca4357 100644 --- a/src/Nazara/Graphics/Material.cpp +++ b/src/Nazara/Graphics/Material.cpp @@ -34,20 +34,6 @@ NzResource() Copy(material); } -NzMaterial::NzMaterial(NzMaterial&& material) -{ - Copy(material); - - // Nous "volons" la référence du matériau - material.m_alphaMap.Reset(); - material.m_diffuseMap.Reset(); - material.m_emissiveMap.Reset(); - material.m_heightMap.Reset(); - material.m_normalMap.Reset(); - material.m_specularMap.Reset(); - material.m_uberShader.Reset(); -} - NzMaterial::~NzMaterial() { NotifyDestroy(); @@ -622,22 +608,6 @@ NzMaterial& NzMaterial::operator=(const NzMaterial& material) return *this; } -NzMaterial& NzMaterial::operator=(NzMaterial&& material) -{ - Copy(material); - - // Comme ça nous volons la référence du matériau - material.m_alphaMap.Reset(); - material.m_diffuseMap.Reset(); - material.m_emissiveMap.Reset(); - material.m_heightMap.Reset(); - material.m_normalMap.Reset(); - material.m_specularMap.Reset(); - material.m_uberShader.Reset(); - - return *this; -} - NzMaterial* NzMaterial::GetDefault() { return s_defaultMaterial; @@ -645,33 +615,32 @@ NzMaterial* NzMaterial::GetDefault() void NzMaterial::Copy(const NzMaterial& material) { - // On relache les références proprement - m_alphaMap.Reset(); - m_diffuseMap.Reset(); - m_emissiveMap.Reset(); - m_heightMap.Reset(); - m_normalMap.Reset(); - m_specularMap.Reset(); - m_uberShader.Reset(); - - std::memcpy(this, &material, sizeof(NzMaterial)); // Autorisé dans notre cas, et bien plus rapide - - // Ensuite une petite astuce pour récupérer correctement les références - m_alphaMap.Release(); - m_diffuseMap.Release(); - m_emissiveMap.Release(); - m_heightMap.Release(); - m_normalMap.Release(); - m_specularMap.Release(); - m_uberShader.Release(); + // Copie des états de base + m_alphaTestEnabled = material.m_alphaTestEnabled; + m_alphaThreshold = material.m_alphaThreshold; + m_ambientColor = material.m_ambientColor; + m_diffuseColor = material.m_diffuseColor; + m_diffuseSampler = material.m_diffuseSampler; + m_lightingEnabled = material.m_lightingEnabled; + m_shininess = material.m_shininess; + m_specularColor = material.m_specularColor; + m_specularSampler = material.m_specularSampler; + m_states = material.m_states; + m_transformEnabled = material.m_transformEnabled; + // Copie des références de texture m_alphaMap = material.m_alphaMap; m_diffuseMap = material.m_diffuseMap; m_emissiveMap = material.m_emissiveMap; m_heightMap = material.m_heightMap; m_normalMap = material.m_normalMap; m_specularMap = material.m_specularMap; + + // Copie de la référence vers l'Über-Shader m_uberShader = material.m_uberShader; + + // On copie les instances de shader par la même occasion + std::memcpy(&m_shaders[0], &material.m_shaders[0], (nzShaderFlags_Max+1)*sizeof(ShaderInstance)); } void NzMaterial::GenerateShader(nzUInt32 flags) const @@ -687,11 +656,14 @@ void NzMaterial::GenerateShader(nzUInt32 flags) const list.SetParameter("PARALLAX_MAPPING", m_heightMap.IsValid()); list.SetParameter("SPECULAR_MAPPING", m_specularMap.IsValid()); list.SetParameter("TEXTURE_MAPPING", m_alphaMap.IsValid() || m_diffuseMap.IsValid() || m_emissiveMap.IsValid() || - m_normalMap.IsValid() || m_heightMap.IsValid() || m_specularMap.IsValid()); + m_normalMap.IsValid() || m_heightMap.IsValid() || m_specularMap.IsValid() || + flags & nzShaderFlags_TextureOverlay); list.SetParameter("TRANSFORM", m_transformEnabled); list.SetParameter("FLAG_DEFERRED", static_cast((flags & nzShaderFlags_Deferred) != 0)); list.SetParameter("FLAG_INSTANCING", static_cast((flags & nzShaderFlags_Instancing) != 0)); + list.SetParameter("FLAG_TEXTUREOVERLAY", static_cast((flags & nzShaderFlags_TextureOverlay) != 0)); + list.SetParameter("FLAG_VERTEXCOLOR", static_cast((flags & nzShaderFlags_VertexColor) != 0)); ShaderInstance& instance = m_shaders[flags]; instance.uberInstance = m_uberShader->Get(list); @@ -758,8 +730,8 @@ bool NzMaterial::Initialize() vertexShader.Set(reinterpret_cast(compatibilityVertexShader), sizeof(compatibilityVertexShader)); } - uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING"); - uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_INSTANCING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH"); + uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING"); + uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH"); NzUberShaderLibrary::Register("Basic", uberShader.get()); uberShader.release(); @@ -799,8 +771,8 @@ bool NzMaterial::Initialize() vertexShader.Set(reinterpret_cast(compatibilityVertexShader), sizeof(compatibilityVertexShader)); } - uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "FLAG_DEFERRED ALPHA_MAPPING ALPHA_TEST DIFFUSE_MAPPING EMISSIVE_MAPPING LIGHTING NORMAL_MAPPING PARALLAX_MAPPING SPECULAR_MAPPING"); - uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_DEFERRED FLAG_INSTANCING COMPUTE_TBNMATRIX LIGHTING PARALLAX_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH"); + uberShader->SetShader(nzShaderStage_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST DIFFUSE_MAPPING EMISSIVE_MAPPING LIGHTING NORMAL_MAPPING PARALLAX_MAPPING SPECULAR_MAPPING"); + uberShader->SetShader(nzShaderStage_Vertex, vertexShader, "FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR COMPUTE_TBNMATRIX LIGHTING PARALLAX_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH"); NzUberShaderLibrary::Register("PhongLighting", uberShader.get()); uberShader.release(); diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp index 54e9b964f..cf32336b8 100644 --- a/src/Nazara/Graphics/Model.cpp +++ b/src/Nazara/Graphics/Model.cpp @@ -36,19 +36,13 @@ NzModel::NzModel(const NzModel& model) : NzSceneNode(model), m_materials(model.m_materials), m_boundingVolume(model.m_boundingVolume), +m_mesh(model.m_mesh), m_boundingVolumeUpdated(model.m_boundingVolumeUpdated), m_matCount(model.m_matCount), m_skin(model.m_skin), m_skinCount(model.m_skinCount) { - if (model.m_mesh) - { - // Nous n'avons des matériaux que si nous avons un mesh - m_mesh = model.m_mesh; - m_materials = model.m_materials; - } - - SetParent(model); + SetParent(model.GetParent()); } NzModel::~NzModel() @@ -420,24 +414,6 @@ NzModel& NzModel::operator=(const NzModel& node) return *this; } -NzModel& NzModel::operator=(NzModel&& node) -{ - NzSceneNode::operator=(node); - - // Ressources - m_mesh = std::move(node.m_mesh); - m_materials = std::move(node.m_materials); - - // Paramètres - m_boundingVolume = node.m_boundingVolume; - m_boundingVolumeUpdated = node.m_boundingVolumeUpdated; - m_matCount = node.m_matCount; - m_skin = node.m_skin; - m_skinCount = node.m_skinCount; - - return *this; -} - void NzModel::InvalidateNode() { NzSceneNode::InvalidateNode(); diff --git a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag index a789242b9..53844cbc6 100644 --- a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag +++ b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag @@ -3,22 +3,24 @@ layout(early_fragment_tests) in; #endif /********************Entrant********************/ +in vec4 vColor; in vec2 vTexCoord; /********************Sortant********************/ out vec4 RenderTarget0; /********************Uniformes********************/ +uniform vec2 InvTargetSize; uniform sampler2D MaterialAlphaMap; uniform float MaterialAlphaThreshold; uniform vec4 MaterialDiffuse; uniform sampler2D MaterialDiffuseMap; -uniform vec2 InvTargetSize; +uniform sampler2D TextureOverlay; /********************Fonctions********************/ void main() { - vec4 fragmentColor = MaterialDiffuse; + vec4 fragmentColor = MaterialDiffuse * vColor; #if AUTO_TEXCOORDS vec2 texCoord = gl_FragCoord.xy * InvTargetSize; @@ -34,6 +36,10 @@ void main() fragmentColor.a *= texture(MaterialAlphaMap, texCoord).r; #endif +#if FLAG_TEXTUREOVERLAY + fragmentColor *= texture(TextureOverlay, texCoord); +#endif + #if ALPHA_TEST if (fragmentColor.a < MaterialAlphaThreshold) discard; diff --git a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h index 97c8ee9b1..c6eff909e 100644 --- a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h +++ b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h @@ -1 +1 @@ -35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,13,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,13,10,35,101,110,100,105,102,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,118,101,99,50,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,13,10,35,105,102,32,65,85,84,79,95,84,69,88,67,79,79,82,68,83,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,103,108,95,70,114,97,103,67,111,111,114,100,46,120,121,32,42,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,35,101,108,115,101,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,125, \ No newline at end of file +35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,13,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,13,10,35,101,110,100,105,102,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,118,101,99,52,32,118,67,111,108,111,114,59,13,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,118,101,99,50,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,84,101,120,116,117,114,101,79,118,101,114,108,97,121,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,32,42,32,118,67,111,108,111,114,59,13,10,13,10,35,105,102,32,65,85,84,79,95,84,69,88,67,79,79,82,68,83,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,103,108,95,70,114,97,103,67,111,111,114,100,46,120,121,32,42,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,13,10,35,101,108,115,101,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,70,76,65,71,95,84,69,88,84,85,82,69,79,86,69,82,76,65,89,13,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,84,101,120,116,117,114,101,79,118,101,114,108,97,121,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,35,101,110,100,105,102,13,10,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,125, \ No newline at end of file diff --git a/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert b/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert index 0516e8090..6a5143444 100644 --- a/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert +++ b/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert @@ -1,9 +1,11 @@ /********************Entrant********************/ in mat4 InstanceData0; +in vec4 VertexColor; in vec3 VertexPosition; in vec2 VertexTexCoord; /********************Sortant********************/ +out vec4 vColor; out vec2 vTexCoord; /********************Uniformes********************/ @@ -14,6 +16,12 @@ uniform mat4 WorldViewProjMatrix; /********************Fonctions********************/ void main() { +#if FLAG_VERTEXCOLOR + vec4 color = VertexColor; +#else + vec4 color = vec4(1.0); +#endif + #if FLAG_INSTANCING #if TRANSFORM gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0); @@ -36,6 +44,7 @@ void main() #endif #endif + vColor = color; #if TEXTURE_MAPPING vTexCoord = vec2(VertexTexCoord); #endif diff --git a/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert.h b/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert.h index 681ed8a5a..6532129d4 100644 --- a/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert.h +++ b/src/Nazara/Graphics/Resources/Shaders/Basic/core.vert.h @@ -1 +1 @@ -47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,109,97,116,52,32,73,110,115,116,97,110,99,101,68,97,116,97,48,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,13,10,105,110,32,118,101,99,50,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,86,101,114,116,101,120,68,101,112,116,104,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,108,115,101,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,84,69,88,84,85,82,69,95,77,65,80,80,73,78,71,13,10,9,118,84,101,120,67,111,111,114,100,32,61,32,118,101,99,50,40,86,101,114,116,101,120,84,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,125,13,10, \ No newline at end of file +47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,109,97,116,52,32,73,110,115,116,97,110,99,101,68,97,116,97,48,59,13,10,105,110,32,118,101,99,52,32,86,101,114,116,101,120,67,111,108,111,114,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,13,10,105,110,32,118,101,99,50,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,118,67,111,108,111,114,59,13,10,111,117,116,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,86,101,114,116,101,120,68,101,112,116,104,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,35,105,102,32,70,76,65,71,95,86,69,82,84,69,88,67,79,76,79,82,13,10,9,118,101,99,52,32,99,111,108,111,114,32,61,32,86,101,114,116,101,120,67,111,108,111,114,59,13,10,35,101,108,115,101,13,10,9,118,101,99,52,32,99,111,108,111,114,32,61,32,118,101,99,52,40,49,46,48,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,108,115,101,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,9,118,67,111,108,111,114,32,61,32,99,111,108,111,114,59,13,10,35,105,102,32,84,69,88,84,85,82,69,95,77,65,80,80,73,78,71,13,10,9,118,84,101,120,67,111,111,114,100,32,61,32,118,101,99,50,40,86,101,114,116,101,120,84,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,125,13,10, \ No newline at end of file diff --git a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag index 055b5472e..b60249edf 100644 --- a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag +++ b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag @@ -7,6 +7,7 @@ layout(early_fragment_tests) in; #define LIGHT_SPOT 2 /********************Entrant********************/ +in vec4 vColor; in mat3 vLightToWorld; in vec3 vNormal; in vec2 vTexCoord; @@ -49,6 +50,8 @@ uniform float ParallaxBias = -0.03; uniform float ParallaxScale = 0.02; uniform vec4 SceneAmbient; +uniform sampler2D TextureOverlay; + /********************Fonctions********************/ vec3 FloatToColor(float f) { @@ -76,7 +79,7 @@ vec4 EncodeNormal(in vec3 normal) void main() { - vec4 diffuseColor = MaterialDiffuse; + vec4 diffuseColor = MaterialDiffuse * vColor; vec2 texCoord = vTexCoord; #if LIGHTING && PARALLAX_MAPPING float height = texture(MaterialHeightMap, texCoord).r; @@ -90,6 +93,10 @@ void main() diffuseColor *= texture(MaterialDiffuseMap, texCoord); #endif +#if FLAG_TEXTUREOVERLAY + diffuseColor *= texture(TextureOverlay, texCoord); +#endif + #if FLAG_DEFERRED #if ALPHA_TEST #if ALPHA_MAPPING // Inutile de faire de l'alpha-mapping sans alpha-test en Deferred (l'alpha n'est pas sauvegardé) diff --git a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h index 54e4bb415..bd6058130 100644 --- a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h +++ b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h @@ -1 +1 @@ -35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,13,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,13,10,35,101,110,100,105,102,13,10,13,10,35,100,101,102,105,110,101,32,76,73,71,72,84,95,68,73,82,69,67,84,73,79,78,65,76,32,48,13,10,35,100,101,102,105,110,101,32,76,73,71,72,84,95,80,79,73,78,84,32,49,13,10,35,100,101,102,105,110,101,32,76,73,71,72,84,95,83,80,79,84,32,50,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,109,97,116,51,32,118,76,105,103,104,116,84,111,87,111,114,108,100,59,13,10,105,110,32,118,101,99,51,32,118,78,111,114,109,97,108,59,13,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,105,110,32,118,101,99,51,32,118,86,105,101,119,68,105,114,59,13,10,105,110,32,118,101,99,51,32,118,87,111,114,108,100,80,111,115,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,49,59,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,50,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,115,116,114,117,99,116,32,76,105,103,104,116,13,10,123,13,10,9,105,110,116,32,116,121,112,101,59,13,10,9,118,101,99,52,32,99,111,108,111,114,59,13,10,9,118,101,99,50,32,102,97,99,116,111,114,115,59,13,10,13,10,9,118,101,99,52,32,112,97,114,97,109,101,116,101,114,115,49,59,13,10,9,118,101,99,52,32,112,97,114,97,109,101,116,101,114,115,50,59,13,10,9,118,101,99,50,32,112,97,114,97,109,101,116,101,114,115,51,59,13,10,125,59,13,10,13,10,117,110,105,102,111,114,109,32,118,101,99,51,32,69,121,101,80,111,115,105,116,105,111,110,59,13,10,117,110,105,102,111,114,109,32,76,105,103,104,116,32,76,105,103,104,116,115,91,51,93,59,13,10,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,69,109,105,115,115,105,118,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,72,101,105,103,104,116,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,78,111,114,109,97,108,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,77,97,112,59,13,10,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,80,97,114,97,108,108,97,120,66,105,97,115,32,61,32,45,48,46,48,51,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,80,97,114,97,108,108,97,120,83,99,97,108,101,32,61,32,48,46,48,50,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,83,99,101,110,101,65,109,98,105,101,110,116,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,101,99,51,32,70,108,111,97,116,84,111,67,111,108,111,114,40,102,108,111,97,116,32,102,41,13,10,123,13,10,9,118,101,99,51,32,99,111,108,111,114,59,13,10,13,10,9,102,32,42,61,32,50,53,54,46,48,59,13,10,9,99,111,108,111,114,46,120,32,61,32,102,108,111,111,114,40,102,41,59,13,10,13,10,9,102,32,61,32,40,102,32,45,32,99,111,108,111,114,46,120,41,32,42,32,50,53,54,46,48,59,13,10,9,99,111,108,111,114,46,121,32,61,32,102,108,111,111,114,40,102,41,59,13,10,13,10,9,99,111,108,111,114,46,122,32,61,32,102,32,45,32,99,111,108,111,114,46,121,59,13,10,9,99,111,108,111,114,46,120,121,32,42,61,32,48,46,48,48,51,57,48,54,50,53,59,32,47,47,32,42,61,32,49,46,48,47,50,53,54,13,10,13,10,9,114,101,116,117,114,110,32,99,111,108,111,114,59,13,10,125,13,10,13,10,35,100,101,102,105,110,101,32,107,80,73,32,51,46,49,52,49,53,57,50,54,53,51,54,13,10,13,10,118,101,99,52,32,69,110,99,111,100,101,78,111,114,109,97,108,40,105,110,32,118,101,99,51,32,110,111,114,109,97,108,41,13,10,123,13,10,9,47,47,114,101,116,117,114,110,32,118,101,99,52,40,110,111,114,109,97,108,42,48,46,53,32,43,32,48,46,53,44,32,48,46,48,41,59,13,10,9,114,101,116,117,114,110,32,118,101,99,52,40,118,101,99,50,40,97,116,97,110,40,110,111,114,109,97,108,46,121,44,32,110,111,114,109,97,108,46,120,41,47,107,80,73,44,32,110,111,114,109,97,108,46,122,41,44,32,48,46,48,44,32,48,46,48,41,59,13,10,125,13,10,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,100,105,102,102,117,115,101,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,13,10,35,105,102,32,76,73,71,72,84,73,78,71,32,38,38,32,80,65,82,65,76,76,65,88,95,77,65,80,80,73,78,71,13,10,9,102,108,111,97,116,32,104,101,105,103,104,116,32,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,72,101,105,103,104,116,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,9,102,108,111,97,116,32,118,32,61,32,104,101,105,103,104,116,42,80,97,114,97,108,108,97,120,83,99,97,108,101,32,43,32,80,97,114,97,108,108,97,120,66,105,97,115,59,13,10,13,10,9,118,101,99,51,32,118,105,101,119,68,105,114,32,61,32,110,111,114,109,97,108,105,122,101,40,118,86,105,101,119,68,105,114,41,59,13,10,9,116,101,120,67,111,111,114,100,32,43,61,32,118,32,42,32,118,105,101,119,68,105,114,46,120,121,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,100,105,102,102,117,115,101,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,9,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,9,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,32,47,47,32,73,110,117,116,105,108,101,32,100,101,32,102,97,105,114,101,32,100,101,32,108,39,97,108,112,104,97,45,109,97,112,112,105,110,103,32,115,97,110,115,32,97,108,112,104,97,45,116,101,115,116,32,101,110,32,68,101,102,101,114,114,101,100,32,40,108,39,97,108,112,104,97,32,110,39,101,115,116,32,112,97,115,32,115,97,117,118,101,103,97,114,100,195,169,41,13,10,9,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,9,9,35,101,110,100,105,102,13,10,9,9,13,10,9,105,102,32,40,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,9,35,101,110,100,105,102,32,47,47,32,65,76,80,72,65,95,84,69,83,84,13,10,13,10,9,35,105,102,32,76,73,71,72,84,73,78,71,13,10,9,9,35,105,102,32,78,79,82,77,65,76,95,77,65,80,80,73,78,71,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,76,105,103,104,116,84,111,87,111,114,108,100,32,42,32,40,50,46,48,32,42,32,118,101,99,51,40,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,78,111,114,109,97,108,77,97,112,44,32,116,101,120,67,111,111,114,100,41,41,32,45,32,49,46,48,41,41,59,13,10,9,9,35,101,108,115,101,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,78,111,114,109,97,108,41,59,13,10,9,9,35,101,110,100,105,102,32,47,47,32,78,79,82,77,65,76,95,77,65,80,80,73,78,71,13,10,13,10,9,118,101,99,51,32,115,112,101,99,117,108,97,114,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,46,114,103,98,59,13,10,9,9,35,105,102,32,83,80,69,67,85,76,65,82,95,77,65,80,80,73,78,71,13,10,9,115,112,101,99,117,108,97,114,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,103,98,59,13,10,9,9,35,101,110,100,105,102,13,10,13,10,9,47,42,13,10,9,84,101,120,116,117,114,101,48,58,32,68,105,102,102,117,115,101,32,67,111,108,111,114,32,43,32,83,112,101,99,117,108,97,114,13,10,9,84,101,120,116,117,114,101,49,58,32,78,111,114,109,97,108,32,43,32,83,112,101,99,117,108,97,114,13,10,9,84,101,120,116,117,114,101,50,58,32,69,110,99,111,100,101,100,32,100,101,112,116,104,32,43,32,83,104,105,110,105,110,101,115,115,13,10,9,42,47,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,118,101,99,52,40,100,105,102,102,117,115,101,67,111,108,111,114,46,114,103,98,44,32,100,111,116,40,115,112,101,99,117,108,97,114,67,111,108,111,114,44,32,118,101,99,51,40,48,46,51,44,32,48,46,53,57,44,32,48,46,49,49,41,41,41,59,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,49,32,61,32,118,101,99,52,40,69,110,99,111,100,101,78,111,114,109,97,108,40,110,111,114,109,97,108,41,41,59,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,50,32,61,32,118,101,99,52,40,70,108,111,97,116,84,111,67,111,108,111,114,40,103,108,95,70,114,97,103,67,111,111,114,100,46,122,41,44,32,40,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,32,61,61,32,48,46,48,41,32,63,32,48,46,48,32,58,32,109,97,120,40,108,111,103,50,40,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,44,32,48,46,49,41,47,49,48,46,53,41,59,32,47,47,32,104,116,116,112,58,47,47,119,119,119,46,103,117,101,114,114,105,108,108,97,45,103,97,109,101,115,46,99,111,109,47,112,117,98,108,105,99,97,116,105,111,110,115,47,100,114,95,107,122,50,95,114,115,120,95,100,101,118,48,55,46,112,100,102,13,10,9,35,101,108,115,101,32,47,47,32,76,73,71,72,84,73,78,71,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,118,101,99,52,40,100,105,102,102,117,115,101,67,111,108,111,114,46,114,103,98,44,32,48,46,48,41,59,13,10,9,35,101,110,100,105,102,13,10,35,101,108,115,101,32,47,47,32,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,9,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,9,35,101,110,100,105,102,13,10,13,10,9,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,9,35,101,110,100,105,102,13,10,13,10,9,35,105,102,32,76,73,71,72,84,73,78,71,13,10,9,118,101,99,51,32,108,105,103,104,116,65,109,98,105,101,110,116,32,61,32,118,101,99,51,40,48,46,48,41,59,13,10,9,118,101,99,51,32,108,105,103,104,116,68,105,102,102,117,115,101,32,61,32,118,101,99,51,40,48,46,48,41,59,13,10,9,118,101,99,51,32,108,105,103,104,116,83,112,101,99,117,108,97,114,32,61,32,118,101,99,51,40,48,46,48,41,59,13,10,13,10,9,9,35,105,102,32,78,79,82,77,65,76,95,77,65,80,80,73,78,71,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,76,105,103,104,116,84,111,87,111,114,108,100,32,42,32,40,50,46,48,32,42,32,118,101,99,51,40,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,78,111,114,109,97,108,77,97,112,44,32,116,101,120,67,111,111,114,100,41,41,32,45,32,49,46,48,41,41,59,13,10,9,9,35,101,108,115,101,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,78,111,114,109,97,108,41,59,13,10,9,9,35,101,110,100,105,102,13,10,13,10,9,105,102,32,40,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,32,62,32,48,46,48,41,13,10,9,123,13,10,9,9,118,101,99,51,32,101,121,101,86,101,99,32,61,32,110,111,114,109,97,108,105,122,101,40,69,121,101,80,111,115,105,116,105,111,110,32,45,32,118,87,111,114,108,100,80,111,115,41,59,13,10,13,10,9,9,102,111,114,32,40,105,110,116,32,105,32,61,32,48,59,32,105,32,60,32,51,59,32,43,43,105,41,13,10,9,9,123,13,10,9,9,9,115,119,105,116,99,104,32,40,76,105,103,104,116,115,91,105,93,46,116,121,112,101,41,13,10,9,9,9,123,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,68,73,82,69,67,84,73,79,78,65,76,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,45,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,13,10,9,9,9,9,9,47,47,32,83,112,101,99,117,108,97,114,13,10,9,9,9,9,9,118,101,99,51,32,114,101,102,108,101,99,116,105,111,110,32,61,32,114,101,102,108,101,99,116,40,45,108,105,103,104,116,68,105,114,44,32,110,111,114,109,97,108,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,109,97,120,40,100,111,116,40,114,101,102,108,101,99,116,105,111,110,44,32,101,121,101,86,101,99,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,112,111,119,40,115,112,101,99,117,108,97,114,70,97,99,116,111,114,44,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,43,61,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,80,79,73,78,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,13,10,9,9,9,9,9,47,47,32,83,112,101,99,117,108,97,114,13,10,9,9,9,9,9,118,101,99,51,32,114,101,102,108,101,99,116,105,111,110,32,61,32,114,101,102,108,101,99,116,40,45,108,105,103,104,116,68,105,114,44,32,110,111,114,109,97,108,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,109,97,120,40,100,111,116,40,114,101,102,108,101,99,116,105,111,110,44,32,101,121,101,86,101,99,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,112,111,119,40,115,112,101,99,117,108,97,114,70,97,99,116,111,114,44,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,43,61,32,97,116,116,32,42,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,83,80,79,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,77,111,100,105,102,105,99,97,116,105,111,110,32,100,101,32,108,39,97,116,116,195,169,110,117,97,116,105,111,110,32,112,111,117,114,32,103,195,169,114,101,114,32,108,101,32,115,112,111,116,13,10,9,9,9,9,9,102,108,111,97,116,32,99,117,114,65,110,103,108,101,32,61,32,100,111,116,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,120,121,122,44,32,45,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,111,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,121,59,13,10,9,9,9,9,9,102,108,111,97,116,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,120,32,45,32,111,117,116,101,114,65,110,103,108,101,59,13,10,9,9,9,9,9,97,116,116,32,42,61,32,109,97,120,40,40,99,117,114,65,110,103,108,101,32,45,32,111,117,116,101,114,65,110,103,108,101,41,32,47,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,13,10,9,9,9,9,9,47,47,32,83,112,101,99,117,108,97,114,13,10,9,9,9,9,9,118,101,99,51,32,114,101,102,108,101,99,116,105,111,110,32,61,32,114,101,102,108,101,99,116,40,45,108,105,103,104,116,68,105,114,44,32,110,111,114,109,97,108,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,109,97,120,40,100,111,116,40,114,101,102,108,101,99,116,105,111,110,44,32,101,121,101,86,101,99,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,112,111,119,40,115,112,101,99,117,108,97,114,70,97,99,116,111,114,44,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,43,61,32,97,116,116,32,42,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,9,9,9,9,13,10,9,9,9,9,100,101,102,97,117,108,116,58,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,125,13,10,9,9,125,13,10,9,125,13,10,9,101,108,115,101,13,10,9,123,13,10,9,9,102,111,114,32,40,105,110,116,32,105,32,61,32,48,59,32,105,32,60,32,51,59,32,43,43,105,41,13,10,9,9,123,13,10,9,9,9,115,119,105,116,99,104,32,40,76,105,103,104,116,115,91,105,93,46,116,121,112,101,41,13,10,9,9,9,123,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,68,73,82,69,67,84,73,79,78,65,76,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,110,111,114,109,97,108,105,122,101,40,45,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,80,79,73,78,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,83,80,79,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,77,111,100,105,102,105,99,97,116,105,111,110,32,100,101,32,108,39,97,116,116,195,169,110,117,97,116,105,111,110,32,112,111,117,114,32,103,195,169,114,101,114,32,108,101,32,115,112,111,116,13,10,9,9,9,9,9,102,108,111,97,116,32,99,117,114,65,110,103,108,101,32,61,32,100,111,116,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,120,121,122,44,32,45,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,111,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,121,59,13,10,9,9,9,9,9,102,108,111,97,116,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,120,32,45,32,111,117,116,101,114,65,110,103,108,101,59,13,10,9,9,9,9,9,97,116,116,32,42,61,32,109,97,120,40,40,99,117,114,65,110,103,108,101,32,45,32,111,117,116,101,114,65,110,103,108,101,41,32,47,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,9,9,9,9,125,13,10,9,9,9,9,13,10,9,9,9,9,100,101,102,97,117,108,116,58,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,125,13,10,9,9,125,13,10,9,125,13,10,13,10,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,42,61,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,46,114,103,98,59,13,10,9,9,35,105,102,32,83,80,69,67,85,76,65,82,95,77,65,80,80,73,78,71,13,10,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,103,98,59,32,47,47,32,85,116,105,108,105,115,101,114,32,108,39,97,108,112,104,97,32,100,101,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,32,110,39,97,117,114,97,105,116,32,97,117,99,117,110,32,115,101,110,115,13,10,9,9,35,101,110,100,105,102,13,10,9,9,13,10,9,118,101,99,51,32,108,105,103,104,116,67,111,108,111,114,32,61,32,40,108,105,103,104,116,65,109,98,105,101,110,116,32,43,32,108,105,103,104,116,68,105,102,102,117,115,101,32,43,32,108,105,103,104,116,83,112,101,99,117,108,97,114,41,59,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,118,101,99,52,40,108,105,103,104,116,67,111,108,111,114,44,32,49,46,48,41,32,42,32,100,105,102,102,117,115,101,67,111,108,111,114,59,13,10,13,10,9,9,35,105,102,32,69,77,73,83,83,73,86,69,95,77,65,80,80,73,78,71,13,10,9,102,108,111,97,116,32,108,105,103,104,116,73,110,116,101,110,115,105,116,121,32,61,32,100,111,116,40,108,105,103,104,116,67,111,108,111,114,44,32,118,101,99,51,40,48,46,51,44,32,48,46,53,57,44,32,48,46,49,49,41,41,59,13,10,13,10,9,118,101,99,51,32,101,109,105,115,115,105,111,110,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,46,114,103,98,32,42,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,69,109,105,115,115,105,118,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,103,98,59,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,118,101,99,52,40,109,105,120,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,114,103,98,44,32,101,109,105,115,115,105,111,110,67,111,108,111,114,44,32,99,108,97,109,112,40,49,46,48,32,45,32,51,46,48,42,108,105,103,104,116,73,110,116,101,110,115,105,116,121,44,32,48,46,48,44,32,49,46,48,41,41,44,32,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,41,59,13,10,9,9,35,101,108,115,101,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,9,9,35,101,110,100,105,102,32,47,47,32,69,77,73,83,83,73,86,69,95,77,65,80,80,73,78,71,13,10,9,35,101,108,115,101,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,100,105,102,102,117,115,101,67,111,108,111,114,59,13,10,9,35,101,110,100,105,102,32,47,47,32,76,73,71,72,84,73,78,71,13,10,35,101,110,100,105,102,32,47,47,32,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,125,13,10, \ No newline at end of file +35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,13,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,13,10,35,101,110,100,105,102,13,10,13,10,35,100,101,102,105,110,101,32,76,73,71,72,84,95,68,73,82,69,67,84,73,79,78,65,76,32,48,13,10,35,100,101,102,105,110,101,32,76,73,71,72,84,95,80,79,73,78,84,32,49,13,10,35,100,101,102,105,110,101,32,76,73,71,72,84,95,83,80,79,84,32,50,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,118,101,99,52,32,118,67,111,108,111,114,59,13,10,105,110,32,109,97,116,51,32,118,76,105,103,104,116,84,111,87,111,114,108,100,59,13,10,105,110,32,118,101,99,51,32,118,78,111,114,109,97,108,59,13,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,105,110,32,118,101,99,51,32,118,86,105,101,119,68,105,114,59,13,10,105,110,32,118,101,99,51,32,118,87,111,114,108,100,80,111,115,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,49,59,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,50,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,115,116,114,117,99,116,32,76,105,103,104,116,13,10,123,13,10,9,105,110,116,32,116,121,112,101,59,13,10,9,118,101,99,52,32,99,111,108,111,114,59,13,10,9,118,101,99,50,32,102,97,99,116,111,114,115,59,13,10,13,10,9,118,101,99,52,32,112,97,114,97,109,101,116,101,114,115,49,59,13,10,9,118,101,99,52,32,112,97,114,97,109,101,116,101,114,115,50,59,13,10,9,118,101,99,50,32,112,97,114,97,109,101,116,101,114,115,51,59,13,10,125,59,13,10,13,10,117,110,105,102,111,114,109,32,118,101,99,51,32,69,121,101,80,111,115,105,116,105,111,110,59,13,10,117,110,105,102,111,114,109,32,76,105,103,104,116,32,76,105,103,104,116,115,91,51,93,59,13,10,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,69,109,105,115,115,105,118,101,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,72,101,105,103,104,116,77,97,112,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,78,111,114,109,97,108,77,97,112,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,59,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,77,97,112,59,13,10,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,80,97,114,97,108,108,97,120,66,105,97,115,32,61,32,45,48,46,48,51,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,80,97,114,97,108,108,97,120,83,99,97,108,101,32,61,32,48,46,48,50,59,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,83,99,101,110,101,65,109,98,105,101,110,116,59,13,10,13,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,84,101,120,116,117,114,101,79,118,101,114,108,97,121,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,101,99,51,32,70,108,111,97,116,84,111,67,111,108,111,114,40,102,108,111,97,116,32,102,41,13,10,123,13,10,9,118,101,99,51,32,99,111,108,111,114,59,13,10,13,10,9,102,32,42,61,32,50,53,54,46,48,59,13,10,9,99,111,108,111,114,46,120,32,61,32,102,108,111,111,114,40,102,41,59,13,10,13,10,9,102,32,61,32,40,102,32,45,32,99,111,108,111,114,46,120,41,32,42,32,50,53,54,46,48,59,13,10,9,99,111,108,111,114,46,121,32,61,32,102,108,111,111,114,40,102,41,59,13,10,13,10,9,99,111,108,111,114,46,122,32,61,32,102,32,45,32,99,111,108,111,114,46,121,59,13,10,9,99,111,108,111,114,46,120,121,32,42,61,32,48,46,48,48,51,57,48,54,50,53,59,32,47,47,32,42,61,32,49,46,48,47,50,53,54,13,10,13,10,9,114,101,116,117,114,110,32,99,111,108,111,114,59,13,10,125,13,10,13,10,35,100,101,102,105,110,101,32,107,80,73,32,51,46,49,52,49,53,57,50,54,53,51,54,13,10,13,10,118,101,99,52,32,69,110,99,111,100,101,78,111,114,109,97,108,40,105,110,32,118,101,99,51,32,110,111,114,109,97,108,41,13,10,123,13,10,9,47,47,114,101,116,117,114,110,32,118,101,99,52,40,110,111,114,109,97,108,42,48,46,53,32,43,32,48,46,53,44,32,48,46,48,41,59,13,10,9,114,101,116,117,114,110,32,118,101,99,52,40,118,101,99,50,40,97,116,97,110,40,110,111,114,109,97,108,46,121,44,32,110,111,114,109,97,108,46,120,41,47,107,80,73,44,32,110,111,114,109,97,108,46,122,41,44,32,48,46,48,44,32,48,46,48,41,59,13,10,125,13,10,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,118,101,99,52,32,100,105,102,102,117,115,101,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,32,42,32,118,67,111,108,111,114,59,13,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,13,10,35,105,102,32,76,73,71,72,84,73,78,71,32,38,38,32,80,65,82,65,76,76,65,88,95,77,65,80,80,73,78,71,13,10,9,102,108,111,97,116,32,104,101,105,103,104,116,32,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,72,101,105,103,104,116,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,9,102,108,111,97,116,32,118,32,61,32,104,101,105,103,104,116,42,80,97,114,97,108,108,97,120,83,99,97,108,101,32,43,32,80,97,114,97,108,108,97,120,66,105,97,115,59,13,10,13,10,9,118,101,99,51,32,118,105,101,119,68,105,114,32,61,32,110,111,114,109,97,108,105,122,101,40,118,86,105,101,119,68,105,114,41,59,13,10,9,116,101,120,67,111,111,114,100,32,43,61,32,118,32,42,32,118,105,101,119,68,105,114,46,120,121,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,13,10,9,100,105,102,102,117,115,101,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,70,76,65,71,95,84,69,88,84,85,82,69,79,86,69,82,76,65,89,13,10,9,100,105,102,102,117,115,101,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,84,101,120,116,117,114,101,79,118,101,114,108,97,121,44,32,116,101,120,67,111,111,114,100,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,9,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,9,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,32,47,47,32,73,110,117,116,105,108,101,32,100,101,32,102,97,105,114,101,32,100,101,32,108,39,97,108,112,104,97,45,109,97,112,112,105,110,103,32,115,97,110,115,32,97,108,112,104,97,45,116,101,115,116,32,101,110,32,68,101,102,101,114,114,101,100,32,40,108,39,97,108,112,104,97,32,110,39,101,115,116,32,112,97,115,32,115,97,117,118,101,103,97,114,100,195,169,41,13,10,9,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,9,9,35,101,110,100,105,102,13,10,9,9,13,10,9,105,102,32,40,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,9,35,101,110,100,105,102,32,47,47,32,65,76,80,72,65,95,84,69,83,84,13,10,13,10,9,35,105,102,32,76,73,71,72,84,73,78,71,13,10,9,9,35,105,102,32,78,79,82,77,65,76,95,77,65,80,80,73,78,71,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,76,105,103,104,116,84,111,87,111,114,108,100,32,42,32,40,50,46,48,32,42,32,118,101,99,51,40,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,78,111,114,109,97,108,77,97,112,44,32,116,101,120,67,111,111,114,100,41,41,32,45,32,49,46,48,41,41,59,13,10,9,9,35,101,108,115,101,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,78,111,114,109,97,108,41,59,13,10,9,9,35,101,110,100,105,102,32,47,47,32,78,79,82,77,65,76,95,77,65,80,80,73,78,71,13,10,13,10,9,118,101,99,51,32,115,112,101,99,117,108,97,114,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,46,114,103,98,59,13,10,9,9,35,105,102,32,83,80,69,67,85,76,65,82,95,77,65,80,80,73,78,71,13,10,9,115,112,101,99,117,108,97,114,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,103,98,59,13,10,9,9,35,101,110,100,105,102,13,10,13,10,9,47,42,13,10,9,84,101,120,116,117,114,101,48,58,32,68,105,102,102,117,115,101,32,67,111,108,111,114,32,43,32,83,112,101,99,117,108,97,114,13,10,9,84,101,120,116,117,114,101,49,58,32,78,111,114,109,97,108,32,43,32,83,112,101,99,117,108,97,114,13,10,9,84,101,120,116,117,114,101,50,58,32,69,110,99,111,100,101,100,32,100,101,112,116,104,32,43,32,83,104,105,110,105,110,101,115,115,13,10,9,42,47,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,118,101,99,52,40,100,105,102,102,117,115,101,67,111,108,111,114,46,114,103,98,44,32,100,111,116,40,115,112,101,99,117,108,97,114,67,111,108,111,114,44,32,118,101,99,51,40,48,46,51,44,32,48,46,53,57,44,32,48,46,49,49,41,41,41,59,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,49,32,61,32,118,101,99,52,40,69,110,99,111,100,101,78,111,114,109,97,108,40,110,111,114,109,97,108,41,41,59,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,50,32,61,32,118,101,99,52,40,70,108,111,97,116,84,111,67,111,108,111,114,40,103,108,95,70,114,97,103,67,111,111,114,100,46,122,41,44,32,40,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,32,61,61,32,48,46,48,41,32,63,32,48,46,48,32,58,32,109,97,120,40,108,111,103,50,40,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,44,32,48,46,49,41,47,49,48,46,53,41,59,32,47,47,32,104,116,116,112,58,47,47,119,119,119,46,103,117,101,114,114,105,108,108,97,45,103,97,109,101,115,46,99,111,109,47,112,117,98,108,105,99,97,116,105,111,110,115,47,100,114,95,107,122,50,95,114,115,120,95,100,101,118,48,55,46,112,100,102,13,10,9,35,101,108,115,101,32,47,47,32,76,73,71,72,84,73,78,71,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,118,101,99,52,40,100,105,102,102,117,115,101,67,111,108,111,114,46,114,103,98,44,32,48,46,48,41,59,13,10,9,35,101,110,100,105,102,13,10,35,101,108,115,101,32,47,47,32,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,9,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,13,10,9,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,13,10,9,35,101,110,100,105,102,13,10,13,10,9,35,105,102,32,65,76,80,72,65,95,84,69,83,84,13,10,9,105,102,32,40,100,105,102,102,117,115,101,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,13,10,9,9,100,105,115,99,97,114,100,59,13,10,9,35,101,110,100,105,102,13,10,13,10,9,35,105,102,32,76,73,71,72,84,73,78,71,13,10,9,118,101,99,51,32,108,105,103,104,116,65,109,98,105,101,110,116,32,61,32,118,101,99,51,40,48,46,48,41,59,13,10,9,118,101,99,51,32,108,105,103,104,116,68,105,102,102,117,115,101,32,61,32,118,101,99,51,40,48,46,48,41,59,13,10,9,118,101,99,51,32,108,105,103,104,116,83,112,101,99,117,108,97,114,32,61,32,118,101,99,51,40,48,46,48,41,59,13,10,13,10,9,9,35,105,102,32,78,79,82,77,65,76,95,77,65,80,80,73,78,71,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,76,105,103,104,116,84,111,87,111,114,108,100,32,42,32,40,50,46,48,32,42,32,118,101,99,51,40,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,78,111,114,109,97,108,77,97,112,44,32,116,101,120,67,111,111,114,100,41,41,32,45,32,49,46,48,41,41,59,13,10,9,9,35,101,108,115,101,13,10,9,118,101,99,51,32,110,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,118,78,111,114,109,97,108,41,59,13,10,9,9,35,101,110,100,105,102,13,10,13,10,9,105,102,32,40,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,32,62,32,48,46,48,41,13,10,9,123,13,10,9,9,118,101,99,51,32,101,121,101,86,101,99,32,61,32,110,111,114,109,97,108,105,122,101,40,69,121,101,80,111,115,105,116,105,111,110,32,45,32,118,87,111,114,108,100,80,111,115,41,59,13,10,13,10,9,9,102,111,114,32,40,105,110,116,32,105,32,61,32,48,59,32,105,32,60,32,51,59,32,43,43,105,41,13,10,9,9,123,13,10,9,9,9,115,119,105,116,99,104,32,40,76,105,103,104,116,115,91,105,93,46,116,121,112,101,41,13,10,9,9,9,123,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,68,73,82,69,67,84,73,79,78,65,76,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,45,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,13,10,9,9,9,9,9,47,47,32,83,112,101,99,117,108,97,114,13,10,9,9,9,9,9,118,101,99,51,32,114,101,102,108,101,99,116,105,111,110,32,61,32,114,101,102,108,101,99,116,40,45,108,105,103,104,116,68,105,114,44,32,110,111,114,109,97,108,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,109,97,120,40,100,111,116,40,114,101,102,108,101,99,116,105,111,110,44,32,101,121,101,86,101,99,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,112,111,119,40,115,112,101,99,117,108,97,114,70,97,99,116,111,114,44,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,43,61,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,80,79,73,78,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,13,10,9,9,9,9,9,47,47,32,83,112,101,99,117,108,97,114,13,10,9,9,9,9,9,118,101,99,51,32,114,101,102,108,101,99,116,105,111,110,32,61,32,114,101,102,108,101,99,116,40,45,108,105,103,104,116,68,105,114,44,32,110,111,114,109,97,108,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,109,97,120,40,100,111,116,40,114,101,102,108,101,99,116,105,111,110,44,32,101,121,101,86,101,99,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,112,111,119,40,115,112,101,99,117,108,97,114,70,97,99,116,111,114,44,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,43,61,32,97,116,116,32,42,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,83,80,79,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,77,111,100,105,102,105,99,97,116,105,111,110,32,100,101,32,108,39,97,116,116,195,169,110,117,97,116,105,111,110,32,112,111,117,114,32,103,195,169,114,101,114,32,108,101,32,115,112,111,116,13,10,9,9,9,9,9,102,108,111,97,116,32,99,117,114,65,110,103,108,101,32,61,32,100,111,116,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,120,121,122,44,32,45,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,111,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,121,59,13,10,9,9,9,9,9,102,108,111,97,116,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,120,32,45,32,111,117,116,101,114,65,110,103,108,101,59,13,10,9,9,9,9,9,97,116,116,32,42,61,32,109,97,120,40,40,99,117,114,65,110,103,108,101,32,45,32,111,117,116,101,114,65,110,103,108,101,41,32,47,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,13,10,9,9,9,9,9,47,47,32,83,112,101,99,117,108,97,114,13,10,9,9,9,9,9,118,101,99,51,32,114,101,102,108,101,99,116,105,111,110,32,61,32,114,101,102,108,101,99,116,40,45,108,105,103,104,116,68,105,114,44,32,110,111,114,109,97,108,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,109,97,120,40,100,111,116,40,114,101,102,108,101,99,116,105,111,110,44,32,101,121,101,86,101,99,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,61,32,112,111,119,40,115,112,101,99,117,108,97,114,70,97,99,116,111,114,44,32,77,97,116,101,114,105,97,108,83,104,105,110,105,110,101,115,115,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,43,61,32,97,116,116,32,42,32,115,112,101,99,117,108,97,114,70,97,99,116,111,114,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,9,9,9,9,13,10,9,9,9,9,100,101,102,97,117,108,116,58,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,125,13,10,9,9,125,13,10,9,125,13,10,9,101,108,115,101,13,10,9,123,13,10,9,9,102,111,114,32,40,105,110,116,32,105,32,61,32,48,59,32,105,32,60,32,51,59,32,43,43,105,41,13,10,9,9,123,13,10,9,9,9,115,119,105,116,99,104,32,40,76,105,103,104,116,115,91,105,93,46,116,121,112,101,41,13,10,9,9,9,123,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,68,73,82,69,67,84,73,79,78,65,76,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,110,111,114,109,97,108,105,122,101,40,45,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,80,79,73,78,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,9,9,9,9,9,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,9,125,13,10,13,10,9,9,9,9,99,97,115,101,32,76,73,71,72,84,95,83,80,79,84,58,13,10,9,9,9,9,123,13,10,9,9,9,9,9,118,101,99,51,32,108,105,103,104,116,68,105,114,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,120,121,122,32,45,32,118,87,111,114,108,100,80,111,115,59,13,10,9,9,9,9,9,102,108,111,97,116,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,32,61,32,108,101,110,103,116,104,40,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,108,105,103,104,116,68,105,114,32,47,61,32,108,105,103,104,116,68,105,114,76,101,110,103,116,104,59,32,47,47,32,78,111,114,109,97,108,105,115,97,116,105,111,110,13,10,9,9,9,9,9,13,10,9,9,9,9,9,102,108,111,97,116,32,97,116,116,32,61,32,109,97,120,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,49,46,119,32,45,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,119,42,108,105,103,104,116,68,105,114,76,101,110,103,116,104,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,65,109,98,105,101,110,116,13,10,9,9,9,9,9,108,105,103,104,116,65,109,98,105,101,110,116,32,43,61,32,97,116,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,120,32,42,32,40,77,97,116,101,114,105,97,108,65,109,98,105,101,110,116,46,114,103,98,32,43,32,83,99,101,110,101,65,109,98,105,101,110,116,46,114,103,98,41,59,13,10,13,10,9,9,9,9,9,47,47,32,77,111,100,105,102,105,99,97,116,105,111,110,32,100,101,32,108,39,97,116,116,195,169,110,117,97,116,105,111,110,32,112,111,117,114,32,103,195,169,114,101,114,32,108,101,32,115,112,111,116,13,10,9,9,9,9,9,102,108,111,97,116,32,99,117,114,65,110,103,108,101,32,61,32,100,111,116,40,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,50,46,120,121,122,44,32,45,108,105,103,104,116,68,105,114,41,59,13,10,9,9,9,9,9,102,108,111,97,116,32,111,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,121,59,13,10,9,9,9,9,9,102,108,111,97,116,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,32,61,32,76,105,103,104,116,115,91,105,93,46,112,97,114,97,109,101,116,101,114,115,51,46,120,32,45,32,111,117,116,101,114,65,110,103,108,101,59,13,10,9,9,9,9,9,97,116,116,32,42,61,32,109,97,120,40,40,99,117,114,65,110,103,108,101,32,45,32,111,117,116,101,114,65,110,103,108,101,41,32,47,32,105,110,110,101,114,77,105,110,117,115,79,117,116,101,114,65,110,103,108,101,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,47,47,32,68,105,102,102,117,115,101,13,10,9,9,9,9,9,102,108,111,97,116,32,108,97,109,98,101,114,116,32,61,32,109,97,120,40,100,111,116,40,110,111,114,109,97,108,44,32,108,105,103,104,116,68,105,114,41,44,32,48,46,48,41,59,13,10,13,10,9,9,9,9,9,108,105,103,104,116,68,105,102,102,117,115,101,32,43,61,32,97,116,116,32,42,32,108,97,109,98,101,114,116,32,42,32,76,105,103,104,116,115,91,105,93,46,99,111,108,111,114,46,114,103,98,32,42,32,76,105,103,104,116,115,91,105,93,46,102,97,99,116,111,114,115,46,121,59,13,10,9,9,9,9,125,13,10,9,9,9,9,13,10,9,9,9,9,100,101,102,97,117,108,116,58,13,10,9,9,9,9,9,98,114,101,97,107,59,13,10,9,9,9,125,13,10,9,9,125,13,10,9,125,13,10,13,10,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,42,61,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,46,114,103,98,59,13,10,9,9,35,105,102,32,83,80,69,67,85,76,65,82,95,77,65,80,80,73,78,71,13,10,9,108,105,103,104,116,83,112,101,99,117,108,97,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,103,98,59,32,47,47,32,85,116,105,108,105,115,101,114,32,108,39,97,108,112,104,97,32,100,101,32,77,97,116,101,114,105,97,108,83,112,101,99,117,108,97,114,32,110,39,97,117,114,97,105,116,32,97,117,99,117,110,32,115,101,110,115,13,10,9,9,35,101,110,100,105,102,13,10,9,9,13,10,9,118,101,99,51,32,108,105,103,104,116,67,111,108,111,114,32,61,32,40,108,105,103,104,116,65,109,98,105,101,110,116,32,43,32,108,105,103,104,116,68,105,102,102,117,115,101,32,43,32,108,105,103,104,116,83,112,101,99,117,108,97,114,41,59,13,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,118,101,99,52,40,108,105,103,104,116,67,111,108,111,114,44,32,49,46,48,41,32,42,32,100,105,102,102,117,115,101,67,111,108,111,114,59,13,10,13,10,9,9,35,105,102,32,69,77,73,83,83,73,86,69,95,77,65,80,80,73,78,71,13,10,9,102,108,111,97,116,32,108,105,103,104,116,73,110,116,101,110,115,105,116,121,32,61,32,100,111,116,40,108,105,103,104,116,67,111,108,111,114,44,32,118,101,99,51,40,48,46,51,44,32,48,46,53,57,44,32,48,46,49,49,41,41,59,13,10,13,10,9,118,101,99,51,32,101,109,105,115,115,105,111,110,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,46,114,103,98,32,42,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,69,109,105,115,115,105,118,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,103,98,59,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,118,101,99,52,40,109,105,120,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,114,103,98,44,32,101,109,105,115,115,105,111,110,67,111,108,111,114,44,32,99,108,97,109,112,40,49,46,48,32,45,32,51,46,48,42,108,105,103,104,116,73,110,116,101,110,115,105,116,121,44,32,48,46,48,44,32,49,46,48,41,41,44,32,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,41,59,13,10,9,9,35,101,108,115,101,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,13,10,9,9,35,101,110,100,105,102,32,47,47,32,69,77,73,83,83,73,86,69,95,77,65,80,80,73,78,71,13,10,9,35,101,108,115,101,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,100,105,102,102,117,115,101,67,111,108,111,114,59,13,10,9,35,101,110,100,105,102,32,47,47,32,76,73,71,72,84,73,78,71,13,10,35,101,110,100,105,102,32,47,47,32,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,125,13,10, \ No newline at end of file diff --git a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert index 09430bb06..454df5b82 100644 --- a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert +++ b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert @@ -1,11 +1,13 @@ /********************Entrant********************/ in mat4 InstanceData0; +in vec4 VertexColor; in vec3 VertexPosition; in vec3 VertexNormal; in vec3 VertexTangent; in vec2 VertexTexCoord; /********************Sortant********************/ +out vec4 vColor; out mat3 vLightToWorld; out vec3 vNormal; out vec2 vTexCoord; @@ -22,6 +24,12 @@ uniform mat4 WorldViewProjMatrix; /********************Fonctions********************/ void main() { +#if FLAG_VERTEXCOLOR + vec4 color = VertexColor; +#else + vec4 color = vec4(1.0); +#endif + #if FLAG_INSTANCING #if TRANSFORM gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0); @@ -44,6 +52,8 @@ void main() #endif #endif + vColor = color; + #if LIGHTING #if FLAG_INSTANCING mat3 rotationMatrix = mat3(InstanceData0); diff --git a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h index c920136a2..3382bc09f 100644 --- a/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h +++ b/src/Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h @@ -1 +1 @@ -47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,109,97,116,52,32,73,110,115,116,97,110,99,101,68,97,116,97,48,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,78,111,114,109,97,108,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,84,97,110,103,101,110,116,59,13,10,105,110,32,118,101,99,50,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,109,97,116,51,32,118,76,105,103,104,116,84,111,87,111,114,108,100,59,13,10,111,117,116,32,118,101,99,51,32,118,78,111,114,109,97,108,59,13,10,111,117,116,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,111,117,116,32,118,101,99,51,32,118,86,105,101,119,68,105,114,59,13,10,111,117,116,32,118,101,99,51,32,118,87,111,114,108,100,80,111,115,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,118,101,99,51,32,69,121,101,80,111,115,105,116,105,111,110,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,86,101,114,116,101,120,68,101,112,116,104,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,77,97,116,114,105,120,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,108,115,101,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,76,73,71,72,84,73,78,71,13,10,9,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,109,97,116,51,32,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,61,32,109,97,116,51,40,73,110,115,116,97,110,99,101,68,97,116,97,48,41,59,13,10,9,35,101,108,115,101,13,10,9,109,97,116,51,32,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,61,32,109,97,116,51,40,87,111,114,108,100,77,97,116,114,105,120,41,59,13,10,9,35,101,110,100,105,102,13,10,9,13,10,9,35,105,102,32,67,79,77,80,85,84,69,95,84,66,78,77,65,84,82,73,88,13,10,9,118,101,99,51,32,98,105,110,111,114,109,97,108,32,61,32,99,114,111,115,115,40,86,101,114,116,101,120,78,111,114,109,97,108,44,32,86,101,114,116,101,120,84,97,110,103,101,110,116,41,59,13,10,9,118,76,105,103,104,116,84,111,87,111,114,108,100,91,48,93,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,86,101,114,116,101,120,84,97,110,103,101,110,116,41,59,13,10,9,118,76,105,103,104,116,84,111,87,111,114,108,100,91,49,93,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,98,105,110,111,114,109,97,108,41,59,13,10,9,118,76,105,103,104,116,84,111,87,111,114,108,100,91,50,93,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,86,101,114,116,101,120,78,111,114,109,97,108,41,59,13,10,9,35,101,108,115,101,13,10,9,118,78,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,86,101,114,116,101,120,78,111,114,109,97,108,41,59,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,84,69,88,84,85,82,69,95,77,65,80,80,73,78,71,13,10,9,35,105,102,32,70,76,65,71,95,70,76,73,80,95,85,86,83,13,10,9,118,84,101,120,67,111,111,114,100,32,61,32,118,101,99,50,40,86,101,114,116,101,120,84,101,120,67,111,111,114,100,46,120,44,32,49,46,48,32,45,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,46,121,41,59,13,10,9,35,101,108,115,101,13,10,9,118,84,101,120,67,111,111,114,100,32,61,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,59,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,76,73,71,72,84,73,78,71,32,38,38,32,80,65,82,65,76,76,65,88,95,77,65,80,80,73,78,71,13,10,9,118,86,105,101,119,68,105,114,32,61,32,69,121,101,80,111,115,105,116,105,111,110,32,45,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,32,13,10,9,118,86,105,101,119,68,105,114,32,42,61,32,118,76,105,103,104,116,84,111,87,111,114,108,100,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,76,73,71,72,84,73,78,71,32,38,38,32,33,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,9,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,118,87,111,114,108,100,80,111,115,32,61,32,118,101,99,51,40,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,41,59,13,10,9,35,101,108,115,101,13,10,9,118,87,111,114,108,100,80,111,115,32,61,32,118,101,99,51,40,87,111,114,108,100,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,41,59,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,125,13,10, \ No newline at end of file +47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,109,97,116,52,32,73,110,115,116,97,110,99,101,68,97,116,97,48,59,13,10,105,110,32,118,101,99,52,32,86,101,114,116,101,120,67,111,108,111,114,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,78,111,114,109,97,108,59,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,84,97,110,103,101,110,116,59,13,10,105,110,32,118,101,99,50,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,118,67,111,108,111,114,59,13,10,111,117,116,32,109,97,116,51,32,118,76,105,103,104,116,84,111,87,111,114,108,100,59,13,10,111,117,116,32,118,101,99,51,32,118,78,111,114,109,97,108,59,13,10,111,117,116,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,13,10,111,117,116,32,118,101,99,51,32,118,86,105,101,119,68,105,114,59,13,10,111,117,116,32,118,101,99,51,32,118,87,111,114,108,100,80,111,115,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,118,101,99,51,32,69,121,101,80,111,115,105,116,105,111,110,59,13,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,86,101,114,116,101,120,68,101,112,116,104,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,77,97,116,114,105,120,59,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,35,105,102,32,70,76,65,71,95,86,69,82,84,69,88,67,79,76,79,82,13,10,9,118,101,99,52,32,99,111,108,111,114,32,61,32,86,101,114,116,101,120,67,111,108,111,114,59,13,10,35,101,108,115,101,13,10,9,118,101,99,52,32,99,111,108,111,114,32,61,32,118,101,99,52,40,49,46,48,41,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,108,115,101,13,10,9,35,105,102,32,84,82,65,78,83,70,79,82,77,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,35,101,108,115,101,13,10,9,9,35,105,102,32,85,78,73,70,79,82,77,95,86,69,82,84,69,88,95,68,69,80,84,72,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,46,120,121,44,32,86,101,114,116,101,120,68,101,112,116,104,44,32,49,46,48,41,59,13,10,9,9,35,101,108,115,101,13,10,9,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,9,9,35,101,110,100,105,102,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,9,118,67,111,108,111,114,32,61,32,99,111,108,111,114,59,13,10,13,10,35,105,102,32,76,73,71,72,84,73,78,71,13,10,9,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,109,97,116,51,32,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,61,32,109,97,116,51,40,73,110,115,116,97,110,99,101,68,97,116,97,48,41,59,13,10,9,35,101,108,115,101,13,10,9,109,97,116,51,32,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,61,32,109,97,116,51,40,87,111,114,108,100,77,97,116,114,105,120,41,59,13,10,9,35,101,110,100,105,102,13,10,9,13,10,9,35,105,102,32,67,79,77,80,85,84,69,95,84,66,78,77,65,84,82,73,88,13,10,9,118,101,99,51,32,98,105,110,111,114,109,97,108,32,61,32,99,114,111,115,115,40,86,101,114,116,101,120,78,111,114,109,97,108,44,32,86,101,114,116,101,120,84,97,110,103,101,110,116,41,59,13,10,9,118,76,105,103,104,116,84,111,87,111,114,108,100,91,48,93,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,86,101,114,116,101,120,84,97,110,103,101,110,116,41,59,13,10,9,118,76,105,103,104,116,84,111,87,111,114,108,100,91,49,93,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,98,105,110,111,114,109,97,108,41,59,13,10,9,118,76,105,103,104,116,84,111,87,111,114,108,100,91,50,93,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,86,101,114,116,101,120,78,111,114,109,97,108,41,59,13,10,9,35,101,108,115,101,13,10,9,118,78,111,114,109,97,108,32,61,32,110,111,114,109,97,108,105,122,101,40,114,111,116,97,116,105,111,110,77,97,116,114,105,120,32,42,32,86,101,114,116,101,120,78,111,114,109,97,108,41,59,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,84,69,88,84,85,82,69,95,77,65,80,80,73,78,71,13,10,9,35,105,102,32,70,76,65,71,95,70,76,73,80,95,85,86,83,13,10,9,118,84,101,120,67,111,111,114,100,32,61,32,118,101,99,50,40,86,101,114,116,101,120,84,101,120,67,111,111,114,100,46,120,44,32,49,46,48,32,45,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,46,121,41,59,13,10,9,35,101,108,115,101,13,10,9,118,84,101,120,67,111,111,114,100,32,61,32,86,101,114,116,101,120,84,101,120,67,111,111,114,100,59,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,76,73,71,72,84,73,78,71,32,38,38,32,80,65,82,65,76,76,65,88,95,77,65,80,80,73,78,71,13,10,9,118,86,105,101,119,68,105,114,32,61,32,69,121,101,80,111,115,105,116,105,111,110,32,45,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,32,13,10,9,118,86,105,101,119,68,105,114,32,42,61,32,118,76,105,103,104,116,84,111,87,111,114,108,100,59,13,10,35,101,110,100,105,102,13,10,13,10,35,105,102,32,76,73,71,72,84,73,78,71,32,38,38,32,33,70,76,65,71,95,68,69,70,69,82,82,69,68,13,10,9,35,105,102,32,70,76,65,71,95,73,78,83,84,65,78,67,73,78,71,13,10,9,118,87,111,114,108,100,80,111,115,32,61,32,118,101,99,51,40,73,110,115,116,97,110,99,101,68,97,116,97,48,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,41,59,13,10,9,35,101,108,115,101,13,10,9,118,87,111,114,108,100,80,111,115,32,61,32,118,101,99,51,40,87,111,114,108,100,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,41,59,13,10,9,35,101,110,100,105,102,13,10,35,101,110,100,105,102,13,10,125,13,10, \ No newline at end of file diff --git a/src/Nazara/Graphics/Scene.cpp b/src/Nazara/Graphics/Scene.cpp index 2c9f286a8..e66a99f03 100644 --- a/src/Nazara/Graphics/Scene.cpp +++ b/src/Nazara/Graphics/Scene.cpp @@ -134,6 +134,58 @@ NzAbstractBackground* NzScene::GetBackground() const return m_impl->background.get(); } +NzVector3f NzScene::GetBackward() const +{ + #if NAZARA_GRAPHICS_SAFE + if (!m_impl->viewer) + { + NazaraError("No viewer"); + return NzVector3f::Backward(); + } + #endif + + return -m_impl->viewer->GetGlobalForward(); +} + +NzVector3f NzScene::GetDown() const +{ + #if NAZARA_GRAPHICS_SAFE + if (!m_impl->viewer) + { + NazaraError("No viewer"); + return NzVector3f::Down(); + } + #endif + + return -m_impl->viewer->GetGlobalUp(); +} + +NzVector3f NzScene::GetForward() const +{ + #if NAZARA_GRAPHICS_SAFE + if (!m_impl->viewer) + { + NazaraError("No viewer"); + return NzVector3f::Forward(); + } + #endif + + return m_impl->viewer->GetGlobalForward(); +} + +NzVector3f NzScene::GetLeft() const +{ + #if NAZARA_GRAPHICS_SAFE + if (!m_impl->viewer) + { + NazaraError("No viewer"); + return NzVector3f::Left(); + } + #endif + + return -m_impl->viewer->GetGlobalRight(); +} + NzAbstractRenderTechnique* NzScene::GetRenderTechnique() const { if (!m_impl->renderTechnique) @@ -142,6 +194,19 @@ NzAbstractRenderTechnique* NzScene::GetRenderTechnique() const return m_impl->renderTechnique.get(); } +NzVector3f NzScene::GetRight() const +{ + #if NAZARA_GRAPHICS_SAFE + if (!m_impl->viewer) + { + NazaraError("No viewer"); + return NzVector3f::Right(); + } + #endif + + return m_impl->viewer->GetGlobalRight(); +} + NzSceneNode& NzScene::GetRoot() const { return m_impl->root; @@ -152,6 +217,19 @@ NzAbstractViewer* NzScene::GetViewer() const return m_impl->viewer; } +NzVector3f NzScene::GetUp() const +{ + #if NAZARA_GRAPHICS_SAFE + if (!m_impl->viewer) + { + NazaraError("No viewer"); + return NzVector3f::Up(); + } + #endif + + return m_impl->viewer->GetGlobalUp(); +} + float NzScene::GetUpdateTime() const { return m_impl->updateTime; @@ -197,7 +275,13 @@ void NzScene::SetRenderTechnique(NzAbstractRenderTechnique* renderTechnique) void NzScene::SetViewer(NzAbstractViewer* viewer) { - m_impl->viewer = viewer; + if (m_impl->viewer != viewer) + { + m_impl->viewer = viewer; + + // Invalidation de tous les nodes de la scène (utile pour la régénération des sommets dépendant du viewer) + m_impl->root.InvalidateNode(); + } } void NzScene::SetViewer(NzAbstractViewer& viewer) diff --git a/src/Nazara/Graphics/SceneNode.cpp b/src/Nazara/Graphics/SceneNode.cpp index fbd88b866..d5ae7da72 100644 --- a/src/Nazara/Graphics/SceneNode.cpp +++ b/src/Nazara/Graphics/SceneNode.cpp @@ -31,16 +31,94 @@ void NzSceneNode::EnableDrawing(bool drawingEnabled) m_drawingEnabled = drawingEnabled; } +NzVector3f NzSceneNode::GetBackward() const +{ + if (m_scene) + { + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedRotation * m_scene->GetBackward(); + } + else + return NzNode::GetBackward(); +} + +NzVector3f NzSceneNode::GetDown() const +{ + if (m_scene) + { + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedRotation * m_scene->GetDown(); + } + else + return NzNode::GetDown(); +} + +NzVector3f NzSceneNode::GetForward() const +{ + if (m_scene) + { + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedRotation * m_scene->GetForward(); + } + else + return NzNode::GetForward(); +} + +NzVector3f NzSceneNode::GetLeft() const +{ + if (m_scene) + { + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedRotation * m_scene->GetLeft(); + } + else + return NzNode::GetLeft(); +} + nzNodeType NzSceneNode::GetNodeType() const { return nzNodeType_Scene; } +NzVector3f NzSceneNode::GetRight() const +{ + if (m_scene) + { + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedRotation * m_scene->GetRight(); + } + else + return NzNode::GetRight(); +} + NzScene* NzSceneNode::GetScene() const { return m_scene; } +NzVector3f NzSceneNode::GetUp() const +{ + if (m_scene) + { + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedRotation * m_scene->GetUp(); + } + else + return NzNode::GetUp(); +} + bool NzSceneNode::IsDrawingEnabled() const { return m_drawingEnabled; @@ -62,17 +140,6 @@ NzSceneNode& NzSceneNode::operator=(const NzSceneNode& sceneNode) return *this; } -NzSceneNode& NzSceneNode::operator=(NzSceneNode&& sceneNode) -{ - NzNode::operator=(sceneNode); - - // La scène est affectée via le parenting du node - m_drawingEnabled = sceneNode.m_drawingEnabled; - m_visible = sceneNode.m_visible; - - return *this; -} - bool NzSceneNode::FrustumCull(const NzFrustumf& frustum) const { return frustum.Contains(GetBoundingVolume()); @@ -82,6 +149,7 @@ void NzSceneNode::OnParenting(const NzNode* parent) { if (parent) { + ///FIXME: Remonter jusqu'au premier parent de type SceneNode plutôt que de s'arrêter au premier venu if (parent->GetNodeType() == nzNodeType_Scene) SetScene(static_cast(parent)->m_scene); } diff --git a/src/Nazara/Graphics/SkinningManager.cpp b/src/Nazara/Graphics/SkinningManager.cpp index 9200b1186..2e47fc11e 100644 --- a/src/Nazara/Graphics/SkinningManager.cpp +++ b/src/Nazara/Graphics/SkinningManager.cpp @@ -174,7 +174,7 @@ NzVertexBuffer* NzSkinningManager::GetBuffer(const NzSkeletalMesh* mesh, const N { std::unique_ptr vertexBuffer(new NzVertexBuffer); vertexBuffer->SetPersistent(false); - vertexBuffer->Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), mesh->GetVertexCount(), nzBufferStorage_Hardware, nzBufferUsage_Dynamic); + vertexBuffer->Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), mesh->GetVertexCount(), nzDataStorage_Hardware, nzBufferUsage_Dynamic); BufferData data({vertexBuffer.get(), true}); meshMap.insert(std::make_pair(mesh, data)); diff --git a/src/Nazara/Graphics/SkyboxBackground.cpp b/src/Nazara/Graphics/SkyboxBackground.cpp index d1d7b8ca3..76cbd7b08 100644 --- a/src/Nazara/Graphics/SkyboxBackground.cpp +++ b/src/Nazara/Graphics/SkyboxBackground.cpp @@ -21,7 +21,7 @@ namespace { NzIndexBuffer* BuildIndexBuffer() { - std::unique_ptr indexBuffer(new NzIndexBuffer(false, 36, nzBufferStorage_Hardware, nzBufferUsage_Static)); + std::unique_ptr indexBuffer(new NzIndexBuffer(false, 36, nzDataStorage_Hardware, nzBufferUsage_Static)); indexBuffer->SetPersistent(false); nzUInt16 indices[6*6] = @@ -155,7 +155,7 @@ namespace NzVertexBuffer* BuildVertexBuffer() { - std::unique_ptr vertexBuffer(new NzVertexBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 8, nzBufferStorage_Hardware, nzBufferUsage_Static)); + std::unique_ptr vertexBuffer(new NzVertexBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 8, nzDataStorage_Hardware, nzBufferUsage_Static)); vertexBuffer->SetPersistent(false); float vertices[8*(sizeof(float)*3)] = diff --git a/src/Nazara/Graphics/Sprite.cpp b/src/Nazara/Graphics/Sprite.cpp index df181ac5d..542f17cd4 100644 --- a/src/Nazara/Graphics/Sprite.cpp +++ b/src/Nazara/Graphics/Sprite.cpp @@ -3,39 +3,31 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include #include NzSprite::NzSprite() : m_boundingVolume(NzBoundingVolumef::Null()), +m_color(NzColor::White), m_textureCoords(0.f, 0.f, 1.f, 1.f), m_size(64.f, 64.f), -m_boundingVolumeUpdated(true) +m_boundingVolumeUpdated(true), +m_verticesUpdated(false) { + SetDefaultMaterial(); } NzSprite::NzSprite(NzTexture* texture) : m_boundingVolume(NzBoundingVolumef::Null()), -m_textureCoords(0.f, 0.f, 1.f, 1.f) +m_color(NzColor::White), +m_textureCoords(0.f, 0.f, 1.f, 1.f), +m_size(64.f, 64.f), +m_boundingVolumeUpdated(false), +m_verticesUpdated(false) { - if (texture) - { - m_material = new NzMaterial; - m_material->SetPersistent(false); - m_material->SetDiffuseMap(texture); - - if (texture->IsValid()) - m_size.Set(texture->GetWidth(), texture->GetHeight()); - else - m_size.Set(64.f, 64.f); - - m_boundingVolumeUpdated = false; - } - else - { - m_size.Set(64.f, 64.f); - m_boundingVolumeUpdated = true; - } + SetTexture(texture, true); } NzSprite::NzSprite(const NzSprite& sprite) : @@ -44,32 +36,32 @@ m_boundingVolume(sprite.m_boundingVolume), m_material(sprite.m_material), m_textureCoords(sprite.m_textureCoords), m_size(sprite.m_size), -m_boundingVolumeUpdated(sprite.m_boundingVolumeUpdated) +m_vertices(sprite.m_vertices), +m_boundingVolumeUpdated(sprite.m_boundingVolumeUpdated), +m_verticesUpdated(sprite.m_verticesUpdated) { - SetParent(sprite); + SetParent(sprite.GetParent()); } -NzSprite::NzSprite(NzSprite&& sprite) : -NzSceneNode(sprite), -m_boundingVolume(sprite.m_boundingVolume), -m_material(std::move(sprite.m_material)), -m_textureCoords(sprite.m_textureCoords), -m_size(sprite.m_size), -m_boundingVolumeUpdated(sprite.m_boundingVolumeUpdated) -{ -} - -NzSprite::~NzSprite() = default; - void NzSprite::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const { - renderQueue->AddSprite(this); + if (!m_verticesUpdated) + UpdateVertices(); + + renderQueue->AddSprites(m_material, m_vertices, 1); } const NzBoundingVolumef& NzSprite::GetBoundingVolume() const { - static NzBoundingVolumef infinity(NzBoundingVolumef::Infinite()); - return infinity; + if (!m_boundingVolumeUpdated) + UpdateBoundingVolume(); + + return m_boundingVolume; +} + +const NzColor& NzSprite::GetColor() const +{ + return m_color; } NzMaterial* NzSprite::GetMaterial() const @@ -97,13 +89,33 @@ bool NzSprite::IsDrawable() const return m_material != nullptr; } +void NzSprite::SetColor(const NzColor& color) +{ + m_color = color; + m_verticesUpdated = false; +} + +void NzSprite::SetDefaultMaterial() +{ + std::unique_ptr material(new NzMaterial); + material->Enable(nzRendererParameter_FaceCulling, false); + material->EnableLighting(false); + + SetMaterial(material.get()); + + material->SetPersistent(false); + material.release(); +} + void NzSprite::SetMaterial(NzMaterial* material, bool resizeSprite) { m_material = material; - - NzTexture* diffuseMap = m_material->GetDiffuseMap(); - if (resizeSprite && diffuseMap && diffuseMap->IsValid()) - SetSize(NzVector2f(diffuseMap->GetSize())); + if (m_material && resizeSprite) + { + NzTexture* diffuseMap = m_material->GetDiffuseMap(); + if (diffuseMap && diffuseMap->IsValid()) + SetSize(NzVector2f(NzVector2ui(diffuseMap->GetSize()))); + } } void NzSprite::SetSize(const NzVector2f& size) @@ -113,6 +125,7 @@ void NzSprite::SetSize(const NzVector2f& size) // On invalide la bounding box m_boundingVolume.MakeNull(); m_boundingVolumeUpdated = false; + m_verticesUpdated = false; } void NzSprite::SetSize(float sizeX, float sizeY) @@ -122,20 +135,23 @@ void NzSprite::SetSize(float sizeX, float sizeY) void NzSprite::SetTexture(NzTexture* texture, bool resizeSprite) { - std::unique_ptr material(new NzMaterial); - material->SetPersistent(false); + if (!m_material) + SetDefaultMaterial(); + else if (m_material->GetResourceReferenceCount() > 1) + { + m_material = new NzMaterial(*m_material); + m_material->SetPersistent(false); + } - material->Enable(nzRendererParameter_FaceCulling, false); - material->EnableLighting(false); - material->SetDiffuseMap(texture); - - SetMaterial(material.get(), resizeSprite); - material.release(); + m_material->SetDiffuseMap(texture); + if (resizeSprite && texture && texture->IsValid()) + SetSize(NzVector2f(NzVector2ui(texture->GetSize()))); } void NzSprite::SetTextureCoords(const NzRectf& coords) { m_textureCoords = coords; + m_verticesUpdated = false; } void NzSprite::SetTextureRect(const NzRectui& rect) @@ -162,15 +178,34 @@ void NzSprite::SetTextureRect(const NzRectui& rect) SetTextureCoords(NzRectf(invWidth*rect.x, invHeight*rect.y, invWidth*rect.width, invHeight*rect.height)); } +NzSprite& NzSprite::operator=(const NzSprite& sprite) +{ + NzSceneNode::operator=(sprite); + + m_color = sprite.m_color; + m_material = sprite.m_material; + m_textureCoords = sprite.m_textureCoords; + m_size = sprite.m_size; + + // 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_boundingVolumeUpdated = false; + m_verticesUpdated = false; + + return *this; +} + void NzSprite::InvalidateNode() { NzSceneNode::InvalidateNode(); m_boundingVolumeUpdated = false; + m_verticesUpdated = false; } void NzSprite::Register() { + // Le changement de scène peut affecter les sommets + m_verticesUpdated = false; } void NzSprite::Unregister() @@ -180,7 +215,12 @@ void NzSprite::Unregister() void NzSprite::UpdateBoundingVolume() const { if (m_boundingVolume.IsNull()) - m_boundingVolume.Set(-m_size.x*0.5f, -m_size.y*0.5f, 0.f, m_size.x, m_size.y, 0.f); + { + NzVector3f down = m_scene->GetDown(); + NzVector3f right = m_scene->GetRight(); + + m_boundingVolume.Set(NzVector3f(0.f), m_size.x*right + m_size.y*down); + } if (!m_transformMatrixUpdated) UpdateTransformMatrix(); @@ -188,3 +228,30 @@ void NzSprite::UpdateBoundingVolume() const m_boundingVolume.Update(m_transformMatrix); m_boundingVolumeUpdated = true; } + +void NzSprite::UpdateVertices() const +{ + if (!m_transformMatrixUpdated) + UpdateTransformMatrix(); + + NzVector3f down = m_scene->GetDown(); + NzVector3f right = m_scene->GetRight(); + + m_vertices[0].color = m_color; + m_vertices[0].position = m_transformMatrix.Transform(NzVector3f(0.f)); + m_vertices[0].uv.Set(m_textureCoords.GetCorner(nzRectCorner_LeftTop)); + + m_vertices[1].color = m_color; + m_vertices[1].position = m_transformMatrix.Transform(m_size.x*right); + m_vertices[1].uv.Set(m_textureCoords.GetCorner(nzRectCorner_RightTop)); + + m_vertices[2].color = m_color; + m_vertices[2].position = m_transformMatrix.Transform(m_size.y*down); + m_vertices[2].uv.Set(m_textureCoords.GetCorner(nzRectCorner_LeftBottom)); + + m_vertices[3].color = m_color; + m_vertices[3].position = m_transformMatrix.Transform(m_size.x*right + m_size.y*down); + m_vertices[3].uv.Set(m_textureCoords.GetCorner(nzRectCorner_RightBottom)); + + m_verticesUpdated = true; +} diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp new file mode 100644 index 000000000..ab028ec91 --- /dev/null +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -0,0 +1,407 @@ +// Copyright (C) 2014 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 +#include +#include +#include +#include + +///TODO: Gérer allocation nouvel atlas + +NzTextSprite::NzTextSprite() : +m_boundingVolume(NzBoundingVolumef::Null()), +m_color(NzColor::White), +m_verticesUpdated(false) +{ + SetDefaultMaterial(); +} + +NzTextSprite::NzTextSprite(const NzTextSprite& sprite) : +NzSceneNode(sprite), +m_atlases(sprite.m_atlases), +m_renderInfos(sprite.m_renderInfos), +m_localVertices(sprite.m_localVertices), +m_vertices(sprite.m_vertices), +m_boundingVolume(sprite.m_boundingVolume), +m_color(sprite.m_color), +m_material(sprite.m_material), +m_localBounds(sprite.m_localBounds), +m_boundingVolumeUpdated(sprite.m_boundingVolumeUpdated), +m_verticesUpdated(sprite.m_verticesUpdated) +{ + SetParent(sprite.GetParent()); + + for (const NzAbstractAtlas* atlas : m_atlases) + atlas->AddListener(this); +} + +NzTextSprite::~NzTextSprite() +{ + ClearAtlases(); +} + +void NzTextSprite::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) 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); + } +} + +void NzTextSprite::Clear() +{ + ClearAtlases(); + m_boundingVolume.MakeNull(); + m_localVertices.clear(); + m_renderInfos.clear(); + m_vertices.clear(); +} + +const NzBoundingVolumef& NzTextSprite::GetBoundingVolume() const +{ + if (!m_boundingVolumeUpdated) + UpdateBoundingVolume(); + + return m_boundingVolume; +} + +const NzColor& NzTextSprite::GetColor() const +{ + return m_color; +} + +NzMaterial* NzTextSprite::GetMaterial() const +{ + return m_material; +} + +nzSceneNodeType NzTextSprite::GetSceneNodeType() const +{ + return nzSceneNodeType_TextSprite; +} + +void NzTextSprite::InvalidateVertices() +{ + m_verticesUpdated = false; +} + +bool NzTextSprite::IsDrawable() const +{ + return m_material != nullptr; +} + +void NzTextSprite::SetColor(const NzColor& color) +{ + m_color = color; + m_verticesUpdated = false; +} + +void NzTextSprite::SetDefaultMaterial() +{ + std::unique_ptr material(new NzMaterial); + material->Enable(nzRendererParameter_Blend, true); + material->Enable(nzRendererParameter_DepthWrite, false); + material->Enable(nzRendererParameter_FaceCulling, false); + material->EnableLighting(false); + material->SetDstBlend(nzBlendFunc_InvSrcAlpha); + material->SetSrcBlend(nzBlendFunc_SrcAlpha); + + SetMaterial(material.get()); + + material->SetPersistent(false); + material.release(); +} + +void NzTextSprite::SetMaterial(NzMaterial* material) +{ + m_material = material; +} + +void NzTextSprite::SetText(const NzAbstractTextDrawer& drawer) +{ + ClearAtlases(); + + unsigned int fontCount = drawer.GetFontCount(); + for (unsigned int i = 0; i < fontCount; ++i) + { + const NzAbstractAtlas* atlas = drawer.GetFont(i)->GetAtlas(); + if (m_atlases.insert(atlas).second) + atlas->AddListener(this); + } + + unsigned int glyphCount = drawer.GetGlyphCount(); + m_localVertices.resize(glyphCount * 4); + m_vertices.resize(glyphCount * 4); + + NzTexture* lastTexture = nullptr; + unsigned int* count = nullptr; + for (unsigned int i = 0; i < glyphCount; ++i) + { + const NzAbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i); + + NzTexture* texture = static_cast(glyph.atlas); + if (lastTexture != texture) + { + auto pair = m_renderInfos.insert(std::make_pair(texture, RenderIndices{0U, 0U})); + + count = &pair.first->second.count; + lastTexture = texture; + } + + (*count)++; + } + + // Attribution des indices + unsigned int index = 0; + for (auto& pair : m_renderInfos) + { + RenderIndices& indices = pair.second; + + indices.first = index; + + index += indices.count; + indices.count = 0; // On réinitialise count à zéro (on va s'en servir pour 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) + { + const NzAbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i); + + NzTexture* texture = static_cast(glyph.atlas); + if (lastTexture != texture) + { + indices = &m_renderInfos[texture]; // On a changé de texture, on ajuste le pointeur + 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; + float invHeight = 1.f/size.y; + + NzRectf uvRect(glyph.atlasRect); + uvRect.x *= invWidth; + uvRect.y *= invHeight; + uvRect.width *= invWidth; + uvRect.height *= invHeight; + + // Extraction des quatre coins et attribution + NzSparsePtr texCoord = texCoordPtr + indices->first*4 + indices->count*4; + if (!glyph.flipped) + { + // 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); + } + + // Et on passe au prochain + indices->count++; + } + + m_localBounds = drawer.GetBounds(); + m_boundingVolume.MakeNull(); + m_boundingVolumeUpdated = false; + m_verticesUpdated = false; +} + +NzTextSprite& NzTextSprite::operator=(const NzTextSprite& text) +{ + NzSceneNode::operator=(text); + + m_atlases = text.m_atlases; + m_color = text.m_color; + m_material = text.m_material; + m_renderInfos = text.m_renderInfos; + m_localBounds = text.m_localBounds; + m_localVertices = text.m_localVertices; + + // 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_boundingVolumeUpdated = false; + m_verticesUpdated = false; + + return *this; +} + +void NzTextSprite::ClearAtlases() +{ + for (const NzAbstractAtlas* atlas : m_atlases) + atlas->RemoveListener(this); + + m_atlases.clear(); +} + +void NzTextSprite::InvalidateNode() +{ + NzSceneNode::InvalidateNode(); + + m_boundingVolumeUpdated = false; + m_verticesUpdated = false; +} + +bool NzTextSprite::OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata) +{ + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + if (m_atlases.find(atlas) == m_atlases.end()) + { + NazaraInternalError("Not listening to " + NzString::Pointer(atlas)); + return false; + } + #endif + + NazaraWarning("TextSprite " + NzString::Pointer(this) + " has been cleared because atlas " + NzString::Pointer(atlas) + " that was under use has been cleared"); + Clear(); + + return false; +} + +bool NzTextSprite::OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + if (m_atlases.find(atlas) == m_atlases.end()) + { + NazaraInternalError("Not listening to " + NzString::Pointer(atlas)); + return false; + } + #endif + + NzTexture* oldTexture = static_cast(oldLayer); + NzTexture* newTexture = static_cast(newLayer); + + auto it = m_renderInfos.find(oldTexture); + if (it != m_renderInfos.end()) + { + // Nous utilisons bien cette texture, nous devons mettre à jour les coordonnées de texture + RenderIndices indices = std::move(it->second); + + NzVector2ui oldSize(oldTexture->GetSize()); + NzVector2ui newSize(newTexture->GetSize()); + NzVector2f scale = NzVector2f(oldSize)/NzVector2f(newSize); + + NzSparsePtr texCoordPtr(&m_vertices[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; + } + + // Nous enlevons l'ancienne texture et rajoutons la nouvelle à sa place (pour les mêmes indices) + m_renderInfos.erase(it); + m_renderInfos.insert(std::make_pair(newTexture, std::move(indices))); + } + + return true; +} + +void NzTextSprite::OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata) +{ + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + if (m_atlases.find(atlas) == m_atlases.end()) + { + NazaraInternalError("Not listening to " + NzString::Pointer(atlas)); + return; + } + #endif + + NazaraWarning("TextSprite " + NzString::Pointer(this) + " has been cleared because atlas " + NzString::Pointer(atlas) + " that was under use has been released"); + Clear(); +} + +void NzTextSprite::Register() +{ + // Le changement de scène peut affecter les sommets + m_verticesUpdated = false; +} + +void NzTextSprite::Unregister() +{ +} + +void NzTextSprite::UpdateBoundingVolume() const +{ + if (m_boundingVolume.IsNull()) + { + NzVector3f down = m_scene->GetDown(); + NzVector3f right = m_scene->GetRight(); + + m_boundingVolume.Set(NzVector3f(0.f), static_cast(m_localBounds.width)*right + static_cast(m_localBounds.height)*down); + } + + if (!m_transformMatrixUpdated) + UpdateTransformMatrix(); + + m_boundingVolume.Update(m_transformMatrix); + m_boundingVolumeUpdated = true; +} + +void NzTextSprite::UpdateVertices() const +{ + if (!m_transformMatrixUpdated) + UpdateTransformMatrix(); + + NzVector3f down = m_scene->GetDown(); + NzVector3f right = m_scene->GetRight(); + + NzSparsePtr colorPtr(&m_vertices[0].color, sizeof(NzVertexStruct_XYZ_Color_UV)); + NzSparsePtr posPtr(&m_vertices[0].position, sizeof(NzVertexStruct_XYZ_Color_UV)); + + for (auto& pair : m_renderInfos) + { + RenderIndices& indices = pair.second; + + NzSparsePtr color = colorPtr + indices.first*4; + NzSparsePtr pos = posPtr + indices.first*4; + NzVertexStruct_XY_Color* 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); + *color++ = m_color * localVertex->color; + + localVertex++; + } + } + } + + m_verticesUpdated = true; +} diff --git a/src/Nazara/Graphics/View.cpp b/src/Nazara/Graphics/View.cpp index 44d00294c..fb55c5054 100644 --- a/src/Nazara/Graphics/View.cpp +++ b/src/Nazara/Graphics/View.cpp @@ -24,7 +24,7 @@ m_zNear(-1.f) NzView::NzView(const NzVector2f& size) : NzView() // On délègue { - m_size = size; + SetSize(size); } NzView::~NzView() @@ -80,6 +80,21 @@ const NzFrustumf& NzView::GetFrustum() const return m_frustum; } +NzVector3f NzView::GetGlobalForward() const +{ + return NzVector3f::UnitZ(); +} + +NzVector3f NzView::GetGlobalRight() const +{ + return NzVector3f::UnitX(); +} + +NzVector3f NzView::GetGlobalUp() const +{ + return -NzVector3f::UnitY(); +} + const NzMatrix4f& NzView::GetProjectionMatrix() const { if (!m_projectionMatrixUpdated) @@ -132,6 +147,17 @@ float NzView::GetZNear() const return m_zNear; } +void NzView::SetSize(const NzVector2f& size) +{ + SetSize(size.x, size.y); +} + +void NzView::SetSize(float width, float height) +{ + m_size.Set(width, height); + m_projectionMatrixUpdated = false; +} + void NzView::SetTarget(const NzRenderTarget* renderTarget) { if (m_target) diff --git a/src/Nazara/Renderer/DebugDrawer.cpp b/src/Nazara/Renderer/DebugDrawer.cpp index 066566bc1..5f7090a81 100644 --- a/src/Nazara/Renderer/DebugDrawer.cpp +++ b/src/Nazara/Renderer/DebugDrawer.cpp @@ -159,64 +159,64 @@ void NzDebugDrawer::Draw(const NzFrustumf& frustum) NzBufferMapper mapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, 24); NzVertexStruct_XYZ* vertex = reinterpret_cast(mapper.GetPointer()); - vertex->position.Set(frustum.GetCorner(nzCorner_NearLeftBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearRightBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearLeftBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearLeftTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearLeftBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarLeftBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarRightTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarLeftTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarRightTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarRightBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarRightTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearRightTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarLeftBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarRightBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarLeftBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarLeftTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearLeftTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearRightTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearLeftTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarLeftTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearRightBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearRightTop)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightTop)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_NearRightBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; - vertex->position.Set(frustum.GetCorner(nzCorner_FarRightBottom)); + vertex->position.Set(frustum.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; mapper.Unmap(); @@ -241,64 +241,64 @@ void NzDebugDrawer::Draw(const NzOrientedBoxf& orientedBox) NzBufferMapper mapper(s_vertexBuffer, nzBufferAccess_DiscardAndWrite, 0, 24); NzVertexStruct_XYZ* vertex = reinterpret_cast(mapper.GetPointer()); - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearLeftBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearRightBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearLeftBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearLeftTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearLeftBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarLeftBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarRightTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarLeftTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarRightTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarRightBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarRightTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearRightTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarLeftBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarRightBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarLeftBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarLeftTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearLeftTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearRightTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearLeftTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearLeftTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarLeftTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarLeftTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearRightBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearRightTop)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightTop)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_NearRightBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_NearRightBottom)); vertex++; - vertex->position.Set(orientedBox.GetCorner(nzCorner_FarRightBottom)); + vertex->position.Set(orientedBox.GetCorner(nzBoxCorner_FarRightBottom)); vertex++; mapper.Unmap(); @@ -363,6 +363,11 @@ void NzDebugDrawer::Draw(const NzSkeleton* skeleton) } } +void NzDebugDrawer::Draw(const NzVector3f& position, float size) +{ + Draw(NzBoxf(position.x - size*0.5f, position.y - size*0.5f, position.z - size*0.5f, size, size, size)); +} + void NzDebugDrawer::DrawBinormals(const NzStaticMesh* subMesh) { if (!Initialize()) @@ -662,7 +667,7 @@ bool NzDebugDrawer::Initialize() try { NzErrorFlags flags(nzErrorFlag_ThrowException, true); - s_vertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 65365, nzBufferStorage_Hardware, nzBufferUsage_Dynamic); + s_vertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ), 65365, nzDataStorage_Hardware, nzBufferUsage_Dynamic); } catch (const std::exception& e) { diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index ef9e096d9..3edf4e499 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -1463,8 +1463,42 @@ void NzOpenGL::SetViewport(const NzRecti& viewport) bool NzOpenGL::TranslateFormat(nzPixelFormat pixelFormat, Format* format, FormatType type) { + // Par défaut + format->swizzle[0] = GL_RED; + format->swizzle[1] = GL_GREEN; + format->swizzle[2] = GL_BLUE; + format->swizzle[3] = GL_ALPHA; + switch (pixelFormat) { + case nzPixelFormat_A8: + if (type == FormatType_Texture) // Format supporté uniquement par les textures + { + if (GetVersion() >= 300) + { + format->dataFormat = GL_RED; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_R8; + + // Simulation du format + format->swizzle[0] = GL_ONE; + format->swizzle[1] = GL_ONE; + format->swizzle[2] = GL_ONE; + format->swizzle[3] = GL_RED; + } + else + { + // Le bon vieux format GL_ALPHA + format->dataFormat = GL_ALPHA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_ALPHA; + } + + return true; + } + else + return false; + case nzPixelFormat_BGR8: format->dataFormat = GL_BGR; format->dataType = GL_UNSIGNED_BYTE; @@ -1496,8 +1530,58 @@ bool NzOpenGL::TranslateFormat(nzPixelFormat pixelFormat, Format* format, Format return true; case nzPixelFormat_L8: + if (type == FormatType_Texture) // Format supporté uniquement par les textures + { + if (GetVersion() >= 300) + { + format->dataFormat = GL_RED; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_R8; + + // Simulation du format + format->swizzle[0] = GL_RED; + format->swizzle[1] = GL_RED; + format->swizzle[2] = GL_RED; + format->swizzle[3] = GL_ONE; + } + else + { + format->dataFormat = 0x1909; // GL_LUMINANCE + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = 0x1909; // GL_LUMINANCE + } + + return true; + } + else + return false; + case nzPixelFormat_LA8: - return false; + if (type == FormatType_Texture) // Format supporté uniquement par les textures + { + if (GetVersion() >= 300) + { + format->dataFormat = GL_RG; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RG8; + + // Simulation du format + format->swizzle[0] = GL_RED; + format->swizzle[1] = GL_RED; + format->swizzle[2] = GL_RED; + format->swizzle[3] = GL_GREEN; + } + else + { + format->dataFormat = 0x190A; // GL_LUMINANCE_ALPHA + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = 0x190A; // GL_LUMINANCE_ALPHA; + } + + return true; + } + else + return false; case nzPixelFormat_R8: format->dataFormat = GL_RED; diff --git a/src/Nazara/Renderer/RenderTexture.cpp b/src/Nazara/Renderer/RenderTexture.cpp index 5c5ae4cdf..ee53e0ed0 100644 --- a/src/Nazara/Renderer/RenderTexture.cpp +++ b/src/Nazara/Renderer/RenderTexture.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 28e0b5288..0e5b42855 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -92,6 +92,7 @@ namespace bool s_useVertexArrayObjects; unsigned int s_maxColorAttachments; unsigned int s_maxRenderTarget; + unsigned int s_maxTextureSize; unsigned int s_maxTextureUnit; unsigned int s_maxVertexAttribs; @@ -612,6 +613,11 @@ unsigned int NzRenderer::GetMaxRenderTargets() return s_maxRenderTarget; } +unsigned int NzRenderer::GetMaxTextureSize() +{ + return s_maxTextureSize; +} + unsigned int NzRenderer::GetMaxTextureUnits() { return s_maxTextureUnit; @@ -692,7 +698,10 @@ bool NzRenderer::Initialize() return false; } - NzBuffer::SetBufferFunction(nzBufferStorage_Hardware, [](NzBuffer* parent, nzBufferType type) -> NzAbstractBuffer* { return new NzHardwareBuffer(parent, type); } ); + NzBuffer::SetBufferFactory(nzDataStorage_Hardware, [](NzBuffer* parent, nzBufferType type) -> NzAbstractBuffer* + { + return new NzHardwareBuffer(parent, type); + }); for (unsigned int i = 0; i <= nzMatrixType_Max; ++i) { @@ -703,19 +712,19 @@ bool NzRenderer::Initialize() } // Récupération des capacités d'OpenGL - s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter); - s_capabilities[nzRendererCap_ConditionalRendering] = NzOpenGL::IsSupported(nzOpenGLExtension_ConditionalRender); - s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(nzOpenGLExtension_FP64); - s_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5 - s_capabilities[nzRendererCap_Instancing] = NzOpenGL::IsSupported(nzOpenGLExtension_DrawInstanced) && NzOpenGL::IsSupported(nzOpenGLExtension_InstancedArray); + s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter); + s_capabilities[nzRendererCap_ConditionalRendering] = NzOpenGL::IsSupported(nzOpenGLExtension_ConditionalRender); + s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(nzOpenGLExtension_FP64); + s_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5 + s_capabilities[nzRendererCap_Instancing] = NzOpenGL::IsSupported(nzOpenGLExtension_DrawInstanced) && NzOpenGL::IsSupported(nzOpenGLExtension_InstancedArray); s_capabilities[nzRendererCap_MultipleRenderTargets] = (glBindFragDataLocation != nullptr); // Natif depuis OpenGL 2.0 mais inutile sans glBindFragDataLocation - s_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5 - s_capabilities[nzRendererCap_PixelBufferObject] = NzOpenGL::IsSupported(nzOpenGLExtension_PixelBufferObject); - s_capabilities[nzRendererCap_RenderTexture] = NzOpenGL::IsSupported(nzOpenGLExtension_FrameBufferObject); - s_capabilities[nzRendererCap_Texture3D] = true; // Natif depuis OpenGL 1.2 - s_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3 - s_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3 - s_capabilities[nzRendererCap_TextureNPOT] = true; // Natif depuis OpenGL 2.0 + s_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5 + s_capabilities[nzRendererCap_PixelBufferObject] = NzOpenGL::IsSupported(nzOpenGLExtension_PixelBufferObject); + s_capabilities[nzRendererCap_RenderTexture] = NzOpenGL::IsSupported(nzOpenGLExtension_FrameBufferObject); + s_capabilities[nzRendererCap_Texture3D] = true; // Natif depuis OpenGL 1.2 + s_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3 + s_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3 + s_capabilities[nzRendererCap_TextureNPOT] = true; // Natif depuis OpenGL 2.0 NzContext::EnsureContext(); @@ -759,6 +768,10 @@ bool NzRenderer::Initialize() else s_maxTextureUnit = 1; + GLint maxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + s_maxTextureSize = maxTextureSize; + GLint maxVertexAttribs; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); s_maxVertexAttribs = static_cast(maxVertexAttribs); @@ -775,7 +788,7 @@ bool NzRenderer::Initialize() s_updateFlags = Update_Matrices | Update_Shader | Update_VAO; s_vertexBuffer = nullptr; - s_fullscreenQuadBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XY), 4, nzBufferStorage_Hardware, nzBufferUsage_Static); + s_fullscreenQuadBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XY), 4, nzDataStorage_Hardware, nzBufferUsage_Static); float vertices[4*2] = { @@ -796,7 +809,7 @@ bool NzRenderer::Initialize() try { NzErrorFlags errFlags(nzErrorFlag_ThrowException, true); - s_instanceBuffer.Reset(nullptr, NAZARA_RENDERER_INSTANCE_BUFFER_SIZE, nzBufferStorage_Hardware, nzBufferUsage_Dynamic); + s_instanceBuffer.Reset(nullptr, NAZARA_RENDERER_INSTANCE_BUFFER_SIZE, nzDataStorage_Hardware, nzBufferUsage_Dynamic); } catch (const std::exception& e) { @@ -1963,7 +1976,8 @@ void NzRenderer::OnTextureReleased(const NzTexture* texture) { if (unit.texture == texture) unit.texture = nullptr; - // Inutile de changer le flag pour une texture désactivée + + // Inutile de changer le flag pour une texture désactivée } } diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index cb5b4ff45..bee9c9ae8 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -3,16 +3,17 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include +#include #include #include #include +#include #include #include #include -///TODO: Virer les méthodes faisant référence aux faces et gérer ces dernières comme de simples niveaux de profondeurs (malgré OpenGL) - struct NzTextureImpl { GLuint id; @@ -28,112 +29,10 @@ struct NzTextureImpl namespace { - bool CreateTexture(NzTextureImpl* impl, bool proxy) + inline unsigned int GetLevelSize(unsigned int size, nzUInt8 level) { - NzOpenGL::Format openGLFormat; - if (!NzOpenGL::TranslateFormat(impl->format, &openGLFormat, NzOpenGL::FormatType_Texture)) - { - NazaraError("Format " + NzPixelFormat::ToString(impl->format) + " not supported by OpenGL"); - return false; - } - - GLenum target = (proxy) ? NzOpenGL::TextureTargetProxy[impl->type] : NzOpenGL::TextureTarget[impl->type]; - switch (impl->type) - { - case nzImageType_1D: - { - if (glTexStorage1D && !proxy) // Les drivers AMD semblent ne pas aimer glTexStorage avec un format proxy - glTexStorage1D(target, impl->levelCount, openGLFormat.internalFormat, impl->width); - else - { - unsigned int w = impl->width; - for (nzUInt8 level = 0; level < impl->levelCount; ++level) - { - glTexImage1D(target, level, openGLFormat.internalFormat, w, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - if (w > 1U) - w >>= 1; - } - } - break; - } - - case nzImageType_1D_Array: - case nzImageType_2D: - { - if (glTexStorage2D && !proxy) - glTexStorage2D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height); - else - { - unsigned int w = impl->width; - unsigned int h = impl->height; - for (nzUInt8 level = 0; level < impl->levelCount; ++level) - { - glTexImage2D(target, level, openGLFormat.internalFormat, w, h, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - if (w > 1U) - w >>= 1; - - if (h > 1U) - h >>= 1; - } - } - break; - } - - case nzImageType_2D_Array: - case nzImageType_3D: - { - if (glTexStorage3D && !proxy) - glTexStorage3D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height, impl->depth); - else - { - unsigned int w = impl->width; - unsigned int h = impl->height; - unsigned int d = impl->depth; - for (nzUInt8 level = 0; level < impl->levelCount; ++level) - { - glTexImage3D(target, level, openGLFormat.internalFormat, w, h, d, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - if (w > 1U) - w >>= 1; - - if (h > 1U) - h >>= 1; - - if (d > 1U) - d >>= 1; - } - } - break; - } - - case nzImageType_Cubemap: - { - if (glTexStorage2D && !proxy) - glTexStorage2D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height); - else - { - unsigned int size = impl->width; // Les cubemaps ont une longueur et largeur identique - for (nzUInt8 level = 0; level < impl->levelCount; ++level) - { - for (GLenum face : NzOpenGL::CubemapFace) - glTexImage2D(face, level, openGLFormat.internalFormat, size, size, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - - if (size > 1U) - size >>= 1; - } - } - break; - } - } - - if (proxy) - { - GLint internalFormat = 0; - glGetTexLevelParameteriv(target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat); - if (internalFormat == 0) - return false; - } - - return true; + // Contrairement à la classe Image, un appel à GetLevelSize(0, level) n'est pas possible + return std::max(size >> level, 1U); } inline void SetUnpackAlignement(nzUInt8 bpp) @@ -149,17 +48,16 @@ namespace } } +NzTexture::NzTexture(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount) +{ + NzErrorFlags flags(nzErrorFlag_ThrowException); + Create(type, format, width, height, depth, levelCount); +} + NzTexture::NzTexture(const NzImage& image) { + NzErrorFlags flags(nzErrorFlag_ThrowException); LoadFromImage(image); - - #ifdef NAZARA_DEBUG - if (!m_impl) - { - NazaraError("Failed to create texture"); - throw std::runtime_error("Constructor failed"); - } - #endif } NzTexture::~NzTexture() @@ -220,7 +118,7 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt if (depth > 1) { - NazaraError("1D textures must be 1 depth"); + NazaraError("1D textures must be 1 deep"); return false; } break; @@ -229,7 +127,7 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt case nzImageType_2D: if (depth > 1) { - NazaraError("2D textures must be 1 depth"); + NazaraError("2D textures must be 1 deep"); return false; } break; @@ -241,7 +139,7 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt case nzImageType_Cubemap: if (depth > 1) { - NazaraError("Cubemaps must be 1 depth"); + NazaraError("Cubemaps must be 1 deep"); return false; } @@ -264,40 +162,44 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt levelCount = 1; } - std::unique_ptr impl(new NzTextureImpl); - glGenTextures(1, &impl->id); + m_impl = new NzTextureImpl; + m_impl->depth = GetValidSize(depth); + m_impl->format = format; + m_impl->height = GetValidSize(height); + m_impl->levelCount = levelCount; + m_impl->type = type; + m_impl->width = GetValidSize(width); - impl->depth = GetValidSize(depth); - impl->format = format; - impl->height = GetValidSize(height); - impl->levelCount = levelCount; - impl->type = type; - impl->width = GetValidSize(width); + glGenTextures(1, &m_impl->id); + NzOpenGL::BindTexture(m_impl->type, m_impl->id); - NzOpenGL::BindTexture(impl->type, impl->id); - - // Vérification du support par la carte graphique - if (!CreateTexture(impl.get(), true)) + // En cas d'erreur (sortie prématurée), on détruit la texture + NzCallOnExit onExit([this]() { - NzOpenGL::DeleteTexture(m_impl->id); + Destroy(); + }); + // On précise le nombre de mipmaps avant la spécification de la texture + // https://www.opengl.org/wiki/Hardware_specifics:_NVidia + SetMipmapRange(0, m_impl->levelCount-1); + if (m_impl->levelCount > 1U) + EnableMipmapping(true); + + // Vérification du support par la carte graphique (texture proxy) + if (!CreateTexture(true)) + { NazaraError("Texture's parameters not supported by driver"); return false; } // Création de la texture - if (!CreateTexture(impl.get(), false)) + if (!CreateTexture(false)) { - NzOpenGL::DeleteTexture(m_impl->id); - NazaraError("Failed to create texture"); return false; } - m_impl = impl.release(); - - if (m_impl->levelCount > 1U) - EnableMipmapping(true); + onExit.Reset(); NotifyCreated(); return true; @@ -346,29 +248,10 @@ bool NzTexture::Download(NzImage* image) const return false; } - unsigned int width = m_impl->width; - unsigned int height = m_impl->height; - unsigned int depth = m_impl->depth; - // Téléchargement... NzOpenGL::BindTexture(m_impl->type, m_impl->id); for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) - { - glGetTexImage(NzOpenGL::TextureTarget[m_impl->type], level, format.dataFormat, format.dataType, image->GetPixels(level)); - - if (width > 1) - width >>= 1; - - if (height > 1) - height >>= 1; - - if (depth > 1) - depth >>= 1; - } - - // Inversion de la texture pour le repère d'OpenGL - if (!image->FlipVertically()) - NazaraWarning("Failed to flip image"); + glGetTexImage(NzOpenGL::TextureTarget[m_impl->type], level, format.dataFormat, format.dataType, image->GetPixels(0, 0, 0, level)); return true; } @@ -390,7 +273,11 @@ bool NzTexture::EnableMipmapping(bool enable) } if (m_impl->levelCount == 1) // Transformation d'une texture sans mipmaps vers une texture avec mipmaps + { + ///FIXME: Est-ce que cette opération est seulement possible ? m_impl->levelCount = NzImage::GetMaxLevel(m_impl->width, m_impl->height, m_impl->depth); + SetMipmapRange(0, m_impl->levelCount-1); + } if (!m_impl->mipmapping && enable) m_impl->mipmapsUpdated = false; @@ -410,7 +297,7 @@ void NzTexture::EnsureMipmapsUpdate() const } } -nzUInt8 NzTexture::GetBytesPerPixel() const +unsigned int NzTexture::GetDepth(nzUInt8 level) const { #if NAZARA_RENDERER_SAFE if (!m_impl) @@ -420,20 +307,7 @@ nzUInt8 NzTexture::GetBytesPerPixel() const } #endif - return NzPixelFormat::GetBytesPerPixel(m_impl->format); -} - -unsigned int NzTexture::GetDepth() const -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return 0; - } - #endif - - return m_impl->depth; + return GetLevelSize(m_impl->depth, level); } nzPixelFormat NzTexture::GetFormat() const @@ -449,7 +323,7 @@ nzPixelFormat NzTexture::GetFormat() const return m_impl->format; } -unsigned int NzTexture::GetHeight() const +unsigned int NzTexture::GetHeight(nzUInt8 level) const { #if NAZARA_RENDERER_SAFE if (!m_impl) @@ -459,20 +333,103 @@ unsigned int NzTexture::GetHeight() const } #endif - return m_impl->height; + return GetLevelSize(m_impl->height, level); } -NzVector2ui NzTexture::GetSize() const +nzUInt8 NzTexture::GetLevelCount() const { #if NAZARA_RENDERER_SAFE if (!m_impl) { NazaraError("Texture must be valid"); - return NzVector2ui(0, 0); + return 0; } #endif - return NzVector2ui(m_impl->width, m_impl->height); + return m_impl->levelCount; +} + +nzUInt8 NzTexture::GetMaxLevel() const +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Texture must be valid"); + return 0; + } + #endif + + return NzImage::GetMaxLevel(m_impl->type, m_impl->width, m_impl->height, m_impl->depth); +} + +unsigned int NzTexture::GetMemoryUsage() const +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Texture must be valid"); + return 0; + } + #endif + + unsigned int width = m_impl->width; + unsigned int height = m_impl->height; + unsigned int depth = m_impl->depth; + + unsigned int size = 0; + for (unsigned int i = 0; i < m_impl->levelCount; ++i) + { + size += width * height * depth; + + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + if (depth > 1) + depth >>= 1; + } + + if (m_impl->type == nzImageType_Cubemap) + size *= 6; + + return size * NzPixelFormat::GetBytesPerPixel(m_impl->format); +} + +unsigned int NzTexture::GetMemoryUsage(nzUInt8 level) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Texture must be valid"); + return 0; + } + + if (level >= m_impl->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); + return 0; + } + #endif + + return (GetLevelSize(m_impl->width, level)) * + (GetLevelSize(m_impl->height, level)) * + ((m_impl->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_impl->depth, level)) * + NzPixelFormat::GetBytesPerPixel(m_impl->format); +} + +NzVector3ui NzTexture::GetSize(nzUInt8 level) const +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Texture must be valid"); + return NzVector3ui(0, 0, 0); + } + #endif + + return NzVector3ui(GetLevelSize(m_impl->width, level), GetLevelSize(m_impl->height, level), GetLevelSize(m_impl->depth, level)); } nzImageType NzTexture::GetType() const @@ -488,7 +445,7 @@ nzImageType NzTexture::GetType() const return m_impl->type; } -unsigned int NzTexture::GetWidth() const +unsigned int NzTexture::GetWidth(nzUInt8 level) const { #if NAZARA_RENDERER_SAFE if (!m_impl) @@ -498,7 +455,7 @@ unsigned int NzTexture::GetWidth() const } #endif - return m_impl->width; + return GetLevelSize(m_impl->width, level); } bool NzTexture::HasMipmaps() const @@ -514,30 +471,17 @@ bool NzTexture::HasMipmaps() const return m_impl->levelCount > 1; } -bool NzTexture::IsCompressed() const +void NzTexture::InvalidateMipmaps() { #if NAZARA_RENDERER_SAFE if (!m_impl) { - NazaraError("Texture must be valid"); - return false; + NazaraInternalError("Texture must be valid"); + return; } #endif - return NzPixelFormat::IsCompressed(m_impl->format); -} - -bool NzTexture::IsCubemap() const -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return false; - } - #endif - - return m_impl->type == nzImageType_Cubemap; + m_impl->mipmapsUpdated = false; } bool NzTexture::IsValid() const @@ -573,6 +517,7 @@ bool NzTexture::LoadFromImage(const NzImage& image, bool generateMipmaps) nzPixelFormat format = newImage.GetFormat(); if (!IsFormatSupported(format)) { + ///TODO: Sélectionner le format le plus adapté selon les composantes présentes dans le premier format nzPixelFormat newFormat = (NzPixelFormat::HasAlpha(format)) ? nzPixelFormat_BGRA8 : nzPixelFormat_BGR8; NazaraWarning("Format " + NzPixelFormat::ToString(format) + " not supported, trying to convert it to " + NzPixelFormat::ToString(newFormat) + "..."); @@ -604,17 +549,20 @@ bool NzTexture::LoadFromImage(const NzImage& image, bool generateMipmaps) return false; } + NzCallOnExit destroyOnExit([this]() + { + Destroy(); + }); + if (type == nzImageType_Cubemap) { for (nzUInt8 level = 0; level < levelCount; ++level) { for (unsigned int i = 0; i <= nzCubemapFace_Max; ++i) { - if (!UpdateFace(static_cast(i), newImage.GetConstPixels(0, 0, i, level), level)) + if (!Update(newImage.GetConstPixels(0, 0, i, level), NzRectui(0, 0, newImage.GetWidth(level), newImage.GetHeight(level)), i, level)) { NazaraError("Failed to update texture"); - Destroy(); - return false; } } @@ -627,13 +575,13 @@ bool NzTexture::LoadFromImage(const NzImage& image, bool generateMipmaps) if (!Update(newImage.GetConstPixels(0, 0, 0, level), level)) { NazaraError("Failed to update texture"); - Destroy(); - return false; } } } + destroyOnExit.Reset(); + return true; } @@ -793,7 +741,7 @@ bool NzTexture::LoadFaceFromFile(nzCubemapFace face, const NzString& filePath, c return false; } - return UpdateFace(face, image); + return Update(image, NzRectui(0, 0, faceSize, faceSize), face); } bool NzTexture::LoadFaceFromMemory(nzCubemapFace face, const void* data, std::size_t size, const NzImageParams& params) @@ -832,7 +780,7 @@ bool NzTexture::LoadFaceFromMemory(nzCubemapFace face, const void* data, std::si return false; } - return UpdateFace(face, image); + return Update(image, NzRectui(0, 0, faceSize, faceSize), face); } bool NzTexture::LoadFaceFromStream(nzCubemapFace face, NzInputStream& stream, const NzImageParams& params) @@ -872,7 +820,7 @@ bool NzTexture::LoadFaceFromStream(nzCubemapFace face, NzInputStream& stream, co return false; } - return UpdateFace(face, image); + return Update(image, NzRectui(0, 0, faceSize, faceSize), face); } bool NzTexture::SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel) @@ -992,7 +940,7 @@ bool NzTexture::Update(const nzUInt8* pixels, unsigned int srcWidth, unsigned in } #endif - return Update(pixels, NzBoxui(std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), std::max(m_impl->depth >> level, 1U)), srcWidth, srcHeight, level); + return Update(pixels, NzBoxui(GetLevelSize(m_impl->width, level), GetLevelSize(m_impl->height, level), GetLevelSize(m_impl->depth, level)), srcWidth, srcHeight, level); } bool NzTexture::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) @@ -1004,12 +952,6 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int s return false; } - if (m_impl->type == nzImageType_Cubemap) - { - NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); - return false; - } - if (!pixels) { NazaraError("Invalid pixel source"); @@ -1023,12 +965,13 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int s } #endif - unsigned int height = std::max(m_impl->height >> level, 1U); + unsigned int height = GetLevelSize(m_impl->height, level); #if NAZARA_RENDERER_SAFE - if (box.x+box.width > std::max(m_impl->width >> level, 1U) || - box.y+box.height > height || - box.z+box.depth > std::max(m_impl->depth >> level, 1U)) + unsigned int width = GetLevelSize(m_impl->width, level); + unsigned int depth = (m_impl->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_impl->depth, level); + if (box.x+box.width > width || box.y+box.height > height || box.z+box.depth > depth || + (m_impl->type == nzImageType_Cubemap && box.depth > 1)) // Nous n'autorisons pas de modifier plus d'une face du cubemap à la fois { NazaraError("Cube dimensions are out of bounds"); return false; @@ -1061,16 +1004,16 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int s case nzImageType_1D_Array: case nzImageType_2D: - glTexSubImage2D(NzOpenGL::TextureTarget[m_impl->type], level, box.x, height-box.height-box.y, box.width, box.height, format.dataFormat, format.dataType, pixels); + glTexSubImage2D(NzOpenGL::TextureTarget[m_impl->type], level, box.x, box.y, box.width, box.height, format.dataFormat, format.dataType, pixels); break; case nzImageType_2D_Array: case nzImageType_3D: - glTexSubImage3D(NzOpenGL::TextureTarget[m_impl->type], level, box.x, height-box.height-box.y, box.z, box.width, box.height, box.depth, format.dataFormat, format.dataType, pixels); + glTexSubImage3D(NzOpenGL::TextureTarget[m_impl->type], level, box.x, box.y, box.z, box.width, box.height, box.depth, format.dataFormat, format.dataType, pixels); break; case nzImageType_Cubemap: - NazaraError("Update used on a cubemap texture, please enable safe mode"); + glTexSubImage2D(NzOpenGL::CubemapFace[box.z], level, box.x, box.y, box.width, box.height, format.dataFormat, format.dataType, pixels); break; } @@ -1082,118 +1025,6 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int return Update(pixels, NzBoxui(rect.x, rect.y, z, rect.width, rect.height, 1), srcWidth, srcHeight, level); } -bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 level) -{ - #if NAZARA_RENDERER_SAFE - if (!image.IsValid()) - { - NazaraError("Image must be valid"); - return false; - } - - if (image.GetFormat() != m_impl->format) - { - NazaraError("Image format does not match texture format"); - return false; - } - #endif - - return UpdateFace(face, image.GetConstPixels(0, 0, 0, level), NzRectui(0, 0, image.GetWidth(level), image.GetHeight(level)), 0, 0, level); -} - -bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, const NzRectui& rect, nzUInt8 level) -{ - #if NAZARA_RENDERER_SAFE - if (!image.IsValid()) - { - NazaraError("Image must be valid"); - return false; - } - - if (image.GetFormat() != m_impl->format) - { - NazaraError("Image format does not match texture format"); - return false; - } - #endif - - return UpdateFace(face, image.GetConstPixels(0, 0, 0, level), rect, image.GetWidth(level), image.GetHeight(level), level); -} - -bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return false; - } - #endif - - return UpdateFace(face, pixels, NzRectui(0, 0, m_impl->width, m_impl->height), srcWidth, srcHeight, level); -} - -bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return false; - } - - if (m_impl->type != nzImageType_Cubemap) - { - NazaraError("UpdateFace is designed for cubemaps, use Update instead"); - return false; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return false; - } - - if (!rect.IsValid()) - { - NazaraError("Invalid rectangle"); - return false; - } - #endif - - unsigned int height = std::max(m_impl->height >> level, 1U); - - #if NAZARA_RENDERER_SAFE - if (rect.x+rect.width > std::max(m_impl->width >> level, 1U) || rect.y+rect.height > height) - { - NazaraError("Rectangle dimensions are out of bounds"); - return false; - } - - if (level >= m_impl->levelCount) - { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); - return false; - } - #endif - - NzOpenGL::Format format; - if (!NzOpenGL::TranslateFormat(m_impl->format, &format, NzOpenGL::FormatType_Texture)) - { - NazaraError("Failed to get OpenGL format"); - return false; - } - - SetUnpackAlignement(NzPixelFormat::GetBytesPerPixel(m_impl->format)); - glPixelStorei(GL_UNPACK_ROW_LENGTH, srcWidth); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, srcHeight); - - NzOpenGL::BindTexture(m_impl->type, m_impl->id); - glTexSubImage2D(NzOpenGL::CubemapFace[face], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, pixels); - - return true; -} - unsigned int NzTexture::GetOpenGLID() const { #if NAZARA_RENDERER_SAFE @@ -1226,8 +1057,11 @@ bool NzTexture::IsFormatSupported(nzPixelFormat format) switch (format) { // Formats de base + case nzPixelFormat_A8: case nzPixelFormat_BGR8: case nzPixelFormat_BGRA8: + case nzPixelFormat_L8: + case nzPixelFormat_LA8: case nzPixelFormat_RGB8: case nzPixelFormat_RGBA8: return true; @@ -1286,12 +1120,7 @@ bool NzTexture::IsFormatSupported(nzPixelFormat format) case nzPixelFormat_Stencil16: return false; - // Dépréciés depuis OpenGL 3 - ///FIXME: Il doit bien exister des remplaçants (GL_RED ?) - case nzPixelFormat_L8: - case nzPixelFormat_LA8: - return false; - + // Formats compressés case nzPixelFormat_DXT1: case nzPixelFormat_DXT3: case nzPixelFormat_DXT5: @@ -1302,7 +1131,6 @@ bool NzTexture::IsFormatSupported(nzPixelFormat format) } NazaraError("Invalid pixel format"); - return false; } @@ -1330,15 +1158,119 @@ bool NzTexture::IsTypeSupported(nzImageType type) return false; } -void NzTexture::InvalidateMipmaps() +bool NzTexture::CreateTexture(bool proxy) { - #if NAZARA_RENDERER_SAFE - if (!m_impl) + NzOpenGL::Format openGLFormat; + if (!NzOpenGL::TranslateFormat(m_impl->format, &openGLFormat, NzOpenGL::FormatType_Texture)) { - NazaraInternalError("Texture must be valid"); - return; + NazaraError("Format " + NzPixelFormat::ToString(m_impl->format) + " not supported by OpenGL"); + return false; } - #endif - m_impl->mipmapsUpdated = false; + GLenum target = (proxy) ? NzOpenGL::TextureTargetProxy[m_impl->type] : NzOpenGL::TextureTarget[m_impl->type]; + switch (m_impl->type) + { + case nzImageType_1D: + { + if (glTexStorage1D && !proxy) // Les drivers AMD semblent ne pas aimer glTexStorage avec un format proxy + glTexStorage1D(target, m_impl->levelCount, openGLFormat.internalFormat, m_impl->width); + else + { + unsigned int w = m_impl->width; + for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) + { + glTexImage1D(target, level, openGLFormat.internalFormat, w, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + if (w > 1U) + w >>= 1; + } + } + break; + } + + case nzImageType_1D_Array: + case nzImageType_2D: + { + if (glTexStorage2D && !proxy) + glTexStorage2D(target, m_impl->levelCount, openGLFormat.internalFormat, m_impl->width, m_impl->height); + else + { + unsigned int w = m_impl->width; + unsigned int h = m_impl->height; + for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) + { + glTexImage2D(target, level, openGLFormat.internalFormat, w, h, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + if (w > 1U) + w >>= 1; + + if (h > 1U) + h >>= 1; + } + } + break; + } + + case nzImageType_2D_Array: + case nzImageType_3D: + { + if (glTexStorage3D && !proxy) + glTexStorage3D(target, m_impl->levelCount, openGLFormat.internalFormat, m_impl->width, m_impl->height, m_impl->depth); + else + { + unsigned int w = m_impl->width; + unsigned int h = m_impl->height; + unsigned int d = m_impl->depth; + for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) + { + glTexImage3D(target, level, openGLFormat.internalFormat, w, h, d, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + if (w > 1U) + w >>= 1; + + if (h > 1U) + h >>= 1; + + if (d > 1U) + d >>= 1; + } + } + break; + } + + case nzImageType_Cubemap: + { + if (glTexStorage2D && !proxy) + glTexStorage2D(target, m_impl->levelCount, openGLFormat.internalFormat, m_impl->width, m_impl->height); + else + { + unsigned int size = m_impl->width; // Les cubemaps ont une longueur et largeur identique + for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) + { + for (GLenum face : NzOpenGL::CubemapFace) + glTexImage2D(face, level, openGLFormat.internalFormat, size, size, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + + if (size > 1U) + size >>= 1; + } + } + break; + } + } + + if (proxy) + { + GLint internalFormat = 0; + glGetTexLevelParameteriv(target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat); + if (internalFormat == 0) + return false; + } + + // Application du swizzle + if (!proxy && NzOpenGL::GetVersion() >= 300) + { + glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, openGLFormat.swizzle[0]); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, openGLFormat.swizzle[1]); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, openGLFormat.swizzle[2]); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, openGLFormat.swizzle[3]); + } + + return true; } diff --git a/src/Nazara/Utility/AbstractAtlas.cpp b/src/Nazara/Utility/AbstractAtlas.cpp new file mode 100644 index 000000000..dac73acf7 --- /dev/null +++ b/src/Nazara/Utility/AbstractAtlas.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +NzAbstractAtlas::NzAbstractAtlas() : +m_listenersLocked(false) +{ +} + +NzAbstractAtlas::~NzAbstractAtlas() +{ + m_listenersLocked = true; + for (auto& pair : m_listeners) + pair.first->OnAtlasReleased(this, pair.second); +} + +void NzAbstractAtlas::AddListener(Listener* listener, void* userdata) const +{ + if (!m_listenersLocked) + m_listeners.insert(std::make_pair(listener, userdata)); +} + +void NzAbstractAtlas::RemoveListener(Listener* listener) const +{ + if (!m_listenersLocked) + m_listeners.erase(listener); +} + +void NzAbstractAtlas::NotifyCleared() +{ + m_listenersLocked = true; + + auto it = m_listeners.begin(); + while (it != m_listeners.end()) + { + if (!it->first->OnAtlasCleared(this, it->second)) + m_listeners.erase(it++); + else + ++it; + } + + m_listenersLocked = false; +} + +void NzAbstractAtlas::NotifyLayerChange(NzAbstractImage* oldLayer, NzAbstractImage* newLayer) +{ + m_listenersLocked = true; + + auto it = m_listeners.begin(); + while (it != m_listeners.end()) + { + if (!it->first->OnAtlasLayerChange(this, oldLayer, newLayer, it->second)) + m_listeners.erase(it++); + else + ++it; + } + + m_listenersLocked = false; +} + + +NzAbstractAtlas::Listener::~Listener() = default; + +bool NzAbstractAtlas::Listener::OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); + + return true; +} + +bool NzAbstractAtlas::Listener::OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(oldLayer); + NazaraUnused(newLayer); + NazaraUnused(userdata); + + return true; +} + +void NzAbstractAtlas::Listener::OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); +} diff --git a/src/Nazara/Utility/AbstractImage.cpp b/src/Nazara/Utility/AbstractImage.cpp new file mode 100644 index 000000000..9e5ea28a0 --- /dev/null +++ b/src/Nazara/Utility/AbstractImage.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +NzAbstractImage::~NzAbstractImage() = default; + +nzUInt8 NzAbstractImage::GetBytesPerPixel() const +{ + return NzPixelFormat::GetBytesPerPixel(GetFormat()); +} + +bool NzAbstractImage::IsCompressed() const +{ + return NzPixelFormat::IsCompressed(GetFormat()); +} + +bool NzAbstractImage::IsCubemap() const +{ + return GetType() == nzImageType_Cubemap; +} diff --git a/src/Nazara/Utility/AbstractTextDrawer.cpp b/src/Nazara/Utility/AbstractTextDrawer.cpp new file mode 100644 index 000000000..289836751 --- /dev/null +++ b/src/Nazara/Utility/AbstractTextDrawer.cpp @@ -0,0 +1,9 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +NzAbstractTextDrawer::~NzAbstractTextDrawer() = default; + diff --git a/src/Nazara/Utility/Buffer.cpp b/src/Nazara/Utility/Buffer.cpp index 18d4e0583..1a631e990 100644 --- a/src/Nazara/Utility/Buffer.cpp +++ b/src/Nazara/Utility/Buffer.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -16,7 +17,7 @@ namespace { - NzAbstractBuffer* SoftwareBufferFunction(NzBuffer* parent, nzBufferType type) + NzAbstractBuffer* SoftwareBufferFactory(NzBuffer* parent, nzBufferType type) { return new NzSoftwareBuffer(parent, type); } @@ -29,7 +30,7 @@ m_size(0) { } -NzBuffer::NzBuffer(nzBufferType type, unsigned int size, nzBufferStorage storage, nzBufferUsage usage) : +NzBuffer::NzBuffer(nzBufferType type, unsigned int size, nzUInt32 storage, nzBufferUsage usage) : m_type(type), m_impl(nullptr) { @@ -59,22 +60,21 @@ bool NzBuffer::CopyContent(const NzBuffer& buffer) #endif NzBufferMapper mapper(buffer, nzBufferAccess_ReadOnly); - return Fill(mapper.GetPointer(), 0, buffer.GetSize()); } -bool NzBuffer::Create(unsigned int size, nzBufferStorage storage, nzBufferUsage usage) +bool NzBuffer::Create(unsigned int size, nzUInt32 storage, nzBufferUsage usage) { Destroy(); // Notre buffer est-il supporté ? - if (!s_bufferFunctions[storage]) + if (!IsStorageSupported(storage)) { NazaraError("Buffer storage not supported"); return false; } - std::unique_ptr impl(s_bufferFunctions[storage](this, m_type)); + std::unique_ptr impl(s_bufferFactories[storage](this, m_type)); if (!impl->Create(size, usage)) { NazaraError("Failed to create buffer"); @@ -131,7 +131,7 @@ unsigned int NzBuffer::GetSize() const return m_size; } -nzBufferStorage NzBuffer::GetStorage() const +nzUInt32 NzBuffer::GetStorage() const { return m_storage; } @@ -148,7 +148,7 @@ nzBufferUsage NzBuffer::GetUsage() const bool NzBuffer::IsHardware() const { - return m_storage == nzBufferStorage_Hardware; + return m_storage & nzDataStorage_Hardware; } bool NzBuffer::IsValid() const @@ -200,7 +200,7 @@ void* NzBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int siz return m_impl->Map(access, offset, (size == 0) ? m_size-offset : size); } -bool NzBuffer::SetStorage(nzBufferStorage storage) +bool NzBuffer::SetStorage(nzUInt32 storage) { #if NAZARA_UTILITY_SAFE if (!m_impl) @@ -213,13 +213,11 @@ bool NzBuffer::SetStorage(nzBufferStorage storage) if (m_storage == storage) return true; - #if NAZARA_UTILITY_SAFE - if (!IsSupported(storage)) + if (!IsStorageSupported(storage)) { NazaraError("Storage not supported"); return false; } - #endif void* ptr = m_impl->Map(nzBufferAccess_ReadOnly, 0, m_size); if (!ptr) @@ -228,31 +226,36 @@ bool NzBuffer::SetStorage(nzBufferStorage storage) return false; } - NzAbstractBuffer* impl = s_bufferFunctions[storage](this, m_type); + NzCallOnExit unmapMyImpl([this]() + { + m_impl->Unmap(); + }); + + std::unique_ptr impl(s_bufferFactories[storage](this, m_type)); if (!impl->Create(m_size, m_usage)) { NazaraError("Failed to create buffer"); - delete impl; - m_impl->Unmap(); - return false; } + NzCallOnExit destroyImpl([&impl]() + { + impl->Destroy(); + }); + if (!impl->Fill(ptr, 0, m_size)) { NazaraError("Failed to fill buffer"); - impl->Destroy(); - delete impl; - m_impl->Unmap(); - return false; } - m_impl->Unmap(); + destroyImpl.Reset(); + + unmapMyImpl.CallAndReset(); m_impl->Destroy(); delete m_impl; - m_impl = impl; + m_impl = impl.release(); m_storage = storage; return true; @@ -269,29 +272,29 @@ void NzBuffer::Unmap() const #endif if (!m_impl->Unmap()) - NazaraWarning("Failed to unmap buffer (it's content is undefined)"); ///TODO: Unexpected ? + NazaraWarning("Failed to unmap buffer (it's content may be undefined)"); ///TODO: Unexpected ? } -bool NzBuffer::IsSupported(nzBufferStorage storage) +bool NzBuffer::IsStorageSupported(nzUInt32 storage) { - return s_bufferFunctions[storage] != nullptr; + return s_bufferFactories[storage] != nullptr; } -void NzBuffer::SetBufferFunction(nzBufferStorage storage, BufferFunction func) +void NzBuffer::SetBufferFactory(nzUInt32 storage, BufferFactory func) { - s_bufferFunctions[storage] = func; + s_bufferFactories[storage] = func; } bool NzBuffer::Initialize() { - s_bufferFunctions[nzBufferStorage_Software] = SoftwareBufferFunction; + s_bufferFactories[nzDataStorage_Software] = SoftwareBufferFactory; return true; } void NzBuffer::Uninitialize() { - std::memset(s_bufferFunctions, 0, (nzBufferStorage_Max+1)*sizeof(NzBuffer::BufferFunction)); + std::memset(s_bufferFactories, 0, (nzDataStorage_Max+1)*sizeof(NzBuffer::BufferFactory)); } -NzBuffer::BufferFunction NzBuffer::s_bufferFunctions[nzBufferStorage_Max+1] = {0}; +NzBuffer::BufferFactory NzBuffer::s_bufferFactories[nzDataStorage_Max+1] = {0}; diff --git a/src/Nazara/Utility/Font.cpp b/src/Nazara/Utility/Font.cpp new file mode 100644 index 000000000..79ce37878 --- /dev/null +++ b/src/Nazara/Utility/Font.cpp @@ -0,0 +1,484 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +bool NzFontParams::IsValid() const +{ + return true; // Rien à tester +} + +NzFont::NzFont() : +m_glyphBorder(1), +m_minimumSizeStep(1) +{ +} + +NzFont::~NzFont() +{ + Destroy(); + SetAtlas(nullptr); // On libère l'atlas par la même occasion +} + +void NzFont::ClearGlyphCache() +{ + if (m_atlas) + { + if (m_atlas.unique()) + m_atlas->Clear(); // Appellera OnAtlasCleared + else + { + // Au moins une autre police utilise cet atlas, on vire nos glyphes un par un + for (auto mapIt = m_glyphes.begin(); mapIt != m_glyphes.end(); ++mapIt) + { + GlyphMap& glyphMap = mapIt->second; + for (auto glyphIt = glyphMap.begin(); glyphIt != glyphMap.end(); ++glyphIt) + { + Glyph& glyph = glyphIt->second; + m_atlas->Free(&glyph.atlasRect, &glyph.layerIndex, 1); + } + } + + // Destruction des glyphes mémorisés et notification + m_glyphes.clear(); + NotifyModified(ModificationCode_GlyphCacheCleared); + } + } +} + +void NzFont::ClearKerningCache() +{ + m_kerningCache.clear(); + NotifyModified(ModificationCode_KerningCacheCleared); +} + +void NzFont::ClearSizeInfoCache() +{ + m_sizeInfoCache.clear(); + NotifyModified(ModificationCode_SizeInfoCacheCleared); +} + +bool NzFont::Create(NzFontData* data) +{ + Destroy(); + + #if NAZARA_UTILITY_SAFE + if (!data) + { + NazaraError("Invalid font data"); + return false; + } + #endif + + m_data.reset(data); + + return true; +} + +void NzFont::Destroy() +{ + ClearGlyphCache(); + + m_data.reset(); + m_kerningCache.clear(); + m_sizeInfoCache.clear(); +} + +bool NzFont::ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt32 style, NzFontGlyph* glyph) const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Invalid font"); + return false; + } + #endif + + return m_data->ExtractGlyph(characterSize, character, style, glyph); +} + +const NzAbstractAtlas* NzFont::GetAtlas() const +{ + return m_atlas.get(); +} + +unsigned int NzFont::GetCachedGlyphCount(unsigned int characterSize, nzUInt32 style) const +{ + nzUInt64 key = ComputeKey(characterSize, style); + auto it = m_glyphes.find(key); + if (it == m_glyphes.end()) + return 0; + + return it->second.size(); +} + +unsigned int NzFont::GetCachedGlyphCount() const +{ + unsigned int count = 0; + for (auto& pair : m_glyphes) + count += pair.second.size(); + + return count; +} + +NzString NzFont::GetFamilyName() const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Invalid font"); + return NzString("Invalid font"); + } + #endif + + return m_data->GetFamilyName(); +} + +int NzFont::GetKerning(unsigned int characterSize, char32_t first, char32_t second) const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Invalid font"); + return 0; + } + #endif + + // On utilise un cache car la méthode interne QueryKerning peut se révéler coûteuse (car pouvant induire un changement de taille) + auto& map = m_kerningCache[characterSize]; + + nzUInt64 key = (static_cast(first) << 32) | second; // Combinaison de deux caractères 32 bits dans un nombre 64 bits + + auto it = map.find(key); + if (it == map.end()) + { + // Absent du cache: on va demander l'information à la police + int kerning = m_data->QueryKerning(characterSize, first, second); + map.insert(std::make_pair(key, kerning)); + + return kerning; + } + else + return it->second; // Présent dans le cache, tout va bien +} + +const NzFont::Glyph& NzFont::GetGlyph(unsigned int characterSize, nzUInt32 style, char32_t character) const +{ + nzUInt64 key = ComputeKey(characterSize, style); + return PrecacheGlyph(m_glyphes[key], characterSize, style, character); +} + +unsigned int NzFont::GetGlyphBorder() const +{ + return m_glyphBorder; +} + +unsigned int NzFont::GetMinimumStepSize() const +{ + return m_minimumSizeStep; +} + +const NzFont::SizeInfo& NzFont::GetSizeInfo(unsigned int characterSize) const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Invalid font"); + + static SizeInfo dummy; + return dummy; + } + #endif + + auto it = m_sizeInfoCache.find(characterSize); + if (it == m_sizeInfoCache.end()) + { + SizeInfo sizeInfo; + sizeInfo.lineHeight = m_data->QueryLineHeight(characterSize); + sizeInfo.underlinePosition = m_data->QueryUnderlinePosition(characterSize); + sizeInfo.underlineThickness = m_data->QueryUnderlineThickness(characterSize); + + NzFontGlyph glyph; + if (m_data->ExtractGlyph(characterSize, ' ', nzTextStyle_Regular, &glyph)) + sizeInfo.spaceAdvance = glyph.advance; + else + { + NazaraWarning("Failed to extract space character from font, using half the size"); + sizeInfo.spaceAdvance = characterSize/2; + } + + it = m_sizeInfoCache.insert(std::make_pair(characterSize, sizeInfo)).first; + } + + return it->second; +} + +NzString NzFont::GetStyleName() const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Invalid font"); + return NzString("Invalid font"); + } + #endif + + return m_data->GetStyleName(); +} + +bool NzFont::IsValid() const +{ + return m_data != nullptr; +} + +bool NzFont::Precache(unsigned int characterSize, nzUInt32 style, char32_t character) const +{ + nzUInt64 key = ComputeKey(characterSize, style); + return PrecacheGlyph(m_glyphes[key], characterSize, style, character).valid; +} + +bool NzFont::Precache(unsigned int characterSize, nzUInt32 style, const NzString& characterSet) const +{ + unsigned int size; + std::unique_ptr characters(characterSet.GetUtf32Buffer(&size)); + if (!characters) + { + NazaraError("Invalid character set"); + return false; + } + + nzUInt64 key = ComputeKey(characterSize, style); + auto& glyphMap = m_glyphes[key]; + for (unsigned int i = 0; i < size; ++i) + PrecacheGlyph(glyphMap, characterSize, style, characters[i]); + + return true; +} + +bool NzFont::OpenFromFile(const NzString& filePath, const NzFontParams& params) +{ + return NzFontLoader::LoadFromFile(this, filePath, params); +} + +bool NzFont::OpenFromMemory(const void* data, std::size_t size, const NzFontParams& params) +{ + return NzFontLoader::LoadFromMemory(this, data, size, params); +} + +bool NzFont::OpenFromStream(NzInputStream& stream, const NzFontParams& params) +{ + return NzFontLoader::LoadFromStream(this, stream, params); +} + +void NzFont::SetAtlas(std::shared_ptr atlas) +{ + if (m_atlas != atlas) + { + ClearGlyphCache(); + + if (m_atlas) + m_atlas->RemoveListener(this); + + m_atlas = atlas; + if (m_atlas) + m_atlas->AddListener(this); + + NotifyModified(ModificationCode_AtlasChanged); + } +} + +void NzFont::SetGlyphBorder(unsigned int borderSize) +{ + if (m_glyphBorder != borderSize) + { + m_glyphBorder = borderSize; + ClearGlyphCache(); + } +} + +void NzFont::SetMinimumStepSize(unsigned int minimumStepSize) +{ + #if NAZARA_UTILITY_SAFE + if (minimumStepSize == 0) + { + NazaraError("Minimum step size cannot be zero as it implies division by zero"); + return; + } + #endif + + if (m_minimumSizeStep != minimumStepSize) + { + m_minimumSizeStep = minimumStepSize; + ClearGlyphCache(); + } +} + +nzUInt64 NzFont::ComputeKey(unsigned int characterSize, nzUInt32 style) const +{ + // On prend le pas en compte + nzUInt64 sizePart = static_cast((characterSize/m_minimumSizeStep)*m_minimumSizeStep); + + // Ainsi que le style (uniquement le gras et l'italique, les autres sont gérés par un TextDrawer) + nzUInt64 stylePart = 0; + + if (style & nzTextStyle_Bold) + stylePart |= nzTextStyle_Bold; + + if (style & nzTextStyle_Italic) + stylePart |= nzTextStyle_Italic; + + return (stylePart << 32) | sizePart; +} + +bool NzFont::OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + // Est-ce qu'il s'agit bien de notre atlas ? + if (m_atlas.get() != atlas) + { + NazaraInternalError("Notified by a non-listening-to resource"); + return false; // On ne veut plus être notifié par cette ressource, évidemment + } + #endif + + // Notre atlas vient d'être vidé, détruisons le cache de glyphe + m_glyphes.clear(); + NotifyModified(ModificationCode_GlyphCacheCleared); + + return true; +} + +bool NzFont::OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(oldLayer); + NazaraUnused(newLayer); + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + // Est-ce qu'il s'agit bien de notre atlas ? + if (m_atlas.get() != atlas) + { + NazaraInternalError("Notified by a non-listening-to resource"); + return false; // On ne veut plus être notifié par cette ressource, évidemment + } + #endif + + // Pour faciliter le travail des ressources qui nous écoutent + NotifyModified(ModificationCode_AtlasLayerChanged); + + return true; +} + +void NzFont::OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + // Est-ce qu'il s'agit bien de notre atlas ? + if (m_atlas.get() != atlas) + { + NazaraInternalError("Notified by a non-listening-to resource"); + return; + } + #endif + + // Nous ne pouvons pas faire grand chose d'autre que se balancer une erreur à la tête de l'utilisateur avant un potentiel crash... + NazaraError("Atlas has been released while in use"); +} + +const NzFont::Glyph& NzFont::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, nzUInt32 style, char32_t character) const +{ + auto it = glyphMap.find(character); + if (it != glyphMap.end()) // Si le glyphe n'est pas déjà chargé + return it->second; + + Glyph& glyph = glyphMap[character]; // Insertion du glyphe + glyph.requireFauxBold = false; + glyph.requireFauxItalic = false; + glyph.valid = false; + + // On vérifie que le style demandé est supporté par la police (dans le cas contraire il devra être simulé au rendu) + nzUInt32 supportedStyle = style; + if (style & nzTextStyle_Bold && !m_data->SupportsStyle(nzTextStyle_Bold)) + { + glyph.requireFauxBold = true; + supportedStyle &= ~nzTextStyle_Bold; + } + + if (style & nzTextStyle_Italic && !m_data->SupportsStyle(nzTextStyle_Italic)) + { + glyph.requireFauxItalic = true; + supportedStyle &= ~nzTextStyle_Italic; + } + + // Est-ce que la police supporte le style demandé ? + if (style == supportedStyle) + { + // On extrait le glyphe depuis la police + NzFontGlyph fontGlyph; + if (ExtractGlyph(characterSize, character, style, &fontGlyph)) + { + glyph.atlasRect.width = fontGlyph.image.GetWidth(); + glyph.atlasRect.height = fontGlyph.image.GetHeight(); + + // Insertion du rectangle dans l'un des atlas + if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) // Si l'image contient quelque chose + { + // Bordure (pour éviter le débordement lors du filtrage) + glyph.atlasRect.width += m_glyphBorder*2; + glyph.atlasRect.height += m_glyphBorder*2; + + // Insertion du rectangle dans l'atlas virtuel + if (!m_atlas->Insert(fontGlyph.image, &glyph.atlasRect, &glyph.flipped, &glyph.layerIndex)) + { + NazaraError("Failed to insert glyph into atlas"); + return glyph; + } + + // Compensation de la bordure (centrage du glyphe) + glyph.atlasRect.x += m_glyphBorder; + glyph.atlasRect.y += m_glyphBorder; + glyph.atlasRect.width -= m_glyphBorder*2; + glyph.atlasRect.height -= m_glyphBorder*2; + } + + glyph.aabb = fontGlyph.aabb; + glyph.advance = fontGlyph.advance; + glyph.valid = true; + } + else + { + NazaraWarning("Failed to extract glyph \"" + NzString::Unicode(character) + "\""); + } + } + else + { + // La police ne supporte pas le style demandé, nous allons donc précharger le glyphe supportant le style "minimum" supporté + // et copier ses données + nzUInt64 newKey = ComputeKey(characterSize, supportedStyle); + const Glyph& referenceGlyph = PrecacheGlyph(m_glyphes[newKey], characterSize, supportedStyle, character); + if (referenceGlyph.valid) + { + glyph.aabb = referenceGlyph.aabb; + glyph.advance = referenceGlyph.advance; + glyph.atlasRect = referenceGlyph.atlasRect; + glyph.flipped = referenceGlyph.flipped; + glyph.layerIndex = referenceGlyph.layerIndex; + glyph.valid = true; + } + } + + return glyph; +} + +NzFontLoader::LoaderList NzFont::s_loaders; diff --git a/src/Nazara/Utility/FontData.cpp b/src/Nazara/Utility/FontData.cpp new file mode 100644 index 000000000..a5f4b13bd --- /dev/null +++ b/src/Nazara/Utility/FontData.cpp @@ -0,0 +1,8 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +NzFontData::~NzFontData() = default; diff --git a/src/Nazara/Utility/GuillotineImageAtlas.cpp b/src/Nazara/Utility/GuillotineImageAtlas.cpp new file mode 100644 index 000000000..bd7486ab7 --- /dev/null +++ b/src/Nazara/Utility/GuillotineImageAtlas.cpp @@ -0,0 +1,260 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace +{ + const unsigned int s_atlasStartSize = 512; +} + +NzGuillotineImageAtlas::NzGuillotineImageAtlas() : +m_rectChoiceHeuristic(NzGuillotineBinPack::RectBestAreaFit), +m_rectSplitHeuristic(NzGuillotineBinPack::SplitMinimizeArea) +{ +} + +NzGuillotineImageAtlas::~NzGuillotineImageAtlas() = default; + +void NzGuillotineImageAtlas::Clear() +{ + m_layers.clear(); + NotifyCleared(); +} + +void NzGuillotineImageAtlas::Free(NzSparsePtr rects, NzSparsePtr layers, unsigned int count) +{ + for (unsigned int i = 0; i < count; ++i) + { + #ifdef NAZARA_DEBUG + if (layers[i] >= m_layers.size()) + { + NazaraWarning("Rectangle #" + NzString::Number(i) + " belong to an out-of-bounds layer (" + NzString::Number(i) + " >= " + NzString::Number(m_layers.size()) + ")"); + continue; + } + #endif + + m_layers[layers[i]].binPack.FreeRectangle(rects[i]); + m_layers[layers[i]].freedRectangles++; + } +} + +NzGuillotineBinPack::FreeRectChoiceHeuristic NzGuillotineImageAtlas::GetRectChoiceHeuristic() const +{ + return m_rectChoiceHeuristic; +} + +NzGuillotineBinPack::GuillotineSplitHeuristic NzGuillotineImageAtlas::GetRectSplitHeuristic() const +{ + return m_rectSplitHeuristic; +} + +NzAbstractImage* NzGuillotineImageAtlas::GetLayer(unsigned int layerIndex) const +{ + #if NAZARA_UTILITY_SAFE + if (layerIndex >= m_layers.size()) + { + NazaraError("Layer index out of range (" + NzString::Number(layerIndex) + " >= " + NzString::Number(m_layers.size()) + ')'); + return nullptr; + } + #endif + + Layer& layer = m_layers[layerIndex]; + ProcessGlyphQueue(layer); + + return layer.image.get(); +} + +unsigned int NzGuillotineImageAtlas::GetLayerCount() const +{ + return m_layers.size(); +} + +bool NzGuillotineImageAtlas::Insert(const NzImage& image, NzRectui* rect, bool* flipped, unsigned int* layerIndex) +{ + if (m_layers.empty()) + { + // On créé une première couche s'il n'y en a pas + m_layers.resize(1); + Layer& layer = m_layers.back(); + layer.binPack.Reset(s_atlasStartSize, s_atlasStartSize); + } + + // Cette fonction ne fait qu'insérer un rectangle de façon virtuelle, l'insertion des images se fait après + for (unsigned int i = 0; i < m_layers.size(); ++i) + { + Layer& layer = m_layers[i]; + + // Une fois qu'un certain nombre de rectangles ont étés libérés d'une couche, on fusionne les rectangles libres + if (layer.freedRectangles > 10) // Valeur totalement arbitraire + { + while (layer.binPack.MergeFreeRectangles()); // Tant qu'une fusion est possible + layer.freedRectangles = 0; // Et on repart de zéro + } + + if (layer.binPack.Insert(rect, flipped, 1, false, m_rectChoiceHeuristic, m_rectSplitHeuristic)) + { + // Insertion réussie dans l'une des couches, on place le glyphe en file d'attente + layer.queuedGlyphs.resize(layer.queuedGlyphs.size()+1); + QueuedGlyph& glyph = layer.queuedGlyphs.back(); + glyph.flipped = *flipped; + glyph.image = image; // Merci le Copy-On-Write + glyph.rect = *rect; + + *layerIndex = i; + return true; + } + else if (i == m_layers.size() - 1) // Dernière itération ? + { + // Dernière couche, et le glyphe ne rentre pas, peut-on agrandir la taille de l'image ? + NzVector2ui newSize = layer.binPack.GetSize()*2; + if (ResizeLayer(layer, newSize)) + { + // Oui on peut ! + layer.binPack.Expand(newSize); // On ajuste l'atlas virtuel + + // Et on relance la boucle sur la nouvelle dernière couche + i--; + } + else + { + // On ne peut plus agrandir la dernière couche, il est temps d'en créer une nouvelle + newSize.Set(s_atlasStartSize); + + Layer newLayer; + if (!ResizeLayer(newLayer, newSize)) + { + // Impossible d'allouer une nouvelle couche, nous manquons probablement de mémoire (ou le glyphe est trop grand) + NazaraError("Failed to allocate new layer, we are probably out of memory"); + return false; + } + + newLayer.binPack.Reset(newSize); + + m_layers.emplace_back(std::move(newLayer)); // Insertion du layer + + // On laisse la boucle insérer toute seule le rectangle à la prochaine itération + } + } + } + + NazaraInternalError("Unknown error"); // Normalement on ne peut pas arriver ici + return false; +} + +void NzGuillotineImageAtlas::SetRectChoiceHeuristic(NzGuillotineBinPack::FreeRectChoiceHeuristic heuristic) +{ + m_rectChoiceHeuristic = heuristic; +} + +void NzGuillotineImageAtlas::SetRectSplitHeuristic(NzGuillotineBinPack::GuillotineSplitHeuristic heuristic) +{ + m_rectSplitHeuristic = heuristic; +} + +NzAbstractImage* NzGuillotineImageAtlas::ResizeImage(NzAbstractImage* oldImage, const NzVector2ui& size) const +{ + std::unique_ptr newImage(new NzImage(nzImageType_2D, nzPixelFormat_A8, size.x, size.y)); + if (oldImage) + { + NzImage& image = *static_cast(oldImage); + newImage->Copy(image, NzRectui(size), NzVector2ui(0, 0)); // Copie des anciennes données + } + + return newImage.release(); +} + +bool NzGuillotineImageAtlas::ResizeLayer(Layer& layer, const NzVector2ui& size) +{ + NzAbstractImage* oldLayer = layer.image.get(); + + std::unique_ptr newImage(ResizeImage(layer.image.get(), size)); + if (!newImage) + return false; // Nous n'avons pas pu allouer + + if (newImage.get() == oldLayer) // Le layer a été agrandi dans le même objet, pas de souci + { + newImage.release(); // On possède déjà un unique_ptr sur cette ressource + return true; + } + + // On indique à ceux que ça intéresse qu'on a changé de pointeur + // (chose très importante pour ceux qui le stockent) + NotifyLayerChange(layer.image.get(), newImage.get()); + + // Et on ne met à jour le pointeur qu'après (car cette ligne libère également l'ancienne image) + layer.image = std::move(newImage); + + return true; +} + +void NzGuillotineImageAtlas::ProcessGlyphQueue(Layer& layer) const +{ + std::vector pixelBuffer; + + for (QueuedGlyph& glyph : layer.queuedGlyphs) + { + unsigned int glyphWidth = glyph.image.GetWidth(); + unsigned int glyphHeight = glyph.image.GetHeight(); + + // Calcul de l'éventuel padding (pixels de contour) + unsigned int paddingX; + unsigned int paddingY; + if (glyph.flipped) + { + paddingX = (glyph.rect.height - glyphWidth)/2; + paddingY = (glyph.rect.width - glyphHeight)/2; + } + else + { + paddingX = (glyph.rect.width - glyphWidth)/2; + paddingY = (glyph.rect.height - glyphHeight)/2; + } + + if (paddingX > 0 || paddingY > 0) + { + // On remplit les contours + pixelBuffer.resize(glyph.rect.width * glyph.rect.height); + std::memset(pixelBuffer.data(), 0, glyph.rect.width*glyph.rect.height*sizeof(nzUInt8)); + + layer.image->Update(pixelBuffer.data(), glyph.rect); + } + + const nzUInt8* pixels; + // On copie le glyphe dans l'atlas + if (glyph.flipped) + { + pixelBuffer.resize(glyphHeight * glyphWidth); + + // On tourne le glyphe pour qu'il rentre dans le rectangle + const nzUInt8* src = glyph.image.GetConstPixels(); + nzUInt8* ptr = pixelBuffer.data(); + + unsigned int lineStride = glyphWidth*sizeof(nzUInt8); // BPP = 1 + src += lineStride-1; // Départ en haut à droite + for (unsigned int x = 0; x < glyphWidth; ++x) + { + for (unsigned int y = 0; y < glyphHeight; ++y) + { + *ptr++ = *src; + src += lineStride; + } + + src -= glyphHeight*lineStride + 1; + } + + pixels = pixelBuffer.data(); + std::swap(glyphWidth, glyphHeight); + } + else + pixels = glyph.image.GetConstPixels(); + + layer.image->Update(pixels, NzRectui(glyph.rect.x + paddingX, glyph.rect.y + paddingY, glyphWidth, glyphHeight), 0, glyphWidth, glyphHeight); + glyph.image.Destroy(); // On libère l'image dès que possible (pour réduire la consommation) + } + + layer.queuedGlyphs.clear(); +} diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 7dc412dc8..b25ccdfd4 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -4,7 +4,9 @@ #include #include +#include #include +#include #include #include #include @@ -43,15 +45,8 @@ m_sharedImage(&emptyImage) NzImage::NzImage(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount) : m_sharedImage(&emptyImage) { + NzErrorFlags flags(nzErrorFlag_ThrowException); Create(type, format, width, height, depth, levelCount); - - #ifdef NAZARA_DEBUG - if (!m_sharedImage) - { - NazaraError("Failed to create image"); - throw std::runtime_error("Constructor failed"); - } - #endif } NzImage::NzImage(const NzImage& image) : @@ -62,12 +57,6 @@ m_sharedImage(image.m_sharedImage) m_sharedImage->refCount++; } -NzImage::NzImage(NzImage&& image) noexcept : -m_sharedImage(image.m_sharedImage) -{ - image.m_sharedImage = &emptyImage; -} - NzImage::NzImage(SharedImage* sharedImage) : m_sharedImage(sharedImage) { @@ -590,11 +579,6 @@ bool NzImage::FlipVertically() return true; } -nzUInt8 NzImage::GetBytesPerPixel() const -{ - return NzPixelFormat::GetBytesPerPixel(m_sharedImage->format); -} - const nzUInt8* NzImage::GetConstPixels(unsigned int x, unsigned int y, unsigned int z, nzUInt8 level) const { #if NAZARA_UTILITY_SAFE @@ -680,6 +664,49 @@ nzUInt8 NzImage::GetMaxLevel() const return GetMaxLevel(m_sharedImage->type, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); } +unsigned int NzImage::GetMemoryUsage() const +{ + unsigned int width = m_sharedImage->width; + unsigned int height = m_sharedImage->height; + unsigned int depth = m_sharedImage->depth; + + unsigned int size = 0; + for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) + { + size += width * height * depth; + + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + if (depth > 1) + depth >>= 1; + } + + if (m_sharedImage->type == nzImageType_Cubemap) + size *= 6; + + return size * NzPixelFormat::GetBytesPerPixel(m_sharedImage->format); +} + +unsigned int NzImage::GetMemoryUsage(nzUInt8 level) const +{ + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + + return (GetLevelSize(m_sharedImage->width, level)) * + (GetLevelSize(m_sharedImage->height, level)) * + ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level)) * + NzPixelFormat::GetBytesPerPixel(m_sharedImage->format); +} + NzColor NzImage::GetPixelColor(unsigned int x, unsigned int y, unsigned int z) const { #if NAZARA_UTILITY_SAFE @@ -776,34 +803,7 @@ nzUInt8* NzImage::GetPixels(unsigned int x, unsigned int y, unsigned int z, nzUI return GetPixelPtr(m_sharedImage->pixels[level], NzPixelFormat::GetBytesPerPixel(m_sharedImage->format), x, y, z, width, height); } -unsigned int NzImage::GetSize() const -{ - unsigned int width = m_sharedImage->width; - unsigned int height = m_sharedImage->height; - unsigned int depth = m_sharedImage->depth; - - unsigned int size = 0; - for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) - { - size += width * height * depth; - - if (width > 1) - width >>= 1; - - if (height > 1) - height >>= 1; - - if (depth > 1) - depth >>= 1; - } - - if (m_sharedImage->type == nzImageType_Cubemap) - size *= 6; - - return size * NzPixelFormat::GetBytesPerPixel(m_sharedImage->format); -} - -unsigned int NzImage::GetSize(nzUInt8 level) const +NzVector3ui NzImage::GetSize(nzUInt8 level) const { #if NAZARA_UTILITY_SAFE if (level >= m_sharedImage->levelCount) @@ -813,10 +813,7 @@ unsigned int NzImage::GetSize(nzUInt8 level) const } #endif - return (GetLevelSize(m_sharedImage->width, level)) * - (GetLevelSize(m_sharedImage->height, level)) * - ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level)) * - NzPixelFormat::GetBytesPerPixel(m_sharedImage->format); + return NzVector3ui(GetLevelSize(m_sharedImage->width, level), GetLevelSize(m_sharedImage->height, level), GetLevelSize(m_sharedImage->depth, level)); } nzImageType NzImage::GetType() const @@ -837,16 +834,6 @@ unsigned int NzImage::GetWidth(nzUInt8 level) const return GetLevelSize(m_sharedImage->width, level); } -bool NzImage::IsCompressed() const -{ - return NzPixelFormat::IsCompressed(m_sharedImage->format); -} - -bool NzImage::IsCubemap() const -{ - return m_sharedImage->type == nzImageType_Cubemap; -} - bool NzImage::IsValid() const { return m_sharedImage != &emptyImage; @@ -1122,7 +1109,7 @@ void NzImage::SetLevelCount(nzUInt8 levelCount) nzUInt8 oldLevelCount = m_sharedImage->levelCount; nzUInt8 maxLevelCount = std::max(levelCount, oldLevelCount); - m_sharedImage->levelCount = levelCount; // Pour faire fonctionner GetSize + m_sharedImage->levelCount = levelCount; // Pour faire fonctionner GetMemoryUsage nzUInt8** pixels = new nzUInt8*[levelCount]; for (unsigned int i = 0; i < maxLevelCount; ++i) @@ -1130,7 +1117,7 @@ void NzImage::SetLevelCount(nzUInt8 levelCount) if (i < oldLevelCount) pixels[i] = m_sharedImage->pixels[i]; else if (i < levelCount) - pixels[i] = new nzUInt8[GetSize(i)]; + pixels[i] = new nzUInt8[GetMemoryUsage(i)]; else delete[] m_sharedImage->pixels[i]; } @@ -1186,25 +1173,25 @@ bool NzImage::SetPixelColor(const NzColor& color, unsigned int x, unsigned int y return true; } -void NzImage::Update(const nzUInt8* pixels, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) +bool NzImage::Update(const nzUInt8* pixels, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) { #if NAZARA_UTILITY_SAFE if (m_sharedImage == &emptyImage) { NazaraError("Image must be valid"); - return; + return false; } if (!pixels) { NazaraError("Invalid pixel source"); - return; + return false; } if (level >= m_sharedImage->levelCount) { NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); - return; + return false; } #endif @@ -1216,27 +1203,29 @@ void NzImage::Update(const nzUInt8* pixels, unsigned int srcWidth, unsigned int GetLevelSize(m_sharedImage->depth, level), 0, 0, srcWidth, srcHeight); + + return true; } -void NzImage::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) +bool NzImage::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) { #if NAZARA_UTILITY_SAFE if (m_sharedImage == &emptyImage) { NazaraError("Image must be valid"); - return; + return false; } if (!pixels) { NazaraError("Invalid pixel source"); - return; + return false; } if (level >= m_sharedImage->levelCount) { NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); - return; + return false; } #endif @@ -1247,15 +1236,15 @@ void NzImage::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int src if (!box.IsValid()) { NazaraError("Invalid box"); - return; + return false; } - // Nous n'autorisons pas de modifier plus d'une face du cubemap à la fois (Nous prenons donc la profondeur de base) - ///FIXME: Ce code n'autorise même pas la modification d'une autre face du cubemap Oo - if (box.x+box.width > width || box.y+box.height > height || box.z+box.depth > GetLevelSize(m_sharedImage->depth, level)) + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); + if (box.x+box.width > width || box.y+box.height > height || box.z+box.depth > depth || + (m_sharedImage->type == nzImageType_Cubemap && box.depth > 1)) // Nous n'autorisons pas de modifier plus d'une face du cubemap à la fois { NazaraError("Box dimensions are out of bounds"); - return; + return false; } #endif @@ -1268,64 +1257,13 @@ void NzImage::Update(const nzUInt8* pixels, const NzBoxui& box, unsigned int src box.width, box.height, box.depth, width, height, srcWidth, srcHeight); + + return true; } -void NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) +bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z, unsigned int srcWidth, unsigned int srcHeight, nzUInt8 level) { - ///FIXME: Cette surcharge possède-t-elle la moindre utilité ? (Update(pixels, NzBoxui(rect.x, rect.y, z, rect.width, rect.height, 1), srcWidth, ..) devrait donner le même résultat - #if NAZARA_UTILITY_SAFE - if (m_sharedImage == &emptyImage) - { - NazaraError("Image must be valid"); - return; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return; - } - - if (!rect.IsValid()) - { - NazaraError("Invalid rectangle"); - return; - } - - if (level >= m_sharedImage->levelCount) - { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); - return; - } - #endif - - unsigned int width = GetLevelSize(m_sharedImage->width, level); - unsigned int height = GetLevelSize(m_sharedImage->height, level); - - #if NAZARA_UTILITY_SAFE - if (rect.x+rect.width > width || rect.y+rect.height > height) - { - NazaraError("Rectangle dimensions are out of bounds"); - return; - } - - unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); - if (z >= depth) - { - NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= " + NzString::Number(depth) + ')'); - return; - } - #endif - - EnsureOwnership(); - - nzUInt8 bpp = NzPixelFormat::GetBytesPerPixel(m_sharedImage->format); - nzUInt8* dstPixels = GetPixelPtr(m_sharedImage->pixels[level], bpp, rect.x, rect.y, z, width, height); - - Copy(dstPixels, pixels, bpp, - rect.width, rect.height, 1, - width, height, - srcWidth, srcHeight); + return Update(pixels, NzBoxui(rect.x, rect.y, z, rect.width, rect.height, 1), srcWidth, srcHeight, level); } NzImage& NzImage::operator=(const NzImage& image) @@ -1339,13 +1277,6 @@ NzImage& NzImage::operator=(const NzImage& image) return *this; } -NzImage& NzImage::operator=(NzImage&& image) noexcept -{ - std::swap(m_sharedImage, image.m_sharedImage); - - return *this; -} - void NzImage::Copy(nzUInt8* destination, const nzUInt8* source, nzUInt8 bpp, unsigned int width, unsigned int height, unsigned int depth, unsigned int dstWidth, unsigned int dstHeight, unsigned int srcWidth, unsigned int srcHeight) { if (dstWidth == 0) @@ -1434,7 +1365,7 @@ void NzImage::EnsureOwnership() nzUInt8** pixels = new nzUInt8*[m_sharedImage->levelCount]; for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) { - unsigned int size = GetSize(i); + unsigned int size = GetMemoryUsage(i); pixels[i] = new nzUInt8[size]; std::memcpy(pixels[i], m_sharedImage->pixels[i], size); } diff --git a/src/Nazara/Utility/IndexBuffer.cpp b/src/Nazara/Utility/IndexBuffer.cpp index f96c220b8..5a4f5007a 100644 --- a/src/Nazara/Utility/IndexBuffer.cpp +++ b/src/Nazara/Utility/IndexBuffer.cpp @@ -24,7 +24,7 @@ NzIndexBuffer::NzIndexBuffer(bool largeIndices, NzBuffer* buffer, unsigned int s Reset(largeIndices, buffer, startOffset, endOffset); } -NzIndexBuffer::NzIndexBuffer(bool largeIndices, unsigned int length, nzBufferStorage storage, nzBufferUsage usage) +NzIndexBuffer::NzIndexBuffer(bool largeIndices, unsigned int length, nzUInt32 storage, nzBufferUsage usage) { NzErrorFlags(nzErrorFlag_ThrowException, true); Reset(largeIndices, length, storage, usage); @@ -220,7 +220,7 @@ void NzIndexBuffer::Reset(bool largeIndices, NzBuffer* buffer, unsigned int star m_startOffset = startOffset; } -void NzIndexBuffer::Reset(bool largeIndices, unsigned int length, nzBufferStorage storage, nzBufferUsage usage) +void NzIndexBuffer::Reset(bool largeIndices, unsigned int length, nzUInt32 storage, nzBufferUsage usage) { unsigned int stride = (largeIndices) ? sizeof(nzUInt32) : sizeof(nzUInt16); @@ -251,7 +251,7 @@ void NzIndexBuffer::Reset(NzIndexBuffer&& indexBuffer) noexcept m_startOffset = indexBuffer.m_startOffset; } -bool NzIndexBuffer::SetStorage(nzBufferStorage storage) +bool NzIndexBuffer::SetStorage(nzUInt32 storage) { return m_buffer->SetStorage(storage); } diff --git a/src/Nazara/Utility/Loaders/FreeType.hpp b/src/Nazara/Utility/Loaders/FreeType.hpp new file mode 100644 index 000000000..6ee1f60ab --- /dev/null +++ b/src/Nazara/Utility/Loaders/FreeType.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_FREETYPE_HPP +#define NAZARA_LOADERS_FREETYPE_HPP + +#include + +void NzLoaders_FreeType_Register(); +void NzLoaders_FreeType_Unregister(); + +#endif // NAZARA_LOADERS_FREETYPE_HPP diff --git a/src/Nazara/Utility/Loaders/FreeType/Loader.cpp b/src/Nazara/Utility/Loaders/FreeType/Loader.cpp new file mode 100644 index 000000000..1bf65dcbd --- /dev/null +++ b/src/Nazara/Utility/Loaders/FreeType/Loader.cpp @@ -0,0 +1,403 @@ +// Copyright (C) 2014 Jérôme Leclercq - 2009 Cruden BV +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include FT_FREETYPE_H +#include FT_BITMAP_H +#include FT_OUTLINE_H +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + FT_Library s_library = nullptr; + float s_invScaleFactor = 1.f / (1 << 6); // 1/64 + + extern "C" + unsigned long FT_StreamRead(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count) + { + // http://www.freetype.org/freetype2/docs/reference/ft2-system_interface.html#FT_Stream_IoFunc + NzInputStream& inputStream = *static_cast(stream->descriptor.pointer); + + // La valeur de count indique une opération de lecture ou de positionnement + if (count > 0) + { + // Dans le premier cas, une erreur est symbolisée par un retour nul + if (inputStream.SetCursorPos(offset)) + return static_cast(inputStream.Read(buffer, count)); + else + return 0; + } + else + { + // Dans le second cas, une erreur est symbolisée par un retour non-nul + if (inputStream.SetCursorPos(offset)) + return 0; + else + return 42; // La réponse à la grande question + } + } + + extern "C" + void FT_StreamClose(FT_Stream stream) + { + // http://www.freetype.org/freetype2/docs/reference/ft2-system_interface.html#FT_Stream_CloseFunc + // Les streams dans Nazara ne se ferment pas explicitement + NazaraUnused(stream); + } + + class FreeTypeStream : public NzFontData + { + public: + FreeTypeStream() : + m_face(nullptr), + m_characterSize(0) + { + } + + ~FreeTypeStream() + { + if (m_face) + FT_Done_Face(m_face); + } + + bool Check() + { + // Test d'ouverture (http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Open_Face) + return FT_Open_Face(s_library, &m_args, -1, nullptr) == 0; + } + + bool ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt32 style, NzFontGlyph* dst) override + { + #ifdef NAZARA_DEBUG + if (!dst) + { + NazaraError("Glyph destination cannot be null"); + return false; + } + #endif + + SetCharacterSize(characterSize); + + if (FT_Load_Char(m_face, character, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL) != 0) + { + NazaraError("Failed to load character"); + return false; + } + + FT_GlyphSlot& glyph = m_face->glyph; + + const FT_Pos boldStrength = 2 << 6; + + bool embolden = (style & nzTextStyle_Bold); + + dst->advance = (embolden) ? boldStrength >> 6 : 0; + + if (embolden && glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + // http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Embolden + FT_Outline_Embolden(&glyph->outline, boldStrength); + embolden = false; + } + + // http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap + // Conversion du glyphe vers le format bitmap + // Cette fonction ne fait rien dans le cas où le glyphe est déjà un bitmap + if (FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) != 0) + { + NazaraError("Failed to convert glyph to bitmap"); + return false; + } + + // Dans le cas où nous voulons des caractères gras mais que nous n'avons pas pu agir plus tôt + // nous demandons à FreeType d'agir directement sur le bitmap généré + if (embolden) + { + // http://www.freetype.org/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden + // "If you want to embolden the bitmap owned by a FT_GlyphSlot_Rec, you should call FT_GlyphSlot_Own_Bitmap on the slot first" + FT_GlyphSlot_Own_Bitmap(glyph); + FT_Bitmap_Embolden(s_library, &glyph->bitmap, boldStrength, boldStrength); + embolden = false; + } + + dst->advance += glyph->metrics.horiAdvance >> 6; + dst->aabb.x = glyph->metrics.horiBearingX >> 6; + dst->aabb.y = -(glyph->metrics.horiBearingY >> 6); // Inversion du repère + dst->aabb.width = glyph->metrics.width >> 6; + dst->aabb.height = glyph->metrics.height >> 6; + + unsigned int width = glyph->bitmap.width; + unsigned int height = glyph->bitmap.rows; + + if (width > 0 && height > 0) + { + dst->image.Create(nzImageType_2D, nzPixelFormat_A8, width, height); + nzUInt8* pixels = dst->image.GetPixels(); + + const nzUInt8* data = glyph->bitmap.buffer; + + // Selon la documentation FreeType, le glyphe peut être encodé en format A8 (huit bits d'alpha par pixel) + // ou au format A1 (un bit d'alpha par pixel). + // Cependant dans un cas comme dans l'autre, il nous faut gérer le pitch (les données peuvent ne pas être contigues) + // ainsi que le padding dans le cas du format A1 (Chaque ligne prends un nombre fixe d'octets) + if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) + { + // Format A1 + for (unsigned int y = 0; y < height; ++y) + { + for (unsigned int x = 0; x < width; ++x) + *pixels++ = (data[x/8] & (1 << (7 - x%8)) ? 255 : 0); + + data += glyph->bitmap.pitch; + } + } + else + { + // Format A8 + if (glyph->bitmap.pitch == static_cast(width*sizeof(nzUInt8))) // Pouvons-nous copier directement ? + dst->image.Update(glyph->bitmap.buffer); + else + { + for (unsigned int y = 0; y < height; ++y) + { + std::memcpy(pixels, data, width*sizeof(nzUInt8)); + data += glyph->bitmap.pitch; + pixels += width*sizeof(nzUInt8); + } + } + } + } + else + dst->image.Destroy(); // On s'assure que l'image ne contient alors rien + + return true; + } + + NzString GetFamilyName() const override + { + return m_face->family_name; + } + + NzString GetStyleName() const override + { + return m_face->style_name; + } + + bool HasKerning() const override + { + return FT_HAS_KERNING(m_face); + } + + bool IsScalable() const override + { + return FT_IS_SCALABLE(m_face); + } + + bool Open() + { + return FT_Open_Face(s_library, &m_args, 0, &m_face) == 0; + } + + int QueryKerning(unsigned int characterSize, char32_t first, char32_t second) const override + { + if (FT_HAS_KERNING(m_face)) + { + SetCharacterSize(characterSize); + + FT_Vector kerning; + FT_Get_Kerning(m_face, FT_Get_Char_Index(m_face, first), FT_Get_Char_Index(m_face, second), FT_KERNING_DEFAULT, &kerning); + + if (!FT_IS_SCALABLE(m_face)) + return kerning.x; // Taille déjà précisée en pixels dans ce cas + + return kerning.x >> 6; + } + else + return 0; + } + + unsigned int QueryLineHeight(unsigned int characterSize) const override + { + SetCharacterSize(characterSize); + + // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Size_Metrics + return m_face->size->metrics.height >> 6; + } + + float QueryUnderlinePosition(unsigned int characterSize) const override + { + if (FT_IS_SCALABLE(m_face)) + { + SetCharacterSize(characterSize); + + // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec + return static_cast(FT_MulFix(m_face->underline_position, m_face->size->metrics.y_scale)) * s_invScaleFactor; + } + else + return characterSize / 10.f; // Joker ? + } + + float QueryUnderlineThickness(unsigned int characterSize) const override + { + if (FT_IS_SCALABLE(m_face)) + { + SetCharacterSize(characterSize); + + // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec + return static_cast(FT_MulFix(m_face->underline_thickness, m_face->size->metrics.y_scale)) * s_invScaleFactor; + } + else + return characterSize/15.f; // Joker ? + } + + bool SetFile(const NzString& filePath) + { + if (!m_file.Open(filePath, NzFile::ReadOnly)) + { + NazaraError("Failed to open stream from file: " + NzError::GetLastError()); + return false; + } + + SetStream(m_file); + return true; + } + + void SetStream(NzInputStream& stream) + { + m_stream.base = nullptr; + m_stream.close = FT_StreamClose; + m_stream.descriptor.pointer = &stream; + m_stream.read = FT_StreamRead; + m_stream.pos = 0; + m_stream.size = stream.GetSize(); + + m_args.driver = 0; + m_args.flags = FT_OPEN_STREAM; + m_args.stream = &m_stream; + } + + bool SupportsStyle(nzUInt32 style) const override + { + ///TODO + return style == nzTextStyle_Regular || style == nzTextStyle_Bold; + } + + private: + void SetCharacterSize(unsigned int characterSize) const + { + if (m_characterSize != characterSize) + { + FT_Set_Pixel_Sizes(m_face, 0, characterSize); + m_characterSize = characterSize; + } + } + + FT_Open_Args m_args; + FT_Face m_face; + FT_StreamRec m_stream; + NzFile m_file; + mutable unsigned int m_characterSize; + }; + + bool IsSupported(const NzString& extension) + { + ///FIXME: Je suppose qu'il en manque quelques unes.. + static std::set supportedExtensions = { + "afm", "bdf", "cff", "cid", "dfont", "fnt", "fon", "otf", "pfa", "pfb", "pfm", "pfr", "sfnt", "ttc", "tte", "ttf" + }; + + return supportedExtensions.find(extension) != supportedExtensions.end(); + } + + nzTernary Check(NzInputStream& stream, const NzFontParams& parameters) + { + NazaraUnused(parameters); + + FreeTypeStream face; + face.SetStream(stream); + + if (face.Check()) + return nzTernary_True; + else + return nzTernary_False; + } + + bool LoadFile(NzFont* font, const NzString& filePath, const NzFontParams& parameters) + { + NazaraUnused(parameters); + + std::unique_ptr face(new FreeTypeStream); + + if (!face->SetFile(filePath)) + { + NazaraError("Failed to open file"); + return false; + } + + if (!face->Open()) + { + NazaraError("Failed to open face"); + return false; + } + + if (font->Create(face.get())) + { + face.release(); + return true; + } + else + return false; + } + + bool LoadStream(NzFont* font, NzInputStream& stream, const NzFontParams& parameters) + { + NazaraUnused(parameters); + + std::unique_ptr face(new FreeTypeStream); + face->SetStream(stream); + + if (!face->Open()) + { + NazaraError("Failed to open face"); + return false; + } + + if (font->Create(face.get())) + { + face.release(); + return true; + } + else + return false; + } +} + +void NzLoaders_FreeType_Register() +{ + if (FT_Init_FreeType(&s_library) == 0) + NzFontLoader::RegisterLoader(IsSupported, Check, LoadStream, LoadFile); + else + { + s_library = nullptr; // On s'assure que le pointeur ne pointe pas sur n'importe quoi + NazaraWarning("Failed to initialize FreeType library"); + } +} + +void NzLoaders_FreeType_Unregister() +{ + if (s_library) + { + NzFontLoader::UnregisterLoader(IsSupported, Check, LoadStream, LoadFile); + + FT_Done_FreeType(s_library); + s_library = nullptr; + } +} diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index 61427fa3d..ee6489dfc 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -25,13 +25,13 @@ NzMeshParams::NzMeshParams() { - if (!NzBuffer::IsSupported(storage)) - storage = nzBufferStorage_Software; + if (!NzBuffer::IsStorageSupported(storage)) + storage = nzDataStorage_Software; } bool NzMeshParams::IsValid() const { - if (!NzBuffer::IsSupported(storage)) + if (!NzBuffer::IsStorageSupported(storage)) { NazaraError("Storage not supported"); return false; diff --git a/src/Nazara/Utility/Node.cpp b/src/Nazara/Utility/Node.cpp index 459f6d74f..b9105aece 100644 --- a/src/Nazara/Utility/Node.cpp +++ b/src/Nazara/Utility/Node.cpp @@ -270,7 +270,7 @@ NzNode& NzNode::Move(const NzVector3f& movement, nzCoordSys coordSys) } case nzCoordSys_Local: - m_position += m_scale * (m_rotation * movement); + m_position += m_rotation * movement; break; } @@ -685,7 +685,7 @@ void NzNode::UpdateDerived() const m_derivedRotation.Normalize(); } else - m_derivedRotation = m_initialRotation * m_rotation; ///FIXME: Besoin d'une normalisation ? + m_derivedRotation = m_initialRotation * m_rotation; m_derivedScale = m_initialScale * m_scale; if (m_inheritScale) diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 776781251..b6679598d 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -50,6 +50,94 @@ namespace return nullptr; } + /**********************************A8***********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = 0xFF; + *dst++ = 0xFF; + *dst++ = 0xFF; + *dst++ = *start; + + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = 0xFF; + *dst++ = *start; + + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *ptr = (static_cast(0x1F) << 11) | + (static_cast(0x1F) << 6) | + (static_cast(0x1F) << 1) | + ((*start > 0xF) ? 1 : 0); // > 128 + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + start += 1; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *ptr = 0xFFF0 | c8to4(*start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = 0xFF; + *dst++ = 0xFF; + *dst++ = 0xFF; + *dst++ = *start; + + start += 1; + } + + return dst; + } + /**********************************BGR8***********************************/ template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) @@ -170,6 +258,19 @@ namespace } /**********************************BGRA8**********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[3]; + + start += 4; + } + + return dst; + } + template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { @@ -243,7 +344,7 @@ namespace *ptr = (static_cast(c8to5(start[2])) << 11) | (static_cast(c8to5(start[1])) << 6) | (static_cast(c8to5(start[0])) << 1) | - ((start[3] == 0xFF) ? 1 : 0); + ((start[3] > 0xF) ? 1 : 0); // > 128 #ifdef NAZARA_BIG_ENDIAN NzByteSwap(ptr, sizeof(nzUInt16)); @@ -413,6 +514,19 @@ namespace } /***********************************LA8***********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[1]; + + start += 2; + } + + return dst; + } + template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { @@ -465,7 +579,7 @@ namespace { nzUInt16 l = static_cast(c8to5(start[0])); - *ptr = (l << 11) | (l << 6) | (l << 1) | ((start[1] == 0xFF) ? 1 : 0); + *ptr = (l << 11) | (l << 6) | (l << 1) | ((start[1] > 0xF) ? 1 : 0); #ifdef NAZARA_BIG_ENDIAN NzByteSwap(ptr, sizeof(nzUInt16)); @@ -531,6 +645,25 @@ namespace } /*********************************RGBA4***********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + *dst++ = c4to8(pixel & 0x000F); + + start += 2; + } + + return dst; + } + template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { @@ -638,7 +771,7 @@ namespace nzUInt16 b = c4to5((pixel & 0x00F0) >> 4); nzUInt16 a = c4to5((pixel & 0x000F) >> 0); - *ptr = (r << 11) | (g << 6) | (b << 1) | ((a == 0xFF) ? 1 : 0); + *ptr = (r << 11) | (g << 6) | (b << 1) | ((a > 0x3) ? 1 : 0); #ifdef NAZARA_BIG_ENDIAN NzByteSwap(ptr, sizeof(nzUInt16)); @@ -695,6 +828,25 @@ namespace } /*********************************RGB5A1**********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + *dst++ = static_cast((pixel & 0x1)*0xFF); + + start += 2; + } + + return dst; + } + template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { @@ -977,6 +1129,19 @@ namespace } /**********************************RGBA8**********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[3]; + + start += 4; + } + + return dst; + } + template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { @@ -1044,7 +1209,7 @@ namespace *ptr = (static_cast(c8to5(start[0])) << 11) | (static_cast(c8to5(start[1])) << 6) | (static_cast(c8to5(start[2])) << 1) | - ((start[3] == 0xFF) ? 1 : 0); + ((start[3] > 0xF) ? 1 : 0); // > 128 #ifdef NAZARA_BIG_ENDIAN NzByteSwap(ptr, sizeof(nzUInt16)); @@ -1106,6 +1271,13 @@ bool NzPixelFormat::Initialize() // Réinitialisation std::memset(s_convertFunctions, 0, (nzPixelFormat_Max+1)*(nzPixelFormat_Max+1)*sizeof(NzPixelFormat::ConvertFunction)); + /***********************************A8************************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + /**********************************BGR8***********************************/ RegisterConverter(); RegisterConverter(); @@ -1124,6 +1296,7 @@ bool NzPixelFormat::Initialize() RegisterConverter(); /**********************************BGRA8**********************************/ + RegisterConverter(); RegisterConverter(); RegisterConverter(); RegisterConverter();/* @@ -1227,6 +1400,7 @@ bool NzPixelFormat::Initialize() RegisterConverter(); /***********************************LA8***********************************/ + RegisterConverter(); RegisterConverter(); RegisterConverter(); RegisterConverter();/* @@ -1244,6 +1418,7 @@ bool NzPixelFormat::Initialize() RegisterConverter(); /**********************************RGBA4**********************************/ + RegisterConverter(); RegisterConverter(); RegisterConverter(); RegisterConverter(); @@ -1261,6 +1436,7 @@ bool NzPixelFormat::Initialize() RegisterConverter(); /*********************************RGB5A1**********************************/ + RegisterConverter(); RegisterConverter(); RegisterConverter(); RegisterConverter(); @@ -1295,6 +1471,7 @@ bool NzPixelFormat::Initialize() RegisterConverter(); /**********************************RGBA8**********************************/ + RegisterConverter(); RegisterConverter(); RegisterConverter(); RegisterConverter(); diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp new file mode 100644 index 000000000..e16161d69 --- /dev/null +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -0,0 +1,305 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +///TODO: Listener de font (cas où l'atlas a changé) + +NzSimpleTextDrawer::NzSimpleTextDrawer() : +m_color(NzColor::White), +m_style(nzTextStyle_Regular) +{ + // SetFont(NzFont::GetDefault()); +} + +NzSimpleTextDrawer::~NzSimpleTextDrawer() +{ + if (m_font) + m_font->RemoveResourceListener(this); +} + +const NzRectui& NzSimpleTextDrawer::GetBounds() const +{ + if (!m_glyphUpdated) + UpdateGlyphs(); + + return m_bounds; +} + +unsigned int NzSimpleTextDrawer::GetCharacterSize() const +{ + return m_characterSize; +} + +const NzColor& NzSimpleTextDrawer::GetColor() const +{ + return m_color; +} + +NzFont* NzSimpleTextDrawer::GetFont() const +{ + return m_font; +} + +nzUInt32 NzSimpleTextDrawer::GetStyle() const +{ + return m_style; +} + +void NzSimpleTextDrawer::SetCharacterSize(unsigned int characterSize) +{ + m_characterSize = characterSize; + + m_glyphUpdated = false; +} + +void NzSimpleTextDrawer::SetColor(const NzColor& color) +{ + m_color = color; + + m_glyphUpdated = false; +} + +void NzSimpleTextDrawer::SetFont(NzFont* font) +{ + if (m_font) + m_font->RemoveResourceListener(this); + + m_font = font; + if (m_font) + m_font->AddResourceListener(this); + + m_glyphUpdated = false; +} + +void NzSimpleTextDrawer::SetStyle(nzUInt32 style) +{ + m_style = style; + + m_glyphUpdated = false; +} + +void NzSimpleTextDrawer::SetText(const NzString& str) +{ + m_text = str; + + m_glyphUpdated = false; +} + +NzSimpleTextDrawer NzSimpleTextDrawer::Draw(unsigned int characterSize, const NzString& str, nzUInt32 style, const NzColor& color) +{ + ///FIXME: Sans default font ça n'a aucun intérêt + NzSimpleTextDrawer drawer; + drawer.SetCharacterSize(characterSize); + drawer.SetColor(color); + drawer.SetStyle(style); + drawer.SetText(str); + + return drawer; +} + +NzSimpleTextDrawer NzSimpleTextDrawer::Draw(NzFont* font, unsigned int characterSize, const NzString& str, nzUInt32 style, const NzColor& color) +{ + NzSimpleTextDrawer drawer; + drawer.SetCharacterSize(characterSize); + drawer.SetColor(color); + drawer.SetFont(font); + drawer.SetStyle(style); + drawer.SetText(str); + + return drawer; +} + +NzFont* NzSimpleTextDrawer::GetFont(unsigned int index) const +{ + #if NAZARA_UTILITY_SAFE + if (index > 0) + { + NazaraError("Font index out of range (" + NzString::Number(index) + " >= 1)"); + return nullptr; + } + #endif + + return m_font; +} + +unsigned int NzSimpleTextDrawer::GetFontCount() const +{ + return 1; +} + +const NzAbstractTextDrawer::Glyph& NzSimpleTextDrawer::GetGlyph(unsigned int index) const +{ + if (!m_glyphUpdated) + UpdateGlyphs(); + + return m_glyphs[index]; +} + +unsigned int NzSimpleTextDrawer::GetGlyphCount() const +{ + if (!m_glyphUpdated) + UpdateGlyphs(); + + return m_glyphs.size(); +} + +bool NzSimpleTextDrawer::OnResourceModified(const NzResource* resource, int index, unsigned int code) +{ + NazaraUnused(resource); + NazaraUnused(index); + + #ifdef NAZARA_DEBUG + if (m_font != resource) + { + NazaraInternalError("Not listening to " + NzString::Pointer(resource)); + return false; + } + #endif + + if (code == NzFont::ModificationCode_AtlasChanged || + code == NzFont::ModificationCode_AtlasLayerChanged || + code == NzFont::ModificationCode_GlyphCacheCleared) + { + m_glyphUpdated = false; + } + + return true; +} + +void NzSimpleTextDrawer::OnResourceReleased(const NzResource* resource, int index) +{ + NazaraUnused(resource); + NazaraUnused(index); + + #ifdef NAZARA_DEBUG + if (m_font != resource) + { + NazaraInternalError("Not listening to " + NzString::Pointer(resource)); + return; + } + #endif + + SetFont(nullptr); +} + +void NzSimpleTextDrawer::UpdateGlyphs() const +{ + m_bounds.MakeZero(); + m_glyphs.clear(); + m_glyphUpdated = true; + + #if NAZARA_UTILITY_SAFE + if (!m_font || !m_font->IsValid()) + { + NazaraError("Invalid font"); + return; + } + #endif + + if (m_text.IsEmpty()) + return; + + ///TODO: Itération UTF-8 => UTF-32 sans allocation de buffer (Exposer utf8cpp ?) + unsigned int size; + std::unique_ptr characters(m_text.GetUtf32Buffer(&size)); + if (!characters) + { + NazaraError("Invalid character set"); + return; + } + + const NzFont::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize); + + // "Curseur" de dessin + NzVector2ui drawPos(0, m_characterSize); + NzVector2ui lastPos(0, 0); + + m_glyphs.reserve(size); + nzUInt32 previousCharacter = 0; + for (unsigned int i = 0; i < size; ++i) + { + char32_t character = characters[i]; + + if (previousCharacter != 0) + drawPos.x += m_font->GetKerning(m_characterSize, previousCharacter, character); + + previousCharacter = character; + + bool whitespace = true; + switch (character) + { + case ' ': + drawPos.x += sizeInfo.spaceAdvance; + break; + + case '\n': + drawPos.x = 0; + drawPos.y += sizeInfo.lineHeight; + break; + + case '\t': + drawPos.x += sizeInfo.spaceAdvance*4; + break; + + default: + whitespace = false; + break; + } + + if (whitespace) + continue; // Inutile d'avoir un glyphe pour un espace blanc + + const NzFont::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, character); + if (!fontGlyph.valid) + continue; // Le glyphe n'a pas été correctement chargé, que pouvons-nous faire d'autre que le passer + + Glyph glyph; + glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex); + glyph.atlasRect = fontGlyph.atlasRect; + glyph.color = m_color; + glyph.flipped = fontGlyph.flipped; + + float advance = fontGlyph.advance; + + NzRectf bounds(fontGlyph.aabb); + bounds.x += drawPos.x; + bounds.y += drawPos.y; + + if (fontGlyph.requireFauxBold) + { + // On va agrandir le glyphe pour simuler le gras (idée moisie, mais idée quand même) + NzVector2f center = bounds.GetCenter(); + + bounds.width *= 1.1f; + bounds.height *= 1.1f; + + // On le replace à la bonne hauteur + NzVector2f offset(bounds.GetCenter() - center); + bounds.y -= offset.y; + + // On ajuste l'espacement + advance *= 1.1f; + } + + // On "penche" le glyphe pour obtenir un semblant d'italique + float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f; + float italicTop = italic * bounds.y; + float italicBottom = italic * bounds.GetMaximum().y; + + glyph.corners[0].Set(bounds.x - italicTop, bounds.y); + glyph.corners[1].Set(bounds.x + bounds.width - italicTop, bounds.y); + glyph.corners[2].Set(bounds.x - italicBottom, bounds.y + bounds.height); + glyph.corners[3].Set(bounds.x + bounds.width - italicBottom, bounds.y + bounds.height); + + m_glyphs.push_back(glyph); + + lastPos = drawPos; + drawPos.x += advance; + } + + m_bounds.ExtendTo(lastPos); +} diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index 885e4a578..c12459277 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,9 @@ bool NzUtility::Initialize() // Il s'agit ici d'une liste LIFO, le dernier loader enregistré possède la priorité /// Loaders génériques + // Font + NzLoaders_FreeType_Register(); + // Image NzLoaders_STB_Register(); // Loader générique (STB) @@ -109,6 +113,7 @@ void NzUtility::Uninitialize() // Libération du module s_moduleReferenceCounter = 0; + NzLoaders_FreeType_Unregister(); NzLoaders_MD2_Unregister(); NzLoaders_MD5Anim_Unregister(); NzLoaders_MD5Mesh_Unregister(); diff --git a/src/Nazara/Utility/VertexBuffer.cpp b/src/Nazara/Utility/VertexBuffer.cpp index 45c572fea..12f72051f 100644 --- a/src/Nazara/Utility/VertexBuffer.cpp +++ b/src/Nazara/Utility/VertexBuffer.cpp @@ -20,7 +20,7 @@ NzVertexBuffer::NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, NzB Reset(vertexDeclaration, buffer, startOffset, endOffset); } -NzVertexBuffer::NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzBufferStorage storage, nzBufferUsage usage) +NzVertexBuffer::NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzUInt32 storage, nzBufferUsage usage) { NzErrorFlags(nzErrorFlag_ThrowException, true); Reset(vertexDeclaration, length, storage, usage); @@ -230,7 +230,7 @@ void NzVertexBuffer::Reset(const NzVertexDeclaration* vertexDeclaration, NzBuffe m_vertexDeclaration = vertexDeclaration; } -void NzVertexBuffer::Reset(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzBufferStorage storage, nzBufferUsage usage) +void NzVertexBuffer::Reset(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzUInt32 storage, nzBufferUsage usage) { m_endOffset = length * ((vertexDeclaration) ? vertexDeclaration->GetStride() : 1); m_startOffset = 0; @@ -259,7 +259,7 @@ void NzVertexBuffer::Reset(NzVertexBuffer&& vertexBuffer) noexcept m_vertexDeclaration = std::move(vertexBuffer.m_vertexDeclaration); } -bool NzVertexBuffer::SetStorage(nzBufferStorage storage) +bool NzVertexBuffer::SetStorage(nzUInt32 storage) { return m_buffer->SetStorage(storage); } diff --git a/src/Nazara/Utility/VertexDeclaration.cpp b/src/Nazara/Utility/VertexDeclaration.cpp index de4860d82..e65814660 100644 --- a/src/Nazara/Utility/VertexDeclaration.cpp +++ b/src/Nazara/Utility/VertexDeclaration.cpp @@ -192,6 +192,13 @@ bool NzVertexDeclaration::Initialize() NazaraAssert(declaration->GetStride() == sizeof(NzVertexStruct_XY), "Invalid stride for declaration nzVertexLayout_XY"); + // nzVertexLayout_XY_Color : NzVertexStruct_XY_Color + declaration = &s_declarations[nzVertexLayout_XY_Color]; + declaration->EnableComponent(nzVertexComponent_Position, nzComponentType_Float2, NzOffsetOf(NzVertexStruct_XY_Color, position)); + declaration->EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(NzVertexStruct_XY_Color, color)); + + NazaraAssert(declaration->GetStride() == sizeof(NzVertexStruct_XY_Color), "Invalid stride for declaration nzVertexLayout_XY_Color"); + // nzVertexLayout_XY_UV : NzVertexStruct_XY_UV declaration = &s_declarations[nzVertexLayout_XY_UV]; declaration->EnableComponent(nzVertexComponent_Position, nzComponentType_Float2, NzOffsetOf(NzVertexStruct_XY_UV, position)); @@ -205,6 +212,21 @@ bool NzVertexDeclaration::Initialize() NazaraAssert(declaration->GetStride() == sizeof(NzVertexStruct_XYZ), "Invalid stride for declaration nzVertexLayout_XYZ"); + // nzVertexLayout_XYZ_Color : NzVertexStruct_XYZ_Color + declaration = &s_declarations[nzVertexLayout_XYZ_Color]; + declaration->EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(NzVertexStruct_XYZ_Color, position)); + declaration->EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(NzVertexStruct_XYZ_Color, color)); + + NazaraAssert(declaration->GetStride() == sizeof(NzVertexStruct_XYZ_Color), "Invalid stride for declaration nzVertexLayout_XYZ_Color"); + + // nzVertexLayout_XYZ_Color_UV : NzVertexStruct_XYZ_Color_UV + declaration = &s_declarations[nzVertexLayout_XYZ_Color_UV]; + declaration->EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(NzVertexStruct_XYZ_Color_UV, position)); + declaration->EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(NzVertexStruct_XYZ_Color_UV, color)); + declaration->EnableComponent(nzVertexComponent_TexCoord, nzComponentType_Float2, NzOffsetOf(NzVertexStruct_XYZ_Color_UV, uv)); + + NazaraAssert(declaration->GetStride() == sizeof(NzVertexStruct_XYZ_Color_UV), "Invalid stride for declaration nzVertexLayout_XYZ_Color_UV"); + // nzVertexLayout_XYZ_Normal : NzVertexStruct_XYZ_Normal declaration = &s_declarations[nzVertexLayout_XYZ_Normal]; declaration->EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(NzVertexStruct_XYZ_Normal, position));