Documentation for module: Graphics

Former-commit-id: 5e3ee3c61779fbdd1a083117f537a45e1bad820b
This commit is contained in:
Gawaboumga 2016-05-30 14:21:36 +02:00
parent 6400ba2e28
commit 96b958d655
94 changed files with 4858 additions and 504 deletions

View File

@ -7,6 +7,10 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a Billboard object by default
*/
inline Billboard::Billboard() inline Billboard::Billboard()
{ {
SetColor(Color::White); SetColor(Color::White);
@ -15,6 +19,12 @@ namespace Nz
SetSize(64.f, 64.f); SetSize(64.f, 64.f);
} }
/*!
* \brief Constructs a Billboard object with a reference to a material
*
* \param material Reference to a material
*/
inline Billboard::Billboard(MaterialRef material) inline Billboard::Billboard(MaterialRef material)
{ {
SetColor(Color::White); SetColor(Color::White);
@ -23,6 +33,12 @@ namespace Nz
SetSize(64.f, 64.f); SetSize(64.f, 64.f);
} }
/*!
* \brief Constructs a Billboard object with a pointer to a texture
*
* \param texture Pointer to a texture
*/
inline Billboard::Billboard(Texture* texture) inline Billboard::Billboard(Texture* texture)
{ {
SetColor(Color::White); SetColor(Color::White);
@ -31,6 +47,12 @@ namespace Nz
SetTexture(texture, true); SetTexture(texture, true);
} }
/*!
* \brief Constructs a Billboard object by assignation
*
* \param billboard Billboard to copy into this
*/
inline Billboard::Billboard(const Billboard& billboard) : inline Billboard::Billboard(const Billboard& billboard) :
InstancedRenderable(billboard), InstancedRenderable(billboard),
m_color(billboard.m_color), m_color(billboard.m_color),
@ -41,31 +63,61 @@ namespace Nz
{ {
} }
/*!
* \brief Gets the color of the billboard
* \return Current color
*/
inline const Color& Billboard::GetColor() const inline const Color& Billboard::GetColor() const
{ {
return m_color; return m_color;
} }
/*!
* \brief Gets the material of the billboard
* \return Current material
*/
inline const MaterialRef& Billboard::GetMaterial() const inline const MaterialRef& Billboard::GetMaterial() const
{ {
return m_material; return m_material;
} }
/*!
* \brief Gets the rotation of the billboard
* \return Current rotation
*/
inline float Billboard::GetRotation() const inline float Billboard::GetRotation() const
{ {
return m_rotation; return m_rotation;
} }
/*!
* \brief Gets the size of the billboard
* \return Current size
*/
inline const Vector2f& Billboard::GetSize() const inline const Vector2f& Billboard::GetSize() const
{ {
return m_size; return m_size;
} }
/*!
* \brief Sets the color of the billboard
*
* \param color Color for the billboard
*/
inline void Billboard::SetColor(const Color& color) inline void Billboard::SetColor(const Color& color)
{ {
m_color = color; m_color = color;
} }
/*!
* \brief Sets the default material of the billboard (just default material)
*/
inline void Billboard::SetDefaultMaterial() inline void Billboard::SetDefaultMaterial()
{ {
MaterialRef material = Material::New(); MaterialRef material = Material::New();
@ -75,6 +127,13 @@ namespace Nz
SetMaterial(std::move(material)); SetMaterial(std::move(material));
} }
/*!
* \brief Sets the material of the billboard
*
* \param material Material for the billboard
* \param resizeBillboard Should billboard be resized to the material size (diffuse map)
*/
inline void Billboard::SetMaterial(MaterialRef material, bool resizeBillboard) inline void Billboard::SetMaterial(MaterialRef material, bool resizeBillboard)
{ {
m_material = std::move(material); m_material = std::move(material);
@ -86,25 +145,51 @@ namespace Nz
} }
} }
/*!
* \brief Sets the rotation of the billboard
*
* \param rotation Rotation for the billboard
*/
inline void Billboard::SetRotation(float rotation) inline void Billboard::SetRotation(float rotation)
{ {
m_rotation = rotation; m_rotation = rotation;
m_sinCos.Set(std::sin(m_rotation), std::cos(m_rotation)); m_sinCos.Set(std::sin(m_rotation), std::cos(m_rotation));
} }
/*!
* \brief Sets the size of the billboard
*
* \param size Size for the billboard
*/
inline void Billboard::SetSize(const Vector2f& size) inline void Billboard::SetSize(const Vector2f& size)
{ {
m_size = size; m_size = size;
// On invalide la bounding box // We invalidate the bounding volume
InvalidateBoundingVolume(); InvalidateBoundingVolume();
} }
/*!
* \brief Sets the size of the billboard
*
* \param sizeX Size in X for the billboard
* \param sizeY Size in Y for the billboard
*/
inline void Billboard::SetSize(float sizeX, float sizeY) inline void Billboard::SetSize(float sizeX, float sizeY)
{ {
SetSize(Vector2f(sizeX, sizeY)); SetSize(Vector2f(sizeX, sizeY));
} }
/*!
* \brief Sets the texture of the billboard
*
* \param texture Texture for the billboard
* \param resizeBillboard Should billboard be resized to the texture size
*/
inline void Billboard::SetTexture(TextureRef texture, bool resizeBillboard) inline void Billboard::SetTexture(TextureRef texture, bool resizeBillboard)
{ {
if (!m_material) if (!m_material)
@ -118,6 +203,13 @@ namespace Nz
m_material->SetDiffuseMap(std::move(texture)); m_material->SetDiffuseMap(std::move(texture));
} }
/*!
* \brief Sets the current billboard with the content of the other one
* \return A reference to this
*
* \param billboard The other Billboard
*/
inline Billboard& Billboard::operator=(const Billboard& billboard) inline Billboard& Billboard::operator=(const Billboard& billboard)
{ {
InstancedRenderable::operator=(billboard); InstancedRenderable::operator=(billboard);
@ -131,6 +223,13 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Creates a new billboard from the arguments
* \return A reference to the newly created billboard
*
* \param args Arguments for the billboard
*/
template<typename... Args> template<typename... Args>
BillboardRef Billboard::New(Args&&... args) BillboardRef Billboard::New(Args&&... args)
{ {

View File

@ -7,6 +7,13 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Creates a new color background from the arguments
* \return A reference to the newly created color background
*
* \param args Arguments for the color background
*/
template<typename... Args> template<typename... Args>
ColorBackgroundRef ColorBackground::New(Args&&... args) ColorBackgroundRef ColorBackground::New(Args&&... args)
{ {

View File

@ -27,23 +27,28 @@
#ifndef NAZARA_CONFIG_GRAPHICS_HPP #ifndef NAZARA_CONFIG_GRAPHICS_HPP
#define NAZARA_CONFIG_GRAPHICS_HPP #define NAZARA_CONFIG_GRAPHICS_HPP
/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci /*!
* \defgroup graphics (NazaraGraphics) Graphics module
* Graphics/System module including classes to handle graphical elements...
*/
// À partir de combien d'instances d'un même mesh/matériau l'instancing doit-il être utilisé ? /// Each modification of a paramater of the module needs a recompilation of the unit
// How much instances are need of a same mesh/material to enable instancing ?
#define NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT 10 #define NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT 10
// Utilise un manager de mémoire pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) // Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower)
#define NAZARA_GRAPHICS_MANAGE_MEMORY 0 #define NAZARA_GRAPHICS_MANAGE_MEMORY 0
// Active les tests de sécurité basés sur le code (Conseillé pour le développement) // Activate the security tests based on the code (Advised for development)
#define NAZARA_GRAPHICS_SAFE 1 #define NAZARA_GRAPHICS_SAFE 1
/// Chaque modification d'un paramètre ci-dessous implique une modification (souvent mineure) du code /// Each modification of a parameter following implies a modification (often minor) of the code
// Le nombre maximum de lumières qu'un shader standard supportera // The maximum number of lights in a standard shader
#define NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS 3 #define NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS 3
/// Vérification des valeurs et types de certaines constantes /// Checking the values and types of certain constants
#include <Nazara/Graphics/ConfigCheck.hpp> #include <Nazara/Graphics/ConfigCheck.hpp>
#if defined(NAZARA_STATIC) #if defined(NAZARA_STATIC)

View File

@ -7,12 +7,12 @@
#ifndef NAZARA_CONFIG_CHECK_GRAPHICS_HPP #ifndef NAZARA_CONFIG_CHECK_GRAPHICS_HPP
#define NAZARA_CONFIG_CHECK_GRAPHICS_HPP #define NAZARA_CONFIG_CHECK_GRAPHICS_HPP
/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp /// This file is used to check the constant values defined in Config.hpp
#include <type_traits> #include <type_traits>
#define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type <decltype(name)>::value && name op val, #type err) #define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type <decltype(name)>::value && name op val, #type err)
// On force la valeur de MANAGE_MEMORY en mode debug // We fore the value of MANAGE_MEMORY in debug
#if defined(NAZARA_DEBUG) && !NAZARA_GRAPHICS_MANAGE_MEMORY #if defined(NAZARA_DEBUG) && !NAZARA_GRAPHICS_MANAGE_MEMORY
#undef NAZARA_GRAPHICS_MANAGE_MEMORY #undef NAZARA_GRAPHICS_MANAGE_MEMORY
#define NAZARA_GRAPHICS_MANAGE_MEMORY 0 #define NAZARA_GRAPHICS_MANAGE_MEMORY 0

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Engine - Graphics module" // This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp // We suppose that Debug.hpp is already included, same goes for Config.hpp
#if NAZARA_GRAPHICS_MANAGE_MEMORY #if NAZARA_GRAPHICS_MANAGE_MEMORY
#undef delete #undef delete
#undef new #undef new

View File

@ -29,7 +29,7 @@ namespace Nz
float GetBrightThreshold() const; float GetBrightThreshold() const;
Texture* GetTexture(unsigned int i) const; Texture* GetTexture(unsigned int i) const;
bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const;
bool Resize(const Vector2ui& dimensions); bool Resize(const Vector2ui& dimensions);
void SetBlurPassCount(unsigned int passCount); void SetBlurPassCount(unsigned int passCount);

View File

@ -23,7 +23,7 @@ namespace Nz
DeferredDOFPass(); DeferredDOFPass();
virtual ~DeferredDOFPass(); virtual ~DeferredDOFPass();
bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const;
bool Resize(const Vector2ui& dimensions); bool Resize(const Vector2ui& dimensions);
protected: protected:

View File

@ -21,7 +21,7 @@ namespace Nz
DeferredFXAAPass(); DeferredFXAAPass();
virtual ~DeferredFXAAPass(); virtual ~DeferredFXAAPass();
bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const;
protected: protected:
RenderStates m_states; RenderStates m_states;

View File

@ -21,7 +21,7 @@ namespace Nz
DeferredFinalPass(); DeferredFinalPass();
virtual ~DeferredFinalPass(); virtual ~DeferredFinalPass();
bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const;
protected: protected:
RenderStates m_states; RenderStates m_states;

View File

@ -21,7 +21,7 @@ namespace Nz
DeferredFogPass(); DeferredFogPass();
virtual ~DeferredFogPass(); virtual ~DeferredFogPass();
bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const;
protected: protected:
RenderStates m_states; RenderStates m_states;

View File

@ -21,7 +21,7 @@ namespace Nz
virtual ~DeferredForwardPass(); virtual ~DeferredForwardPass();
void Initialize(DeferredRenderTechnique* technique); void Initialize(DeferredRenderTechnique* technique);
bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const; bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const;
protected: protected:
const ForwardRenderTechnique* m_forwardTechnique; const ForwardRenderTechnique* m_forwardTechnique;

View File

@ -21,7 +21,7 @@ namespace Nz
DeferredGeometryPass(); DeferredGeometryPass();
virtual ~DeferredGeometryPass(); virtual ~DeferredGeometryPass();
bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const;
bool Resize(const Vector2ui& dimensions); bool Resize(const Vector2ui& dimensions);
protected: protected:

View File

@ -28,7 +28,7 @@ namespace Nz
bool IsLightMeshesDrawingEnabled() const; bool IsLightMeshesDrawingEnabled() const;
bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const;
protected: protected:
LightUniforms m_directionalLightUniforms; LightUniforms m_directionalLightUniforms;

View File

@ -38,7 +38,7 @@ namespace Nz
bool IsEnabled() const; bool IsEnabled() const;
virtual bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const = 0; virtual bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const = 0;
virtual bool Resize(const Vector2ui& GBufferSize); virtual bool Resize(const Vector2ui& GBufferSize);
DeferredRenderPass& operator=(const DeferredRenderPass&) = delete; DeferredRenderPass& operator=(const DeferredRenderPass&) = delete;

View File

@ -67,7 +67,7 @@ namespace Nz
}; };
std::map<RenderPassType, std::map<int, std::unique_ptr<DeferredRenderPass>>, RenderPassComparator> m_passes; std::map<RenderPassType, std::map<int, std::unique_ptr<DeferredRenderPass>>, RenderPassComparator> m_passes;
ForwardRenderTechnique m_forwardTechnique; // Doit être initialisé avant la RenderQueue ForwardRenderTechnique m_forwardTechnique; // Must be initialized before the RenderQueue
DeferredRenderQueue m_renderQueue; DeferredRenderQueue m_renderQueue;
mutable RenderBufferRef m_depthStencilBuffer; mutable RenderBufferRef m_depthStencilBuffer;
mutable RenderTexture m_GBufferRTT; mutable RenderTexture m_GBufferRTT;

View File

@ -6,6 +6,14 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Checks whether the material is suitable to fit in the render queue
* \return true If it is the case
*
* \param material Material to verify
*/
bool DepthRenderQueue::IsMaterialSuitable(const Material* material) const bool DepthRenderQueue::IsMaterialSuitable(const Material* material) const
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");

View File

@ -128,7 +128,7 @@ namespace Nz
SceneNodeType_Max = SceneNodeType_User SceneNodeType_Max = SceneNodeType_User
}; };
// Ces paramètres sont indépendants du matériau: ils peuvent être demandés à tout moment // These parameters are independant of the material: they can not be asked for the moment
enum ShaderFlags enum ShaderFlags
{ {
ShaderFlags_None = 0, ShaderFlags_None = 0,
@ -139,7 +139,7 @@ namespace Nz
ShaderFlags_TextureOverlay = 0x08, ShaderFlags_TextureOverlay = 0x08,
ShaderFlags_VertexColor = 0x10, ShaderFlags_VertexColor = 0x10,
ShaderFlags_Max = ShaderFlags_VertexColor*2-1 ShaderFlags_Max = ShaderFlags_VertexColor * 2 - 1
}; };
} }

View File

@ -159,6 +159,7 @@ namespace Nz
std::map<int, Layer> layers; std::map<int, Layer> layers;
private: private:
BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count);
Layer& GetLayer(int i); ///TODO: Inline Layer& GetLayer(int i); ///TODO: Inline
void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer); void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer);

View File

@ -31,7 +31,7 @@ namespace Nz
AbstractRenderQueue* GetRenderQueue() override; AbstractRenderQueue* GetRenderQueue() override;
RenderTechniqueType GetType() const override; RenderTechniqueType GetType() const override;
void SetMaxLightPassPerObject(unsigned int passCount); void SetMaxLightPassPerObject(unsigned int maxLightPassPerObject);
static bool Initialize(); static bool Initialize();
static void Uninitialize(); static void Uninitialize();
@ -70,11 +70,11 @@ namespace Nz
LightUniforms lightUniforms; LightUniforms lightUniforms;
bool hasLightUniforms; bool hasLightUniforms;
/// Moins coûteux en mémoire que de stocker un LightUniforms par index de lumière, /// Less costly in memory than storing a LightUniforms by index of light,
/// à voir si ça fonctionne chez tout le monde /// this may not work everywhere
int lightOffset; // "Distance" entre Lights[0].type et Lights[1].type int lightOffset; // "Distance" between Lights[0].type and Lights[1].type
// Autre uniformes // Other uniforms
int eyePosition; int eyePosition;
int sceneAmbient; int sceneAmbient;
int textureOverlay; int textureOverlay;

View File

@ -6,6 +6,16 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Sens the uniforms for light
*
* \param shader Shader to send uniforms to
* \param uniforms Uniforms to send
* \param index Index of the light
* \param uniformOffset Offset for the uniform
* \param availableTextureUnit Unit texture available
*/
inline void ForwardRenderTechnique::SendLightUniforms(const Shader* shader, const LightUniforms& uniforms, unsigned int index, unsigned int uniformOffset, UInt8 availableTextureUnit) const inline void ForwardRenderTechnique::SendLightUniforms(const Shader* shader, const LightUniforms& uniforms, unsigned int index, unsigned int uniformOffset, UInt8 availableTextureUnit) const
{ {
// If anyone got a better idea.. // If anyone got a better idea..
@ -104,6 +114,14 @@ namespace Nz
} }
} }
/*!
* \brief Computes the score for directional light
* \return 0.f
*
* \param object Sphere symbolising the object
* \param light Light to compute
*/
inline float ForwardRenderTechnique::ComputeDirectionalLightScore(const Spheref& object, const AbstractRenderQueue::DirectionalLight& light) inline float ForwardRenderTechnique::ComputeDirectionalLightScore(const Spheref& object, const AbstractRenderQueue::DirectionalLight& light)
{ {
NazaraUnused(object); NazaraUnused(object);
@ -113,18 +131,42 @@ namespace Nz
return 0.f; return 0.f;
} }
/*!
* \brief Computes the score for point light
* \return Distance to the light
*
* \param object Sphere symbolising the object
* \param light Light to compute
*/
inline float ForwardRenderTechnique::ComputePointLightScore(const Spheref& object, const AbstractRenderQueue::PointLight& light) inline float ForwardRenderTechnique::ComputePointLightScore(const Spheref& object, const AbstractRenderQueue::PointLight& light)
{ {
///TODO: Compute a score depending on the light luminosity ///TODO: Compute a score depending on the light luminosity
return object.SquaredDistance(light.position); return object.SquaredDistance(light.position);
} }
/*!
* \brief Computes the score for spot light
* \return Distance to the light
*
* \param object Sphere symbolising the object
* \param light Light to compute
*/
inline float ForwardRenderTechnique::ComputeSpotLightScore(const Spheref& object, const AbstractRenderQueue::SpotLight& light) inline float ForwardRenderTechnique::ComputeSpotLightScore(const Spheref& object, const AbstractRenderQueue::SpotLight& light)
{ {
///TODO: Compute a score depending on the light luminosity and spot direction ///TODO: Compute a score depending on the light luminosity and spot direction
return object.SquaredDistance(light.position); return object.SquaredDistance(light.position);
} }
/*!
* \brief Checks whether the directional light is suitable for the computations
* \return true if light is enoughly close
*
* \param object Sphere symbolising the object
* \param light Light to compute
*/
inline bool ForwardRenderTechnique::IsDirectionalLightSuitable(const Spheref& object, const AbstractRenderQueue::DirectionalLight& light) inline bool ForwardRenderTechnique::IsDirectionalLightSuitable(const Spheref& object, const AbstractRenderQueue::DirectionalLight& light)
{ {
NazaraUnused(object); NazaraUnused(object);
@ -134,12 +176,28 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Checks whether the point light is suitable for the computations
* \return true if light is enoughly close
*
* \param object Sphere symbolising the object
* \param light Light to compute
*/
inline bool ForwardRenderTechnique::IsPointLightSuitable(const Spheref& object, const AbstractRenderQueue::PointLight& light) inline bool ForwardRenderTechnique::IsPointLightSuitable(const Spheref& object, const AbstractRenderQueue::PointLight& light)
{ {
// If the object is too far away from this point light, there is not way it could light it // If the object is too far away from this point light, there is not way it could light it
return object.SquaredDistance(light.position) <= light.radius * light.radius; return object.SquaredDistance(light.position) <= light.radius * light.radius;
} }
/*!
* \brief Checks whether the spot light is suitable for the computations
* \return true if light is enoughly close
*
* \param object Sphere symbolising the object
* \param light Light to compute
*/
inline bool ForwardRenderTechnique::IsSpotLightSuitable(const Spheref& object, const AbstractRenderQueue::SpotLight& light) inline bool ForwardRenderTechnique::IsSpotLightSuitable(const Spheref& object, const AbstractRenderQueue::SpotLight& light)
{ {
///TODO: Exclude spot lights based on their direction and outer angle? ///TODO: Exclude spot lights based on their direction and outer angle?

View File

@ -4,6 +4,12 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a InstancedRenderable object by assignation
*
* \param renderable InstancedRenderable to copy into this
*/
inline InstancedRenderable::InstancedRenderable(const InstancedRenderable& renderable) : inline InstancedRenderable::InstancedRenderable(const InstancedRenderable& renderable) :
RefCounted(), RefCounted(),
m_boundingVolume(renderable.m_boundingVolume), m_boundingVolume(renderable.m_boundingVolume),
@ -11,22 +17,43 @@ namespace Nz
{ {
} }
/*!
* \brief Ensures that the bounding volume is up to date
*/
inline void InstancedRenderable::EnsureBoundingVolumeUpdated() const inline void InstancedRenderable::EnsureBoundingVolumeUpdated() const
{ {
if (!m_boundingVolumeUpdated) if (!m_boundingVolumeUpdated)
UpdateBoundingVolume(); UpdateBoundingVolume();
} }
/*!
* \brief Invalidates the bounding volume
*/
inline void InstancedRenderable::InvalidateBoundingVolume() inline void InstancedRenderable::InvalidateBoundingVolume()
{ {
m_boundingVolumeUpdated = false; m_boundingVolumeUpdated = false;
} }
/*!
* \brief Invalidates the instance data based on flags
*
* \param flags Flags to invalidate
*/
inline void InstancedRenderable::InvalidateInstanceData(UInt32 flags) inline void InstancedRenderable::InvalidateInstanceData(UInt32 flags)
{ {
OnInstancedRenderableInvalidateData(this, flags); OnInstancedRenderableInvalidateData(this, flags);
} }
/*!
* \brief Sets the current instanced renderable with the content of the other one
* \return A reference to this
*
* \param renderable The other InstancedRenderable
*/
inline InstancedRenderable& InstancedRenderable::operator=(const InstancedRenderable& renderable) inline InstancedRenderable& InstancedRenderable::operator=(const InstancedRenderable& renderable)
{ {
m_boundingVolume = renderable.m_boundingVolume; m_boundingVolume = renderable.m_boundingVolume;
@ -35,6 +62,10 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Updates the bounding volume
*/
inline void InstancedRenderable::UpdateBoundingVolume() const inline void InstancedRenderable::UpdateBoundingVolume() const
{ {
MakeBoundingVolume(); MakeBoundingVolume();

View File

@ -7,6 +7,10 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a Light object by default
*/
inline Light::Light(const Light& light) : inline Light::Light(const Light& light) :
Renderable(light), Renderable(light),
m_color(light.m_color), m_color(light.m_color),
@ -28,6 +32,12 @@ namespace Nz
{ {
} }
/*!
* \brief Enables shadow casting
*
* \param castShadows Should shadows be cast
*/
inline void Light::EnableShadowCasting(bool castShadows) inline void Light::EnableShadowCasting(bool castShadows)
{ {
if (m_shadowCastingEnabled != castShadows) if (m_shadowCastingEnabled != castShadows)
@ -37,72 +47,141 @@ namespace Nz
} }
} }
/*!
* \brief Ensures that the shadow map is up to date
*/
inline void Light::EnsureShadowMapUpdate() const inline void Light::EnsureShadowMapUpdate() const
{ {
if (!m_shadowMapUpdated) if (!m_shadowMapUpdated)
UpdateShadowMap(); UpdateShadowMap();
} }
/*!
* \brief Gets the ambient factor
* \return Current ambient factor
*/
inline float Light::GetAmbientFactor() const inline float Light::GetAmbientFactor() const
{ {
return m_ambientFactor; return m_ambientFactor;
} }
/*!
* \brief Gets the light attenuation (in 1 / R^2)
* \return Attenuation
*/
inline float Light::GetAttenuation() const inline float Light::GetAttenuation() const
{ {
return m_attenuation; return m_attenuation;
} }
/*!
* \brief Gets the color of the light
* \return Light color
*/
inline Color Light::GetColor() const inline Color Light::GetColor() const
{ {
return m_color; return m_color;
} }
/*!
* \brief Gets the diffuse factor
* \return Current diffuse factor
*/
inline float Light::GetDiffuseFactor() const inline float Light::GetDiffuseFactor() const
{ {
return m_diffuseFactor; return m_diffuseFactor;
} }
/*!
* \brief Gets the inner angle in spot light
* \return Inner angle
*/
inline float Light::GetInnerAngle() const inline float Light::GetInnerAngle() const
{ {
return m_innerAngle; return m_innerAngle;
} }
/*!
* \brief Gets the cosine inner angle in spot light
* \return Cosine inner angle
*/
inline float Light::GetInnerAngleCosine() const inline float Light::GetInnerAngleCosine() const
{ {
return m_innerAngleCosine; return m_innerAngleCosine;
} }
/*!
* \brief Gets the inverse of the radius
* \return Inverse of the radius
*/
inline float Light::GetInvRadius() const inline float Light::GetInvRadius() const
{ {
return m_invRadius; return m_invRadius;
} }
/*!
* \brief Gets the type of the light
* \return Light type
*/
inline LightType Light::GetLightType() const inline LightType Light::GetLightType() const
{ {
return m_type; return m_type;
} }
/*!
* \brief Gets the outer angle in spot light
* \return Outer angle
*/
inline float Light::GetOuterAngle() const inline float Light::GetOuterAngle() const
{ {
return m_outerAngle; return m_outerAngle;
} }
/*!
* \brief Gets the cosine outer angle in spot light
* \return Cosine outer angle
*/
inline float Light::GetOuterAngleCosine() const inline float Light::GetOuterAngleCosine() const
{ {
return m_outerAngleCosine; return m_outerAngleCosine;
} }
/*!
* \brief Gets the tangent outer angle in spot light
* \return Tangent outer angle
*/
inline float Light::GetOuterAngleTangent() const inline float Light::GetOuterAngleTangent() const
{ {
return m_outerAngleTangent; return m_outerAngleTangent;
} }
/*!
* \brief Gets the radius of the light
* \return Light radius
*/
inline float Light::GetRadius() const inline float Light::GetRadius() const
{ {
return m_radius; return m_radius;
} }
/*!
* \brief Gets the shadow map
* \return Reference to the shadow map texture
*/
inline TextureRef Light::GetShadowMap() const inline TextureRef Light::GetShadowMap() const
{ {
EnsureShadowMapUpdate(); EnsureShadowMapUpdate();
@ -110,47 +189,97 @@ namespace Nz
return m_shadowMap; return m_shadowMap;
} }
/*!
* \brief Gets the format of the shadow map
* \return Shadow map format
*/
inline PixelFormatType Light::GetShadowMapFormat() const inline PixelFormatType Light::GetShadowMapFormat() const
{ {
return m_shadowMapFormat; return m_shadowMapFormat;
} }
/*!
* \brief Gets the size of the shadow map
* \return Shadow map size
*/
inline const Vector2ui& Light::GetShadowMapSize() const inline const Vector2ui& Light::GetShadowMapSize() const
{ {
return m_shadowMapSize; return m_shadowMapSize;
} }
/*!
* \brief Checks whether the shadow casting is enabled
* \return true If it is the case
*/
inline bool Light::IsShadowCastingEnabled() const inline bool Light::IsShadowCastingEnabled() const
{ {
return m_shadowCastingEnabled; return m_shadowCastingEnabled;
} }
/*!
* \brief Sets the ambient factor
*
* \param factor Ambient factor
*/
inline void Light::SetAmbientFactor(float factor) inline void Light::SetAmbientFactor(float factor)
{ {
m_ambientFactor = factor; m_ambientFactor = factor;
} }
/*!
* \brief Sets the light attenuation (in 1 / R^2)
*
* \param attenuation Light attenuation
*/
inline void Light::SetAttenuation(float attenuation) inline void Light::SetAttenuation(float attenuation)
{ {
m_attenuation = attenuation; m_attenuation = attenuation;
} }
/*!
* \brief Sets the color of the light
*
* \param color Light color
*/
inline void Light::SetColor(const Color& color) inline void Light::SetColor(const Color& color)
{ {
m_color = color; m_color = color;
} }
/*!
* \brief Sets the diffuse factor
*
* \param factor Diffuse factor
*/
inline void Light::SetDiffuseFactor(float factor) inline void Light::SetDiffuseFactor(float factor)
{ {
m_diffuseFactor = factor; m_diffuseFactor = factor;
} }
/*!
* \brief Sets the inner angle in spot light
* \return innerAngle Inner angle
*/
inline void Light::SetInnerAngle(float innerAngle) inline void Light::SetInnerAngle(float innerAngle)
{ {
m_innerAngle = innerAngle; m_innerAngle = innerAngle;
m_innerAngleCosine = std::cos(DegreeToRadian(m_innerAngle)); m_innerAngleCosine = std::cos(DegreeToRadian(m_innerAngle));
} }
/*!
* \brief Sets the type of light
*
* \param type Light type
*/
inline void Light::SetLightType(LightType type) inline void Light::SetLightType(LightType type)
{ {
m_type = type; m_type = type;
@ -158,6 +287,13 @@ namespace Nz
InvalidateShadowMap(); InvalidateShadowMap();
} }
/*!
* \brief Sets the outer angle in spot light
* \return outerAngle Outer angle
*
* \remark Invalidates the bounding volume
*/
inline void Light::SetOuterAngle(float outerAngle) inline void Light::SetOuterAngle(float outerAngle)
{ {
m_outerAngle = outerAngle; m_outerAngle = outerAngle;
@ -167,6 +303,13 @@ namespace Nz
InvalidateBoundingVolume(); InvalidateBoundingVolume();
} }
/*!
* \brief Sets the radius of the light
* \return radius Light radius
*
* \remark Invalidates the bounding volume
*/
inline void Light::SetRadius(float radius) inline void Light::SetRadius(float radius)
{ {
m_radius = radius; m_radius = radius;
@ -176,6 +319,15 @@ namespace Nz
InvalidateBoundingVolume(); InvalidateBoundingVolume();
} }
/*!
* \brief Sets the shadow map format
*
* \param shadowFormat Shadow map format
*
* \remark Invalidates the shadow map
* \remark Produces a NazaraAssert if format is not a depth type
*/
inline void Light::SetShadowMapFormat(PixelFormatType shadowFormat) inline void Light::SetShadowMapFormat(PixelFormatType shadowFormat)
{ {
NazaraAssert(PixelFormat::GetContent(shadowFormat) == PixelFormatContent_DepthStencil, "Shadow format type is not a depth format"); NazaraAssert(PixelFormat::GetContent(shadowFormat) == PixelFormatContent_DepthStencil, "Shadow format type is not a depth format");
@ -185,6 +337,15 @@ namespace Nz
InvalidateShadowMap(); InvalidateShadowMap();
} }
/*!
* \brief Sets the size of the shadow map
*
* \param size Shadow map size
*
* \remark Invalidates the shadow map
* \remark Produces a NazaraAssert if size is zero
*/
inline void Light::SetShadowMapSize(const Vector2ui& size) inline void Light::SetShadowMapSize(const Vector2ui& size)
{ {
NazaraAssert(size.x > 0 && size.y > 0, "Shadow map size must have a positive size"); NazaraAssert(size.x > 0 && size.y > 0, "Shadow map size must have a positive size");
@ -194,6 +355,15 @@ namespace Nz
InvalidateShadowMap(); InvalidateShadowMap();
} }
/*!
* \brief Sets the current light with the content of the other one
* \return A reference to this
*
* \param light The other Light
*
* \remark Invalidates the shadow map
*/
inline Light& Light::operator=(const Light& light) inline Light& Light::operator=(const Light& light)
{ {
Renderable::operator=(light); Renderable::operator=(light);
@ -218,6 +388,10 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Invalidates the shadow map
*/
inline void Light::InvalidateShadowMap() inline void Light::InvalidateShadowMap()
{ {
m_shadowMapUpdated = false; m_shadowMapUpdated = false;

View File

@ -151,7 +151,7 @@ namespace Nz
inline Material& operator=(const Material& material); inline Material& operator=(const Material& material);
static MaterialRef GetDefault(); inline static MaterialRef GetDefault();
template<typename... Args> static MaterialRef New(Args&&... args); template<typename... Args> static MaterialRef New(Args&&... args);
// Signals: // Signals:
@ -163,7 +163,7 @@ namespace Nz
{ {
const Shader* shader; const Shader* shader;
UberShaderInstance* uberInstance = nullptr; UberShaderInstance* uberInstance = nullptr;
int uniforms[MaterialUniform_Max+1]; int uniforms[MaterialUniform_Max + 1];
}; };
void Copy(const Material& material); void Copy(const Material& material);
@ -187,7 +187,7 @@ namespace Nz
TextureRef m_normalMap; TextureRef m_normalMap;
TextureRef m_specularMap; TextureRef m_specularMap;
UberShaderConstRef m_uberShader; UberShaderConstRef m_uberShader;
mutable ShaderInstance m_shaders[ShaderFlags_Max+1]; mutable ShaderInstance m_shaders[ShaderFlags_Max + 1];
bool m_alphaTestEnabled; bool m_alphaTestEnabled;
bool m_depthSortingEnabled; bool m_depthSortingEnabled;
bool m_lightingEnabled; bool m_lightingEnabled;

View File

@ -7,11 +7,21 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a Material object by default
*/
inline Material::Material() inline Material::Material()
{ {
Reset(); Reset();
} }
/*!
* \brief Constructs a Material object by assignation
*
* \param material Material to copy into this
*/
inline Material::Material(const Material& material) : inline Material::Material(const Material& material) :
RefCounted(), RefCounted(),
Resource(material) Resource(material)
@ -19,11 +29,26 @@ namespace Nz
Copy(material); Copy(material);
} }
/*!
* \brief Destructs the object and calls OnMaterialRelease
*
* \see OnMaterialRelease
*/
inline Material::~Material() inline Material::~Material()
{ {
OnMaterialRelease(this); OnMaterialRelease(this);
} }
/*!
* \brief Enables a renderer parameter
*
* \param renderParameter Parameter for the rendering
* \param enable Should the parameter be enabled
*
* \remark Produces a NazaraAssert if enumeration is invalid
*/
inline void Material::Enable(RendererParameter renderParameter, bool enable) inline void Material::Enable(RendererParameter renderParameter, bool enable)
{ {
NazaraAssert(renderParameter <= RendererParameter_Max, "Renderer parameter out of enum"); NazaraAssert(renderParameter <= RendererParameter_Max, "Renderer parameter out of enum");
@ -31,6 +56,14 @@ namespace Nz
m_states.parameters[renderParameter] = enable; m_states.parameters[renderParameter] = enable;
} }
/*!
* \brief Enables the alpha test
*
* \param alphaTest Should the parameter be enabled
*
* \remark Invalidates the shaders
*/
inline void Material::EnableAlphaTest(bool alphaTest) inline void Material::EnableAlphaTest(bool alphaTest)
{ {
m_alphaTestEnabled = alphaTest; m_alphaTestEnabled = alphaTest;
@ -38,12 +71,26 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Enables the depth sorting
*
* \param depthSorting Should the parameter be enabled
*/
inline void Material::EnableDepthSorting(bool depthSorting) inline void Material::EnableDepthSorting(bool depthSorting)
{ {
// Has no influence on shaders // Has no influence on shaders
m_depthSortingEnabled = depthSorting; m_depthSortingEnabled = depthSorting;
} }
/*!
* \brief Enables the lighting
*
* \param lighting Should the parameter be enabled
*
* \remark Invalidates the shaders
*/
inline void Material::EnableLighting(bool lighting) inline void Material::EnableLighting(bool lighting)
{ {
m_lightingEnabled = lighting; m_lightingEnabled = lighting;
@ -51,12 +98,26 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Enables the shadow casting
*
* \param castShadows Should shadow casting be enabled
*/
inline void Material::EnableShadowCasting(bool castShadows) inline void Material::EnableShadowCasting(bool castShadows)
{ {
// Has no influence on shaders // Has no influence on shaders
m_shadowCastingEnabled = castShadows; m_shadowCastingEnabled = castShadows;
} }
/*!
* \brief Enables the shadow on receiving object
*
* \param receiveShadow Should receiving object have shadows enabled
*
* \remark Invalidates the shaders
*/
inline void Material::EnableShadowReceive(bool receiveShadows) inline void Material::EnableShadowReceive(bool receiveShadows)
{ {
m_shadowReceiveEnabled = receiveShadows; m_shadowReceiveEnabled = receiveShadows;
@ -64,6 +125,14 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Enables the transformation
*
* \param transform Should the parameter be enabled
*
* \remark Invalidates the shaders
*/
inline void Material::EnableTransform(bool transform) inline void Material::EnableTransform(bool transform)
{ {
m_transformEnabled = transform; m_transformEnabled = transform;
@ -71,91 +140,183 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Gets the alpha map
* \return Constant reference to the current texture
*/
inline const TextureRef& Material::GetAlphaMap() const inline const TextureRef& Material::GetAlphaMap() const
{ {
return m_alphaMap; return m_alphaMap;
} }
/*!
* \brief Gets the alpha threshold
* \return The threshold value for the alpha
*/
inline float Material::GetAlphaThreshold() const inline float Material::GetAlphaThreshold() const
{ {
return m_alphaThreshold; return m_alphaThreshold;
} }
/*!
* \brief Gets the ambient color
* \return Ambient color
*/
inline Color Material::GetAmbientColor() const inline Color Material::GetAmbientColor() const
{ {
return m_ambientColor; return m_ambientColor;
} }
/*!
* \brief Gets the function to compare depth
* \return Function comparing the depth of two materials
*/
inline RendererComparison Material::GetDepthFunc() const inline RendererComparison Material::GetDepthFunc() const
{ {
return m_states.depthFunc; return m_states.depthFunc;
} }
/*!
* \brief Gets the depth material
* \return Constant reference to the depth material
*/
inline const MaterialRef& Material::GetDepthMaterial() const inline const MaterialRef& Material::GetDepthMaterial() const
{ {
return m_depthMaterial; return m_depthMaterial;
} }
/*!
* \brief Gets the diffuse color
* \return Diffuse color
*/
inline Color Material::GetDiffuseColor() const inline Color Material::GetDiffuseColor() const
{ {
return m_diffuseColor; return m_diffuseColor;
} }
/*!
* \brief Gets the diffuse sampler
* \return Reference to the current texture sampler for the diffuse
*/
inline TextureSampler& Material::GetDiffuseSampler() inline TextureSampler& Material::GetDiffuseSampler()
{ {
return m_diffuseSampler; return m_diffuseSampler;
} }
/*!
* \brief Gets the diffuse sampler
* \return Constant reference to the current texture sampler for the diffuse
*/
inline const TextureSampler& Material::GetDiffuseSampler() const inline const TextureSampler& Material::GetDiffuseSampler() const
{ {
return m_diffuseSampler; return m_diffuseSampler;
} }
/*!
* \brief Gets the diffuse map
* \return Constant reference to the texture
*/
const TextureRef& Material::GetDiffuseMap() const const TextureRef& Material::GetDiffuseMap() const
{ {
return m_diffuseMap; return m_diffuseMap;
} }
/*!
* \brief Gets the dst in blend
* \return Function for dst blending
*/
inline BlendFunc Material::GetDstBlend() const inline BlendFunc Material::GetDstBlend() const
{ {
return m_states.dstBlend; return m_states.dstBlend;
} }
/*!
* \brief Gets the emissive map
* \return Constant reference to the texture
*/
inline const TextureRef& Material::GetEmissiveMap() const inline const TextureRef& Material::GetEmissiveMap() const
{ {
return m_emissiveMap; return m_emissiveMap;
} }
/*!
* \brief Gets the face culling
* \return Current face culling side
*/
inline FaceSide Material::GetFaceCulling() const inline FaceSide Material::GetFaceCulling() const
{ {
return m_states.faceCulling; return m_states.faceCulling;
} }
/*!
* \brief Gets the face filling
* \return Current face filling
*/
inline FaceFilling Material::GetFaceFilling() const inline FaceFilling Material::GetFaceFilling() const
{ {
return m_states.faceFilling; return m_states.faceFilling;
} }
/*!
* \brief Gets the height map
* \return Constant reference to the texture
*/
inline const TextureRef& Material::GetHeightMap() const inline const TextureRef& Material::GetHeightMap() const
{ {
return m_heightMap; return m_heightMap;
} }
/*!
* \brief Gets the normal map
* \return Constant reference to the texture
*/
inline const TextureRef& Material::GetNormalMap() const inline const TextureRef& Material::GetNormalMap() const
{ {
return m_normalMap; return m_normalMap;
} }
/*!
* \brief Gets the render states
* \return Constant reference to the render states
*/
inline const RenderStates& Material::GetRenderStates() const inline const RenderStates& Material::GetRenderStates() const
{ {
return m_states; return m_states;
} }
/*!
* \brief Gets the shader of this material
* \return Constant pointer to the ubershader used
*/
inline const UberShader* Material::GetShader() const inline const UberShader* Material::GetShader() const
{ {
return m_uberShader; return m_uberShader;
} }
/*!
* \brief Gets the shader instance based on the flag
* \return Constant pointer to the ubershader instance
*
* \param flags Flag of the shader
*/
inline const UberShaderInstance* Material::GetShaderInstance(UInt32 flags) const inline const UberShaderInstance* Material::GetShaderInstance(UInt32 flags) const
{ {
const ShaderInstance& instance = m_shaders[flags]; const ShaderInstance& instance = m_shaders[flags];
@ -165,81 +326,165 @@ namespace Nz
return instance.uberInstance; return instance.uberInstance;
} }
/*!
* \brief Gets the shininess
* \return Current shininess
*/
inline float Material::GetShininess() const inline float Material::GetShininess() const
{ {
return m_shininess; return m_shininess;
} }
/*!
* \brief Gets the specular color
* \return Specular color
*/
inline Color Material::GetSpecularColor() const inline Color Material::GetSpecularColor() const
{ {
return m_specularColor; return m_specularColor;
} }
/*!
* \brief Gets the specular map
* \return Constant reference to the texture
*/
inline const TextureRef& Material::GetSpecularMap() const inline const TextureRef& Material::GetSpecularMap() const
{ {
return m_specularMap; return m_specularMap;
} }
/*!
* \brief Gets the specular sampler
* \return Reference to the current texture sampler for the specular
*/
inline TextureSampler& Material::GetSpecularSampler() inline TextureSampler& Material::GetSpecularSampler()
{ {
return m_specularSampler; return m_specularSampler;
} }
/*!
* \brief Gets the specular sampler
* \return Constant reference to the current texture sampler for the specular
*/
inline const TextureSampler& Material::GetSpecularSampler() const inline const TextureSampler& Material::GetSpecularSampler() const
{ {
return m_specularSampler; return m_specularSampler;
} }
/*!
* \brief Gets the src in blend
* \return Function for src blending
*/
inline BlendFunc Material::GetSrcBlend() const inline BlendFunc Material::GetSrcBlend() const
{ {
return m_states.srcBlend; return m_states.srcBlend;
} }
/*!
* \brief Checks whether this material has an alpha map
* \return true If it is the case
*/
inline bool Material::HasAlphaMap() const inline bool Material::HasAlphaMap() const
{ {
return m_alphaMap.IsValid(); return m_alphaMap.IsValid();
} }
/*!
* \brief Checks whether this material has a depth material
* \return true If it is the case
*/
inline bool Material::HasDepthMaterial() const inline bool Material::HasDepthMaterial() const
{ {
return m_depthMaterial.IsValid(); return m_depthMaterial.IsValid();
} }
/*!
* \brief Checks whether this material has a diffuse map
* \return true If it is the case
*/
inline bool Material::HasDiffuseMap() const inline bool Material::HasDiffuseMap() const
{ {
return m_diffuseMap.IsValid(); return m_diffuseMap.IsValid();
} }
/*!
* \brief Checks whether this material has a emissive map
* \return true If it is the case
*/
inline bool Material::HasEmissiveMap() const inline bool Material::HasEmissiveMap() const
{ {
return m_emissiveMap.IsValid(); return m_emissiveMap.IsValid();
} }
/*!
* \brief Checks whether this material has a height map
* \return true If it is the case
*/
inline bool Material::HasHeightMap() const inline bool Material::HasHeightMap() const
{ {
return m_heightMap.IsValid(); return m_heightMap.IsValid();
} }
/*!
* \brief Checks whether this material has a normal map
* \return true If it is the case
*/
inline bool Material::HasNormalMap() const inline bool Material::HasNormalMap() const
{ {
return m_normalMap.IsValid(); return m_normalMap.IsValid();
} }
/*!
* \brief Checks whether this material has a specular map
* \return true If it is the case
*/
inline bool Material::HasSpecularMap() const inline bool Material::HasSpecularMap() const
{ {
return m_specularMap.IsValid(); return m_specularMap.IsValid();
} }
/*!
* \brief Checks whether this material has alpha test enabled
* \return true If it is the case
*/
inline bool Material::IsAlphaTestEnabled() const inline bool Material::IsAlphaTestEnabled() const
{ {
return m_alphaTestEnabled; return m_alphaTestEnabled;
} }
/*!
* \brief Checks whether this material has depth sorting enabled
* \return true If it is the case
*/
inline bool Material::IsDepthSortingEnabled() const inline bool Material::IsDepthSortingEnabled() const
{ {
return m_depthSortingEnabled; return m_depthSortingEnabled;
} }
/*!
* \brief Checks whether this material has the render parameter enabled
* \return true If it is the case
*
* \param parameter Parameter for the rendering
*
* \remark Produces a NazaraAssert if enumeration is invalid
*/
inline bool Material::IsEnabled(RendererParameter parameter) const inline bool Material::IsEnabled(RendererParameter parameter) const
{ {
NazaraAssert(parameter <= RendererParameter_Max, "Renderer parameter out of enum"); NazaraAssert(parameter <= RendererParameter_Max, "Renderer parameter out of enum");
@ -247,41 +492,93 @@ namespace Nz
return m_states.parameters[parameter]; return m_states.parameters[parameter];
} }
/*!
* \brief Checks whether this material has lightning enabled
* \return true If it is the case
*/
inline bool Material::IsLightingEnabled() const inline bool Material::IsLightingEnabled() const
{ {
return m_lightingEnabled; return m_lightingEnabled;
} }
/*!
* \brief Checks whether this material cast shadow
* \return true If it is the case
*/
inline bool Material::IsShadowCastingEnabled() const inline bool Material::IsShadowCastingEnabled() const
{ {
return m_shadowCastingEnabled; return m_shadowCastingEnabled;
} }
/*!
* \brief Checks whether this material receive shadow
* \return true If it is the case
*/
inline bool Material::IsShadowReceiveEnabled() const inline bool Material::IsShadowReceiveEnabled() const
{ {
return m_shadowReceiveEnabled; return m_shadowReceiveEnabled;
} }
/*!
* \brief Checks whether this material has transformation enabled
* \return true If it is the case
*/
inline bool Material::IsTransformEnabled() const inline bool Material::IsTransformEnabled() const
{ {
return m_transformEnabled; return m_transformEnabled;
} }
/*!
* \brief Loads the material from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the material
*/
inline bool Material::LoadFromFile(const String& filePath, const MaterialParams& params) inline bool Material::LoadFromFile(const String& filePath, const MaterialParams& params)
{ {
return MaterialLoader::LoadFromFile(this, filePath, params); return MaterialLoader::LoadFromFile(this, filePath, params);
} }
/*!
* \brief Loads the material from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the material
*/
inline bool Material::LoadFromMemory(const void* data, std::size_t size, const MaterialParams& params) inline bool Material::LoadFromMemory(const void* data, std::size_t size, const MaterialParams& params)
{ {
return MaterialLoader::LoadFromMemory(this, data, size, params); return MaterialLoader::LoadFromMemory(this, data, size, params);
} }
/*!
* \brief Loads the material from stream
* \return true if loading is successful
*
* \param stream Stream to the material
* \param params Parameters for the material
*/
inline bool Material::LoadFromStream(Stream& stream, const MaterialParams& params) inline bool Material::LoadFromStream(Stream& stream, const MaterialParams& params)
{ {
return MaterialLoader::LoadFromStream(this, stream, params); return MaterialLoader::LoadFromStream(this, stream, params);
} }
/*!
* \brief Sets the alpha map by name
* \return true If successful
*
* \param textureName Named texture
*/
inline bool Material::SetAlphaMap(const String& textureName) inline bool Material::SetAlphaMap(const String& textureName)
{ {
TextureRef texture = TextureLibrary::Query(textureName); TextureRef texture = TextureLibrary::Query(textureName);
@ -296,6 +593,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the alpha map with a reference to a texture
* \return true If successful
*
* \param alphaMap Texture
*
* \remark Invalidates the shaders
*/
inline void Material::SetAlphaMap(TextureRef alphaMap) inline void Material::SetAlphaMap(TextureRef alphaMap)
{ {
m_alphaMap = std::move(alphaMap); m_alphaMap = std::move(alphaMap);
@ -303,31 +609,69 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Sets the alpha threshold
*
* \param alphaThreshold Threshold for the alpha
*/
inline void Material::SetAlphaThreshold(float alphaThreshold) inline void Material::SetAlphaThreshold(float alphaThreshold)
{ {
m_alphaThreshold = alphaThreshold; m_alphaThreshold = alphaThreshold;
} }
/*!
* \brief Sets the color for ambient
*
* \param ambient Color for ambient
*/
inline void Material::SetAmbientColor(const Color& ambient) inline void Material::SetAmbientColor(const Color& ambient)
{ {
m_ambientColor = ambient; m_ambientColor = ambient;
} }
/*!
* \brief Sets the depth functor
*
* \param depthFunc
*/
inline void Material::SetDepthFunc(RendererComparison depthFunc) inline void Material::SetDepthFunc(RendererComparison depthFunc)
{ {
m_states.depthFunc = depthFunc; m_states.depthFunc = depthFunc;
} }
/*!
* \brief Sets the depth material
* \return true If successful
*
* \param depthMaterial Material for depth
*/
inline void Material::SetDepthMaterial(MaterialRef depthMaterial) inline void Material::SetDepthMaterial(MaterialRef depthMaterial)
{ {
m_depthMaterial = std::move(depthMaterial); m_depthMaterial = std::move(depthMaterial);
} }
/*!
* \brief Sets the color for diffuse
*
* \param diffuse Color for diffuse
*/
inline void Material::SetDiffuseColor(const Color& diffuse) inline void Material::SetDiffuseColor(const Color& diffuse)
{ {
m_diffuseColor = diffuse; m_diffuseColor = diffuse;
} }
/*!
* \brief Sets the diffuse map by name
* \return true If successful
*
* \param textureName Named texture
*/
inline bool Material::SetDiffuseMap(const String& textureName) inline bool Material::SetDiffuseMap(const String& textureName)
{ {
TextureRef texture = TextureLibrary::Query(textureName); TextureRef texture = TextureLibrary::Query(textureName);
@ -342,6 +686,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the diffuse map with a reference to a texture
* \return true If successful
*
* \param diffuseMap Texture
*
* \remark Invalidates the shaders
*/
inline void Material::SetDiffuseMap(TextureRef diffuseMap) inline void Material::SetDiffuseMap(TextureRef diffuseMap)
{ {
m_diffuseMap = std::move(diffuseMap); m_diffuseMap = std::move(diffuseMap);
@ -349,16 +702,35 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Sets the diffuse sampler
*
* \param sampler Diffuse sample
*/
inline void Material::SetDiffuseSampler(const TextureSampler& sampler) inline void Material::SetDiffuseSampler(const TextureSampler& sampler)
{ {
m_diffuseSampler = sampler; m_diffuseSampler = sampler;
} }
/*!
* \brief Sets the dst in blend
*
* \param func Function for dst blending
*/
inline void Material::SetDstBlend(BlendFunc func) inline void Material::SetDstBlend(BlendFunc func)
{ {
m_states.dstBlend = func; m_states.dstBlend = func;
} }
/*!
* \brief Sets the emissive map by name
* \return true If successful
*
* \param textureName Named texture
*/
inline bool Material::SetEmissiveMap(const String& textureName) inline bool Material::SetEmissiveMap(const String& textureName)
{ {
TextureRef texture = TextureLibrary::Query(textureName); TextureRef texture = TextureLibrary::Query(textureName);
@ -373,6 +745,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the emissive map with a reference to a texture
* \return true If successful
*
* \param emissiveMap Texture
*
* \remark Invalidates the shaders
*/
inline void Material::SetEmissiveMap(TextureRef emissiveMap) inline void Material::SetEmissiveMap(TextureRef emissiveMap)
{ {
m_emissiveMap = std::move(emissiveMap); m_emissiveMap = std::move(emissiveMap);
@ -380,16 +761,35 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Sets the face culling
*
* \param faceSide Face to cull
*/
inline void Material::SetFaceCulling(FaceSide faceSide) inline void Material::SetFaceCulling(FaceSide faceSide)
{ {
m_states.faceCulling = faceSide; m_states.faceCulling = faceSide;
} }
/*!
* \brief Sets the face filling
*
* \param filling Face to fill
*/
inline void Material::SetFaceFilling(FaceFilling filling) inline void Material::SetFaceFilling(FaceFilling filling)
{ {
m_states.faceFilling = filling; m_states.faceFilling = filling;
} }
/*!
* \brief Sets the height map by name
* \return true If successful
*
* \param textureName Named texture
*/
inline bool Material::SetHeightMap(const String& textureName) inline bool Material::SetHeightMap(const String& textureName)
{ {
TextureRef texture = TextureLibrary::Query(textureName); TextureRef texture = TextureLibrary::Query(textureName);
@ -404,6 +804,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the height map with a reference to a texture
* \return true If successful
*
* \param heightMap Texture
*
* \remark Invalidates the shaders
*/
inline void Material::SetHeightMap(TextureRef heightMap) inline void Material::SetHeightMap(TextureRef heightMap)
{ {
m_heightMap = std::move(heightMap); m_heightMap = std::move(heightMap);
@ -411,6 +820,13 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Sets the normal map by name
* \return true If successful
*
* \param textureName Named texture
*/
inline bool Material::SetNormalMap(const String& textureName) inline bool Material::SetNormalMap(const String& textureName)
{ {
TextureRef texture = TextureLibrary::Query(textureName); TextureRef texture = TextureLibrary::Query(textureName);
@ -425,6 +841,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the normal map with a reference to a texture
* \return true If successful
*
* \param normalMap Texture
*
* \remark Invalidates the shaders
*/
inline void Material::SetNormalMap(TextureRef normalMap) inline void Material::SetNormalMap(TextureRef normalMap)
{ {
m_normalMap = std::move(normalMap); m_normalMap = std::move(normalMap);
@ -432,11 +857,25 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Sets the render states
*
* \param states States for the rendering
*/
inline void Material::SetRenderStates(const RenderStates& states) inline void Material::SetRenderStates(const RenderStates& states)
{ {
m_states = states; m_states = states;
} }
/*!
* \brief Sets the shader with a constant reference to a ubershader
*
* \param uberShader Uber shader to apply
*
* \remark Invalidates the shaders
*/
inline void Material::SetShader(UberShaderConstRef uberShader) inline void Material::SetShader(UberShaderConstRef uberShader)
{ {
m_uberShader = std::move(uberShader); m_uberShader = std::move(uberShader);
@ -444,6 +883,13 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Sets the shader by name
* \return true If successful
*
* \param uberShaderName Named shader
*/
inline bool Material::SetShader(const String& uberShaderName) inline bool Material::SetShader(const String& uberShaderName)
{ {
UberShaderConstRef uberShader = UberShaderLibrary::Get(uberShaderName); UberShaderConstRef uberShader = UberShaderLibrary::Get(uberShaderName);
@ -454,16 +900,35 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the shininess of the material
*
* \param shininess Value of the shininess
*/
inline void Material::SetShininess(float shininess) inline void Material::SetShininess(float shininess)
{ {
m_shininess = shininess; m_shininess = shininess;
} }
/*!
* \brief Sets the color for specular
*
* \param specular Color
*/
inline void Material::SetSpecularColor(const Color& specular) inline void Material::SetSpecularColor(const Color& specular)
{ {
m_specularColor = specular; m_specularColor = specular;
} }
/*!
* \brief Sets the specular map by name
* \return true If successful
*
* \param textureName Named texture
*/
inline bool Material::SetSpecularMap(const String& textureName) inline bool Material::SetSpecularMap(const String& textureName)
{ {
TextureRef texture = TextureLibrary::Query(textureName); TextureRef texture = TextureLibrary::Query(textureName);
@ -478,6 +943,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the specular map with a reference to a texture
* \return true If successful
*
* \param specularMap Texture
*
* \remark Invalidates the shaders
*/
inline void Material::SetSpecularMap(TextureRef specularMap) inline void Material::SetSpecularMap(TextureRef specularMap)
{ {
m_specularMap = std::move(specularMap); m_specularMap = std::move(specularMap);
@ -485,16 +959,35 @@ namespace Nz
InvalidateShaders(); InvalidateShaders();
} }
/*!
* \brief Sets the specular sampler
*
* \param sampler Specular sample
*/
inline void Material::SetSpecularSampler(const TextureSampler& sampler) inline void Material::SetSpecularSampler(const TextureSampler& sampler)
{ {
m_specularSampler = sampler; m_specularSampler = sampler;
} }
/*!
* \brief Sets the src in blend
*
* \param func Function for src blending
*/
inline void Material::SetSrcBlend(BlendFunc func) inline void Material::SetSrcBlend(BlendFunc func)
{ {
m_states.srcBlend = func; m_states.srcBlend = func;
} }
/*!
* \brief Sets the current material with the content of the other one
* \return A reference to this
*
* \param material The other Material
*/
inline Material& Material::operator=(const Material& material) inline Material& Material::operator=(const Material& material)
{ {
Resource::operator=(material); Resource::operator=(material);
@ -503,17 +996,33 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Gets the default material
* \return Reference to the default material
*/
inline MaterialRef Material::GetDefault() inline MaterialRef Material::GetDefault()
{ {
return s_defaultMaterial; return s_defaultMaterial;
} }
/*!
* \brief Invalidates the shaders
*/
inline void Material::InvalidateShaders() inline void Material::InvalidateShaders()
{ {
for (ShaderInstance& instance : m_shaders) for (ShaderInstance& instance : m_shaders)
instance.uberInstance = nullptr; instance.uberInstance = nullptr;
} }
/*!
* \brief Creates a new material from the arguments
* \return A reference to the newly created material
*
* \param args Arguments for the material
*/
template<typename... Args> template<typename... Args>
MaterialRef Material::New(Args&&... args) MaterialRef Material::New(Args&&... args)
{ {

View File

@ -68,8 +68,6 @@ namespace Nz
bool SetMaterial(unsigned int skinIndex, const String& subMeshName, Material* material); bool SetMaterial(unsigned int skinIndex, const String& subMeshName, Material* material);
void SetMaterial(unsigned int skinIndex, unsigned int matIndex, Material* material); void SetMaterial(unsigned int skinIndex, unsigned int matIndex, Material* material);
virtual void SetMesh(Mesh* mesh); virtual void SetMesh(Mesh* mesh);
bool SetSequence(const String& sequenceName);
void SetSequence(unsigned int sequenceIndex);
void SetSkin(unsigned int skin); void SetSkin(unsigned int skin);
void SetSkinCount(unsigned int skinCount); void SetSkinCount(unsigned int skinCount);

View File

@ -7,6 +7,13 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Creates a new Model from the arguments
* \return A reference to the newly created model
*
* \param args Arguments for the model
*/
template<typename... Args> template<typename... Args>
ModelRef Model::New(Args&&... args) ModelRef Model::New(Args&&... args)
{ {

View File

@ -62,16 +62,16 @@ namespace Nz
/* /*
** -Lynix: ** -Lynix:
** Il serait aussi possible de préciser le stride de façon indépendante, ce que je ne permets pas ** It would be also possible to precise the stride by an independant way, what I don't allow
** pour décomplexifier l'interface en enlevant quelque chose que je juge inutile. ** to decomplexify the interface of something I consider useless.
** Si vous pensez que ça peut être utile, n'hésitez pas à me le faire savoir ! ** If you think that could be useful, don't hesitate to make me aware !
*/ */
}; };
Component m_components[ParticleComponent_Max+1]; Component m_components[ParticleComponent_Max + 1];
unsigned int m_stride; unsigned int m_stride;
static ParticleDeclaration s_declarations[ParticleLayout_Max+1]; static ParticleDeclaration s_declarations[ParticleLayout_Max + 1];
static ParticleDeclarationLibrary::LibraryMap s_library; static ParticleDeclarationLibrary::LibraryMap s_library;
}; };
} }

View File

@ -7,10 +7,20 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Gets a pointer to iterate through same components
* \return SparsePtr pointing to same components
*
* \param component Component to get in the declaration
*
* \remark The same components are not continguous but separated by sizeof(ParticleSize)
* \remark Produces a NazaraError if component is disabled
*/
template <typename T> template <typename T>
SparsePtr<T> ParticleMapper::GetComponentPtr(ParticleComponent component) SparsePtr<T> ParticleMapper::GetComponentPtr(ParticleComponent component)
{ {
// Ensuite le composant qui nous intéresse // Then the component that are interesting
bool enabled; bool enabled;
ComponentType type; ComponentType type;
unsigned int offset; unsigned int offset;
@ -18,7 +28,7 @@ namespace Nz
if (enabled) if (enabled)
{ {
///TODO: Vérifier le rapport entre le type de l'attribut et le type template ? ///TODO: Check the ratio between the type of the attribute and the template type ?
return SparsePtr<T>(m_ptr + offset, m_declaration->GetStride()); return SparsePtr<T>(m_ptr + offset, m_declaration->GetStride());
} }
else else
@ -28,10 +38,20 @@ namespace Nz
} }
} }
/*!
* \brief Gets a pointer to iterate through same components
* \return SparsePtr pointing to same components
*
* \param component Component to get in the declaration
*
* \remark The same components are not continguous but separated by sizeof(ParticleSize)
* \remark Produces a NazaraError if component is disabled
*/
template <typename T> template <typename T>
SparsePtr<const T> ParticleMapper::GetComponentPtr(ParticleComponent component) const SparsePtr<const T> ParticleMapper::GetComponentPtr(ParticleComponent component) const
{ {
// Ensuite le composant qui nous intéresse // Then the component that are interesting
bool enabled; bool enabled;
ComponentType type; ComponentType type;
unsigned int offset; unsigned int offset;
@ -39,7 +59,7 @@ namespace Nz
if (enabled) if (enabled)
{ {
///TODO: Vérifier le rapport entre le type de l'attribut et le type template ? ///TODO: Check the ratio between the type of the attribute and the template type ?
return SparsePtr<const T>(m_ptr + offset, m_declaration->GetStride()); return SparsePtr<const T>(m_ptr + offset, m_declaration->GetStride());
} }
else else

View File

@ -4,17 +4,31 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Ensures that the bounding volume is up to date
*/
inline void Renderable::EnsureBoundingVolumeUpdated() const inline void Renderable::EnsureBoundingVolumeUpdated() const
{ {
if (!m_boundingVolumeUpdated) if (!m_boundingVolumeUpdated)
UpdateBoundingVolume(); UpdateBoundingVolume();
} }
/*!
* \brief Invalidates the bounding volume
*/
inline void Renderable::InvalidateBoundingVolume() inline void Renderable::InvalidateBoundingVolume()
{ {
m_boundingVolumeUpdated = false; m_boundingVolumeUpdated = false;
} }
/*!
* \brief Updates the bounding volume by a matrix
*
* \param transformMatrix Matrix transformation for our bounding volume
*/
inline void Renderable::UpdateBoundingVolume() const inline void Renderable::UpdateBoundingVolume() const
{ {
MakeBoundingVolume(); MakeBoundingVolume();

View File

@ -7,31 +7,62 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Gets the movement offset
* \return Offset of the movement
*/
inline const Vector3f& Nz::SkyboxBackground::GetMovementOffset() const inline const Vector3f& Nz::SkyboxBackground::GetMovementOffset() const
{ {
return m_movementOffset; return m_movementOffset;
} }
/*!
* \brief Gets the movement scale
* \return Scale of the movement
*/
inline float SkyboxBackground::GetMovementScale() const inline float SkyboxBackground::GetMovementScale() const
{ {
return m_movementScale; return m_movementScale;
} }
/*!
* \brief Gets the texture of the background
* \return Texture of the background
*/
inline const TextureRef& SkyboxBackground::GetTexture() const inline const TextureRef& SkyboxBackground::GetTexture() const
{ {
return m_texture; return m_texture;
} }
/*!
* \brief Gets the texture sampler of the background
* \return A reference to the texture sampler of the background
*/
inline TextureSampler& SkyboxBackground::GetTextureSampler() inline TextureSampler& SkyboxBackground::GetTextureSampler()
{ {
return m_sampler; return m_sampler;
} }
/*!
* \brief Gets the texture sampler of the background
* \return A constant reference to the texture sampler of the background
*/
inline const TextureSampler& SkyboxBackground::GetTextureSampler() const inline const TextureSampler& SkyboxBackground::GetTextureSampler() const
{ {
return m_sampler; return m_sampler;
} }
/*!
* \brief Sets the movement offset
*
* \param offset Offset of the movement
*/
inline void SkyboxBackground::SetMovementOffset(const Vector3f& offset) inline void SkyboxBackground::SetMovementOffset(const Vector3f& offset)
{ {
NazaraAssert(std::isfinite(offset.x) && std::isfinite(offset.y) && std::isfinite(offset.z), "Offset must be a finite vector"); NazaraAssert(std::isfinite(offset.x) && std::isfinite(offset.y) && std::isfinite(offset.z), "Offset must be a finite vector");
@ -39,6 +70,12 @@ namespace Nz
m_movementOffset = offset; m_movementOffset = offset;
} }
/*!
* \brief Sets the movement scale
*
* \param scale Scale of the movement
*/
inline void SkyboxBackground::SetMovementScale(float scale) inline void SkyboxBackground::SetMovementScale(float scale)
{ {
NazaraAssert(std::isfinite(scale), "Scale must be a finite value"); NazaraAssert(std::isfinite(scale), "Scale must be a finite value");
@ -46,6 +83,12 @@ namespace Nz
m_movementScale = scale; m_movementScale = scale;
} }
/*!
* \brief Sets the texture of the background
*
* \param cubemapTexture Texture of the background
*/
inline void SkyboxBackground::SetTexture(TextureRef cubemapTexture) inline void SkyboxBackground::SetTexture(TextureRef cubemapTexture)
{ {
NazaraAssert(!cubemapTexture || cubemapTexture->IsValid(), "Invalid texture"); NazaraAssert(!cubemapTexture || cubemapTexture->IsValid(), "Invalid texture");
@ -54,11 +97,24 @@ namespace Nz
m_texture = std::move(cubemapTexture); m_texture = std::move(cubemapTexture);
} }
/*!
* \brief Sets the texture sampler of the background
*
* \param sampler Texture sampler of the background
*/
void SkyboxBackground::SetTextureSampler(const TextureSampler& sampler) void SkyboxBackground::SetTextureSampler(const TextureSampler& sampler)
{ {
m_sampler = sampler; m_sampler = sampler;
} }
/*!
* \brief Creates a new skybox background from the arguments
* \return A reference to the newly created skybox background
*
* \param args Arguments for the skybox background
*/
template<typename... Args> template<typename... Args>
SkyboxBackgroundRef SkyboxBackground::New(Args&&... args) SkyboxBackgroundRef SkyboxBackground::New(Args&&... args)
{ {

View File

@ -8,6 +8,10 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a Sprite object by default
*/
inline Sprite::Sprite() : inline Sprite::Sprite() :
m_color(Color::White), m_color(Color::White),
m_textureCoords(0.f, 0.f, 1.f, 1.f), m_textureCoords(0.f, 0.f, 1.f, 1.f),
@ -16,6 +20,12 @@ namespace Nz
SetDefaultMaterial(); SetDefaultMaterial();
} }
/*!
* \brief Constructs a Sprite object with a reference to a material
*
* \param material Reference to a material
*/
inline Sprite::Sprite(MaterialRef material) : inline Sprite::Sprite(MaterialRef material) :
m_color(Color::White), m_color(Color::White),
m_textureCoords(0.f, 0.f, 1.f, 1.f), m_textureCoords(0.f, 0.f, 1.f, 1.f),
@ -24,6 +34,12 @@ namespace Nz
SetMaterial(std::move(material), true); SetMaterial(std::move(material), true);
} }
/*!
* \brief Constructs a Sprite object with a pointer to a texture
*
* \param texture Pointer to a texture
*/
inline Sprite::Sprite(Texture* texture) : inline Sprite::Sprite(Texture* texture) :
m_color(Color::White), m_color(Color::White),
m_textureCoords(0.f, 0.f, 1.f, 1.f), m_textureCoords(0.f, 0.f, 1.f, 1.f),
@ -32,6 +48,12 @@ namespace Nz
SetTexture(texture, true); SetTexture(texture, true);
} }
/*!
* \brief Constructs a Sprite object by assignation
*
* \param sprite Sprite to copy into this
*/
inline Sprite::Sprite(const Sprite& sprite) : inline Sprite::Sprite(const Sprite& sprite) :
InstancedRenderable(sprite), InstancedRenderable(sprite),
m_color(sprite.m_color), m_color(sprite.m_color),
@ -41,26 +63,52 @@ namespace Nz
{ {
} }
/*!
* \brief Gets the color of the sprite
* \return Current color
*/
inline const Color& Sprite::GetColor() const inline const Color& Sprite::GetColor() const
{ {
return m_color; return m_color;
} }
/*!
* \brief Gets the material of the sprite
* \return Current material
*/
inline const MaterialRef& Sprite::GetMaterial() const inline const MaterialRef& Sprite::GetMaterial() const
{ {
return m_material; return m_material;
} }
/*!
* \brief Gets the size of the sprite
* \return Current size
*/
inline const Vector2f& Sprite::GetSize() const inline const Vector2f& Sprite::GetSize() const
{ {
return m_size; return m_size;
} }
/*!
* \brief Gets the texture coordinates of the sprite
* \return Current texture coordinates
*/
inline const Rectf& Sprite::GetTextureCoords() const inline const Rectf& Sprite::GetTextureCoords() const
{ {
return m_textureCoords; return m_textureCoords;
} }
/*!
* \brief Sets the color of the billboard
*
* \param color Color for the billboard
*/
inline void Sprite::SetColor(const Color& color) inline void Sprite::SetColor(const Color& color)
{ {
m_color = color; m_color = color;
@ -68,6 +116,10 @@ namespace Nz
InvalidateVertices(); InvalidateVertices();
} }
/*!
* \brief Sets the default material of the sprite (just default material)
*/
inline void Sprite::SetDefaultMaterial() inline void Sprite::SetDefaultMaterial()
{ {
MaterialRef material = Material::New(); MaterialRef material = Material::New();
@ -77,6 +129,13 @@ namespace Nz
SetMaterial(std::move(material)); SetMaterial(std::move(material));
} }
/*!
* \brief Sets the material of the sprite
*
* \param material Material for the sprite
* \param resizeSprite Should sprite be resized to the material size (diffuse map)
*/
inline void Sprite::SetMaterial(MaterialRef material, bool resizeSprite) inline void Sprite::SetMaterial(MaterialRef material, bool resizeSprite)
{ {
m_material = std::move(material); m_material = std::move(material);
@ -88,6 +147,12 @@ namespace Nz
} }
} }
/*!
* \brief Sets the size of the sprite
*
* \param size Size for the sprite
*/
inline void Sprite::SetSize(const Vector2f& size) inline void Sprite::SetSize(const Vector2f& size)
{ {
m_size = size; m_size = size;
@ -97,11 +162,25 @@ namespace Nz
InvalidateVertices(); InvalidateVertices();
} }
/*!
* \brief Sets the size of the sprite
*
* \param sizeX Size in X for the sprite
* \param sizeY Size in Y for the sprite
*/
inline void Sprite::SetSize(float sizeX, float sizeY) inline void Sprite::SetSize(float sizeX, float sizeY)
{ {
SetSize(Vector2f(sizeX, sizeY)); SetSize(Vector2f(sizeX, sizeY));
} }
/*!
* \brief Sets the texture of the sprite
*
* \param texture Texture for the sprite
* \param resizeSprite Should sprite be resized to the texture size
*/
inline void Sprite::SetTexture(TextureRef texture, bool resizeSprite) inline void Sprite::SetTexture(TextureRef texture, bool resizeSprite)
{ {
if (!m_material) if (!m_material)
@ -115,12 +194,27 @@ namespace Nz
m_material->SetDiffuseMap(std::move(texture)); m_material->SetDiffuseMap(std::move(texture));
} }
/*!
* \brief Sets the texture coordinates of the sprite
*
* \param coords Texture coordinates
*/
inline void Sprite::SetTextureCoords(const Rectf& coords) inline void Sprite::SetTextureCoords(const Rectf& coords)
{ {
m_textureCoords = coords; m_textureCoords = coords;
InvalidateVertices(); InvalidateVertices();
} }
/*!
* \brief Sets the texture rectangle of the sprite
*
* \param rect Rectangles symbolizing the size of the texture
*
* \remark Produces a NazaraAssert if material is invalid
* \remark Produces a NazaraAssert if material has no diffuse map
*/
inline void Sprite::SetTextureRect(const Rectui& rect) inline void Sprite::SetTextureRect(const Rectui& rect)
{ {
NazaraAssert(m_material, "Sprite has no material"); NazaraAssert(m_material, "Sprite has no material");
@ -128,12 +222,19 @@ namespace Nz
Texture* diffuseMap = m_material->GetDiffuseMap(); Texture* diffuseMap = m_material->GetDiffuseMap();
float invWidth = 1.f/diffuseMap->GetWidth(); float invWidth = 1.f / diffuseMap->GetWidth();
float invHeight = 1.f/diffuseMap->GetHeight(); float invHeight = 1.f / diffuseMap->GetHeight();
SetTextureCoords(Rectf(invWidth*rect.x, invHeight*rect.y, invWidth*rect.width, invHeight*rect.height)); SetTextureCoords(Rectf(invWidth * rect.x, invHeight * rect.y, invWidth * rect.width, invHeight * rect.height));
} }
/*!
* \brief Sets the current sprite with the content of the other one
* \return A reference to this
*
* \param sprite The other Sprite
*/
inline Sprite& Sprite::operator=(const Sprite& sprite) inline Sprite& Sprite::operator=(const Sprite& sprite)
{ {
InstancedRenderable::operator=(sprite); InstancedRenderable::operator=(sprite);
@ -143,18 +244,29 @@ namespace Nz
m_textureCoords = sprite.m_textureCoords; m_textureCoords = sprite.m_textureCoords;
m_size = sprite.m_size; 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 // We do not copy final vertices because it's highly probable that our parameters are modified and they must be regenerated
InvalidateBoundingVolume(); InvalidateBoundingVolume();
InvalidateVertices(); InvalidateVertices();
return *this; return *this;
} }
/*!
* \brief Invalidates the vertices
*/
inline void Sprite::InvalidateVertices() inline void Sprite::InvalidateVertices()
{ {
InvalidateInstanceData(0); InvalidateInstanceData(0);
} }
/*!
* \brief Creates a new sprite from the arguments
* \return A reference to the newly created sprite
*
* \param args Arguments for the sprite
*/
template<typename... Args> template<typename... Args>
SpriteRef Sprite::New(Args&&... args) SpriteRef Sprite::New(Args&&... args)
{ {

View File

@ -7,6 +7,10 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Constructs a TextSprite object by default
*/
inline TextSprite::TextSprite() : inline TextSprite::TextSprite() :
m_color(Color::White), m_color(Color::White),
m_scale(1.f) m_scale(1.f)
@ -14,12 +18,24 @@ namespace Nz
SetDefaultMaterial(); SetDefaultMaterial();
} }
/*!
* \brief Constructs a TextSprite object with a drawer
*
* \param drawer Drawer used to compose text on the sprite
*/
inline TextSprite::TextSprite(const AbstractTextDrawer& drawer) : inline TextSprite::TextSprite(const AbstractTextDrawer& drawer) :
TextSprite() TextSprite()
{ {
Update(drawer); Update(drawer);
} }
/*!
* \brief Constructs a TextSprite object by assignation
*
* \param sprite TextSprite to copy into this
*/
inline TextSprite::TextSprite(const TextSprite& sprite) : inline TextSprite::TextSprite(const TextSprite& sprite) :
InstancedRenderable(sprite), InstancedRenderable(sprite),
m_renderInfos(sprite.m_renderInfos), m_renderInfos(sprite.m_renderInfos),
@ -40,6 +56,10 @@ namespace Nz
} }
} }
/*!
* \brief Clears the data
*/
inline void TextSprite::Clear() inline void TextSprite::Clear()
{ {
m_atlases.clear(); m_atlases.clear();
@ -48,21 +68,42 @@ namespace Nz
m_renderInfos.clear(); m_renderInfos.clear();
} }
/*!
* \brief Gets the color of the text sprite
* \return Current color
*/
inline const Color& TextSprite::GetColor() const inline const Color& TextSprite::GetColor() const
{ {
return m_color; return m_color;
} }
/*!
* \brief Gets the material of the text sprite
* \return Current material
*/
inline const MaterialRef& TextSprite::GetMaterial() const inline const MaterialRef& TextSprite::GetMaterial() const
{ {
return m_material; return m_material;
} }
/*!
* \brief Gets the current scale of the text sprite
* \return Current scale
*/
inline float TextSprite::GetScale() const inline float TextSprite::GetScale() const
{ {
return m_scale; return m_scale;
} }
/*!
* \brief Sets the color of the text sprite
*
* \param color Color for the text sprite
*/
inline void TextSprite::SetColor(const Color& color) inline void TextSprite::SetColor(const Color& color)
{ {
m_color = color; m_color = color;
@ -70,6 +111,11 @@ namespace Nz
InvalidateVertices(); InvalidateVertices();
} }
/*!
* \brief Sets the default material of the text sprite (just default material)
*/
inline void TextSprite::SetDefaultMaterial() inline void TextSprite::SetDefaultMaterial()
{ {
MaterialRef material = Material::New(); MaterialRef material = Material::New();
@ -83,11 +129,23 @@ namespace Nz
SetMaterial(material); SetMaterial(material);
} }
/*!
* \brief Sets the material of the text sprite
*
* \param material Material for the text sprite
*/
inline void TextSprite::SetMaterial(MaterialRef material) inline void TextSprite::SetMaterial(MaterialRef material)
{ {
m_material = std::move(material); m_material = std::move(material);
} }
/*!
* \brief Sets the current scale of the text sprite
*
* \param scale Scale of the text sprite
*/
inline void TextSprite::SetScale(float scale) inline void TextSprite::SetScale(float scale)
{ {
m_scale = scale; m_scale = scale;
@ -95,10 +153,12 @@ namespace Nz
InvalidateVertices(); InvalidateVertices();
} }
inline void TextSprite::InvalidateVertices() /*!
{ * \brief Sets the current text sprite with the content of the other one
InvalidateInstanceData(0); * \return A reference to this
} *
* \param text sprite The other TextSprite
*/
inline TextSprite& TextSprite::operator=(const TextSprite& text) inline TextSprite& TextSprite::operator=(const TextSprite& text)
{ {
@ -130,6 +190,22 @@ namespace Nz
return *this; return *this;
} }
/*!
* \brief Invalidates the vertices
*/
inline void TextSprite::InvalidateVertices()
{
InvalidateInstanceData(0);
}
/*!
* \brief Creates a new text sprite from the arguments
* \return A reference to the newly created text sprite
*
* \param args Arguments for the text sprite
*/
template<typename... Args> template<typename... Args>
TextSpriteRef TextSprite::New(Args&&... args) TextSpriteRef TextSprite::New(Args&&... args)
{ {

View File

@ -7,11 +7,22 @@
namespace Nz namespace Nz
{ {
/*!
* \brief Gets the texture of the background
* \return Texture of the background
*/
inline const TextureRef& TextureBackground::GetTexture() const inline const TextureRef& TextureBackground::GetTexture() const
{ {
return m_texture; return m_texture;
} }
/*!
* \brief Sets the texture of the background
*
* \param texture Texture of the background
*/
inline void TextureBackground::SetTexture(TextureRef texture) inline void TextureBackground::SetTexture(TextureRef texture)
{ {
NazaraAssert(!texture || texture->IsValid(), "Invalid texture"); NazaraAssert(!texture || texture->IsValid(), "Invalid texture");
@ -19,6 +30,13 @@ namespace Nz
m_texture = std::move(texture); m_texture = std::move(texture);
} }
/*!
* \brief Creates a new texture background from the arguments
* \return A reference to the newly created texture background
*
* \param args Arguments for the texture background
*/
template<typename... Args> template<typename... Args>
TextureBackgroundRef TextureBackground::New(Args&&... args) TextureBackgroundRef TextureBackground::New(Args&&... args)
{ {

View File

@ -491,8 +491,8 @@ namespace Nz
* *
* \remark If volume is infinite, IntersectionSide_Intersecting is returned * \remark If volume is infinite, IntersectionSide_Intersecting is returned
* \remark If volume is null, IntersectionSide_Outside is returned * \remark If volume is null, IntersectionSide_Outside is returned
* \remark If enumeration of the volume is not defined in Extend, a NazaraError is thrown and false is returned * \remark If enumeration of the volume is not defined in Extend, a NazaraError is thrown and IntersectionSide_Outside is returned
* \remark If enumeration of the intersection is not defined in IntersectionSide, a NazaraError is thrown and false is returned. This should not never happen for a user of the library * \remark If enumeration of the intersection is not defined in IntersectionSide, a NazaraError is thrown and IntersectionSide_Outside is returned. This should not never happen for a user of the library
*/ */
template<typename T> template<typename T>

View File

@ -485,7 +485,7 @@ namespace Nz
template<typename T> template<typename T>
T Sphere<T>::SquaredDistance(const Vector3<T>& point) const T Sphere<T>::SquaredDistance(const Vector3<T>& point) const
{ {
return Vector3f::Distance(point, GetPosition()) - radius * radius; return Vector3f::SquaredDistance(point, GetPosition() + (point - GetPosition()).Normalize() * radius);
} }
/*! /*!

View File

@ -7,6 +7,14 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::AbstractBackground
* \brief Graphics class that represents the background for our scene
*
* \remark This class is abstract
*/
AbstractBackground::~AbstractBackground() = default; AbstractBackground::~AbstractBackground() = default;
BackgroundLibrary::LibraryMap AbstractBackground::s_library; BackgroundLibrary::LibraryMap AbstractBackground::s_library;

View File

@ -7,23 +7,55 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::AbstractRenderQueue
* \brief Graphics class that represents the rendering queue for our scene
*
* \remark This class is abstract
*/
AbstractRenderQueue::~AbstractRenderQueue() = default; AbstractRenderQueue::~AbstractRenderQueue() = default;
/*!
* \brief Adds a directional light to the rendering queue
*
* \param light Directional light
*/
void AbstractRenderQueue::AddDirectionalLight(const DirectionalLight& light) void AbstractRenderQueue::AddDirectionalLight(const DirectionalLight& light)
{ {
directionalLights.push_back(light); directionalLights.push_back(light);
} }
/*!
* \brief Adds a point light to the rendering queue
*
* \param light Point light
*/
void AbstractRenderQueue::AddPointLight(const PointLight& light) void AbstractRenderQueue::AddPointLight(const PointLight& light)
{ {
pointLights.push_back(light); pointLights.push_back(light);
} }
/*!
* \brief Adds a spot light to the rendering queue
*
* \param light Spot light
*/
void AbstractRenderQueue::AddSpotLight(const SpotLight& light) void AbstractRenderQueue::AddSpotLight(const SpotLight& light)
{ {
spotLights.push_back(light); spotLights.push_back(light);
} }
/*!
* \brief Clears the rendering queue
*
* \param fully Should everything be cleared ?
*/
void AbstractRenderQueue::Clear(bool fully) void AbstractRenderQueue::Clear(bool fully)
{ {
NazaraUnused(fully); NazaraUnused(fully);

View File

@ -10,6 +10,18 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::AbstractRenderTechnique
* \brief Graphics class that represents the rendering technique for our scene
*
* \remark This class is abstract
*/
/*!
* \brief Constructs a AbstractRenderTechnique object
*/
AbstractRenderTechnique::AbstractRenderTechnique() : AbstractRenderTechnique::AbstractRenderTechnique() :
m_instancingEnabled(true) m_instancingEnabled(true)
{ {
@ -17,16 +29,34 @@ namespace Nz
AbstractRenderTechnique::~AbstractRenderTechnique() = default; AbstractRenderTechnique::~AbstractRenderTechnique() = default;
/*!
* \brief Enables the instancing
*
* \param instancing Should instancing be enabled
*
* \remark This may improve performances
*/
void AbstractRenderTechnique::EnableInstancing(bool instancing) void AbstractRenderTechnique::EnableInstancing(bool instancing)
{ {
m_instancingEnabled = instancing; m_instancingEnabled = instancing;
} }
/*!
* \brief Gets the name of the actual technique
* \return Name of the technique being used
*/
String AbstractRenderTechnique::GetName() const String AbstractRenderTechnique::GetName() const
{ {
return RenderTechniques::ToString(GetType()); return RenderTechniques::ToString(GetType());
} }
/*!
* \brief Checks whether the instancing is enabled
* \return true If it is the case
*/
bool AbstractRenderTechnique::IsInstancingEnabled() const bool AbstractRenderTechnique::IsInstancingEnabled() const
{ {
return m_instancingEnabled; return m_instancingEnabled;

View File

@ -7,5 +7,13 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::AbstractViewer
* \brief Graphics class that represents the viewer for our scene
*
* \remark This class is abstract
*/
AbstractViewer::~AbstractViewer() = default; AbstractViewer::~AbstractViewer() = default;
} }

View File

@ -12,6 +12,19 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::Billboard
* \brief Graphics class that represents a billboard, a 2D surface which simulates a 3D object
*/
/*!
* \brief Adds this billboard to the render queue
*
* \param renderQueue Queue to be added
* \param instanceData Data used for instance
*/
void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
if (!m_material) if (!m_material)
@ -20,11 +33,15 @@ namespace Nz
renderQueue->AddBillboard(instanceData.renderOrder, m_material, instanceData.transformMatrix.GetTranslation(), m_size, m_sinCos, m_color); renderQueue->AddBillboard(instanceData.renderOrder, m_material, instanceData.transformMatrix.GetTranslation(), m_size, m_sinCos, m_color);
} }
/*
* \brief Makes the bounding volume of this billboard
*/
void Billboard::MakeBoundingVolume() const void Billboard::MakeBoundingVolume() const
{ {
constexpr float sqrt2 = float(M_SQRT2); constexpr float sqrt2 = float(M_SQRT2);
m_boundingVolume.Set(Vector3f(0.f), sqrt2*m_size.x*Vector3f::Right() + sqrt2*m_size.y*Vector3f::Down()); m_boundingVolume.Set(Vector3f(0.f), sqrt2 * m_size.x * Vector3f::Right() + sqrt2 * m_size.y * Vector3f::Down());
} }
BillboardLibrary::LibraryMap Billboard::s_library; BillboardLibrary::LibraryMap Billboard::s_library;

View File

@ -11,6 +11,11 @@ namespace Nz
{ {
namespace namespace
{ {
/*!
* \brief Defines render states
* \return RenderStates for the color background
*/
RenderStates BuildRenderStates() RenderStates BuildRenderStates()
{ {
RenderStates states; RenderStates states;
@ -24,6 +29,18 @@ namespace Nz
} }
} }
/*!
* \ingroup graphics
* \class Nz::ColorBackground
* \brief Graphics class that represents a background with uniform color
*/
/*!
* \brief Constructs a ColorBackground object with a color
*
* \param color Uniform color (by default Black)
*/
ColorBackground::ColorBackground(const Color& color) : ColorBackground::ColorBackground(const Color& color) :
m_color(color) m_color(color)
{ {
@ -38,6 +55,12 @@ namespace Nz
m_vertexDepthUniform = shader->GetUniformLocation("VertexDepth"); m_vertexDepthUniform = shader->GetUniformLocation("VertexDepth");
} }
/*!
* \brief Draws this relatively to the viewer
*
* \param viewer Viewer for the background
*/
void ColorBackground::Draw(const AbstractViewer* viewer) const void ColorBackground::Draw(const AbstractViewer* viewer) const
{ {
NazaraUnused(viewer); NazaraUnused(viewer);
@ -55,16 +78,32 @@ namespace Nz
Renderer::DrawFullscreenQuad(); Renderer::DrawFullscreenQuad();
} }
/*!
* \brief Gets the background type
* \return Type of background
*/
BackgroundType ColorBackground::GetBackgroundType() const BackgroundType ColorBackground::GetBackgroundType() const
{ {
return BackgroundType_Color; return BackgroundType_Color;
} }
/*!
* \brief Gets the color of the background
* \return Background color
*/
Color ColorBackground::GetColor() const Color ColorBackground::GetColor() const
{ {
return m_color; return m_color;
} }
/*!
* \brief Sets the color of the background
*
* \param color Background color
*/
void ColorBackground::SetColor(const Color& color) void ColorBackground::SetColor(const Color& color)
{ {
m_color = color; m_color = color;

View File

@ -9,6 +9,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredBloomPass
* \brief Graphics class that represents the pass for bloom in deferred rendering
*/
/*!
* \brief Constructs a DeferredBloomPass object by default
*/
DeferredBloomPass::DeferredBloomPass() : DeferredBloomPass::DeferredBloomPass() :
m_uniformUpdated(false), m_uniformUpdated(false),
m_brightLuminance(0.8f), m_brightLuminance(0.8f),
@ -32,26 +42,55 @@ namespace Nz
DeferredBloomPass::~DeferredBloomPass() = default; DeferredBloomPass::~DeferredBloomPass() = default;
/*!
* \brief Gets the number of pass for blur
* \return Number of pass for blur
*/
unsigned int DeferredBloomPass::GetBlurPassCount() const unsigned int DeferredBloomPass::GetBlurPassCount() const
{ {
return m_blurPassCount; return m_blurPassCount;
} }
/*!
* \brief Gets the coefficiant for luminosity
* \return Luminosity of bright elements
*/
float DeferredBloomPass::GetBrightLuminance() const float DeferredBloomPass::GetBrightLuminance() const
{ {
return m_brightLuminance; return m_brightLuminance;
} }
/*!
* \brief Gets the coefficiant for the middle grey
* \return Luminosity of grey elements
*/
float DeferredBloomPass::GetBrightMiddleGrey() const float DeferredBloomPass::GetBrightMiddleGrey() const
{ {
return m_brightMiddleGrey; return m_brightMiddleGrey;
} }
/*!
* \brief Gets the coefficiant for things to be bright
* \return Threshold for bright elements
*/
float DeferredBloomPass::GetBrightThreshold() const float DeferredBloomPass::GetBrightThreshold() const
{ {
return m_brightThreshold; return m_brightThreshold;
} }
/*!
* \brief Gets the ith texture
* \return Texture computed
*
* \param i Index of the texture
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if index is invalid
*/
Texture* DeferredBloomPass::GetTexture(unsigned int i) const Texture* DeferredBloomPass::GetTexture(unsigned int i) const
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -65,7 +104,16 @@ namespace Nz
return m_bloomTextures[i]; return m_bloomTextures[i];
} }
bool DeferredBloomPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const /*!
* \brief Processes the work on the data while working with textures
* \return true
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredBloomPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const
{ {
NazaraUnused(sceneData); NazaraUnused(sceneData);
@ -91,7 +139,7 @@ namespace Nz
Renderer::DrawFullscreenQuad(); Renderer::DrawFullscreenQuad();
Renderer::SetTarget(&m_bloomRTT); Renderer::SetTarget(&m_bloomRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x/8, m_dimensions.y/8)); Renderer::SetViewport(Recti(0, 0, m_dimensions.x / 8, m_dimensions.y / 8));
Renderer::SetShader(m_gaussianBlurShader); Renderer::SetShader(m_gaussianBlurShader);
@ -124,6 +172,13 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Resizes the texture sizes
* \return true If successful
*
* \param dimensions Dimensions for the compute texture
*/
bool DeferredBloomPass::Resize(const Vector2ui& dimensions) bool DeferredBloomPass::Resize(const Vector2ui& dimensions)
{ {
DeferredRenderPass::Resize(dimensions); DeferredRenderPass::Resize(dimensions);
@ -131,7 +186,7 @@ namespace Nz
m_bloomRTT.Create(true); m_bloomRTT.Create(true);
for (unsigned int i = 0; i < 2; ++i) for (unsigned int i = 0; i < 2; ++i)
{ {
m_bloomTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, dimensions.x/8, dimensions.y/8); m_bloomTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, dimensions.x / 8, dimensions.y / 8);
m_bloomRTT.AttachTexture(AttachmentPoint_Color, i, m_bloomTextures[i]); m_bloomRTT.AttachTexture(AttachmentPoint_Color, i, m_bloomTextures[i]);
} }
m_bloomRTT.Unlock(); m_bloomRTT.Unlock();
@ -145,23 +200,47 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the number of pass for blur
*
* \param passCount Number of pass for blur
*/
void DeferredBloomPass::SetBlurPassCount(unsigned int passCount) void DeferredBloomPass::SetBlurPassCount(unsigned int passCount)
{ {
m_blurPassCount = passCount; // N'est pas une uniforme m_blurPassCount = passCount; // N'est pas une uniforme
} }
/*!
* \brief Sets the coefficiant for luminosity
*
* \param luminance Luminosity of bright elements
*/
void DeferredBloomPass::SetBrightLuminance(float luminance) void DeferredBloomPass::SetBrightLuminance(float luminance)
{ {
m_brightLuminance = luminance; m_brightLuminance = luminance;
m_uniformUpdated = false; m_uniformUpdated = false;
} }
/*!
* \brief Sets the coefficiant for the middle grey
*
* \param middleGrey Luminosity of grey elements
*/
void DeferredBloomPass::SetBrightMiddleGrey(float middleGrey) void DeferredBloomPass::SetBrightMiddleGrey(float middleGrey)
{ {
m_brightMiddleGrey = middleGrey; m_brightMiddleGrey = middleGrey;
m_uniformUpdated = false; m_uniformUpdated = false;
} }
/*!
* \brief Sets the coefficiant for things to be bright
*
* \param threshold Threshold for bright elements
*/
void DeferredBloomPass::SetBrightThreshold(float threshold) void DeferredBloomPass::SetBrightThreshold(float threshold)
{ {
m_brightThreshold = threshold; m_brightThreshold = threshold;

View File

@ -13,6 +13,10 @@ namespace Nz
{ {
namespace namespace
{ {
/*!
* \brief Builds the shader for the depth of field
* \return Reference to the shader newly created
*/
// http://digitalerr0r.wordpress.com/2009/05/16/xna-shader-programming-tutorial-20-depth-of-field/ // http://digitalerr0r.wordpress.com/2009/05/16/xna-shader-programming-tutorial-20-depth-of-field/
ShaderRef BuildDepthOfFieldShader() ShaderRef BuildDepthOfFieldShader()
{ {
@ -92,6 +96,16 @@ namespace Nz
} }
} }
/*!
* \ingroup graphics
* \class Nz::DeferredDOFPass
* \brief Graphics class that represents the pass for depth of field in deferred rendering
*/
/*!
* \brief Constructs a DeferredDOFPass object by default
*/
DeferredDOFPass::DeferredDOFPass() DeferredDOFPass::DeferredDOFPass()
{ {
m_dofShader = BuildDepthOfFieldShader(); m_dofShader = BuildDepthOfFieldShader();
@ -118,7 +132,16 @@ namespace Nz
DeferredDOFPass::~DeferredDOFPass() = default; DeferredDOFPass::~DeferredDOFPass() = default;
bool DeferredDOFPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const /*!
* \brief Processes the work on the data while working with textures
* \return true
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredDOFPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const
{ {
NazaraUnused(sceneData); NazaraUnused(sceneData);
@ -162,6 +185,13 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Resizes the texture sizes
* \return true If successful
*
* \param dimensions Dimensions for the compute texture
*/
bool DeferredDOFPass::Resize(const Vector2ui& dimensions) bool DeferredDOFPass::Resize(const Vector2ui& dimensions)
{ {
DeferredRenderPass::Resize(dimensions); DeferredRenderPass::Resize(dimensions);
@ -181,5 +211,5 @@ namespace Nz
} }
return true; return true;
} }
} }

View File

@ -10,6 +10,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredFXAAPass
* \brief Graphics class that represents the pass for FXAA in deferred rendering
*/
/*!
* \brief Constructs a DeferredFXAAPass object by default
*/
DeferredFXAAPass::DeferredFXAAPass() DeferredFXAAPass::DeferredFXAAPass()
{ {
m_fxaaShader = ShaderLibrary::Get("DeferredFXAA"); m_fxaaShader = ShaderLibrary::Get("DeferredFXAA");
@ -23,7 +33,16 @@ namespace Nz
DeferredFXAAPass::~DeferredFXAAPass() = default; DeferredFXAAPass::~DeferredFXAAPass() = default;
bool DeferredFXAAPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const /*!
* \brief Processes the work on the data while working with textures
* \return true
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredFXAAPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const
{ {
NazaraUnused(sceneData); NazaraUnused(sceneData);

View File

@ -10,6 +10,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredFinalPass
* \brief Graphics class that represents the final pass in deferred rendering
*/
/*!
* \brief Constructs a DeferredFinalPass object by default
*/
DeferredFinalPass::DeferredFinalPass() DeferredFinalPass::DeferredFinalPass()
{ {
m_pointSampler.SetAnisotropyLevel(1); m_pointSampler.SetAnisotropyLevel(1);
@ -34,7 +44,16 @@ namespace Nz
DeferredFinalPass::~DeferredFinalPass() = default; DeferredFinalPass::~DeferredFinalPass() = default;
bool DeferredFinalPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const /*!
* \brief Processes the work on the data while working with textures
* \return true
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredFinalPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");

View File

@ -13,6 +13,11 @@ namespace Nz
{ {
namespace namespace
{ {
/*!
* \brief Builds the shader for the fog
* \return Reference to the shader newly created
*/
ShaderRef BuildFogShader() ShaderRef BuildFogShader()
{ {
/*const UInt8 fragmentSource[] = { /*const UInt8 fragmentSource[] = {
@ -117,6 +122,16 @@ namespace Nz
} }
} }
/*!
* \ingroup graphics
* \class Nz::DeferredFogPass
* \brief Graphics class that represents the pass for fog in deferred rendering
*/
/*!
* \brief Constructs a DeferredFogPass object by default
*/
DeferredFogPass::DeferredFogPass() DeferredFogPass::DeferredFogPass()
{ {
m_pointSampler.SetAnisotropyLevel(1); m_pointSampler.SetAnisotropyLevel(1);
@ -131,7 +146,16 @@ namespace Nz
DeferredFogPass::~DeferredFogPass() = default; DeferredFogPass::~DeferredFogPass() = default;
bool DeferredFogPass::Process( const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const /*!
* \brief Processes the work on the data while working with textures
* \return true
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredFogPass::Process( const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");

View File

@ -13,9 +13,21 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredForwardPass
* \brief Graphics class that represents the forward pass in deferred rendering
*/
DeferredForwardPass::DeferredForwardPass() = default; DeferredForwardPass::DeferredForwardPass() = default;
DeferredForwardPass::~DeferredForwardPass() = default; DeferredForwardPass::~DeferredForwardPass() = default;
/*!
* \brief Initializes the deferred forward pass which needs the forward technique
*
* \param technique Rendering technique
*/
void DeferredForwardPass::Initialize(DeferredRenderTechnique* technique) void DeferredForwardPass::Initialize(DeferredRenderTechnique* technique)
{ {
DeferredRenderPass::Initialize(technique); DeferredRenderPass::Initialize(technique);
@ -23,7 +35,16 @@ namespace Nz
m_forwardTechnique = technique->GetForwardTechnique(); m_forwardTechnique = technique->GetForwardTechnique();
} }
bool DeferredForwardPass::Process(const SceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const /*!
* \brief Processes the work on the data while working with textures
* \return true
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredForwardPass::Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(workTexture); NazaraUnused(workTexture);

View File

@ -18,6 +18,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredGeometryPass
* \brief Graphics class that represents the pass for geometries in deferred rendering
*/
/*!
* \brief Constructs a DeferredGeometryPass object by default
*/
DeferredGeometryPass::DeferredGeometryPass() DeferredGeometryPass::DeferredGeometryPass()
{ {
m_clearShader = ShaderLibrary::Get("DeferredGBufferClear"); m_clearShader = ShaderLibrary::Get("DeferredGBufferClear");
@ -31,7 +41,16 @@ namespace Nz
DeferredGeometryPass::~DeferredGeometryPass() = default; DeferredGeometryPass::~DeferredGeometryPass() = default;
bool DeferredGeometryPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const /*!
* \brief Processes the work on the data while working with textures
* \return false
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredGeometryPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(firstWorkTexture); NazaraUnused(firstWorkTexture);
@ -72,22 +91,22 @@ namespace Nz
bool useInstancing = instancingEnabled && matEntry.instancingEnabled; bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
// On commence par récupérer le programme du matériau // We begin by getting the program for materials
UInt32 flags = ShaderFlags_Deferred; UInt32 flags = ShaderFlags_Deferred;
if (useInstancing) if (useInstancing)
flags |= ShaderFlags_Instancing; flags |= ShaderFlags_Instancing;
const Shader* shader = material->Apply(flags); const Shader* shader = material->Apply(flags);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // The uniforms are conserved in our program, there's no point to send them back if they don't change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène // Ambient color for the scene
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
lastShader = shader; lastShader = shader;
@ -105,7 +124,7 @@ namespace Nz
const IndexBuffer* indexBuffer = meshData.indexBuffer; const IndexBuffer* indexBuffer = meshData.indexBuffer;
const VertexBuffer* vertexBuffer = meshData.vertexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu // Handle draw call before rendering loop
Renderer::DrawCall drawFunc; Renderer::DrawCall drawFunc;
Renderer::DrawCallInstanced instancedDrawFunc; Renderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount; unsigned int indexCount;
@ -128,33 +147,33 @@ namespace Nz
if (useInstancing) if (useInstancing)
{ {
// On récupère le buffer d'instancing du Renderer et on le configure pour fonctionner avec des matrices // We get the buffer for instance of Renderer and we configure it to work with matrices
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
const Matrix4f* instanceMatrices = &instances[0]; const Matrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size(); unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre de matrices que peut contenir le buffer unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The number of matrices that can be hold in the buffer
while (instanceCount > 0) while (instanceCount > 0)
{ {
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) // We compute the number of instances that we will be able to show this time (Depending on the instance buffer size)
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount); unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount; instanceCount -= renderedInstanceCount;
// On remplit l'instancing buffer avec nos matrices world // We fill the instancing buffer with our world matrices
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true); instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
instanceMatrices += renderedInstanceCount; instanceMatrices += renderedInstanceCount;
// Et on affiche // And we show
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
} }
} }
else else
{ {
// Sans instancing, on doit effectuer un draw call pour chaque instance // Without instancing, we must do one draw call for each instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances // This may be faster than instancing under a threshold
// À cause du temps de modification du buffer d'instancing // Due to the time to modify the instancing buffer
for (const Matrix4f& matrix : instances) for (const Matrix4f& matrix : instances)
{ {
Renderer::SetMatrix(MatrixType_World, matrix); Renderer::SetMatrix(MatrixType_World, matrix);
@ -167,16 +186,23 @@ namespace Nz
} }
} }
// Et on remet à zéro les données // Abd we set it back data to zero
matEntry.enabled = false; matEntry.enabled = false;
matEntry.instancingEnabled = false; matEntry.instancingEnabled = false;
} }
} }
} }
return false; // On ne fait que remplir le G-Buffer, les work texture ne sont pas affectées return false; // We only fill the G-Buffer, the work texture are unchanged
} }
/*!
* \brief Resizes the texture sizes
* \return true If successful
*
* \param dimensions Dimensions for the compute texture
*/
bool DeferredGeometryPass::Resize(const Vector2ui& dimensions) bool DeferredGeometryPass::Resize(const Vector2ui& dimensions)
{ {
DeferredRenderPass::Resize(dimensions); DeferredRenderPass::Resize(dimensions);
@ -241,6 +267,13 @@ namespace Nz
} }
} }
/*!
* \brief Gets the uniforms of a shader
* \return Uniforms of the shader
*
* \param shader Shader to get uniforms from
*/
const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const
{ {
auto it = m_shaderUniforms.find(shader); auto it = m_shaderUniforms.find(shader);
@ -260,6 +293,12 @@ namespace Nz
return &it->second; return &it->second;
} }
/*!
* \brief Handle the invalidation of a shader
*
* \param shader Shader being invalidated
*/
void DeferredGeometryPass::OnShaderInvalidated(const Shader* shader) const void DeferredGeometryPass::OnShaderInvalidated(const Shader* shader) const
{ {
m_shaderUniforms.erase(shader); m_shaderUniforms.erase(shader);

View File

@ -13,6 +13,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredPhongLightingPass
* \brief Graphics class that represents the pass for phong lighting in deferred rendering
*/
/*!
* \brief Constructs a DeferredPhongLightingPass object by default
*/
DeferredPhongLightingPass::DeferredPhongLightingPass() : DeferredPhongLightingPass::DeferredPhongLightingPass() :
m_lightMeshesDrawing(false) m_lightMeshesDrawing(false)
{ {
@ -21,7 +31,7 @@ namespace Nz
m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient"); m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient");
m_directionalLightUniforms.ubo = false; m_directionalLightUniforms.ubo = false;
m_directionalLightUniforms.locations.type = -1; // Type déjà connu m_directionalLightUniforms.locations.type = -1; // Type already known
m_directionalLightUniforms.locations.color = m_directionalLightShader->GetUniformLocation("LightColor"); m_directionalLightUniforms.locations.color = m_directionalLightShader->GetUniformLocation("LightColor");
m_directionalLightUniforms.locations.factors = m_directionalLightShader->GetUniformLocation("LightFactors"); m_directionalLightUniforms.locations.factors = m_directionalLightShader->GetUniformLocation("LightFactors");
m_directionalLightUniforms.locations.parameters1 = m_directionalLightShader->GetUniformLocation("LightDirection"); m_directionalLightUniforms.locations.parameters1 = m_directionalLightShader->GetUniformLocation("LightDirection");
@ -56,16 +66,36 @@ namespace Nz
DeferredPhongLightingPass::~DeferredPhongLightingPass() = default; DeferredPhongLightingPass::~DeferredPhongLightingPass() = default;
/*!
* \brief Enables the drawing of meshes with light
*
* \param enable Should meshes with light parameter be drawed
*/
void DeferredPhongLightingPass::EnableLightMeshesDrawing(bool enable) void DeferredPhongLightingPass::EnableLightMeshesDrawing(bool enable)
{ {
m_lightMeshesDrawing = enable; m_lightMeshesDrawing = enable;
} }
/*!
* \brief Checks whether the drawing of meshes with light is enabled
* \return true If it is the case
*/
bool DeferredPhongLightingPass::IsLightMeshesDrawingEnabled() const bool DeferredPhongLightingPass::IsLightMeshesDrawingEnabled() const
{ {
return m_lightMeshesDrawing; return m_lightMeshesDrawing;
} }
/*!
* \brief Processes the work on the data while working with textures
* \return true
*
* \param sceneData Data for the scene
* \param firstWorkTexture Index of the first texture to work with
* \param firstWorkTexture Index of the second texture to work with
*/
bool DeferredPhongLightingPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const bool DeferredPhongLightingPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
@ -151,12 +181,12 @@ namespace Nz
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters1, Vector4f(light.position, light.attenuation)); m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters1, Vector4f(light.position, light.attenuation));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters2, Vector4f(0.f, 0.f, 0.f, light.invRadius)); m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters2, Vector4f(0.f, 0.f, 0.f, light.invRadius));
lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // To correct imperfections due to the sphere
lightMatrix.SetTranslation(light.position); lightMatrix.SetTranslation(light.position);
Renderer::SetMatrix(MatrixType_World, lightMatrix); Renderer::SetMatrix(MatrixType_World, lightMatrix);
// Rendu de la sphère dans le stencil buffer // Sphere rendering in the stencil buffer
Renderer::Enable(RendererParameter_ColorWrite, false); Renderer::Enable(RendererParameter_ColorWrite, false);
Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_DepthBuffer, true);
Renderer::Enable(RendererParameter_FaceCulling, false); Renderer::Enable(RendererParameter_FaceCulling, false);
@ -166,7 +196,7 @@ namespace Nz
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount()); Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
// Rendu de la sphère comme zone d'effet // Sphere rendering as effect zone
Renderer::Enable(RendererParameter_ColorWrite, true); Renderer::Enable(RendererParameter_ColorWrite, true);
Renderer::Enable(RendererParameter_DepthBuffer, false); Renderer::Enable(RendererParameter_DepthBuffer, false);
Renderer::Enable(RendererParameter_FaceCulling, true); Renderer::Enable(RendererParameter_FaceCulling, true);
@ -192,7 +222,7 @@ namespace Nz
Renderer::SetShader(shader); Renderer::SetShader(shader);
for (const auto& light : m_renderQueue->pointLights) for (const auto& light : m_renderQueue->pointLights)
{ {
lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // To correct imperfections due to the sphere
lightMatrix.SetTranslation(light.position); lightMatrix.SetTranslation(light.position);
Renderer::SetMatrix(MatrixType_World, lightMatrix); Renderer::SetMatrix(MatrixType_World, lightMatrix);
@ -230,7 +260,7 @@ namespace Nz
Renderer::SetMatrix(MatrixType_World, lightMatrix); Renderer::SetMatrix(MatrixType_World, lightMatrix);
// Rendu de la sphère dans le stencil buffer // Sphere rendering in the stencil buffer
Renderer::Enable(RendererParameter_ColorWrite, false); Renderer::Enable(RendererParameter_ColorWrite, false);
Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_DepthBuffer, true);
Renderer::Enable(RendererParameter_FaceCulling, false); Renderer::Enable(RendererParameter_FaceCulling, false);
@ -240,7 +270,7 @@ namespace Nz
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount()); Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
// Rendu de la sphère comme zone d'effet // Sphere rendering as effect zone
Renderer::Enable(RendererParameter_ColorWrite, true); Renderer::Enable(RendererParameter_ColorWrite, true);
Renderer::Enable(RendererParameter_DepthBuffer, false); Renderer::Enable(RendererParameter_DepthBuffer, false);
Renderer::Enable(RendererParameter_FaceCulling, true); Renderer::Enable(RendererParameter_FaceCulling, true);

View File

@ -9,6 +9,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredRenderPass
* \brief Graphics class that represents the pass for rendering in deferred rendering
*/
/*!
* \brief Constructs a DeferredRenderPass object by default
*/
DeferredRenderPass::DeferredRenderPass() : DeferredRenderPass::DeferredRenderPass() :
m_enabled(true) m_enabled(true)
{ {
@ -16,11 +26,23 @@ namespace Nz
DeferredRenderPass::~DeferredRenderPass() = default; DeferredRenderPass::~DeferredRenderPass() = default;
/*!
* \brief Enables the deferred rendering
*
* \param enable Should deferred rendering be activated
*/
void DeferredRenderPass::Enable(bool enable) void DeferredRenderPass::Enable(bool enable)
{ {
m_enabled = enable; m_enabled = enable;
} }
/*!
* \brief Initializes the deferred forward pass which needs the deferred technique
*
* \param technique Rendering technique
*/
void DeferredRenderPass::Initialize(DeferredRenderTechnique* technique) void DeferredRenderPass::Initialize(DeferredRenderTechnique* technique)
{ {
m_deferredTechnique = technique; m_deferredTechnique = technique;
@ -37,11 +59,23 @@ namespace Nz
m_workTextures[i] = technique->GetWorkTexture(i); m_workTextures[i] = technique->GetWorkTexture(i);
} }
/*!
* \brief Checks whether the deferred rendering is enabled
* \return true If it the case
*/
bool DeferredRenderPass::IsEnabled() const bool DeferredRenderPass::IsEnabled() const
{ {
return m_enabled; return m_enabled;
} }
/*!
* \brief Resizes the texture sizes
* \return true If successful
*
* \param dimensions Dimensions for the compute texture
*/
bool DeferredRenderPass::Resize(const Vector2ui& dimensions) bool DeferredRenderPass::Resize(const Vector2ui& dimensions)
{ {
m_dimensions = dimensions; m_dimensions = dimensions;

View File

@ -8,69 +8,207 @@
#include <Nazara/Graphics/Light.hpp> #include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Debug.hpp> #include <Nazara/Graphics/Debug.hpp>
///TODO: Rendre les billboards via Deferred Shading si possible ///TODO: Render billboards using Deferred Shading if possible
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DeferredRenderQueue
* \brief Graphics class that represents the rendering queue for deferred rendering
*/
/*!
* \brief Constructs a DeferredRenderQueue object with the rendering queue of forward rendering
*
* \param forwardQueue Queue of data to render
*/
DeferredRenderQueue::DeferredRenderQueue(ForwardRenderQueue* forwardQueue) : DeferredRenderQueue::DeferredRenderQueue(ForwardRenderQueue* forwardQueue) :
m_forwardQueue(forwardQueue) m_forwardQueue(forwardQueue)
{ {
} }
/*!
* \brief Adds billboard to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboard
* \param position Position of the billboard
* \param size Sizes of the billboard
* \param sinCos Rotation of the billboard
* \param color Color of the billboard
*/
void DeferredRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color) void DeferredRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color)
{ {
m_forwardQueue->AddBillboard(renderOrder, material, position, size, sinCos, color); m_forwardQueue->AddBillboard(renderOrder, material, position, size, sinCos, color);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param colorPtr Color of the billboards if null, Color::White is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param colorPtr Color of the billboards if null, Color::White is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param colorPtr Color of the billboards if null, Color::White is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param colorPtr Color of the billboards if null, Color::White is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*/
void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{ {
m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
} }
/*!
* \brief Adds drawable to the queue
*
* \param renderOrder Order of rendering
* \param drawable Drawable user defined
*
* \remark Produces a NazaraError if drawable is invalid
*/
void DeferredRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) void DeferredRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable)
{ {
m_forwardQueue->AddDrawable(renderOrder, drawable); m_forwardQueue->AddDrawable(renderOrder, drawable);
} }
/*!
* \brief Adds mesh to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the mesh
* \param meshData Data of the mesh
* \param meshAABB Box of the mesh
* \param transformMatrix Matrix of the mesh
*/
void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
{ {
if (material->IsEnabled(RendererParameter_Blend)) if (material->IsEnabled(RendererParameter_Blend))
// Un matériau transparent ? J'aime pas, va voir dans la forward queue si j'y suis // One transparent material ? I don't like it, go see if I'm in the forward queue
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix); m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
else else
{ {
@ -103,21 +241,37 @@ namespace Nz
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first; it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
} }
// On ajoute la matrice à la liste des instances de cet objet // We add matrices to the list of instances of this object
std::vector<Matrix4f>& instances = it2->second.instances; std::vector<Matrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix); instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ? // Do we have enough instances to perform instancing ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT) if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau entry.instancingEnabled = true; // Thus we can activate it
} }
} }
/*!
* \brief Adds sprites to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the sprites
* \param vertices Buffer of data for the sprites
* \param spriteCount Number of sprites
* \param overlay Texture of the sprites
*/
void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
{ {
m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay); m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay);
} }
/*!
* \brief Clears the queue
*
* \param fully Should everything be cleared or we can keep layers
*/
void DeferredRenderQueue::Clear(bool fully) void DeferredRenderQueue::Clear(bool fully)
{ {
AbstractRenderQueue::Clear(fully); AbstractRenderQueue::Clear(fully);
@ -137,6 +291,13 @@ namespace Nz
m_forwardQueue->Clear(fully); m_forwardQueue->Clear(fully);
} }
/*!
* \brief Gets the ith layer
* \return Reference to the ith layer for the queue
*
* \param i Index of the layer
*/
DeferredRenderQueue::Layer& DeferredRenderQueue::GetLayer(unsigned int i) DeferredRenderQueue::Layer& DeferredRenderQueue::GetLayer(unsigned int i)
{ {
auto it = layers.find(i); auto it = layers.find(i);
@ -149,6 +310,12 @@ namespace Nz
return layer; return layer;
} }
/*!
* \brief Handle the invalidation of an index buffer
*
* \param indexBuffer Index buffer being invalidated
*/
void DeferredRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer) void DeferredRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -170,6 +337,12 @@ namespace Nz
} }
} }
/*!
* \brief Handle the invalidation of a material
*
* \param material Material being invalidated
*/
void DeferredRenderQueue::OnMaterialInvalidation(const Material* material) void DeferredRenderQueue::OnMaterialInvalidation(const Material* material)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -180,6 +353,12 @@ namespace Nz
} }
} }
/*!
* \brief Handle the invalidation of a vertex buffer
*
* \param vertexBuffer Vertex buffer being invalidated
*/
void DeferredRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer) void DeferredRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -201,6 +380,14 @@ namespace Nz
} }
} }
/*!
* \brief Functor to compare two batched model with material
* \return true If first material is "smaller" than the second one
*
* \param mat1 First material to compare
* \param mat2 Second material to compare
*/
bool DeferredRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const bool DeferredRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const
{ {
const UberShader* uberShader1 = mat1->GetShader(); const UberShader* uberShader1 = mat1->GetShader();
@ -221,6 +408,14 @@ namespace Nz
return mat1 < mat2; return mat1 < mat2;
} }
/*!
* \brief Functor to compare two mesh data
* \return true If first mesh is "smaller" than the second one
*
* \param data1 First mesh to compare
* \param data2 Second mesh to compare
*/
bool DeferredRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const bool DeferredRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const
{ {
const Buffer* buffer1; const Buffer* buffer1;

View File

@ -77,7 +77,18 @@ namespace Nz
3, // RenderPassType_SSAO 3, // RenderPassType_SSAO
}; };
static_assert(sizeof(RenderPassPriority)/sizeof(unsigned int) == RenderPassType_Max+1, "Render pass priority array is incomplete"); static_assert(sizeof(RenderPassPriority) / sizeof(unsigned int) == RenderPassType_Max + 1, "Render pass priority array is incomplete");
/*!
* \brief Registers the deferred shader
* \return Reference to the newly created shader
*
* \param name Name of the shader
* \param fragmentSource Raw data to fragment shader
* \param fragmentSourceLength Size of the fragment source
* \param vertexStage Stage of the shader
* \param err Pointer to string to contain error message
*/
inline ShaderRef RegisterDeferredShader(const String& name, const UInt8* fragmentSource, unsigned int fragmentSourceLength, const ShaderStage& vertexStage, String* err) inline ShaderRef RegisterDeferredShader(const String& name, const UInt8* fragmentSource, unsigned int fragmentSourceLength, const ShaderStage& vertexStage, String* err)
{ {
@ -109,6 +120,18 @@ namespace Nz
} }
} }
/*!
* \ingroup graphics
* \class Nz::DeferredRenderTechnique
* \brief Graphics class that represents the technique used in deferred rendering
*/
/*!
* \brief Constructs a DeferredRenderTechnique object by default
*
* \remark Produces a NazaraError if one pass could not be created
*/
DeferredRenderTechnique::DeferredRenderTechnique() : DeferredRenderTechnique::DeferredRenderTechnique() :
m_renderQueue(static_cast<ForwardRenderQueue*>(m_forwardTechnique.GetRenderQueue())), m_renderQueue(static_cast<ForwardRenderQueue*>(m_forwardTechnique.GetRenderQueue())),
m_GBufferSize(0U) m_GBufferSize(0U)
@ -204,11 +227,27 @@ namespace Nz
DeferredRenderTechnique::~DeferredRenderTechnique() = default; DeferredRenderTechnique::~DeferredRenderTechnique() = default;
/*!
* \brief Clears the data
*
* \param sceneData Data of the scene
*/
void DeferredRenderTechnique::Clear(const SceneData& sceneData) const void DeferredRenderTechnique::Clear(const SceneData& sceneData) const
{ {
NazaraUnused(sceneData); NazaraUnused(sceneData);
} }
/*!
* \brief Draws the data of the scene
* \return true If successful
*
* \param sceneData Data of the scene
*
* \remark Produces a NazaraAssert if viewer of the scene is invalid
* \remark Produces a NazaraError if updating viewport dimensions failed
*/
bool DeferredRenderTechnique::Draw(const SceneData& sceneData) const bool DeferredRenderTechnique::Draw(const SceneData& sceneData) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
@ -242,6 +281,14 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Enables a pass
*
* \param renderPass Enumeration for the pass
* \param position Position of the pass
* \param enable Should the pass be enabled
*/
void DeferredRenderTechnique::EnablePass(RenderPassType renderPass, int position, bool enable) void DeferredRenderTechnique::EnablePass(RenderPassType renderPass, int position, bool enable)
{ {
auto it = m_passes.find(renderPass); auto it = m_passes.find(renderPass);
@ -253,11 +300,25 @@ namespace Nz
} }
} }
/*!
* \brief Gets the stencil buffer
* \return Pointer to the rendering buffer
*/
RenderBuffer* DeferredRenderTechnique::GetDepthStencilBuffer() const RenderBuffer* DeferredRenderTechnique::GetDepthStencilBuffer() const
{ {
return m_depthStencilBuffer; return m_depthStencilBuffer;
} }
/*!
* \brief Gets the G-buffer
* \return Pointer to the ith texture
*
* \param i Index of the G-buffer
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if index is invalid
*/
Texture* DeferredRenderTechnique::GetGBuffer(unsigned int i) const Texture* DeferredRenderTechnique::GetGBuffer(unsigned int i) const
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -271,16 +332,34 @@ namespace Nz
return m_GBuffer[i]; return m_GBuffer[i];
} }
/*!
* \brief Gets the rendering texture of the G-buffer
* \return Pointer to the rendering buffer
*/
RenderTexture* DeferredRenderTechnique::GetGBufferRTT() const RenderTexture* DeferredRenderTechnique::GetGBufferRTT() const
{ {
return &m_GBufferRTT; return &m_GBufferRTT;
} }
/*!
* \brief Gets the forward technique
* \return Constant pointer to the forward technique
*/
const ForwardRenderTechnique* DeferredRenderTechnique::GetForwardTechnique() const const ForwardRenderTechnique* DeferredRenderTechnique::GetForwardTechnique() const
{ {
return &m_forwardTechnique; return &m_forwardTechnique;
} }
/*!
* \brief Gets the pass
* \return Pointer to the deferred render pass
*
* \param renderPass Enumeration for the pass
* \param position Position of the pass
*/
DeferredRenderPass* DeferredRenderTechnique::GetPass(RenderPassType renderPass, int position) DeferredRenderPass* DeferredRenderTechnique::GetPass(RenderPassType renderPass, int position)
{ {
auto it = m_passes.find(renderPass); auto it = m_passes.find(renderPass);
@ -294,21 +373,45 @@ namespace Nz
return nullptr; return nullptr;
} }
/*!
* \brief Gets the render queue
* \return Pointer to the render queue
*/
AbstractRenderQueue* DeferredRenderTechnique::GetRenderQueue() AbstractRenderQueue* DeferredRenderTechnique::GetRenderQueue()
{ {
return &m_renderQueue; return &m_renderQueue;
} }
/*!
* \brief Gets the type of the current technique
* \return Type of the render technique
*/
RenderTechniqueType DeferredRenderTechnique::GetType() const RenderTechniqueType DeferredRenderTechnique::GetType() const
{ {
return RenderTechniqueType_DeferredShading; return RenderTechniqueType_DeferredShading;
} }
/*!
* \brief Gets the render texture used to work
* \return Pointer to the rendering texture
*/
RenderTexture* DeferredRenderTechnique::GetWorkRTT() const RenderTexture* DeferredRenderTechnique::GetWorkRTT() const
{ {
return &m_workRTT; return &m_workRTT;
} }
/*!
* \brief Gets the ith texture to work
* \return Pointer to the texture
*
* \param i Index of the texture used to work
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if index is invalid
*/
Texture* DeferredRenderTechnique::GetWorkTexture(unsigned int i) const Texture* DeferredRenderTechnique::GetWorkTexture(unsigned int i) const
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -322,6 +425,14 @@ namespace Nz
return m_workTextures[i]; return m_workTextures[i];
} }
/*!
* \brief Checks whether the pass is enable
* \return true If it is the case
*
* \param renderPass Enumeration for the pass
* \param position Position of the pass
*/
bool DeferredRenderTechnique::IsPassEnabled(RenderPassType renderPass, int position) bool DeferredRenderTechnique::IsPassEnabled(RenderPassType renderPass, int position)
{ {
auto it = m_passes.find(renderPass); auto it = m_passes.find(renderPass);
@ -335,9 +446,17 @@ namespace Nz
return false; return false;
} }
/*!
* \brief Resets the pass
* \return Pointer to the new deferred render pass
*
* \param renderPass Enumeration for the pass
* \param position Position of the pass
*/
DeferredRenderPass* DeferredRenderTechnique::ResetPass(RenderPassType renderPass, int position) DeferredRenderPass* DeferredRenderTechnique::ResetPass(RenderPassType renderPass, int position)
{ {
std::unique_ptr<DeferredRenderPass> smartPtr; // Nous évite un leak en cas d'exception std::unique_ptr<DeferredRenderPass> smartPtr; // We avoid to leak in case of exception
switch (renderPass) switch (renderPass)
{ {
@ -386,6 +505,14 @@ namespace Nz
return smartPtr.release(); return smartPtr.release();
} }
/*!
* \brief Sets the pass
*
* \param relativeTo Enumeration for the pass
* \param position Position of the pass
* \param pass Render pass to set
*/
void DeferredRenderTechnique::SetPass(RenderPassType relativeTo, int position, DeferredRenderPass* pass) void DeferredRenderTechnique::SetPass(RenderPassType relativeTo, int position, DeferredRenderPass* pass)
{ {
if (pass) if (pass)
@ -400,12 +527,26 @@ namespace Nz
m_passes[relativeTo].erase(position); m_passes[relativeTo].erase(position);
} }
/*!
* \brief Checks whether the technique is supported
* \return true if it is the case
*/
bool DeferredRenderTechnique::IsSupported() bool DeferredRenderTechnique::IsSupported()
{ {
// Depuis qu'OpenGL 3.3 est la version minimale, le Renderer supporte ce qu'il faut, mais par acquis de conscience... // Since OpenGL 3.3 is the minimal version, the Renderer supports what it needs, but we are never sure...
return Renderer::GetMaxColorAttachments() >= 4 && Renderer::GetMaxRenderTargets() >= 4; return Renderer::GetMaxColorAttachments() >= 4 && Renderer::GetMaxRenderTargets() >= 4;
} }
/*!
* \brief Resizes the texture sizes used for the render technique
* \return true If successful
*
* \param dimensions Dimensions for the render technique
*
* \param Produces a NazaraError if one pass could not be resized
*/
bool DeferredRenderTechnique::Resize(const Vector2ui& dimensions) const bool DeferredRenderTechnique::Resize(const Vector2ui& dimensions) const
{ {
try try
@ -427,6 +568,13 @@ namespace Nz
} }
} }
/*!
* \brief Initializes the deferred render technique
* \return true If successful
*
* \remark Produces a NazaraError if one shader creation failed
*/
bool DeferredRenderTechnique::Initialize() bool DeferredRenderTechnique::Initialize()
{ {
const char vertexSource_Basic[] = const char vertexSource_Basic[] =
@ -560,6 +708,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the deferred render technique
*/
void DeferredRenderTechnique::Uninitialize() void DeferredRenderTechnique::Uninitialize()
{ {
ShaderLibrary::Unregister("DeferredGBufferClear"); ShaderLibrary::Unregister("DeferredGBufferClear");
@ -571,6 +723,14 @@ namespace Nz
ShaderLibrary::Unregister("DeferredGaussianBlur"); ShaderLibrary::Unregister("DeferredGaussianBlur");
} }
/*!
* \brief Functor to compare two render pass
* \return true If first render pass is "smaller" than the second one
*
* \param pass1 First render pass to compare
* \param pass2 Second render pass to compare
*/
bool DeferredRenderTechnique::RenderPassComparator::operator()(RenderPassType pass1, RenderPassType pass2) const bool DeferredRenderTechnique::RenderPassComparator::operator()(RenderPassType pass1, RenderPassType pass2) const
{ {
return RenderPassPriority[pass1] < RenderPassPriority[pass2]; return RenderPassPriority[pass1] < RenderPassPriority[pass2];

View File

@ -9,6 +9,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::DepthRenderQueue
* \brief Graphics class that represents the rendering queue for depth rendering
*/
/*!
* \brief Constructs a DepthRenderTechnique object by default
*/
DepthRenderQueue::DepthRenderQueue() DepthRenderQueue::DepthRenderQueue()
{ {
// Material // Material
@ -18,6 +28,19 @@ namespace Nz
//m_baseMaterial->SetFaceCulling(FaceSide_Front); //m_baseMaterial->SetFaceCulling(FaceSide_Front);
} }
/*!
* \brief Adds billboard to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboard
* \param position Position of the billboard
* \param size Sizes of the billboard
* \param sinCos Rotation of the billboard
* \param color Color of the billboard
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color) void DepthRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -34,6 +57,20 @@ namespace Nz
ForwardRenderQueue::AddBillboard(0, material, position, size, sinCos, color); ForwardRenderQueue::AddBillboard(0, material, position, size, sinCos, color);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -50,6 +87,20 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -66,6 +117,20 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -82,6 +147,20 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -98,6 +177,20 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -114,6 +207,20 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -130,6 +237,20 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -146,6 +267,20 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr);
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -162,12 +297,32 @@ namespace Nz
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
} }
/*!
* \brief Adds a direcitonal light to the queue
*
* \param light Light to add
*
* \remark Produces a NazaraAssert
*/
void DepthRenderQueue::AddDirectionalLight(const DirectionalLight& light) void DepthRenderQueue::AddDirectionalLight(const DirectionalLight& light)
{ {
NazaraAssert(false, "Depth render queue doesn't handle lights"); NazaraAssert(false, "Depth render queue doesn't handle lights");
NazaraUnused(light); NazaraUnused(light);
} }
/*!
* \brief Adds mesh to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the mesh
* \param meshData Data of the mesh
* \param meshAABB Box of the mesh
* \param transformMatrix Matrix of the mesh
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) void DepthRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -185,18 +340,46 @@ namespace Nz
ForwardRenderQueue::AddMesh(0, material, meshData, meshAABB, transformMatrix); ForwardRenderQueue::AddMesh(0, material, meshData, meshAABB, transformMatrix);
} }
/*!
* \brief Adds a point light to the queue
*
* \param light Light to add
*
* \remark Produces a NazaraAssert
*/
void DepthRenderQueue::AddPointLight(const PointLight& light) void DepthRenderQueue::AddPointLight(const PointLight& light)
{ {
NazaraAssert(false, "Depth render queue doesn't handle lights"); NazaraAssert(false, "Depth render queue doesn't handle lights");
NazaraUnused(light); NazaraUnused(light);
} }
/*!
* \brief Adds a spot light to the queue
*
* \param light Light to add
*
* \remark Produces a NazaraAssert
*/
void DepthRenderQueue::AddSpotLight(const SpotLight& light) void DepthRenderQueue::AddSpotLight(const SpotLight& light)
{ {
NazaraAssert(false, "Depth render queue doesn't handle lights"); NazaraAssert(false, "Depth render queue doesn't handle lights");
NazaraUnused(light); NazaraUnused(light);
} }
/*!
* \brief Adds sprites to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the sprites
* \param vertices Buffer of data for the sprites
* \param spriteCount Number of sprites
* \param overlay Texture of the sprites
*
* \remark Produces a NazaraAssert if material is invalid
*/
void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");

View File

@ -37,6 +37,16 @@ namespace Nz
unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
} }
/*!
* \ingroup graphics
* \class Nz::DepthRenderTechnique
* \brief Graphics class that represents the technique used in depth rendering
*/
/*!
* \brief Constructs a DepthRenderTechnique object by default
*/
DepthRenderTechnique::DepthRenderTechnique() : DepthRenderTechnique::DepthRenderTechnique() :
m_vertexBuffer(BufferType_Vertex) m_vertexBuffer(BufferType_Vertex)
{ {
@ -48,6 +58,12 @@ namespace Nz
m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer); m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer);
} }
/*!
* \brief Clears the data
*
* \param sceneData Data of the scene
*/
void DepthRenderTechnique::Clear(const SceneData& sceneData) const void DepthRenderTechnique::Clear(const SceneData& sceneData) const
{ {
Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_DepthBuffer, true);
@ -59,6 +75,13 @@ namespace Nz
// sceneData.background->Draw(sceneData.viewer); // sceneData.background->Draw(sceneData.viewer);
} }
/*!
* \brief Draws the data of the scene
* \return true If successful
*
* \param sceneData Data of the scene
*/
bool DepthRenderTechnique::Draw(const SceneData& sceneData) const bool DepthRenderTechnique::Draw(const SceneData& sceneData) const
{ {
for (auto& pair : m_renderQueue.layers) for (auto& pair : m_renderQueue.layers)
@ -81,16 +104,33 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Gets the render queue
* \return Pointer to the render queue
*/
AbstractRenderQueue* DepthRenderTechnique::GetRenderQueue() AbstractRenderQueue* DepthRenderTechnique::GetRenderQueue()
{ {
return &m_renderQueue; return &m_renderQueue;
} }
/*!
* \brief Gets the type of the current technique
* \return Type of the render technique
*/
RenderTechniqueType DepthRenderTechnique::GetType() const RenderTechniqueType DepthRenderTechnique::GetType() const
{ {
return RenderTechniqueType_Depth; return RenderTechniqueType_Depth;
} }
/*!
* \brief Initializes the depth render technique
* \return true If successful
*
* \remark Produces a NazaraError if one shader creation failed
*/
bool DepthRenderTechnique::Initialize() bool DepthRenderTechnique::Initialize()
{ {
try try
@ -149,12 +189,23 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the depth render technique
*/
void DepthRenderTechnique::Uninitialize() void DepthRenderTechnique::Uninitialize()
{ {
s_quadIndexBuffer.Reset(); s_quadIndexBuffer.Reset();
s_quadVertexBuffer.Reset(); s_quadVertexBuffer.Reset();
} }
/*!
* \brief Draws basic sprites
*
* \param sceneData Data of the scene
* \param layer Layer of the rendering
*/
void DepthRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const void DepthRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
{ {
const Shader* lastShader = nullptr; const Shader* lastShader = nullptr;
@ -180,7 +231,7 @@ namespace Nz
unsigned int spriteChainCount = spriteChainVector.size(); unsigned int spriteChainCount = spriteChainVector.size();
if (spriteChainCount > 0) if (spriteChainCount > 0)
{ {
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
UInt32 flags = 0; UInt32 flags = 0;
if (overlay) if (overlay)
flags |= ShaderFlags_TextureOverlay; flags |= ShaderFlags_TextureOverlay;
@ -195,26 +246,26 @@ namespace Nz
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler()); Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
} }
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Overlay // Overlay
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit); shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation()); shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
lastShader = shader; lastShader = shader;
} }
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous unsigned int spriteChain = 0; // Which chain of sprites are we treating
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
do do
{ {
// On ouvre le buffer en écriture // We open the buffer in writing mode
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer()); VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
@ -232,7 +283,7 @@ namespace Nz
spriteCount += count; spriteCount += count;
spriteChainOffset += count; spriteChainOffset += count;
// Avons-nous traité la chaîne entière ? // Have we treated the entire chain ?
if (spriteChainOffset == currentChain.spriteCount) if (spriteChainOffset == currentChain.spriteCount)
{ {
spriteChain++; spriteChain++;
@ -257,6 +308,13 @@ namespace Nz
} }
} }
/*!
* \brief Draws billboards
*
* \param sceneData Data of the scene
* \param layer Layer of the rendering
*/
void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
{ {
const Shader* lastShader = nullptr; const Shader* lastShader = nullptr;
@ -278,16 +336,16 @@ namespace Nz
unsigned int billboardCount = billboardVector.size(); unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0) if (billboardCount > 0)
{ {
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor); const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation()); shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
lastShader = shader; lastShader = shader;
@ -325,16 +383,16 @@ namespace Nz
unsigned int billboardCount = billboardVector.size(); unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0) if (billboardCount > 0)
{ {
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor); const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation()); shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
lastShader = shader; lastShader = shader;
@ -396,6 +454,13 @@ namespace Nz
} }
} }
/*!
* \brief Draws opaques models
*
* \param sceneData Data of the scene
* \param layer Layer of the rendering
*/
void DepthRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const void DepthRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
{ {
const Shader* lastShader = nullptr; const Shader* lastShader = nullptr;
@ -415,14 +480,14 @@ namespace Nz
bool instancing = m_instancingEnabled && matEntry.instancingEnabled; bool instancing = m_instancingEnabled && matEntry.instancingEnabled;
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
UInt8 freeTextureUnit; UInt8 freeTextureUnit;
const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit); const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
lastShader = shader; lastShader = shader;
} }
@ -441,7 +506,7 @@ namespace Nz
const IndexBuffer* indexBuffer = meshData.indexBuffer; const IndexBuffer* indexBuffer = meshData.indexBuffer;
const VertexBuffer* vertexBuffer = meshData.vertexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu // Handle draw call before rendering loop
Renderer::DrawCall drawFunc; Renderer::DrawCall drawFunc;
Renderer::DrawCallInstanced instancedDrawFunc; Renderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount; unsigned int indexCount;
@ -464,33 +529,33 @@ namespace Nz
if (instancing) if (instancing)
{ {
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
const Matrix4f* instanceMatrices = &instances[0]; const Matrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size(); unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The maximum number of instances in one batch
while (instanceCount > 0) while (instanceCount > 0)
{ {
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount); unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount; instanceCount -= renderedInstanceCount;
// On remplit l'instancing buffer avec nos matrices world // We fill the instancing buffer with our world matrices
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true); instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
instanceMatrices += renderedInstanceCount; instanceMatrices += renderedInstanceCount;
// Et on affiche // And we draw
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
} }
} }
else else
{ {
// Sans instancing, on doit effectuer un draw call pour chaque instance // Without instancing, we must do a draw call for each instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances // This may be faster than instancing under a certain number
// À cause du temps de modification du buffer d'instancing // Due to the time to modify the instancing buffer
for (const Matrix4f& matrix : instances) for (const Matrix4f& matrix : instances)
{ {
Renderer::SetMatrix(MatrixType_World, matrix); Renderer::SetMatrix(MatrixType_World, matrix);
@ -502,13 +567,20 @@ namespace Nz
} }
} }
// Et on remet à zéro les données // And we set the data back to zero
matEntry.enabled = false; matEntry.enabled = false;
matEntry.instancingEnabled = false; matEntry.instancingEnabled = false;
} }
} }
} }
/*!
* \brief Gets the shader uniforms
* \return Uniforms of the shader
*
* \param shader Shader to get uniforms from
*/
const DepthRenderTechnique::ShaderUniforms* DepthRenderTechnique::GetShaderUniforms(const Shader* shader) const const DepthRenderTechnique::ShaderUniforms* DepthRenderTechnique::GetShaderUniforms(const Shader* shader) const
{ {
auto it = m_shaderUniforms.find(shader); auto it = m_shaderUniforms.find(shader);
@ -527,6 +599,12 @@ namespace Nz
return &it->second; return &it->second;
} }
/*!
* \brief Handle the invalidation of a shader
*
* \param shader Shader being invalidated
*/
void DepthRenderTechnique::OnShaderInvalidated(const Shader* shader) const void DepthRenderTechnique::OnShaderInvalidated(const Shader* shader) const
{ {
m_shaderUniforms.erase(shader); m_shaderUniforms.erase(shader);

View File

@ -7,5 +7,13 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::Drawable
* \brief Graphics class that represents something drawable for our scene
*
* \remark This class is abstract
*/
Drawable::~Drawable() = default; Drawable::~Drawable() = default;
} }

View File

@ -7,10 +7,29 @@
#include <Nazara/Graphics/Light.hpp> #include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Debug.hpp> #include <Nazara/Graphics/Debug.hpp>
///TODO: Remplacer les sinus/cosinus par une lookup table (va booster les perfs d'un bon x10) ///TODO: Replace sinus/cosinus by a lookup table (which will lead to a speed up about 10x)
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ForwardRenderQueue
* \brief Graphics class that represents the rendering queue for forward rendering
*/
/*!
* \brief Adds billboard to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboard
* \param position Position of the billboard
* \param size Sizes of the billboard
* \param sinCos Rotation of the billboard
* \param color Color of the billboard
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color) void ForwardRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
@ -32,37 +51,33 @@ namespace Nz
billboardVector.push_back(BillboardData{color, position, size, sinCos}); billboardVector.push_back(BillboardData{color, position, size, sinCos});
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr) if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
if (!colorPtr) if (!colorPtr)
colorPtr.Reset(&Color::White, 0); // Pareil colorPtr.Reset(&Color::White, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
billboardData->center = *positionPtr++; billboardData->center = *positionPtr++;
@ -73,39 +88,35 @@ namespace Nz
} }
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr) if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
float defaultAlpha = 1.f; float defaultAlpha = 1.f;
if (!alphaPtr) if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil alphaPtr.Reset(&defaultAlpha, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
billboardData->center = *positionPtr++; billboardData->center = *positionPtr++;
@ -116,37 +127,33 @@ namespace Nz
} }
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f; float defaultRotation = 0.f;
if (!anglePtr) if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
if (!colorPtr) if (!colorPtr)
colorPtr.Reset(&Color::White, 0); // Pareil colorPtr.Reset(&Color::White, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
float sin = std::sin(ToRadians(*anglePtr)); float sin = std::sin(ToRadians(*anglePtr));
@ -161,39 +168,35 @@ namespace Nz
} }
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Sizes of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f; float defaultRotation = 0.f;
if (!anglePtr) if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
float defaultAlpha = 1.f; float defaultAlpha = 1.f;
if (!alphaPtr) if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil alphaPtr.Reset(&defaultAlpha, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
float sin = std::sin(ToRadians(*anglePtr)); float sin = std::sin(ToRadians(*anglePtr));
@ -208,37 +211,33 @@ namespace Nz
} }
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr) if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
if (!colorPtr) if (!colorPtr)
colorPtr.Reset(&Color::White, 0); // Pareil colorPtr.Reset(&Color::White, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
billboardData->center = *positionPtr++; billboardData->center = *positionPtr++;
@ -249,39 +248,35 @@ namespace Nz
} }
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr) if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
float defaultAlpha = 1.f; float defaultAlpha = 1.f;
if (!alphaPtr) if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil alphaPtr.Reset(&defaultAlpha, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
billboardData->center = *positionPtr++; billboardData->center = *positionPtr++;
@ -292,37 +287,33 @@ namespace Nz
} }
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param colorPtr Color of the billboards if null, Color::White is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f; float defaultRotation = 0.f;
if (!anglePtr) if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
if (!colorPtr) if (!colorPtr)
colorPtr.Reset(&Color::White, 0); // Pareil colorPtr.Reset(&Color::White, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
float sin = std::sin(ToRadians(*anglePtr)); float sin = std::sin(ToRadians(*anglePtr));
@ -337,39 +328,35 @@ namespace Nz
} }
} }
/*!
* \brief Adds multiple billboards to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the billboards
* \param count Number of billboards
* \param positionPtr Position of the billboards
* \param sizePtr Size of the billboards
* \param anglePtr Rotation of the billboards if null, 0.f is used
* \param alphaPtr Alpha parameters of the billboards if null, 1.f is used
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
float defaultRotation = 0.f; float defaultRotation = 0.f;
if (!anglePtr) if (!anglePtr)
anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile
float defaultAlpha = 1.f; float defaultAlpha = 1.f;
if (!alphaPtr) if (!alphaPtr)
alphaPtr.Reset(&defaultAlpha, 0); // Pareil alphaPtr.Reset(&defaultAlpha, 0); // Same
auto& billboards = GetLayer(renderOrder).billboards; BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
BillboardData* billboardData = &billboardVector[prevSize];
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
{ {
float sin = std::sin(ToRadians(*anglePtr)); float sin = std::sin(ToRadians(*anglePtr));
@ -384,6 +371,15 @@ namespace Nz
} }
} }
/*!
* \brief Adds drawable to the queue
*
* \param renderOrder Order of rendering
* \param drawable Drawable user defined
*
* \remark Produces a NazaraError if drawable is invalid
*/
void ForwardRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) void ForwardRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -399,15 +395,29 @@ namespace Nz
otherDrawables.push_back(drawable); otherDrawables.push_back(drawable);
} }
/*!
* \brief Adds mesh to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the mesh
* \param meshData Data of the mesh
* \param meshAABB Box of the mesh
* \param transformMatrix Matrix of the mesh
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) void ForwardRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
{ {
NazaraAssert(material, "Invalid material");
if (material->IsEnabled(RendererParameter_Blend)) if (material->IsEnabled(RendererParameter_Blend))
{ {
Layer& currentLayer = GetLayer(renderOrder); Layer& currentLayer = GetLayer(renderOrder);
auto& transparentModels = currentLayer.transparentModels; auto& transparentModels = currentLayer.transparentModels;
auto& transparentModelData = currentLayer.transparentModelData; auto& transparentModelData = currentLayer.transparentModelData;
// Le matériau est transparent, nous devons rendre ce mesh d'une autre façon (après le rendu des objets opaques et en les triant) // The material is transparent, we must draw this mesh using another way (after the rendering of opages objects while sorting them)
unsigned int index = transparentModelData.size(); unsigned int index = transparentModelData.size();
transparentModelData.resize(index+1); transparentModelData.resize(index+1);
@ -455,14 +465,28 @@ namespace Nz
std::vector<Matrix4f>& instances = it2->second.instances; std::vector<Matrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix); instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ? // Do we have enough instances to perform instancing ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT) if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau entry.instancingEnabled = true; // Thus we can activate it
} }
} }
/*!
* \brief Adds sprites to the queue
*
* \param renderOrder Order of rendering
* \param material Material of the sprites
* \param vertices Buffer of data for the sprites
* \param spriteCount Number of sprites
* \param overlay Texture of the sprites
*
* \remark Produces a NazaraAssert if material is invalid
*/
void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
{ {
NazaraAssert(material, "Invalid material");
Layer& currentLayer = GetLayer(renderOrder); Layer& currentLayer = GetLayer(renderOrder);
auto& basicSprites = currentLayer.basicSprites; auto& basicSprites = currentLayer.basicSprites;
@ -494,6 +518,12 @@ namespace Nz
spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount})); spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount}));
} }
/*!
* \brief Clears the queue
*
* \param fully Should everything be cleared or we can keep layers
*/
void ForwardRenderQueue::Clear(bool fully) void ForwardRenderQueue::Clear(bool fully)
{ {
AbstractRenderQueue::Clear(fully); AbstractRenderQueue::Clear(fully);
@ -518,15 +548,21 @@ namespace Nz
} }
} }
/*!
* \brief Sorts the object according to the viewer position, furthest to nearest
*
* \param viewer Viewer of the scene
*/
void ForwardRenderQueue::Sort(const AbstractViewer* viewer) void ForwardRenderQueue::Sort(const AbstractViewer* viewer)
{ {
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near); Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
Vector3f viewerPos = viewer->GetEyePosition(); Vector3f viewerPos = viewer->GetEyePosition();
Vector3f viewerNormal = viewer->GetForward(); Vector3f viewerNormal = viewer->GetForward();
for (auto& layerPair : layers) for (auto& pair : layers)
{ {
Layer& layer = layerPair.second; Layer& layer = pair.second;
std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (unsigned int index1, unsigned int index2) std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (unsigned int index1, unsigned int index2)
{ {
@ -557,18 +593,61 @@ namespace Nz
} }
} }
/*!
* \brief Gets the billboard data
* \return Pointer to the data of the billboards
*
* \param renderOrder Order of rendering
* \param material Material of the billboard
*/
ForwardRenderQueue::BillboardData* ForwardRenderQueue::GetBillboardData(int renderOrder, const Material* material, unsigned int count)
{
auto& billboards = GetLayer(renderOrder).billboards;
auto it = billboards.find(material);
if (it == billboards.end())
{
BatchedBillboardEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedBillboardEntry& entry = it->second;
auto& billboardVector = entry.billboards;
unsigned int prevSize = billboardVector.size();
billboardVector.resize(prevSize + count);
return &billboardVector[prevSize];
}
/*!
* \brief Gets the ith layer
* \return Reference to the ith layer for the queue
*
* \param i Index of the layer
*/
ForwardRenderQueue::Layer& ForwardRenderQueue::GetLayer(int i) ForwardRenderQueue::Layer& ForwardRenderQueue::GetLayer(int i)
{ {
auto it = layers.find(i); auto it = layers.find(i);
if (it == layers.end()) if (it == layers.end())
it = layers.insert(std::make_pair(i, Layer())).first; it = layers.insert(std::make_pair(i, Layer())).first;
Layer& layer = it->second; Layer& layer = it->second;
layer.clearCount = 0; layer.clearCount = 0;
return layer; return layer;
} }
/*!
* \brief Handle the invalidation of an index buffer
*
* \param indexBuffer Index buffer being invalidated
*/
void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer) void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -590,6 +669,12 @@ namespace Nz
} }
} }
/*!
* \brief Handle the invalidation of a material
*
* \param material Material being invalidated
*/
void ForwardRenderQueue::OnMaterialInvalidation(const Material* material) void ForwardRenderQueue::OnMaterialInvalidation(const Material* material)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -602,6 +687,12 @@ namespace Nz
} }
} }
/*!
* \brief Handle the invalidation of a texture
*
* \param texture Texture being invalidated
*/
void ForwardRenderQueue::OnTextureInvalidation(const Texture* texture) void ForwardRenderQueue::OnTextureInvalidation(const Texture* texture)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -615,6 +706,12 @@ namespace Nz
} }
} }
/*!
* \brief Handle the invalidation of a vertex buffer
*
* \param vertexBuffer Vertex buffer being invalidated
*/
void ForwardRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer) void ForwardRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -635,6 +732,14 @@ namespace Nz
} }
} }
/*!
* \brief Functor to compare two batched billboard with material
* \return true If first material is "smaller" than the second one
*
* \param mat1 First material to compare
* \param mat2 Second material to compare
*/
bool ForwardRenderQueue::BatchedBillboardComparator::operator()(const Material* mat1, const Material* mat2) const bool ForwardRenderQueue::BatchedBillboardComparator::operator()(const Material* mat1, const Material* mat2) const
{ {
const UberShader* uberShader1 = mat1->GetShader(); const UberShader* uberShader1 = mat1->GetShader();
@ -655,6 +760,14 @@ namespace Nz
return mat1 < mat2; return mat1 < mat2;
} }
/*!
* \brief Functor to compare two batched model with material
* \return true If first material is "smaller" than the second one
*
* \param mat1 First material to compare
* \param mat2 Second material to compare
*/
bool ForwardRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const bool ForwardRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const
{ {
const UberShader* uberShader1 = mat1->GetShader(); const UberShader* uberShader1 = mat1->GetShader();
@ -675,6 +788,14 @@ namespace Nz
return mat1 < mat2; return mat1 < mat2;
} }
/*!
* \brief Functor to compare two batched sprites with material
* \return true If first material is "smaller" than the second one
*
* \param mat1 First material to compare
* \param mat2 Second material to compare
*/
bool ForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const Material* mat1, const Material* mat2) bool ForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const Material* mat1, const Material* mat2)
{ {
const UberShader* uberShader1 = mat1->GetShader(); const UberShader* uberShader1 = mat1->GetShader();
@ -695,6 +816,14 @@ namespace Nz
return mat1 < mat2; return mat1 < mat2;
} }
/*!
* \brief Functor to compare two mesh data
* \return true If first mesh is "smaller" than the second one
*
* \param data1 First mesh to compare
* \param data2 Second mesh to compare
*/
bool ForwardRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const bool ForwardRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const
{ {
const Buffer* buffer1; const Buffer* buffer1;

View File

@ -33,10 +33,20 @@ namespace Nz
Vector2f uv; Vector2f uv;
}; };
unsigned int s_maxQuads = std::numeric_limits<UInt16>::max()/6; unsigned int s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
unsigned int s_vertexBufferSize = 4*1024*1024; // 4 MiB unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
} }
/*!
* \ingroup graphics
* \class Nz::ForwardRenderTechnique
* \brief Graphics class that represents the technique used in forward rendering
*/
/*!
* \brief Constructs a ForwardRenderTechnique object by default
*/
ForwardRenderTechnique::ForwardRenderTechnique() : ForwardRenderTechnique::ForwardRenderTechnique() :
m_vertexBuffer(BufferType_Vertex), m_vertexBuffer(BufferType_Vertex),
m_maxLightPassPerObject(3) m_maxLightPassPerObject(3)
@ -49,6 +59,12 @@ namespace Nz
m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer); m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer);
} }
/*!
* \brief Clears the data
*
* \param sceneData Data of the scene
*/
void ForwardRenderTechnique::Clear(const SceneData& sceneData) const void ForwardRenderTechnique::Clear(const SceneData& sceneData) const
{ {
Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_DepthBuffer, true);
@ -59,6 +75,15 @@ namespace Nz
sceneData.background->Draw(sceneData.viewer); sceneData.background->Draw(sceneData.viewer);
} }
/*!
* \brief Draws the data of the scene
* \return true If successful
*
* \param sceneData Data of the scene
*
* \remark Produces a NazaraAssert if viewer of the scene is invalid
*/
bool ForwardRenderTechnique::Draw(const SceneData& sceneData) const bool ForwardRenderTechnique::Draw(const SceneData& sceneData) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
@ -88,55 +113,83 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Gets the maximum number of lights available per pass per object
* \return Maximum number of light simulatenously per object
*/
unsigned int ForwardRenderTechnique::GetMaxLightPassPerObject() const unsigned int ForwardRenderTechnique::GetMaxLightPassPerObject() const
{ {
return m_maxLightPassPerObject; return m_maxLightPassPerObject;
} }
/*!
* \brief Gets the render queue
* \return Pointer to the render queue
*/
AbstractRenderQueue* ForwardRenderTechnique::GetRenderQueue() AbstractRenderQueue* ForwardRenderTechnique::GetRenderQueue()
{ {
return &m_renderQueue; return &m_renderQueue;
} }
/*!
* \brief Gets the type of the current technique
* \return Type of the render technique
*/
RenderTechniqueType ForwardRenderTechnique::GetType() const RenderTechniqueType ForwardRenderTechnique::GetType() const
{ {
return RenderTechniqueType_BasicForward; return RenderTechniqueType_BasicForward;
} }
void ForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount) /*!
* \brief Sets the maximum number of lights available per pass per object
*
* \param passCount Maximum number of light simulatenously per object
*/
void ForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int maxLightPassPerObject)
{ {
m_maxLightPassPerObject = passCount; m_maxLightPassPerObject = maxLightPassPerObject;
} }
/*!
* \brief Initializes the forward render technique
* \return true If successful
*
* \remark Produces a NazaraError if one shader creation failed
*/
bool ForwardRenderTechnique::Initialize() bool ForwardRenderTechnique::Initialize()
{ {
try try
{ {
ErrorFlags flags(ErrorFlag_ThrowException, true); ErrorFlags flags(ErrorFlag_ThrowException, true);
s_quadIndexBuffer.Reset(false, s_maxQuads*6, DataStorage_Hardware, BufferUsage_Static); s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, BufferUsage_Static);
BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly);
UInt16* indices = static_cast<UInt16*>(mapper.GetPointer()); UInt16* indices = static_cast<UInt16*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxQuads; ++i) for (unsigned int i = 0; i < s_maxQuads; ++i)
{ {
*indices++ = i*4 + 0; *indices++ = i * 4 + 0;
*indices++ = i*4 + 2; *indices++ = i * 4 + 2;
*indices++ = i*4 + 1; *indices++ = i * 4 + 1;
*indices++ = i*4 + 2; *indices++ = i * 4 + 2;
*indices++ = i*4 + 3; *indices++ = i * 4 + 3;
*indices++ = i*4 + 1; *indices++ = i * 4 + 1;
} }
mapper.Unmap(); // Inutile de garder le buffer ouvert plus longtemps mapper.Unmap(); // No point to keep the buffer open any longer
// Quad buffer (utilisé pour l'instancing de billboard et de sprites) // Quad buffer (used for instancing of billboards and sprites)
//Note: Les UV sont calculés dans le shader //Note: UV are computed in the shader
s_quadVertexBuffer.Reset(VertexDeclaration::Get(VertexLayout_XY), 4, DataStorage_Hardware, BufferUsage_Static); s_quadVertexBuffer.Reset(VertexDeclaration::Get(VertexLayout_XY), 4, DataStorage_Hardware, BufferUsage_Static);
float vertices[2*4] = { float vertices[2 * 4] = {
-0.5f, -0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f, 0.5f,
@ -145,14 +198,14 @@ namespace Nz
s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices)); s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices));
// Déclaration lors du rendu des billboards par sommet // Declaration used when rendering the vertex billboards
s_billboardVertexDeclaration.EnableComponent(VertexComponent_Color, ComponentType_Color, NazaraOffsetOf(BillboardPoint, color)); s_billboardVertexDeclaration.EnableComponent(VertexComponent_Color, ComponentType_Color, NazaraOffsetOf(BillboardPoint, color));
s_billboardVertexDeclaration.EnableComponent(VertexComponent_Position, ComponentType_Float3, NazaraOffsetOf(BillboardPoint, position)); s_billboardVertexDeclaration.EnableComponent(VertexComponent_Position, ComponentType_Float3, NazaraOffsetOf(BillboardPoint, position));
s_billboardVertexDeclaration.EnableComponent(VertexComponent_TexCoord, ComponentType_Float2, NazaraOffsetOf(BillboardPoint, uv)); s_billboardVertexDeclaration.EnableComponent(VertexComponent_TexCoord, ComponentType_Float2, NazaraOffsetOf(BillboardPoint, uv));
s_billboardVertexDeclaration.EnableComponent(VertexComponent_Userdata0, ComponentType_Float4, NazaraOffsetOf(BillboardPoint, size)); // Englobe sincos s_billboardVertexDeclaration.EnableComponent(VertexComponent_Userdata0, ComponentType_Float4, NazaraOffsetOf(BillboardPoint, size)); // Includes sincos
// Declaration utilisée lors du rendu des billboards par instancing // Declaration used when rendering the billboards with intancing
// L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU // The main advantage is the direct copy (std::memcpy) of data in the RenderQueue to the GPU buffer
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(ForwardRenderQueue::BillboardData, center)); s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(ForwardRenderQueue::BillboardData, center));
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(ForwardRenderQueue::BillboardData, size)); // Englobe sincos s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(ForwardRenderQueue::BillboardData, size)); // Englobe sincos
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(ForwardRenderQueue::BillboardData, color)); s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(ForwardRenderQueue::BillboardData, color));
@ -169,12 +222,23 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the forward render technique
*/
void ForwardRenderTechnique::Uninitialize() void ForwardRenderTechnique::Uninitialize()
{ {
s_quadIndexBuffer.Reset(); s_quadIndexBuffer.Reset();
s_quadVertexBuffer.Reset(); s_quadVertexBuffer.Reset();
} }
/*!
* \brief Chooses the nearest lights for one object
*
* \param object Sphere symbolising the object
* \param includeDirectionalLights Should directional lights be included in the computation
*/
void ForwardRenderTechnique::ChooseLights(const Spheref& object, bool includeDirectionalLights) const void ForwardRenderTechnique::ChooseLights(const Spheref& object, bool includeDirectionalLights) const
{ {
m_lights.clear(); m_lights.clear();
@ -213,6 +277,15 @@ namespace Nz
}); });
} }
/*!
* \brief Draws basic sprites
*
* \param sceneData Data of the scene
* \param layer Layer of the rendering
*
* \remark Produces a NazaraAssert is viewer is invalid
*/
void ForwardRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const void ForwardRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
@ -240,7 +313,7 @@ namespace Nz
unsigned int spriteChainCount = spriteChainVector.size(); unsigned int spriteChainCount = spriteChainVector.size();
if (spriteChainCount > 0) if (spriteChainCount > 0)
{ {
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
UInt32 flags = ShaderFlags_VertexColor; UInt32 flags = ShaderFlags_VertexColor;
if (overlay) if (overlay)
flags |= ShaderFlags_TextureOverlay; flags |= ShaderFlags_TextureOverlay;
@ -255,46 +328,46 @@ namespace Nz
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler()); Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
} }
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène // Ambiant color of the scene
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Overlay // Overlay
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit); shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
lastShader = shader; lastShader = shader;
} }
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous unsigned int spriteChain = 0; // Which chain of sprites are we treating
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
do do
{ {
// On ouvre le buffer en écriture // We open the buffer in writing mode
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer()); VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
unsigned int spriteCount = 0; unsigned int spriteCount = 0;
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4); unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
do do
{ {
ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain]; ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset); unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(VertexStruct_XYZ_Color_UV)); std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
vertices += count*4; vertices += count * 4;
spriteCount += count; spriteCount += count;
spriteChainOffset += count; spriteChainOffset += count;
// Avons-nous traité la chaîne entière ? // Have we treated the entire chain ?
if (spriteChainOffset == currentChain.spriteCount) if (spriteChainOffset == currentChain.spriteCount)
{ {
spriteChain++; spriteChain++;
@ -305,7 +378,7 @@ namespace Nz
vertexMapper.Unmap(); vertexMapper.Unmap();
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount*6); Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
} }
while (spriteChain < spriteChainCount); while (spriteChain < spriteChainCount);
@ -313,12 +386,21 @@ namespace Nz
} }
} }
// On remet à zéro // We set it back to zero
matEntry.enabled = false; matEntry.enabled = false;
} }
} }
} }
/*!
* \brief Draws billboards
*
* \param sceneData Data of the scene
* \param layer Layer of the rendering
*
* \remark Produces a NazaraAssert is viewer is invalid
*/
void ForwardRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const void ForwardRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
@ -342,18 +424,18 @@ namespace Nz
unsigned int billboardCount = billboardVector.size(); unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0) if (billboardCount > 0)
{ {
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor); const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène // Ambiant color of the scene
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
lastShader = shader; lastShader = shader;
@ -391,32 +473,32 @@ namespace Nz
unsigned int billboardCount = billboardVector.size(); unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0) if (billboardCount > 0)
{ {
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor); const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène // Ambiant color of the scene
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
lastShader = shader; lastShader = shader;
} }
const ForwardRenderQueue::BillboardData* data = &billboardVector[0]; const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4); unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
do do
{ {
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount; billboardCount -= renderedBillboardCount;
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4); BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4);
BillboardPoint* vertices = static_cast<BillboardPoint*>(vertexMapper.GetPointer()); BillboardPoint* vertices = static_cast<BillboardPoint*>(vertexMapper.GetPointer());
for (unsigned int i = 0; i < renderedBillboardCount; ++i) for (unsigned int i = 0; i < renderedBillboardCount; ++i)
@ -454,7 +536,7 @@ namespace Nz
vertexMapper.Unmap(); vertexMapper.Unmap();
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount*6); Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6);
} }
while (billboardCount > 0); while (billboardCount > 0);
@ -464,6 +546,15 @@ namespace Nz
} }
} }
/*!
* \brief Draws opaques models
*
* \param sceneData Data of the scene
* \param layer Layer of the rendering
*
* \remark Produces a NazaraAssert is viewer is invalid
*/
void ForwardRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const void ForwardRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
@ -483,25 +574,25 @@ namespace Nz
{ {
const Material* material = matIt.first; const Material* material = matIt.first;
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active // We only use instancing when no light (other than directional) is active
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches // This is because instancing is not compatible with the search of nearest lights
// (Le deferred shading n'a pas ce problème) // Deferred shading does not have this problem
bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty(); bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty();
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || noPointSpotLight) && matEntry.instancingEnabled; bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || noPointSpotLight) && matEntry.instancingEnabled;
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
UInt8 freeTextureUnit; UInt8 freeTextureUnit;
const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit); const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène // Ambiant color of the scene
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
lastShader = shader; lastShader = shader;
@ -521,7 +612,7 @@ namespace Nz
const IndexBuffer* indexBuffer = meshData.indexBuffer; const IndexBuffer* indexBuffer = meshData.indexBuffer;
const VertexBuffer* vertexBuffer = meshData.vertexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu // Handle draw call before rendering loop
Renderer::DrawCall drawFunc; Renderer::DrawCall drawFunc;
Renderer::DrawCallInstanced instancedDrawFunc; Renderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount; unsigned int indexCount;
@ -544,17 +635,17 @@ namespace Nz
if (instancing) if (instancing)
{ {
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
// Avec l'instancing, impossible de sélectionner les lumières pour chaque objet // With instancing, impossible to select the lights for each object
// Du coup, il n'est activé que pour les lumières directionnelles // So, it's only activated for directional lights
unsigned int lightCount = m_renderQueue.directionalLights.size(); unsigned int lightCount = m_renderQueue.directionalLights.size();
unsigned int lightIndex = 0; unsigned int lightIndex = 0;
RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); RendererComparison oldDepthFunc = Renderer::GetDepthFunc();
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
for (unsigned int pass = 0; pass < passCount; ++pass) for (unsigned int pass = 0; pass < passCount; ++pass)
{ {
if (shaderUniforms->hasLightUniforms) if (shaderUniforms->hasLightUniforms)
@ -564,10 +655,10 @@ namespace Nz
if (pass == 1) if (pass == 1)
{ {
// Pour additionner le résultat des calculs de lumière // To add the result of light computations
// Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques // We won't interfeer with materials parameters because we only render opaques objects
// (Autrement dit, sans blending) // (A.K.A., without blending)
// Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois // About the depth function, it must be applied only the first time
Renderer::Enable(RendererParameter_Blend, true); Renderer::Enable(RendererParameter_Blend, true);
Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One); Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One);
Renderer::SetDepthFunc(RendererComparison_Equal); Renderer::SetDepthFunc(RendererComparison_Equal);
@ -575,32 +666,32 @@ namespace Nz
// Sends the uniforms // Sends the uniforms
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i); SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset * i, freeTextureUnit + i);
// Et on passe à l'affichage // And we give them to draw
drawFunc(meshData.primitiveMode, 0, indexCount); drawFunc(meshData.primitiveMode, 0, indexCount);
} }
const Matrix4f* instanceMatrices = &instances[0]; const Matrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size(); unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
while (instanceCount > 0) while (instanceCount > 0)
{ {
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount); unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount; instanceCount -= renderedInstanceCount;
// On remplit l'instancing buffer avec nos matrices world // We fill the instancing buffer with our world matrices
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true); instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
instanceMatrices += renderedInstanceCount; instanceMatrices += renderedInstanceCount;
// Et on affiche // And we draw
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
} }
} }
// On n'oublie pas de désactiver le blending pour ne pas interférer sur le reste du rendu // We don't forget to disable the blending to avoid to interfeer with the rest of the rendering
Renderer::Enable(RendererParameter_Blend, false); Renderer::Enable(RendererParameter_Blend, false);
Renderer::SetDepthFunc(oldDepthFunc); Renderer::SetDepthFunc(oldDepthFunc);
} }
@ -617,19 +708,19 @@ namespace Nz
Renderer::SetMatrix(MatrixType_World, matrix); Renderer::SetMatrix(MatrixType_World, matrix);
unsigned int lightIndex = 0; unsigned int lightIndex = 0;
RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // Dans le cas où nous aurions à le changer RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // In the case where we have to change it
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1;
for (unsigned int pass = 0; pass < passCount; ++pass) for (unsigned int pass = 0; pass < passCount; ++pass)
{ {
lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
if (pass == 1) if (pass == 1)
{ {
// Pour additionner le résultat des calculs de lumière // To add the result of light computations
// Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques // We won't interfeer with materials parameters because we only render opaques objects
// (Autrement dit, sans blending) // (A.K.A., without blending)
// Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois // About the depth function, it must be applied only the first time
Renderer::Enable(RendererParameter_Blend, true); Renderer::Enable(RendererParameter_Blend, true);
Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One); Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One);
Renderer::SetDepthFunc(RendererComparison_Equal); Renderer::SetDepthFunc(RendererComparison_Equal);
@ -639,7 +730,7 @@ namespace Nz
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i); SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i);
// Et on passe à l'affichage // And we draw
drawFunc(meshData.primitiveMode, 0, indexCount); drawFunc(meshData.primitiveMode, 0, indexCount);
} }
@ -649,9 +740,9 @@ namespace Nz
} }
else else
{ {
// Sans instancing, on doit effectuer un draw call pour chaque instance // Without instancing, we must do a draw call for each instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances // This may be faster than instancing under a certain number
// À cause du temps de modification du buffer d'instancing // Due to the time to modify the instancing buffer
for (const Matrix4f& matrix : instances) for (const Matrix4f& matrix : instances)
{ {
Renderer::SetMatrix(MatrixType_World, matrix); Renderer::SetMatrix(MatrixType_World, matrix);
@ -664,13 +755,22 @@ namespace Nz
} }
} }
// Et on remet à zéro les données // And we set the data back to zero
matEntry.enabled = false; matEntry.enabled = false;
matEntry.instancingEnabled = false; matEntry.instancingEnabled = false;
} }
} }
} }
/*!
* \brief Draws transparent models
*
* \param sceneData Data of the scene
* \param layer Layer of the rendering
*
* \remark Produces a NazaraAssert is viewer is invalid
*/
void ForwardRenderTechnique::DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const void ForwardRenderTechnique::DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
{ {
NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraAssert(sceneData.viewer, "Invalid viewer");
@ -683,25 +783,25 @@ namespace Nz
{ {
const ForwardRenderQueue::TransparentModelData& modelData = layer.transparentModelData[index]; const ForwardRenderQueue::TransparentModelData& modelData = layer.transparentModelData[index];
// Matériau // Material
const Material* material = modelData.material; const Material* material = modelData.material;
// On commence par appliquer du matériau (et récupérer le shader ainsi activé) // We begin to apply the material (and get the shader activated doing so)
UInt8 freeTextureUnit; UInt8 freeTextureUnit;
const Shader* shader = material->Apply(0, 0, &freeTextureUnit); const Shader* shader = material->Apply(0, 0, &freeTextureUnit);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas // Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader) if (shader != lastShader)
{ {
// Index des uniformes dans le shader // Index of uniforms in the shader
shaderUniforms = GetShaderUniforms(shader); shaderUniforms = GetShaderUniforms(shader);
// Couleur ambiante de la scène // Ambiant color of the scene
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position de la caméra // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous) // We send the directional lights if there is one (same for all)
if (shaderUniforms->hasLightUniforms) if (shaderUniforms->hasLightUniforms)
{ {
lightCount = std::min(m_renderQueue.directionalLights.size(), static_cast<decltype(m_renderQueue.directionalLights.size())>(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)); lightCount = std::min(m_renderQueue.directionalLights.size(), static_cast<decltype(m_renderQueue.directionalLights.size())>(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS));
@ -720,7 +820,7 @@ namespace Nz
const IndexBuffer* indexBuffer = meshData.indexBuffer; const IndexBuffer* indexBuffer = meshData.indexBuffer;
const VertexBuffer* vertexBuffer = meshData.vertexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu // Handle draw call before the rendering loop
Renderer::DrawCall drawFunc; Renderer::DrawCall drawFunc;
unsigned int indexCount; unsigned int indexCount;
@ -754,6 +854,13 @@ namespace Nz
} }
} }
/*!
* \brief Gets the shader uniforms
* \return Uniforms of the shader
*
* \param shader Shader to get uniforms from
*/
const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const
{ {
auto it = m_shaderUniforms.find(shader); auto it = m_shaderUniforms.find(shader);
@ -795,6 +902,12 @@ namespace Nz
return &it->second; return &it->second;
} }
/*!
* \brief Handle the invalidation of a shader
*
* \param shader Shader being invalidated
*/
void ForwardRenderTechnique::OnShaderInvalidated(const Shader* shader) const void ForwardRenderTechnique::OnShaderInvalidated(const Shader* shader) const
{ {
m_shaderUniforms.erase(shader); m_shaderUniforms.erase(shader);

View File

@ -28,15 +28,29 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::Graphics
* \brief Graphics class that represents the module initializer of Graphics
*/
/*!
* \brief Initializes the Graphics module
* \return true if initialization is successful
*
* \remark Produces a NazaraNotice
* \remark Produces a NazaraError if one submodule failed
*/
bool Graphics::Initialize() bool Graphics::Initialize()
{ {
if (s_moduleReferenceCounter > 0) if (IsInitialized())
{ {
s_moduleReferenceCounter++; s_moduleReferenceCounter++;
return true; // Déjà initialisé return true; // Already initialized
} }
// Initialisation des dépendances // Initialisation of dependances
if (!Renderer::Initialize()) if (!Renderer::Initialize())
{ {
NazaraError("Failed to initialize Renderer module"); NazaraError("Failed to initialize Renderer module");
@ -45,7 +59,7 @@ namespace Nz
s_moduleReferenceCounter++; s_moduleReferenceCounter++;
// Initialisation du module // Initialisation of the module
CallOnExit onExit(Graphics::Uninitialize); CallOnExit onExit(Graphics::Uninitialize);
if (!Material::Initialize()) if (!Material::Initialize())
@ -96,7 +110,7 @@ namespace Nz
return false; return false;
} }
// Loaders génériques // Generic loaders
Loaders::RegisterMesh(); Loaders::RegisterMesh();
Loaders::RegisterTexture(); Loaders::RegisterTexture();
@ -133,43 +147,54 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Checks whether the module is initialized
* \return true if module is initialized
*/
bool Graphics::IsInitialized() bool Graphics::IsInitialized()
{ {
return s_moduleReferenceCounter != 0; return s_moduleReferenceCounter != 0;
} }
/*!
* \brief Uninitializes the Core module
*
* \remark Produces a NazaraNotice
*/
void Graphics::Uninitialize() void Graphics::Uninitialize()
{ {
if (s_moduleReferenceCounter != 1) if (s_moduleReferenceCounter != 1)
{ {
// Le module est soit encore utilisé, soit pas initialisé // The module is still in use, or can not be uninitialized
if (s_moduleReferenceCounter > 1) if (s_moduleReferenceCounter > 1)
s_moduleReferenceCounter--; s_moduleReferenceCounter--;
return; return;
} }
// Libération du module // Free of module
s_moduleReferenceCounter = 0; s_moduleReferenceCounter = 0;
// Libération de l'atlas s'il vient de nous // Free of atlas if it is ours
std::shared_ptr<AbstractAtlas> defaultAtlas = Font::GetDefaultAtlas(); std::shared_ptr<AbstractAtlas> defaultAtlas = Font::GetDefaultAtlas();
if (defaultAtlas && defaultAtlas->GetStorage() & DataStorage_Hardware) if (defaultAtlas && defaultAtlas->GetStorage() & DataStorage_Hardware)
{ {
Font::SetDefaultAtlas(nullptr); Font::SetDefaultAtlas(nullptr);
// La police par défaut peut faire vivre un atlas hardware après la libération du module (ce qui va être problématique) // The default police can make live one hardware atlas after the free of a module (which could be problematic)
// du coup, si la police par défaut utilise un atlas hardware, on lui enlève. // So, if the default police use a hardware atlas, we stole it.
// Je n'aime pas cette solution mais je n'en ai pas de meilleure sous la main pour l'instant // I don't like this solution, but I don't have any better
if (!defaultAtlas.unique()) if (!defaultAtlas.unique())
{ {
// Encore au moins une police utilise l'atlas // Still at least one police use the atlas
Font* defaultFont = Font::GetDefault(); Font* defaultFont = Font::GetDefault();
defaultFont->SetAtlas(nullptr); defaultFont->SetAtlas(nullptr);
if (!defaultAtlas.unique()) if (!defaultAtlas.unique())
{ {
// Toujours pas seuls propriétaires ? Ah ben zut. // Still not the only one to own it ? Then crap.
NazaraWarning("Default font atlas uses hardware storage and is still used"); NazaraWarning("Default font atlas uses hardware storage and is still used");
} }
} }
@ -195,7 +220,7 @@ namespace Nz
NazaraNotice("Uninitialized: Graphics module"); NazaraNotice("Uninitialized: Graphics module");
// Libération des dépendances // Free of dependances
Renderer::Uninitialize(); Renderer::Uninitialize();
} }

View File

@ -9,11 +9,32 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::GuillotineTextureAtlas
* \brief Graphics class that represents an atlas texture for guillotine
*/
/*!
* \brief Gets the underlying data storage
* \return Value of the enumeration of the underlying data storage
*/
UInt32 GuillotineTextureAtlas::GetStorage() const UInt32 GuillotineTextureAtlas::GetStorage() const
{ {
return DataStorage_Hardware; return DataStorage_Hardware;
} }
/*!
* \brief Resizes the image
* \return Updated texture
*
* \param oldImage Old image to resize
* \param size New image size
*
* \remark Produces a NazaraError if resize failed
*/
AbstractImage* GuillotineTextureAtlas::ResizeImage(AbstractImage* oldImage, const Vector2ui& size) const AbstractImage* GuillotineTextureAtlas::ResizeImage(AbstractImage* oldImage, const Vector2ui& size) const
{ {
std::unique_ptr<Texture> newTexture(new Texture); std::unique_ptr<Texture> newTexture(new Texture);
@ -23,8 +44,8 @@ namespace Nz
{ {
Texture* oldTexture = static_cast<Texture*>(oldImage); Texture* oldTexture = static_cast<Texture*>(oldImage);
// Copie des anciennes données // Copy of old data
///TODO: Copie de texture à texture ///TODO: Copy from texture to texture
Image image; Image image;
if (!oldTexture->Download(&image)) if (!oldTexture->Download(&image))
{ {
@ -43,8 +64,7 @@ namespace Nz
} }
else else
{ {
// Si on arrive ici c'est que la taille demandée est trop grande pour la carte graphique // If we are here, it is that the size is too big for the graphic card or we don't have enough
// ou que nous manquons de mémoire
return nullptr; return nullptr;
} }
} }

View File

@ -7,16 +7,43 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::InstancedRenderable
* \brief Graphics class that represents an instancer renderable
*
* \remark This class is abstract
*/
/*!
* \brief Destructs the object and calls OnInstancedRenderableRelease
*
* \see OnInstancedRenderableRelease
*/
InstancedRenderable::~InstancedRenderable() InstancedRenderable::~InstancedRenderable()
{ {
OnInstancedRenderableRelease(this); OnInstancedRenderableRelease(this);
} }
/*!
* \brief Culls the instanced if not in the frustum
* \return true If instanced is in the frustum
*
* \param frustum Symbolizing the field of view
* \param transformMatrix Matrix transformation for our object
*/
bool InstancedRenderable::Cull(const Frustumf& frustum, const InstanceData& instanceData) const bool InstancedRenderable::Cull(const Frustumf& frustum, const InstanceData& instanceData) const
{ {
return frustum.Contains(instanceData.volume); return frustum.Contains(instanceData.volume);
} }
/*!
* \brief Gets the bounding volume
* \return Bounding volume of the instanced
*/
const BoundingVolumef& InstancedRenderable::GetBoundingVolume() const const BoundingVolumef& InstancedRenderable::GetBoundingVolume() const
{ {
EnsureBoundingVolumeUpdated(); EnsureBoundingVolumeUpdated();
@ -24,11 +51,30 @@ namespace Nz
return m_boundingVolume; return m_boundingVolume;
} }
/*!
* \brief Invalidates data for instanced
*
* \param instanceData Pointer to data of instances
* \param flags Flags for the instances
*
* \remark Produces a NazaraAssert if instanceData is invalid
*/
void InstancedRenderable::InvalidateData(InstanceData* instanceData, UInt32 flags) const void InstancedRenderable::InvalidateData(InstanceData* instanceData, UInt32 flags) const
{ {
NazaraAssert(instanceData, "Invalid instance data");
instanceData->flags |= flags; instanceData->flags |= flags;
} }
/*!
* \brief Updates the bounding volume
*
* \param instanceData Pointer to data of instances
*
* \remark Produces a NazaraAssert if instanceData is invalid
*/
void InstancedRenderable::UpdateBoundingVolume(InstanceData* instanceData) const void InstancedRenderable::UpdateBoundingVolume(InstanceData* instanceData) const
{ {
NazaraAssert(instanceData, "Invalid instance data"); NazaraAssert(instanceData, "Invalid instance data");
@ -37,6 +83,14 @@ namespace Nz
instanceData->volume.Update(instanceData->transformMatrix); instanceData->volume.Update(instanceData->transformMatrix);
} }
/*!
* \brief Updates the instance data
*
* \param instanceData Pointer to data of instances
*
* \remark Produces a NazaraAssert if instanceData is invalid
*/
void InstancedRenderable::UpdateData(InstanceData* instanceData) const void InstancedRenderable::UpdateData(InstanceData* instanceData) const
{ {
NazaraAssert(instanceData, "Invalid instance data"); NazaraAssert(instanceData, "Invalid instance data");

View File

@ -13,11 +13,23 @@
#include <cstring> #include <cstring>
#include <Nazara/Graphics/Debug.hpp> #include <Nazara/Graphics/Debug.hpp>
///TODO: Utilisation des UBOs ///TODO: Use of UBOs
///TODO: Scale ? ///TODO: Scale ?
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::Light
* \brief Graphics class that represents a light
*/
/*!
* \brief Constructs a Light object with a type
*
* \param type Type of the light
*/
Light::Light(LightType type) : Light::Light(LightType type) :
m_type(type), m_type(type),
m_shadowMapFormat(PixelFormatType_Depth16), m_shadowMapFormat(PixelFormatType_Depth16),
@ -34,6 +46,15 @@ namespace Nz
SetRadius(5.f); SetRadius(5.f);
} }
/*!
* \brief Adds this light to the render queue
*
* \param renderQueue Queue to be added
* \param transformMatrix Matrix transformation for this light
*
* \remark Produces a NazaraError if type is invalid
*/
void Light::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const void Light::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const
{ {
static Matrix4f biasMatrix(0.5f, 0.f, 0.f, 0.f, static Matrix4f biasMatrix(0.5f, 0.f, 0.f, 0.f,
@ -100,16 +121,36 @@ namespace Nz
} }
} }
/*!
* \brief Clones this light
* \return Pointer to newly allocated Light
*/
Light* Light::Clone() const Light* Light::Clone() const
{ {
return new Light(*this); return new Light(*this);
} }
/*!
* \brief Creates a default light
* \return Pointer to newly allocated light
*/
Light* Light::Create() const Light* Light::Create() const
{ {
return new Light; return new Light;
} }
/*!
* \brief Culls the light if not in the frustum
* \return true If light is in the frustum
*
* \param frustum Symbolizing the field of view
* \param transformMatrix Matrix transformation for our object
*
* \remark Produces a NazaraError if type is invalid
*/
bool Light::Cull(const Frustumf& frustum, const Matrix4f& transformMatrix) const bool Light::Cull(const Frustumf& frustum, const Matrix4f& transformMatrix) const
{ {
switch (m_type) switch (m_type)
@ -128,6 +169,14 @@ namespace Nz
return false; return false;
} }
/*!
* \brief Updates the bounding volume by a matrix
*
* \param transformMatrix Matrix transformation for our bounding volume
*
* \remark Produces a NazaraError if type is invalid
*/
void Light::UpdateBoundingVolume(const Matrix4f& transformMatrix) void Light::UpdateBoundingVolume(const Matrix4f& transformMatrix)
{ {
switch (m_type) switch (m_type)
@ -149,6 +198,12 @@ namespace Nz
} }
} }
/*
* \brief Makes the bounding volume of this light
*
* \remark Produces a NazaraError if type is invalid
*/
void Light::MakeBoundingVolume() const void Light::MakeBoundingVolume() const
{ {
switch (m_type) switch (m_type)
@ -166,19 +221,19 @@ namespace Nz
case LightType_Spot: case LightType_Spot:
{ {
// On forme une boite sur l'origine // We make a box center in the origin
Boxf box(Vector3f::Zero()); Boxf box(Vector3f::Zero());
// On calcule le reste des points // We compute the other points
Vector3f base(Vector3f::Forward()*m_radius); Vector3f base(Vector3f::Forward() * m_radius);
// Il nous faut maintenant le rayon du cercle projeté à cette distance // Now we need the radius of the projected circle depending on the distance
// Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente // Tangent = Opposite/Adjacent <=> Opposite = Adjacent * Tangent
float radius = m_radius * m_outerAngleTangent; float radius = m_radius * m_outerAngleTangent;
Vector3f lExtend = Vector3f::Left()*radius; Vector3f lExtend = Vector3f::Left() * radius;
Vector3f uExtend = Vector3f::Up()*radius; Vector3f uExtend = Vector3f::Up() * radius;
// Et on ajoute ensuite les quatres extrémités de la pyramide // And we add the four extremities of our pyramid
box.ExtendTo(base + lExtend + uExtend); box.ExtendTo(base + lExtend + uExtend);
box.ExtendTo(base + lExtend - uExtend); box.ExtendTo(base + lExtend - uExtend);
box.ExtendTo(base - lExtend + uExtend); box.ExtendTo(base - lExtend + uExtend);
@ -194,6 +249,10 @@ namespace Nz
} }
} }
/*!
* \brief Updates the shadow map
*/
void Light::UpdateShadowMap() const void Light::UpdateShadowMap() const
{ {
if (m_shadowCastingEnabled) if (m_shadowCastingEnabled)

View File

@ -3,7 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#ifndef NAZARA_RENDERER_OPENGL #ifndef NAZARA_RENDERER_OPENGL
#define NAZARA_RENDERER_OPENGL // Nécessaire pour inclure les headers OpenGL #define NAZARA_RENDERER_OPENGL // Mandatory to include the OpenGL headers
#endif #endif
#include <Nazara/Graphics/Material.hpp> #include <Nazara/Graphics/Material.hpp>
@ -36,6 +36,17 @@ namespace Nz
}; };
} }
/*!
* \ingroup graphics
* \class Nz::Material
* \brief Graphics class that represents a material
*/
/*!
* \brief Checks whether the parameters for the material are correct
* \return true If parameters are valid
*/
bool MaterialParams::IsValid() const bool MaterialParams::IsValid() const
{ {
if (!UberShaderLibrary::Has(shaderName)) if (!UberShaderLibrary::Has(shaderName))
@ -44,6 +55,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Applies shader to the material
* \return Constant pointer to the shader
*
* \param shaderFlags Flags for the shader
* \param textureUnit Unit for the texture GL_TEXTURE"i"
* \param lastUsedUnit Optional argument to get the last texture unit
*/
const Shader* Material::Apply(UInt32 shaderFlags, UInt8 textureUnit, UInt8* lastUsedUnit) const const Shader* Material::Apply(UInt32 shaderFlags, UInt8 textureUnit, UInt8* lastUsedUnit) const
{ {
const ShaderInstance& instance = m_shaders[shaderFlags]; const ShaderInstance& instance = m_shaders[shaderFlags];
@ -123,6 +143,13 @@ namespace Nz
return instance.shader; return instance.shader;
} }
/*!
* \brief Builds the material from parameters
*
* \param matData Data information for the material
* \param matParams Parameters for the material
*/
void Material::BuildFromParameters(const ParameterList& matData, const MaterialParams& matParams) void Material::BuildFromParameters(const ParameterList& matData, const MaterialParams& matParams)
{ {
Color color; Color color;
@ -283,6 +310,10 @@ namespace Nz
SetShader(matParams.shaderName); SetShader(matParams.shaderName);
} }
/*!
* \brief Resets the material, cleans everything
*/
void Material::Reset() void Material::Reset()
{ {
OnMaterialReset(this); OnMaterialReset(this);
@ -319,9 +350,15 @@ namespace Nz
SetShader("Basic"); SetShader("Basic");
} }
/*!
* \brief Copies the other material
*
* \param material Material to copy into this
*/
void Material::Copy(const Material& material) void Material::Copy(const Material& material)
{ {
// Copie des états de base // Copy of base states
m_alphaTestEnabled = material.m_alphaTestEnabled; m_alphaTestEnabled = material.m_alphaTestEnabled;
m_alphaThreshold = material.m_alphaThreshold; m_alphaThreshold = material.m_alphaThreshold;
m_ambientColor = material.m_ambientColor; m_ambientColor = material.m_ambientColor;
@ -337,7 +374,7 @@ namespace Nz
m_states = material.m_states; m_states = material.m_states;
m_transformEnabled = material.m_transformEnabled; m_transformEnabled = material.m_transformEnabled;
// Copie des références de texture // Copy of reference to the textures
m_alphaMap = material.m_alphaMap; m_alphaMap = material.m_alphaMap;
m_depthMaterial = material.m_depthMaterial; m_depthMaterial = material.m_depthMaterial;
m_diffuseMap = material.m_diffuseMap; m_diffuseMap = material.m_diffuseMap;
@ -347,10 +384,16 @@ namespace Nz
m_specularMap = material.m_specularMap; m_specularMap = material.m_specularMap;
m_uberShader = material.m_uberShader; m_uberShader = material.m_uberShader;
// On copie les instances de shader par la même occasion // We copy the instances of the shader too
std::memcpy(&m_shaders[0], &material.m_shaders[0], (ShaderFlags_Max+1)*sizeof(ShaderInstance)); std::memcpy(&m_shaders[0], &material.m_shaders[0], (ShaderFlags_Max + 1) * sizeof(ShaderInstance));
} }
/*!
* \brief Generates the shader based on flag
*
* \param flags Flag for the shaer
*/
void Material::GenerateShader(UInt32 flags) const void Material::GenerateShader(UInt32 flags) const
{ {
ParameterList list; ParameterList list;
@ -396,6 +439,13 @@ namespace Nz
#undef CacheUniform #undef CacheUniform
} }
/*!
* \brief Initializes the material librairies
* \return true If successful
*
* \remark Produces a NazaraError if the material library failed to be initialized
*/
bool Material::Initialize() bool Material::Initialize()
{ {
if (!MaterialLibrary::Initialize()) if (!MaterialLibrary::Initialize())
@ -462,6 +512,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the material librairies
*/
void Material::Uninitialize() void Material::Uninitialize()
{ {
s_defaultMaterial.Reset(); s_defaultMaterial.Reset();

View File

@ -12,11 +12,26 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::Model
* \brief Graphics class that represents a model
*/
/*!
* \brief Constructs a ModelParameters object by default
*/
ModelParameters::ModelParameters() ModelParameters::ModelParameters()
{ {
material.shaderName = "PhongLighting"; material.shaderName = "PhongLighting";
} }
/*!
* \brief Checks whether the parameters for the model are correct
* \return true If parameters are valid
*/
bool ModelParameters::IsValid() const bool ModelParameters::IsValid() const
{ {
if (loadMaterials && !material.IsValid()) if (loadMaterials && !material.IsValid())
@ -25,6 +40,10 @@ namespace Nz
return mesh.IsValid(); return mesh.IsValid();
} }
/*!
* \brief Constructs a Model object by default
*/
Model::Model() : Model::Model() :
m_matCount(0), m_matCount(0),
m_skin(0), m_skin(0),
@ -32,11 +51,24 @@ namespace Nz
{ {
} }
/*!
* \brief Destructs the object and calls Reset
*
* \see Reset
*/
Model::~Model() Model::~Model()
{ {
Reset(); Reset();
} }
/*!
* \brief Adds this model to the render queue
*
* \param renderQueue Queue to be added
* \param instanceData Data used for this instance
*/
void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
unsigned int submeshCount = m_mesh->GetSubMeshCount(); unsigned int submeshCount = m_mesh->GetSubMeshCount();
@ -54,6 +86,17 @@ namespace Nz
} }
} }
/*!
* \brief Gets the material of the named submesh
* \return Pointer to the current material
*
* \param subMeshName Name of the subMesh
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no mesh
* \remark Produces a NazaraError if there is no subMesh with that name
* \remark Produces a NazaraError if material is invalid
*/
Material* Model::GetMaterial(const String& subMeshName) const Material* Model::GetMaterial(const String& subMeshName) const
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -78,9 +121,18 @@ namespace Nz
return nullptr; return nullptr;
} }
return m_materials[m_skin*m_matCount + matIndex]; return m_materials[m_skin * m_matCount + matIndex];
} }
/*!
* \brief Gets the material by index
* \return Pointer to the current material
*
* \param matIndex Index of the material
*
* \remark Produces a NazaraError if index is invalid
*/
Material* Model::GetMaterial(unsigned int matIndex) const Material* Model::GetMaterial(unsigned int matIndex) const
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -91,9 +143,21 @@ namespace Nz
} }
#endif #endif
return m_materials[m_skin*m_matCount + matIndex]; return m_materials[m_skin * m_matCount + matIndex];
} }
/*!
* \brief Gets the material by index of the named submesh
* \return Pointer to the current material
*
* \param skinIndex Index of the skin
* \param subMeshName Name of the subMesh
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid
* \remark Produces a NazaraError if there is no subMesh with that name
* \remark Produces a NazaraError if material index is invalid
*/
Material* Model::GetMaterial(unsigned int skinIndex, const String& subMeshName) const Material* Model::GetMaterial(unsigned int skinIndex, const String& subMeshName) const
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -118,9 +182,20 @@ namespace Nz
return nullptr; return nullptr;
} }
return m_materials[skinIndex*m_matCount + matIndex]; return m_materials[skinIndex * m_matCount + matIndex];
} }
/*!
* \brief Gets the material by index with skin
* \return Pointer to the current material
*
* \param skinIndex Index of the skin
* \param matIndex Index of the material
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if matIndex is invalid
*/
Material* Model::GetMaterial(unsigned int skinIndex, unsigned int matIndex) const Material* Model::GetMaterial(unsigned int skinIndex, unsigned int matIndex) const
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -137,49 +212,103 @@ namespace Nz
} }
#endif #endif
return m_materials[skinIndex*m_matCount + matIndex]; return m_materials[skinIndex * m_matCount + matIndex];
} }
/*!
* \brief Gets the number of materials
* \return Current number of materials
*/
unsigned int Model::GetMaterialCount() const unsigned int Model::GetMaterialCount() const
{ {
return m_matCount; return m_matCount;
} }
/*!
* \brief Gets the mesh
* \return Current mesh
*/
Mesh* Model::GetMesh() const Mesh* Model::GetMesh() const
{ {
return m_mesh; return m_mesh;
} }
/*!
* \brief Gets the skin
* \return Current skin
*/
unsigned int Model::GetSkin() const unsigned int Model::GetSkin() const
{ {
return m_skin; return m_skin;
} }
/*!
* \brief Gets the number of skins
* \return Current number of skins
*/
unsigned int Model::GetSkinCount() const unsigned int Model::GetSkinCount() const
{ {
return m_skinCount; return m_skinCount;
} }
/*!
* \brief Checks whether the model is animated
* \return false
*/
bool Model::IsAnimated() const bool Model::IsAnimated() const
{ {
return false; return false;
} }
/*!
* \brief Loads the model from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the model
*/
bool Model::LoadFromFile(const String& filePath, const ModelParameters& params) bool Model::LoadFromFile(const String& filePath, const ModelParameters& params)
{ {
return ModelLoader::LoadFromFile(this, filePath, params); return ModelLoader::LoadFromFile(this, filePath, params);
} }
/*!
* \brief Loads the model from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the model
*/
bool Model::LoadFromMemory(const void* data, std::size_t size, const ModelParameters& params) bool Model::LoadFromMemory(const void* data, std::size_t size, const ModelParameters& params)
{ {
return ModelLoader::LoadFromMemory(this, data, size, params); return ModelLoader::LoadFromMemory(this, data, size, params);
} }
/*!
* \brief Loads the model from stream
* \return true if loading is successful
*
* \param stream Stream to the model
* \param params Parameters for the model
*/
bool Model::LoadFromStream(Stream& stream, const ModelParameters& params) bool Model::LoadFromStream(Stream& stream, const ModelParameters& params)
{ {
return ModelLoader::LoadFromStream(this, stream, params); return ModelLoader::LoadFromStream(this, stream, params);
} }
/*!
* \brief Resets the model, cleans everything
*/
void Model::Reset() void Model::Reset()
{ {
m_matCount = 0; m_matCount = 0;
@ -192,6 +321,17 @@ namespace Nz
} }
} }
/*!
* \brief Sets the material of the named submesh
* \return true If successful
*
* \param subMeshName Name of the subMesh
* \param material Pointer to the material
*
* \remark Produces a NazaraError if there is no subMesh with that name
* \remark Produces a NazaraError if material index is invalid
*/
bool Model::SetMaterial(const String& subMeshName, Material* material) bool Model::SetMaterial(const String& subMeshName, Material* material)
{ {
SubMesh* subMesh = m_mesh->GetSubMesh(subMeshName); SubMesh* subMesh = m_mesh->GetSubMesh(subMeshName);
@ -208,7 +348,7 @@ namespace Nz
return false; return false;
} }
unsigned int index = m_skin*m_matCount + matIndex; unsigned int index = m_skin * m_matCount + matIndex;
if (material) if (material)
m_materials[index] = material; m_materials[index] = material;
@ -218,6 +358,16 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the material by index
* \return true If successful
*
* \param matIndex Index of the material
* \param material Pointer to the material
*
* \remark Produces a NazaraError with if NAZARA_GRAPHICS_SAFE defined index is invalid
*/
void Model::SetMaterial(unsigned int matIndex, Material* material) void Model::SetMaterial(unsigned int matIndex, Material* material)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -228,7 +378,7 @@ namespace Nz
} }
#endif #endif
unsigned int index = m_skin*m_matCount + matIndex; unsigned int index = m_skin * m_matCount + matIndex;
if (material) if (material)
m_materials[index] = material; m_materials[index] = material;
@ -236,6 +386,19 @@ namespace Nz
m_materials[index] = Material::GetDefault(); m_materials[index] = Material::GetDefault();
} }
/*!
* \brief Sets the material by index of the named submesh
* \return true If successful
*
* \param skinIndex Index of the skin
* \param subMeshName Name of the subMesh
* \param material Pointer to the material
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid
* \remark Produces a NazaraError if there is no subMesh with that name
* \remark Produces a NazaraError if material index is invalid
*/
bool Model::SetMaterial(unsigned int skinIndex, const String& subMeshName, Material* material) bool Model::SetMaterial(unsigned int skinIndex, const String& subMeshName, Material* material)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -260,7 +423,7 @@ namespace Nz
return false; return false;
} }
unsigned int index = skinIndex*m_matCount + matIndex; unsigned int index = skinIndex * m_matCount + matIndex;
if (material) if (material)
m_materials[index] = material; m_materials[index] = material;
@ -270,6 +433,18 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the material by index with skin
* \return true If successful
*
* \param skinIndex Index of the skin
* \param matIndex Index of the material
* \param material Pointer to the material
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if matIndex is invalid
*/
void Model::SetMaterial(unsigned int skinIndex, unsigned int matIndex, Material* material) void Model::SetMaterial(unsigned int skinIndex, unsigned int matIndex, Material* material)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -286,7 +461,7 @@ namespace Nz
} }
#endif #endif
unsigned int index = skinIndex*m_matCount + matIndex; unsigned int index = skinIndex * m_matCount + matIndex;
if (material) if (material)
m_materials[index] = material; m_materials[index] = material;
@ -294,6 +469,14 @@ namespace Nz
m_materials[index] = Material::GetDefault(); m_materials[index] = Material::GetDefault();
} }
/*!
* \brief Sets the mesh
*
* \param pointer to the mesh
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if mesh is invalid
*/
void Model::SetMesh(Mesh* mesh) void Model::SetMesh(Mesh* mesh)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -323,6 +506,14 @@ namespace Nz
InvalidateBoundingVolume(); InvalidateBoundingVolume();
} }
/*!
* \brief Sets the skin
*
* \param skin Skin to use
*
* \remark Produces a NazaraError if skin is invalid
*/
void Model::SetSkin(unsigned int skin) void Model::SetSkin(unsigned int skin)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -336,6 +527,14 @@ namespace Nz
m_skin = skin; m_skin = skin;
} }
/*!
* \brief Sets the number of skins
*
* \param skinCount Number of skins
*
* \remark Produces a NazaraError if skinCount equals zero
*/
void Model::SetSkinCount(unsigned int skinCount) void Model::SetSkinCount(unsigned int skinCount)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -350,6 +549,10 @@ namespace Nz
m_skinCount = skinCount; m_skinCount = skinCount;
} }
/*
* \brief Makes the bounding volume of this billboard
*/
void Model::MakeBoundingVolume() const void Model::MakeBoundingVolume() const
{ {
if (m_mesh) if (m_mesh)

View File

@ -7,17 +7,44 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ParticleController
* \brief Graphics class which controls a flow of particles
*
* \remark This class is abstract
*/
/*!
* \brief Constructs a ParticleController object by assignation
*
* \param controller ParticleController to copy into this
*/
ParticleController::ParticleController(const ParticleController& controller) : ParticleController::ParticleController(const ParticleController& controller) :
RefCounted() RefCounted()
{ {
NazaraUnused(controller); NazaraUnused(controller);
} }
/*!
* \brief Destructs the object and calls OnParticleControllerRelease
*
* \see OnParticleControllerRelease
*/
ParticleController::~ParticleController() ParticleController::~ParticleController()
{ {
OnParticleControllerRelease(this); OnParticleControllerRelease(this);
} }
/*!
* \brief Initializes the particle controller librairies
* \return true If successful
*
* \remark Produces a NazaraError if the particle controller library failed to be initialized
*/
bool ParticleController::Initialize() bool ParticleController::Initialize()
{ {
if (!ParticleControllerLibrary::Initialize()) if (!ParticleControllerLibrary::Initialize())
@ -29,6 +56,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the particle controller librairies
*/
void ParticleController::Uninitialize() void ParticleController::Uninitialize()
{ {
ParticleControllerLibrary::Uninitialize(); ParticleControllerLibrary::Uninitialize();

View File

@ -15,23 +15,54 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ParticleDeclaration
* \brief Graphics class that represents the declaration of the particle, works like an ECS
*/
/*!
* \brief Constructs a ParticleDeclaration object by default
*/
ParticleDeclaration::ParticleDeclaration() : ParticleDeclaration::ParticleDeclaration() :
m_stride(0) m_stride(0)
{ {
} }
/*!
* \brief Constructs a ParticleDeclaration object by assignation
*
* \param declaration ParticleDeclaration to copy into this
*/
ParticleDeclaration::ParticleDeclaration(const ParticleDeclaration& declaration) : ParticleDeclaration::ParticleDeclaration(const ParticleDeclaration& declaration) :
RefCounted(), RefCounted(),
m_stride(declaration.m_stride) m_stride(declaration.m_stride)
{ {
std::memcpy(m_components, declaration.m_components, sizeof(Component)*(ParticleComponent_Max+1)); std::memcpy(m_components, declaration.m_components, sizeof(Component) * (ParticleComponent_Max + 1));
} }
/*!
* \brief Destructs the object and calls OnParticleDeclarationRelease
*
* \see OnParticleDeclarationRelease
*/
ParticleDeclaration::~ParticleDeclaration() ParticleDeclaration::~ParticleDeclaration()
{ {
OnParticleDeclarationRelease(this); OnParticleDeclarationRelease(this);
} }
/*!
* \brief Disables a component
*
* \param component Component to disable in the declaration
*
* \remark Produces a NazaraError with NAZARA_DEBUG defined if enumeration is invalid
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if enumeration is equal to ParticleComponent_Unused
*/
void ParticleDeclaration::DisableComponent(ParticleComponent component) void ParticleDeclaration::DisableComponent(ParticleComponent component)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -58,6 +89,17 @@ namespace Nz
} }
} }
/*!
* \brief Enables a component
*
* \param component Component to enable in the declaration
* \param type Type of this component
* \param offset Offset in the declaration
*
* \remark Produces a NazaraError with NAZARA_DEBUG defined if enumeration is invalid
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if type is not supported
*/
void ParticleDeclaration::EnableComponent(ParticleComponent component, ComponentType type, unsigned int offset) void ParticleDeclaration::EnableComponent(ParticleComponent component, ComponentType type, unsigned int offset)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -91,6 +133,18 @@ namespace Nz
m_stride += Utility::ComponentStride[type]; m_stride += Utility::ComponentStride[type];
} }
/*!
* \brief Gets a component
*
* \param component Component in the declaration
* \param enabled Optional argument to get if this component is enabled
* \param type Optional argument to get if the type of the component
* \param offset Optional argument to get if the offset in the declaration
*
* \remark Produces a NazaraError with NAZARA_DEBUG defined if enumeration is invalid
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if enumeration is equal to ParticleComponent_Unused
*/
void ParticleDeclaration::GetComponent(ParticleComponent component, bool* enabled, ComponentType* type, unsigned int* offset) const void ParticleDeclaration::GetComponent(ParticleComponent component, bool* enabled, ComponentType* type, unsigned int* offset) const
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -121,24 +175,51 @@ namespace Nz
*offset = particleComponent.offset; *offset = particleComponent.offset;
} }
/*!
* \brief Gets the stride of the declaration
* \return Stride of the declaration
*/
unsigned int ParticleDeclaration::GetStride() const unsigned int ParticleDeclaration::GetStride() const
{ {
return m_stride; return m_stride;
} }
/*!
* \brief Sets the stride of the declaration
*
* \param stride Stride of the declaration
*/
void ParticleDeclaration::SetStride(unsigned int stride) void ParticleDeclaration::SetStride(unsigned int stride)
{ {
m_stride = stride; m_stride = stride;
} }
/*!
* \brief Sets the current particle declaration with the content of the other one
* \return A reference to this
*
* \param declaration The other ParticleDeclaration
*/
ParticleDeclaration& ParticleDeclaration::operator=(const ParticleDeclaration& declaration) ParticleDeclaration& ParticleDeclaration::operator=(const ParticleDeclaration& declaration)
{ {
std::memcpy(m_components, declaration.m_components, sizeof(Component)*(ParticleComponent_Max+1)); std::memcpy(m_components, declaration.m_components, sizeof(Component) * (ParticleComponent_Max + 1));
m_stride = declaration.m_stride; m_stride = declaration.m_stride;
return *this; return *this;
} }
/*!
* \brief Gets the particle declaration based on the layout
* \return Pointer to the declaration
*
* \param layout Layout of the particle declaration
*
* \remark Produces a NazaraError with NAZARA_DEBUG if enumeration is invalid
*/
ParticleDeclaration* ParticleDeclaration::Get(ParticleLayout layout) ParticleDeclaration* ParticleDeclaration::Get(ParticleLayout layout)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -152,6 +233,15 @@ namespace Nz
return &s_declarations[layout]; return &s_declarations[layout];
} }
/*!
* \brief Checks whether the type is supported
* \return true If it is the case
*
* \param type Type of the component
*
* \remark Produces a NazaraError if enumeration is invalid
*/
bool ParticleDeclaration::IsTypeSupported(ComponentType type) bool ParticleDeclaration::IsTypeSupported(ComponentType type)
{ {
switch (type) switch (type)
@ -177,6 +267,14 @@ namespace Nz
return false; return false;
} }
/*!
* \brief Initializes the particle declaration librairies
* \return true If successful
*
* \remark Produces a NazaraError if the particle declaration library failed to be initialized
* \remark Produces a NazaraAssert if memory layout of declaration does not match the corresponding structure
*/
bool ParticleDeclaration::Initialize() bool ParticleDeclaration::Initialize()
{ {
if (!ParticleDeclarationLibrary::Initialize()) if (!ParticleDeclarationLibrary::Initialize())
@ -231,11 +329,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the particle declaration librairies
*/
void ParticleDeclaration::Uninitialize() void ParticleDeclaration::Uninitialize()
{ {
ParticleDeclarationLibrary::Uninitialize(); ParticleDeclarationLibrary::Uninitialize();
} }
ParticleDeclaration ParticleDeclaration::s_declarations[ParticleLayout_Max+1]; ParticleDeclaration ParticleDeclaration::s_declarations[ParticleLayout_Max + 1];
ParticleDeclarationLibrary::LibraryMap ParticleDeclaration::s_library; ParticleDeclarationLibrary::LibraryMap ParticleDeclaration::s_library;
} }

View File

@ -14,6 +14,16 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ParticleEmitter
* \brief Graphics class that represents an emitter of particles
*/
/*!
* \brief Constructs a ParticleEmitter object by default
*/
ParticleEmitter::ParticleEmitter() : ParticleEmitter::ParticleEmitter() :
m_lagCompensationEnabled(false), m_lagCompensationEnabled(false),
m_emissionAccumulator(0.f), m_emissionAccumulator(0.f),
@ -24,28 +34,35 @@ namespace Nz
ParticleEmitter::~ParticleEmitter() = default; ParticleEmitter::~ParticleEmitter() = default;
/*!
* \brief Emits particles according to the delta time between the previous frame
*
* \param system Particle system to work on
* \param elapsedTime Delta time between the previous frame
*/
void ParticleEmitter::Emit(ParticleSystem& system, float elapsedTime) const void ParticleEmitter::Emit(ParticleSystem& system, float elapsedTime) const
{ {
if (m_emissionRate > 0.f) if (m_emissionRate > 0.f)
{ {
// On accumule la partie réelle (pour éviter qu'un taux d'update élevé empêche des particules de se former) // We accumulate the real part (to avoid that a high emission rate prevents particles to form)
m_emissionAccumulator += elapsedTime*m_emissionRate; m_emissionAccumulator += elapsedTime * m_emissionRate;
float emissionCount = std::floor(m_emissionAccumulator); // Le nombre d'émissions de cette mise à jour float emissionCount = std::floor(m_emissionAccumulator); // The number of emissions in this update
m_emissionAccumulator -= emissionCount; // On enlève la partie entière m_emissionAccumulator -= emissionCount; // We get rid off the integer part
if (emissionCount >= 1.f) if (emissionCount >= 1.f)
{ {
// On calcule le nombre maximum de particules pouvant être émises cette fois-ci // We compute the maximum number of particles which can be emitted
unsigned int emissionCountInt = static_cast<unsigned int>(emissionCount); unsigned int emissionCountInt = static_cast<unsigned int>(emissionCount);
unsigned int maxParticleCount = emissionCountInt*m_emissionCount; unsigned int maxParticleCount = emissionCountInt * m_emissionCount;
// On récupère le nombre de particules qu'il est possible de créer selon l'espace libre // We get the number of particles that we are able to create (depending on the free space)
unsigned int particleCount = std::min(maxParticleCount, system.GetMaxParticleCount() - system.GetParticleCount()); unsigned int particleCount = std::min(maxParticleCount, system.GetMaxParticleCount() - system.GetParticleCount());
if (particleCount == 0) if (particleCount == 0)
return; return;
// Et on émet nos particules // And we emit our particles
void* particles = system.GenerateParticles(particleCount); void* particles = system.GenerateParticles(particleCount);
ParticleMapper mapper(particles, system.GetDeclaration()); ParticleMapper mapper(particles, system.GetDeclaration());
@ -53,40 +70,73 @@ namespace Nz
if (m_lagCompensationEnabled) if (m_lagCompensationEnabled)
{ {
// On va maintenant appliquer les contrôleurs // We will now apply our controllers
float invEmissionRate = 1.f/m_emissionRate; float invEmissionRate = 1.f / m_emissionRate;
for (unsigned int i = 1; i <= emissionCountInt; ++i) for (unsigned int i = 1; i <= emissionCountInt; ++i)
system.ApplyControllers(mapper, std::min(m_emissionCount*i, particleCount), invEmissionRate); system.ApplyControllers(mapper, std::min(m_emissionCount * i, particleCount), invEmissionRate);
} }
} }
} }
} }
/*!
* \brief Enables the lag compensation
*
* \param enable Should lag compensation be enabled
*/
void ParticleEmitter::EnableLagCompensation(bool enable) void ParticleEmitter::EnableLagCompensation(bool enable)
{ {
m_lagCompensationEnabled = enable; m_lagCompensationEnabled = enable;
} }
/*!
* \brief Gets the emission count
* \return Current emission count
*/
unsigned int ParticleEmitter::GetEmissionCount() const unsigned int ParticleEmitter::GetEmissionCount() const
{ {
return m_emissionCount; return m_emissionCount;
} }
/*!
* \brief Gets the emission rate
* \return Current emission rate
*/
float ParticleEmitter::GetEmissionRate() const float ParticleEmitter::GetEmissionRate() const
{ {
return m_emissionRate; return m_emissionRate;
} }
/*!
* \brief Checks whether the lag compensation is enabled
* \return true If it is the case
*/
bool ParticleEmitter::IsLagCompensationEnabled() const bool ParticleEmitter::IsLagCompensationEnabled() const
{ {
return m_lagCompensationEnabled; return m_lagCompensationEnabled;
} }
/*!
* \brief Sets the emission count
*
* \param count Emission count
*/
void ParticleEmitter::SetEmissionCount(unsigned int count) void ParticleEmitter::SetEmissionCount(unsigned int count)
{ {
m_emissionCount = count; m_emissionCount = count;
} }
/*!
* \brief Sets the emission rate
*
* \param rate Emission rate
*/
void ParticleEmitter::SetEmissionRate(float rate) void ParticleEmitter::SetEmissionRate(float rate)
{ {
m_emissionRate = rate; m_emissionRate = rate;

View File

@ -7,17 +7,44 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ParticleGenerator
* \brief Graphics class which generates particles
*
* \remark This class is abstract
*/
/*!
* \brief Constructs a ParticleGenerator object by assignation
*
* \param generator ParticleGenerator to copy into this
*/
ParticleGenerator::ParticleGenerator(const ParticleGenerator& generator) : ParticleGenerator::ParticleGenerator(const ParticleGenerator& generator) :
RefCounted() RefCounted()
{ {
NazaraUnused(generator); NazaraUnused(generator);
} }
/*!
* \brief Destructs the object and calls OnParticleGeneratorRelease
*
* \see OnParticleGeneratorRelease
*/
ParticleGenerator::~ParticleGenerator() ParticleGenerator::~ParticleGenerator()
{ {
OnParticleGeneratorRelease(this); OnParticleGeneratorRelease(this);
} }
/*!
* \brief Initializes the particle generator librairies
* \return true If successful
*
* \remark Produces a NazaraError if the particle generator library failed to be initialized
*/
bool ParticleGenerator::Initialize() bool ParticleGenerator::Initialize()
{ {
if (!ParticleGeneratorLibrary::Initialize()) if (!ParticleGeneratorLibrary::Initialize())
@ -29,6 +56,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the particle generator librairies
*/
void ParticleGenerator::Uninitialize() void ParticleGenerator::Uninitialize()
{ {
ParticleGeneratorLibrary::Uninitialize(); ParticleGeneratorLibrary::Uninitialize();

View File

@ -8,6 +8,19 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ParticleMapper
* \brief Graphics class that represents the mapping between the internal buffer and the particle declaration
*/
/*!
* \brief Constructs a ParticleMapper object with a raw buffer and a particle declaration
*
* \param buffer Raw buffer to store particles data
* \param declaration Declaration of the particle
*/
ParticleMapper::ParticleMapper(void* buffer, const ParticleDeclaration* declaration) : ParticleMapper::ParticleMapper(void* buffer, const ParticleDeclaration* declaration) :
m_declaration(declaration), m_declaration(declaration),
m_ptr(static_cast<UInt8*>(buffer)) m_ptr(static_cast<UInt8*>(buffer))

View File

@ -7,17 +7,42 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ParticleRenderer
* \brief Graphics class that represents the rendering of the particle
*/
/*!
* \brief Constructs a ParticleRenderer object by assignation
*
* \param renderer ParticleRenderer to copy into this
*/
ParticleRenderer::ParticleRenderer(const ParticleRenderer& renderer) : ParticleRenderer::ParticleRenderer(const ParticleRenderer& renderer) :
RefCounted() RefCounted()
{ {
NazaraUnused(renderer); NazaraUnused(renderer);
} }
/*!
* \brief Destructs the object and calls OnParticleRendererRelease
*
* \see OnParticleRendererRelease
*/
ParticleRenderer::~ParticleRenderer() ParticleRenderer::~ParticleRenderer()
{ {
OnParticleRendererRelease(this); OnParticleRendererRelease(this);
} }
/*!
* \brief Initializes the particle renderer librairies
* \return true If successful
*
* \remark Produces a NazaraError if the particle renderer library failed to be initialized
*/
bool ParticleRenderer::Initialize() bool ParticleRenderer::Initialize()
{ {
if (!ParticleRendererLibrary::Initialize()) if (!ParticleRendererLibrary::Initialize())
@ -29,6 +54,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the particle renderer librairies
*/
void ParticleRenderer::Uninitialize() void ParticleRenderer::Uninitialize()
{ {
ParticleRendererLibrary::Uninitialize(); ParticleRendererLibrary::Uninitialize();

View File

@ -13,25 +13,51 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::ParticleSystem
* \brief Graphics class that represents the system to handle particles
*/
/*!
* \brief Constructs a ParticleSystem object with a maximal number of particles and a layout
*
* \param maxParticleCount Maximum number of particles to generate
* \param layout Enumeration for the layout of data information for the particles
*/
ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleLayout layout) : ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleLayout layout) :
ParticleSystem(maxParticleCount, ParticleDeclaration::Get(layout)) ParticleSystem(maxParticleCount, ParticleDeclaration::Get(layout))
{ {
} }
/*!
* \brief Constructs a ParticleSystem object with a maximal number of particles and a particle declaration
*
* \param maxParticleCount Maximum number of particles to generate
* \param declaration Data information for the particles
*/
ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleDeclarationConstRef declaration) : ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleDeclarationConstRef declaration) :
m_declaration(std::move(declaration)), m_declaration(std::move(declaration)),
m_processing(false), m_processing(false),
m_maxParticleCount(maxParticleCount), m_maxParticleCount(maxParticleCount),
m_particleCount(0) m_particleCount(0)
{ {
// En cas d'erreur, un constructeur ne peut que lancer une exception // In case of error, the constructor can only throw an exception
ErrorFlags flags(ErrorFlag_ThrowException, true); ErrorFlags flags(ErrorFlag_ThrowException, true);
m_particleSize = m_declaration->GetStride(); // La taille de chaque particule m_particleSize = m_declaration->GetStride(); // The size of each particle
ResizeBuffer(); ResizeBuffer();
} }
/*!
* \brief Constructs a ParticleSystem object by assignation
*
* \param system ParticleSystem to copy into this
*/
ParticleSystem::ParticleSystem(const ParticleSystem& system) : ParticleSystem::ParticleSystem(const ParticleSystem& system) :
Renderable(system), Renderable(system),
m_controllers(system.m_controllers), m_controllers(system.m_controllers),
@ -47,12 +73,20 @@ namespace Nz
ResizeBuffer(); ResizeBuffer();
// On ne copie que les particules vivantes // We only copy alive particles
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize); std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize);
} }
ParticleSystem::~ParticleSystem() = default; ParticleSystem::~ParticleSystem() = default;
/*!
* \brief Adds a controller to the particles
*
* \param controller Controller for the particles
*
* \remark Produces a NazaraAssert if controller is invalid
*/
void ParticleSystem::AddController(ParticleControllerRef controller) void ParticleSystem::AddController(ParticleControllerRef controller)
{ {
NazaraAssert(controller, "Invalid particle controller"); NazaraAssert(controller, "Invalid particle controller");
@ -60,6 +94,14 @@ namespace Nz
m_controllers.emplace_back(std::move(controller)); m_controllers.emplace_back(std::move(controller));
} }
/*!
* \brief Adds an emitter to the particles
*
* \param emitter Emitter for the particles
*
* \remark Produces a NazaraAssert if emitter is invalid
*/
void ParticleSystem::AddEmitter(ParticleEmitter* emitter) void ParticleSystem::AddEmitter(ParticleEmitter* emitter)
{ {
NazaraAssert(emitter, "Invalid particle emitter"); NazaraAssert(emitter, "Invalid particle emitter");
@ -67,6 +109,14 @@ namespace Nz
m_emitters.emplace_back(emitter); m_emitters.emplace_back(emitter);
} }
/*!
* \brief Adds a generator to the particles
*
* \param generator Generator for the particles
*
* \remark Produces a NazaraAssert if generator is invalid
*/
void ParticleSystem::AddGenerator(ParticleGeneratorRef generator) void ParticleSystem::AddGenerator(ParticleGeneratorRef generator)
{ {
NazaraAssert(generator, "Invalid particle generator"); NazaraAssert(generator, "Invalid particle generator");
@ -74,6 +124,16 @@ namespace Nz
m_generators.emplace_back(std::move(generator)); m_generators.emplace_back(std::move(generator));
} }
/*!
* \brief Adds the particle system to the rendering queue
*
* \param renderQueue Queue to be added
* \param transformMatrix Transformation matrix for the system
*
* \remark Produces a NazaraAssert if inner renderer is invalid
* \remark Produces a NazaraAssert if renderQueue is invalid
*/
void ParticleSystem::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const void ParticleSystem::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const
{ {
NazaraAssert(m_renderer, "Invalid particle renderer"); NazaraAssert(m_renderer, "Invalid particle renderer");
@ -83,45 +143,63 @@ namespace Nz
if (m_particleCount > 0) if (m_particleCount > 0)
{ {
ParticleMapper mapper(m_buffer.data(), m_declaration); ParticleMapper mapper(m_buffer.data(), m_declaration);
m_renderer->Render(*this, mapper, 0, m_particleCount-1, renderQueue); m_renderer->Render(*this, mapper, 0, m_particleCount - 1, renderQueue);
} }
} }
/*!
* \brief Applies the controllers
*
* \param mapper Mapper containing layout information of each particle
* \param particleCount Number of particles
* \param elapsedTime Delta time between the previous frame
*/
void ParticleSystem::ApplyControllers(ParticleMapper& mapper, unsigned int particleCount, float elapsedTime) void ParticleSystem::ApplyControllers(ParticleMapper& mapper, unsigned int particleCount, float elapsedTime)
{ {
m_processing = true; m_processing = true;
// Pour éviter un verrouillage en cas d'exception // To avoid a lock in case of exception
CallOnExit onExit([this]() CallOnExit onExit([this]()
{ {
m_processing = false; m_processing = false;
}); });
for (ParticleController* controller : m_controllers) for (ParticleController* controller : m_controllers)
controller->Apply(*this, mapper, 0, particleCount-1, elapsedTime); controller->Apply(*this, mapper, 0, particleCount - 1, elapsedTime);
onExit.CallAndReset(); onExit.CallAndReset();
// On tue maintenant les particules mortes durant la mise à jour // We only kill now the dead particles during the update
if (m_dyingParticles.size() < m_particleCount) if (m_dyingParticles.size() < m_particleCount)
{ {
// On tue les particules depuis la dernière vers la première (en terme de place), le std::set étant trié via std::greater // We kill them in reverse order, std::set sorting them via std::greater
// La raison est simple, étant donné que la mort d'une particule signifie le déplacement de la dernière particule du buffer, // The reason is simple, as the death of a particle means the move of the last particle in the buffer,
// sans cette solution certaines particules pourraient échapper à la mort // without this solution, certain particles could avoid the death
for (unsigned int index : m_dyingParticles) for (unsigned int index : m_dyingParticles)
KillParticle(index); KillParticle(index);
} }
else else
KillParticles(); // Toutes les particules sont mortes, ceci est beaucoup plus rapide KillParticles(); // Every particles are dead, this is way faster
m_dyingParticles.clear(); m_dyingParticles.clear();
} }
/*!
* \brief Creates one particle
* \return Pointer to the particle memory buffer
*/
void* ParticleSystem::CreateParticle() void* ParticleSystem::CreateParticle()
{ {
return CreateParticles(1); return CreateParticles(1);
} }
/*!
* \brief Creates multiple particles
* \return Pointer to the first particle memory buffer
*/
void* ParticleSystem::CreateParticles(unsigned int count) void* ParticleSystem::CreateParticles(unsigned int count)
{ {
if (count == 0) if (count == 0)
@ -133,14 +211,24 @@ namespace Nz
unsigned int particlesIndex = m_particleCount; unsigned int particlesIndex = m_particleCount;
m_particleCount += count; m_particleCount += count;
return &m_buffer[particlesIndex*m_particleSize]; return &m_buffer[particlesIndex * m_particleSize];
} }
/*!
* \brief Generates one particle
* \return Pointer to the particle memory buffer
*/
void* ParticleSystem::GenerateParticle() void* ParticleSystem::GenerateParticle()
{ {
return GenerateParticles(1); return GenerateParticles(1);
} }
/*!
* \brief Generates multiple particles
* \return Pointer to the first particle memory buffer
*/
void* ParticleSystem::GenerateParticles(unsigned int count) void* ParticleSystem::GenerateParticles(unsigned int count)
{ {
void* ptr = CreateParticles(count); void* ptr = CreateParticles(count);
@ -149,57 +237,108 @@ namespace Nz
ParticleMapper mapper(ptr, m_declaration); ParticleMapper mapper(ptr, m_declaration);
for (ParticleGenerator* generator : m_generators) for (ParticleGenerator* generator : m_generators)
generator->Generate(*this, mapper, 0, count-1); generator->Generate(*this, mapper, 0, count - 1);
return ptr; return ptr;
} }
/*!
* \brief Gets the particle declaration
* \return Particle declaration
*/
const ParticleDeclarationConstRef& ParticleSystem::GetDeclaration() const const ParticleDeclarationConstRef& ParticleSystem::GetDeclaration() const
{ {
return m_declaration; return m_declaration;
} }
/*!
* \brief Gets the fixed step size
* \return Current fixed step size
*/
float ParticleSystem::GetFixedStepSize() const float ParticleSystem::GetFixedStepSize() const
{ {
return m_stepSize; return m_stepSize;
} }
/*!
* \brief Gets the maximum number of particles
* \return Current maximum number
*/
unsigned int ParticleSystem::GetMaxParticleCount() const unsigned int ParticleSystem::GetMaxParticleCount() const
{ {
return m_maxParticleCount; return m_maxParticleCount;
} }
/*!
* \brief Gets the number of particles
* \return Current number
*/
unsigned int ParticleSystem::GetParticleCount() const unsigned int ParticleSystem::GetParticleCount() const
{ {
return m_particleCount; return m_particleCount;
} }
/*!
* \brief Gets the size of particles
* \return Current size
*/
unsigned int ParticleSystem::GetParticleSize() const unsigned int ParticleSystem::GetParticleSize() const
{ {
return m_particleSize; return m_particleSize;
} }
/*!
* \brief Checks whether the fixed step is enabled
* \return true If it is the case
*/
bool ParticleSystem::IsFixedStepEnabled() const
{
return m_fixedStepEnabled;
}
/*!
* \brief Kills one particle
*
* \param index Index of the particle
*/
void ParticleSystem::KillParticle(unsigned int index) void ParticleSystem::KillParticle(unsigned int index)
{ {
///FIXME: Vérifier index ///FIXME: Verify the index
if (m_processing) if (m_processing)
{ {
// Le buffer est en train d'être modifié, nous ne pouvons pas réduire sa taille, on place alors la particule dans une liste d'attente // The buffer is being modified, we can not reduce its size, we put the particle in the waiting list
m_dyingParticles.insert(index); m_dyingParticles.insert(index);
return; return;
} }
// On déplace la dernière particule vivante à la place de celle-ci // We move the last alive particle to the place of this one
if (--m_particleCount > 0) if (--m_particleCount > 0)
std::memcpy(&m_buffer[index*m_particleSize], &m_buffer[m_particleCount*m_particleSize], m_particleSize); std::memcpy(&m_buffer[index * m_particleSize], &m_buffer[m_particleCount * m_particleSize], m_particleSize);
} }
/*!
* \brief Kills every particles
*/
void ParticleSystem::KillParticles() void ParticleSystem::KillParticles()
{ {
m_particleCount = 0; m_particleCount = 0;
} }
/*!
* \brief Removes a controller to the particles
*
* \param controller Controller for the particles to remove
*/
void ParticleSystem::RemoveController(ParticleController* controller) void ParticleSystem::RemoveController(ParticleController* controller)
{ {
auto it = std::find(m_controllers.begin(), m_controllers.end(), controller); auto it = std::find(m_controllers.begin(), m_controllers.end(), controller);
@ -207,6 +346,12 @@ namespace Nz
m_controllers.erase(it); m_controllers.erase(it);
} }
/*!
* \brief Removes an emitter to the particles
*
* \param emitter Emitter for the particles to remove
*/
void ParticleSystem::RemoveEmitter(ParticleEmitter* emitter) void ParticleSystem::RemoveEmitter(ParticleEmitter* emitter)
{ {
auto it = std::find(m_emitters.begin(), m_emitters.end(), emitter); auto it = std::find(m_emitters.begin(), m_emitters.end(), emitter);
@ -214,6 +359,12 @@ namespace Nz
m_emitters.erase(it); m_emitters.erase(it);
} }
/*!
* \brief Removes a generator to the particles
*
* \param generator Generator for the particles to remove
*/
void ParticleSystem::RemoveGenerator(ParticleGenerator* generator) void ParticleSystem::RemoveGenerator(ParticleGenerator* generator)
{ {
auto it = std::find(m_generators.begin(), m_generators.end(), generator); auto it = std::find(m_generators.begin(), m_generators.end(), generator);
@ -221,31 +372,55 @@ namespace Nz
m_generators.erase(it); m_generators.erase(it);
} }
/*!
* \brief Sets the fixed step size
*
* \param stepSize Fixed step size
*/
void ParticleSystem::SetFixedStepSize(float stepSize) void ParticleSystem::SetFixedStepSize(float stepSize)
{ {
m_stepSize = stepSize; m_stepSize = stepSize;
} }
/*!
* \brief Sets the renderer of the particles
*
* \param renderer Renderer for the particles
*/
void ParticleSystem::SetRenderer(ParticleRenderer* renderer) void ParticleSystem::SetRenderer(ParticleRenderer* renderer)
{ {
m_renderer = renderer; m_renderer = renderer;
} }
/*!
* \brief Updates the system
*
* \param elapsedTime Delta time between the previous frame
*/
void ParticleSystem::Update(float elapsedTime) void ParticleSystem::Update(float elapsedTime)
{ {
// Émission // Emission
for (ParticleEmitter* emitter : m_emitters) for (ParticleEmitter* emitter : m_emitters)
emitter->Emit(*this, elapsedTime); emitter->Emit(*this, elapsedTime);
// Mise à jour // Update
if (m_particleCount > 0) if (m_particleCount > 0)
{ {
///TODO: Mettre à jour en utilisant des threads ///TODO: Update using threads
ParticleMapper mapper(m_buffer.data(), m_declaration); ParticleMapper mapper(m_buffer.data(), m_declaration);
ApplyControllers(mapper, m_particleCount, elapsedTime); ApplyControllers(mapper, m_particleCount, elapsedTime);
} }
} }
/*!
* \brief Updates the bounding volume by a matrix
*
* \param transformMatrix Matrix transformation for our bounding volume
*/
void ParticleSystem::UpdateBoundingVolume(const Matrix4f& transformMatrix) void ParticleSystem::UpdateBoundingVolume(const Matrix4f& transformMatrix)
{ {
NazaraUnused(transformMatrix); NazaraUnused(transformMatrix);
@ -253,6 +428,13 @@ namespace Nz
// Nothing to do here (our bounding volume is global) // Nothing to do here (our bounding volume is global)
} }
/*!
* \brief Sets the current particle system with the content of the other one
* \return A reference to this
*
* \param system The other ParticleSystem
*/
ParticleSystem& ParticleSystem::operator=(const ParticleSystem& system) ParticleSystem& ParticleSystem::operator=(const ParticleSystem& system)
{ {
ErrorFlags flags(ErrorFlag_ThrowException, true); ErrorFlags flags(ErrorFlag_ThrowException, true);
@ -268,29 +450,39 @@ namespace Nz
m_renderer = system.m_renderer; m_renderer = system.m_renderer;
m_stepSize = system.m_stepSize; m_stepSize = system.m_stepSize;
// La copie ne peut pas (ou plutôt ne devrait pas) avoir lieu pendant une mise à jour, inutile de copier // The copy can not (or should not) happen during the update, there is no use to copy
m_dyingParticles.clear(); m_dyingParticles.clear();
m_processing = false; m_processing = false;
m_stepAccumulator = 0.f; m_stepAccumulator = 0.f;
m_buffer.clear(); // Pour éviter une recopie lors du resize() qui ne servira pas à grand chose m_buffer.clear(); // To avoid a copy due to resize() which will be pointless
ResizeBuffer(); ResizeBuffer();
// On ne copie que les particules vivantes // We only copy alive particles
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize); std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount * m_particleSize);
return *this; return *this;
} }
/*!
* \brief Makes the bounding volume of this text
*/
void ParticleSystem::MakeBoundingVolume() const void ParticleSystem::MakeBoundingVolume() const
{ {
///TODO: Calculer l'AABB (prendre la taille des particules en compte s'il y a) ///TODO: Compute the AABB (taking into account the size of particles)
m_boundingVolume.MakeInfinite(); m_boundingVolume.MakeInfinite();
} }
/*!
* \brief Resizes the internal buffer
*
* \remark Produces a NazaraError if resize did not work
*/
void ParticleSystem::ResizeBuffer() void ParticleSystem::ResizeBuffer()
{ {
// Histoire de décrire un peu mieux l'erreur en cas d'échec // Just to have a better description of our problem in case of error
try try
{ {
m_buffer.resize(m_maxParticleCount*m_particleSize); m_buffer.resize(m_maxParticleCount*m_particleSize);

View File

@ -23,7 +23,7 @@ namespace Nz
"User" "User"
}; };
static_assert(sizeof(techniquesName)/sizeof(const char*) == RenderTechniqueType_Max+1, "Render technique type name array is incomplete"); static_assert(sizeof(techniquesName) / sizeof(const char*) == RenderTechniqueType_Max + 1, "Render technique type name array is incomplete");
struct RenderTechnique struct RenderTechnique
{ {
@ -34,6 +34,22 @@ namespace Nz
std::unordered_map<String, RenderTechnique> s_renderTechniques; std::unordered_map<String, RenderTechnique> s_renderTechniques;
} }
/*!
* \ingroup graphics
* \class Nz::RenderTechniques
* \brief Graphics class that represents the techniques used in rendering
*/
/*!
* \brief Gets the technique by enumeration
* \return A reference to the newly created technique
*
* \param renderTechnique Enumeration of the technique
* \param techniqueRanking Ranking for the technique
*
* \remark Produces a NazaraError if renderTechnique does not exist
*/
AbstractRenderTechnique* RenderTechniques::GetByEnum(RenderTechniqueType renderTechnique, int* techniqueRanking) AbstractRenderTechnique* RenderTechniques::GetByEnum(RenderTechniqueType renderTechnique, int* techniqueRanking)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -47,6 +63,16 @@ namespace Nz
return GetByName(techniquesName[renderTechnique], techniqueRanking); return GetByName(techniquesName[renderTechnique], techniqueRanking);
} }
/*!
* \brief Gets the technique by index
* \return A reference to the newly created technique
*
* \param index Index of the technique
* \param techniqueRanking Ranking for the technique
*
* \remark Produces a NazaraError if index is out or range
*/
AbstractRenderTechnique* RenderTechniques::GetByIndex(unsigned int index, int* techniqueRanking) AbstractRenderTechnique* RenderTechniques::GetByIndex(unsigned int index, int* techniqueRanking)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -66,6 +92,16 @@ namespace Nz
return it->second.factory(); return it->second.factory();
} }
/*!
* \brief Gets the technique by name
* \return A reference to the newly created technique
*
* \param name Name of the technique
* \param techniqueRanking Ranking for the technique
*
* \remark Produces a NazaraError if name does not exist or is invalid
*/
AbstractRenderTechnique* RenderTechniques::GetByName(const String& name, int* techniqueRanking) AbstractRenderTechnique* RenderTechniques::GetByName(const String& name, int* techniqueRanking)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -89,6 +125,16 @@ namespace Nz
return it->second.factory(); return it->second.factory();
} }
/*!
* \brief Gets the technique by ranking
* \return A reference to the newly created technique
*
* \param maxRanking Ranking maximum of the technique
* \param techniqueRanking Ranking for the technique
*
* \remark Produces a NazaraError if name does not exist or is invalid
*/
AbstractRenderTechnique* RenderTechniques::GetByRanking(int maxRanking, int* techniqueRanking) AbstractRenderTechnique* RenderTechniques::GetByRanking(int maxRanking, int* techniqueRanking)
{ {
if (maxRanking < 0) if (maxRanking < 0)
@ -119,11 +165,28 @@ namespace Nz
return technique->factory(); return technique->factory();
} }
/*!
* \brief Gets the number of techniques available
* \return Number of techniques
*/
unsigned int RenderTechniques::GetCount() unsigned int RenderTechniques::GetCount()
{ {
return s_renderTechniques.size(); return s_renderTechniques.size();
} }
/*!
* \brief Registers a technique
*
* \param name Name of the technique
* \param ranking Ranking of the technique
* \param factory Factory to create the technique
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if name is empty
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if ranking is negative
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if factory is invalid is invalid
*/
void RenderTechniques::Register(const String& name, int ranking, RenderTechniqueFactory factory) void RenderTechniques::Register(const String& name, int ranking, RenderTechniqueFactory factory)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -149,6 +212,15 @@ namespace Nz
s_renderTechniques[name] = {factory, ranking}; s_renderTechniques[name] = {factory, ranking};
} }
/*!
* \brief Converts the enumeration to string
* \return String symbolizing the technique
*
* \param renderTechnique Enumeration of the technique
*
* \remark Produces a NazaraError if renderTechnique does not exist and returns "Error"
*/
String RenderTechniques::ToString(RenderTechniqueType renderTechnique) String RenderTechniques::ToString(RenderTechniqueType renderTechnique)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -162,6 +234,12 @@ namespace Nz
return techniquesName[renderTechnique]; return techniquesName[renderTechnique];
} }
/*!
* \brief Unregisters a technique
*
* \param name Name of the technique
*/
void RenderTechniques::Unregister(const String& name) void RenderTechniques::Unregister(const String& name)
{ {
s_renderTechniques.erase(name); s_renderTechniques.erase(name);

View File

@ -7,8 +7,24 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::Renderable
* \brief Graphics class that represents a renderable element for our scene
*
* \remark This class is abstract
*/
Renderable::~Renderable() = default; Renderable::~Renderable() = default;
/*!
* \brief Culls the model if not in the frustum
* \return true If renderable is in the frustum
*
* \param frustum Symbolizing the field of view
* \param transformMatrix Matrix transformation for our object
*/
bool Renderable::Cull(const Frustumf& frustum, const Matrix4f& transformMatrix) const bool Renderable::Cull(const Frustumf& frustum, const Matrix4f& transformMatrix) const
{ {
NazaraUnused(transformMatrix); NazaraUnused(transformMatrix);
@ -16,6 +32,11 @@ namespace Nz
return frustum.Contains(m_boundingVolume); return frustum.Contains(m_boundingVolume);
} }
/*!
* \brief Gets the bounding volume
* \return Bounding volume of the renderable element
*/
const BoundingVolumef& Renderable::GetBoundingVolume() const const BoundingVolumef& Renderable::GetBoundingVolume() const
{ {
EnsureBoundingVolumeUpdated(); EnsureBoundingVolumeUpdated();
@ -23,6 +44,12 @@ namespace Nz
return m_boundingVolume; return m_boundingVolume;
} }
/*!
* \brief Updates the bounding volume by a matrix
*
* \param transformMatrix Matrix transformation for our bounding volume
*/
void Renderable::UpdateBoundingVolume(const Matrix4f& transformMatrix) void Renderable::UpdateBoundingVolume(const Matrix4f& transformMatrix)
{ {
m_boundingVolume.Update(transformMatrix); m_boundingVolume.Update(transformMatrix);

View File

@ -14,6 +14,17 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::SkeletalModel
* \brief Graphics class that represents a model with a skeleton
*/
/*!
* \brief Checks whether the parameters for the skeletal mesh are correct
* \return true If parameters are valid
*/
bool SkeletalModelParameters::IsValid() const bool SkeletalModelParameters::IsValid() const
{ {
if (!ModelParameters::IsValid()) if (!ModelParameters::IsValid())
@ -25,12 +36,23 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Constructs a SkeletalModel object by default
*/
SkeletalModel::SkeletalModel() : SkeletalModel::SkeletalModel() :
m_currentSequence(nullptr), m_currentSequence(nullptr),
m_animationEnabled(true) m_animationEnabled(true)
{ {
} }
/*!
* \brief Adds the skeletal mesh to the rendering queue
*
* \param renderQueue Queue to be added
* \param instanceData Data for the instance
*/
void SkeletalModel::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const void SkeletalModel::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
if (!m_mesh) if (!m_mesh)
@ -51,6 +73,14 @@ namespace Nz
} }
} }
/*!
* \brief Updates the animation of the mesh
*
* \param elapsedTime Delta time between two frames
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if there is no animation
*/
void SkeletalModel::AdvanceAnimation(float elapsedTime) void SkeletalModel::AdvanceAnimation(float elapsedTime)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -67,7 +97,7 @@ namespace Nz
m_interpolation -= 1.f; m_interpolation -= 1.f;
unsigned lastFrame = m_currentSequence->firstFrame + m_currentSequence->frameCount - 1; unsigned lastFrame = m_currentSequence->firstFrame + m_currentSequence->frameCount - 1;
if (m_nextFrame+1 > lastFrame) if (m_nextFrame + 1 > lastFrame)
{ {
if (m_animation->IsLoopPointInterpolationEnabled()) if (m_animation->IsLoopPointInterpolationEnabled())
{ {
@ -77,7 +107,7 @@ namespace Nz
else else
{ {
m_currentFrame = m_currentSequence->firstFrame; m_currentFrame = m_currentSequence->firstFrame;
m_nextFrame = m_currentFrame+1; m_nextFrame = m_currentFrame + 1;
} }
} }
else else
@ -92,26 +122,52 @@ namespace Nz
InvalidateBoundingVolume(); InvalidateBoundingVolume();
} }
/*!
* \brief Clones this skeletal model
* \return Pointer to newly allocated SkeletalModel
*/
SkeletalModel* SkeletalModel::Clone() const SkeletalModel* SkeletalModel::Clone() const
{ {
return new SkeletalModel(*this); return new SkeletalModel(*this);
} }
/*!
* \brief Creates a default skeletal model
* \return Pointer to newly allocated SkeletalModel
*/
SkeletalModel* SkeletalModel::Create() const SkeletalModel* SkeletalModel::Create() const
{ {
return new SkeletalModel; return new SkeletalModel;
} }
/*!
* \brief Enables the animation of the model
*
* \param animation Should the model be animated
*/
void SkeletalModel::EnableAnimation(bool animation) void SkeletalModel::EnableAnimation(bool animation)
{ {
m_animationEnabled = animation; m_animationEnabled = animation;
} }
/*!
* \brief Gets the animation of the model
* \return Pointer to the animation
*/
Animation* SkeletalModel::GetAnimation() const Animation* SkeletalModel::GetAnimation() const
{ {
return m_animation; return m_animation;
} }
/*!
* \brief Gets the skeleton of the model
* \return Pointer to the skeleton
*/
Skeleton* SkeletalModel::GetSkeleton() Skeleton* SkeletalModel::GetSkeleton()
{ {
InvalidateBoundingVolume(); InvalidateBoundingVolume();
@ -119,41 +175,96 @@ namespace Nz
return &m_skeleton; return &m_skeleton;
} }
/*!
* \brief Gets the skeleton of the model
* \return Constant pointer to the skeleton
*/
const Skeleton* SkeletalModel::GetSkeleton() const const Skeleton* SkeletalModel::GetSkeleton() const
{ {
return &m_skeleton; return &m_skeleton;
} }
/*!
* \brief Checks whether the skeleton has an animation
* \return true If it is the case
*
* \see IsAnimated, IsAnimationEnabled
*/
bool SkeletalModel::HasAnimation() const bool SkeletalModel::HasAnimation() const
{ {
return m_animation != nullptr; return m_animation != nullptr;
} }
/*!
* \brief Checks whether the skeleton is animated
* \return true
*
* \see HasAnimation, IsAnimationEnabled
*/
bool SkeletalModel::IsAnimated() const bool SkeletalModel::IsAnimated() const
{ {
return true; return true;
} }
/*!
* \brief Checks whether the skeleton is currently animated
* \return true If it is the case
*
* \see HasAnimation, IsAnimated
*/
bool SkeletalModel::IsAnimationEnabled() const bool SkeletalModel::IsAnimationEnabled() const
{ {
return m_animationEnabled; return m_animationEnabled;
} }
/*!
* \brief Loads the skeleton model from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the skeleton model
*/
bool SkeletalModel::LoadFromFile(const String& filePath, const SkeletalModelParameters& params) bool SkeletalModel::LoadFromFile(const String& filePath, const SkeletalModelParameters& params)
{ {
return SkeletalModelLoader::LoadFromFile(this, filePath, params); return SkeletalModelLoader::LoadFromFile(this, filePath, params);
} }
/*!
* \brief Loads the skeleton model from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the skeleton model
*/
bool SkeletalModel::LoadFromMemory(const void* data, std::size_t size, const SkeletalModelParameters& params) bool SkeletalModel::LoadFromMemory(const void* data, std::size_t size, const SkeletalModelParameters& params)
{ {
return SkeletalModelLoader::LoadFromMemory(this, data, size, params); return SkeletalModelLoader::LoadFromMemory(this, data, size, params);
} }
/*!
* \brief Loads the skeleton model from stream
* \return true if loading is successful
*
* \param stream Stream to the skeleton model
* \param params Parameters for the skeleton model
*/
bool SkeletalModel::LoadFromStream(Stream& stream, const SkeletalModelParameters& params) bool SkeletalModel::LoadFromStream(Stream& stream, const SkeletalModelParameters& params)
{ {
return SkeletalModelLoader::LoadFromStream(this, stream, params); return SkeletalModelLoader::LoadFromStream(this, stream, params);
} }
/*!
* \brief Resets the model
*/
void SkeletalModel::Reset() void SkeletalModel::Reset()
{ {
Model::Reset(); Model::Reset();
@ -161,6 +272,16 @@ namespace Nz
m_skeleton.Destroy(); m_skeleton.Destroy();
} }
/*!
* \brief Sets the animation for the model
* \return true If successful
*
* \param animation Animation for the model
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no mesh
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if animation is invalid
*/
bool SkeletalModel::SetAnimation(Animation* animation) bool SkeletalModel::SetAnimation(Animation* animation)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -204,6 +325,14 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the mesh for the model
*
* \param mesh Mesh for the model
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no mesh or if invalid
*/
void SkeletalModel::SetMesh(Mesh* mesh) void SkeletalModel::SetMesh(Mesh* mesh)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -224,13 +353,23 @@ namespace Nz
SetAnimation(nullptr); SetAnimation(nullptr);
} }
m_skeleton = *m_mesh->GetSkeleton(); // Copie du squelette template m_skeleton = *m_mesh->GetSkeleton(); // Copy of skeleton template
} }
} }
/*!
* \brief Sets the sequence for the model
* \return true If successful
*
* \param sequenceName Name for the sequence animation
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no animation
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if sequence name does not exist for the current animation
*/
bool SkeletalModel::SetSequence(const String& sequenceName) bool SkeletalModel::SetSequence(const String& sequenceName)
{ {
///TODO: Rendre cette erreur "safe" avec le nouveau système de gestions d'erreur (No-log) ///TODO: Make this error "safe" with the new system of error handling (No-log)
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
if (!m_animation) if (!m_animation)
{ {
@ -240,11 +379,13 @@ namespace Nz
#endif #endif
const Sequence* currentSequence = m_animation->GetSequence(sequenceName); const Sequence* currentSequence = m_animation->GetSequence(sequenceName);
#if NAZARA_GRAPHICS_SAFE
if (!currentSequence) if (!currentSequence)
{ {
NazaraError("Sequence not found"); NazaraError("Sequence not found");
return false; return false;
} }
#endif
m_currentSequence = currentSequence; m_currentSequence = currentSequence;
m_nextFrame = m_currentSequence->firstFrame; m_nextFrame = m_currentSequence->firstFrame;
@ -252,6 +393,15 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Sets the sequence for the model
*
* \param sequenceIndex Index for the sequence animation
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no animation
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if sequence name does not exist for the current animation
*/
void SkeletalModel::SetSequence(unsigned int sequenceIndex) void SkeletalModel::SetSequence(unsigned int sequenceIndex)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -275,13 +425,22 @@ namespace Nz
m_nextFrame = m_currentSequence->firstFrame; m_nextFrame = m_currentSequence->firstFrame;
} }
/*
* \brief Makes the bounding volume of this text
*/
void SkeletalModel::MakeBoundingVolume() const void SkeletalModel::MakeBoundingVolume() const
{ {
m_boundingVolume.Set(m_skeleton.GetAABB()); m_boundingVolume.Set(m_skeleton.GetAABB());
} }
/*!
* \brief Updates the model
*/
void SkeletalModel::Update() void SkeletalModel::Update()
{ {
///TODO
/*if (m_animationEnabled && m_animation) /*if (m_animationEnabled && m_animation)
AdvanceAnimation(m_scene->GetUpdateTime());*/ AdvanceAnimation(m_scene->GetUpdateTime());*/
} }

View File

@ -46,6 +46,13 @@ namespace Nz
SkeletonMap s_cache; SkeletonMap s_cache;
std::vector<QueueData> s_skinningQueue; std::vector<QueueData> s_skinningQueue;
/*!
* \brief Skins the mesh for a single thread context
*
* \param mesh Skeletal mesh to get vertex buffer from
* \param skeleton Skeleton to consider for getting data
* \param buffer Vertex buffer symbolizing the transition
*/
void Skin_MonoCPU(const SkeletalMesh* mesh, const Skeleton* skeleton, VertexBuffer* buffer) void Skin_MonoCPU(const SkeletalMesh* mesh, const Skeleton* skeleton, VertexBuffer* buffer)
{ {
@ -60,6 +67,14 @@ namespace Nz
SkinPositionNormalTangent(skinningData, 0, mesh->GetVertexCount()); SkinPositionNormalTangent(skinningData, 0, mesh->GetVertexCount());
} }
/*!
* \brief Skins the mesh for a multi-threaded context
*
* \param mesh Skeletal mesh to get vertex buffer from
* \param skeleton Skeleton to consider for getting data
* \param buffer Vertex buffer symbolizing the transition
*/
void Skin_MultiCPU(const SkeletalMesh* mesh, const Skeleton* skeleton, VertexBuffer* buffer) void Skin_MultiCPU(const SkeletalMesh* mesh, const Skeleton* skeleton, VertexBuffer* buffer)
{ {
BufferMapper<VertexBuffer> inputMapper(mesh->GetVertexBuffer(), BufferAccess_ReadOnly); BufferMapper<VertexBuffer> inputMapper(mesh->GetVertexBuffer(), BufferAccess_ReadOnly);
@ -70,8 +85,8 @@ namespace Nz
skinningData.outputVertex = static_cast<MeshVertex*>(outputMapper.GetPointer()); skinningData.outputVertex = static_cast<MeshVertex*>(outputMapper.GetPointer());
skinningData.joints = skeleton->GetJoints(); skinningData.joints = skeleton->GetJoints();
// Afin d'empêcher les différents threads de vouloir mettre à jour la même matrice en même temps, // To avoid different threads to update the same matrix at the same time
// on se charge de la mettre à jour avant de les lancer // We try to update them before launching the tasks
unsigned int jointCount = skeleton->GetJointCount(); unsigned int jointCount = skeleton->GetJointCount();
for (unsigned int i = 0; i < jointCount; ++i) for (unsigned int i = 0; i < jointCount; ++i)
skinningData.joints[i].EnsureSkinningMatrixUpdate(); skinningData.joints[i].EnsureSkinningMatrixUpdate();
@ -87,6 +102,23 @@ namespace Nz
} }
} }
/*!
* \ingroup graphics
* \class Nz::SkinningManager
* \brief Graphics class that represents the management of skinning
*/
/*!
* \brief Gets the vertex buffer from a skeletal mesh with its skeleton
* \return A pointer to the vertex buffer newly created
*
* \param mesh Skeletal mesh to get vertex buffer from
* \param skeleton Skeleton to consider for getting data
*
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if mesh is invalid
* \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skeleton is invalid
*/
VertexBuffer* SkinningManager::GetBuffer(const SkeletalMesh* mesh, const Skeleton* skeleton) VertexBuffer* SkinningManager::GetBuffer(const SkeletalMesh* mesh, const Skeleton* skeleton)
{ {
#if NAZARA_GRAPHICS_SAFE #if NAZARA_GRAPHICS_SAFE
@ -149,6 +181,10 @@ namespace Nz
return buffer; return buffer;
} }
/*!
* \brief Skins the skeletal mesh
*/
void SkinningManager::Skin() void SkinningManager::Skin()
{ {
for (QueueData& data : s_skinningQueue) for (QueueData& data : s_skinningQueue)
@ -157,6 +193,11 @@ namespace Nz
s_skinningQueue.clear(); s_skinningQueue.clear();
} }
/*!
* \brief Initializes the skinning librairies
* \return true
*/
bool SkinningManager::Initialize() bool SkinningManager::Initialize()
{ {
///TODO: GPU Skinning ///TODO: GPU Skinning
@ -165,9 +206,15 @@ namespace Nz
else else
s_skinFunc = Skin_MonoCPU; s_skinFunc = Skin_MonoCPU;
return true; // Rien de particulier à faire return true; // Nothing particular to do
} }
/*!
* \brief Handle the destruction of a skeletal mesh
*
* \param mesh SkeletalMesh being destroyed
*/
void SkinningManager::OnSkeletalMeshDestroy(const SkeletalMesh* mesh) void SkinningManager::OnSkeletalMeshDestroy(const SkeletalMesh* mesh)
{ {
for (auto& pair : s_cache) for (auto& pair : s_cache)
@ -177,17 +224,33 @@ namespace Nz
} }
} }
/*!
* \brief Handle the invalidation of a skeletal mesh
*
* \param mesh SkeletalMesh being invalidated
*/
void SkinningManager::OnSkeletonInvalidated(const Skeleton* skeleton) void SkinningManager::OnSkeletonInvalidated(const Skeleton* skeleton)
{ {
for (auto& pair : s_cache.at(skeleton).meshMap) for (auto& pair : s_cache.at(skeleton).meshMap)
pair.second.updated = false; pair.second.updated = false;
} }
/*!
* \brief Handle the release of a skeletal mesh
*
* \param skeleton SkeletalMesh being released
*/
void SkinningManager::OnSkeletonRelease(const Skeleton* skeleton) void SkinningManager::OnSkeletonRelease(const Skeleton* skeleton)
{ {
s_cache.erase(skeleton); s_cache.erase(skeleton);
} }
/*!
* \brief Uninitializes the skinning librairies
*/
void SkinningManager::Uninitialize() void SkinningManager::Uninitialize()
{ {
s_cache.clear(); s_cache.clear();

View File

@ -22,6 +22,18 @@ namespace Nz
static VertexBufferRef s_vertexBuffer; static VertexBufferRef s_vertexBuffer;
} }
/*!
* \ingroup graphics
* \class Nz::SkyboxBackground
* \brief Graphics class that represents a background with a cubemap texture
*/
/*!
* \brief Constructs a SkyboxBackground object with a cubemap texture
*
* \param cubemapTexture Cubemap texture
*/
SkyboxBackground::SkyboxBackground(TextureRef cubemapTexture) : SkyboxBackground::SkyboxBackground(TextureRef cubemapTexture) :
m_movementOffset(Vector3f::Zero()), m_movementOffset(Vector3f::Zero()),
m_movementScale(0.f) m_movementScale(0.f)
@ -31,6 +43,12 @@ namespace Nz
SetTexture(std::move(cubemapTexture)); SetTexture(std::move(cubemapTexture));
} }
/*!
* \brief Draws this relatively to the viewer
*
* \param viewer Viewer for the background
*/
void SkyboxBackground::Draw(const AbstractViewer* viewer) const void SkyboxBackground::Draw(const AbstractViewer* viewer) const
{ {
Matrix4f skyboxMatrix(viewer->GetViewMatrix()); Matrix4f skyboxMatrix(viewer->GetViewMatrix());
@ -65,14 +83,26 @@ namespace Nz
Renderer::SetMatrix(MatrixType_View, viewer->GetViewMatrix()); Renderer::SetMatrix(MatrixType_View, viewer->GetViewMatrix());
} }
/*!
* \brief Gets the background type
* \return Type of background
*/
BackgroundType SkyboxBackground::GetBackgroundType() const BackgroundType SkyboxBackground::GetBackgroundType() const
{ {
return BackgroundType_Skybox; return BackgroundType_Skybox;
} }
/*!
* \brief Initializes the skybox
* \return true If successful
*
* \remark Produces a NazaraError if initialization failed
*/
bool SkyboxBackground::Initialize() bool SkyboxBackground::Initialize()
{ {
const UInt16 indices[6*6] = const UInt16 indices[6 * 6] =
{ {
0, 1, 2, 0, 2, 3, 0, 1, 2, 0, 2, 3,
3, 2, 6, 3, 6, 7, 3, 2, 6, 3, 6, 7,
@ -170,6 +200,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the skybox
*/
void SkyboxBackground::Uninitialize() void SkyboxBackground::Uninitialize()
{ {
s_indexBuffer.Reset(); s_indexBuffer.Reset();

View File

@ -11,6 +11,19 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::Sprite
* \brief Graphics class that represents the rendering of a sprite
*/
/*!
* \brief Adds the sprite to the rendering queue
*
* \param renderQueue Queue to be added
* \param instanceData Data for the instance
*/
void Sprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const void Sprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
if (!m_material) if (!m_material)
@ -20,11 +33,21 @@ namespace Nz
renderQueue->AddSprites(instanceData.renderOrder, m_material, vertices, 1); renderQueue->AddSprites(instanceData.renderOrder, m_material, vertices, 1);
} }
/*!
* \brief Makes the bounding volume of this text
*/
void Sprite::MakeBoundingVolume() const void Sprite::MakeBoundingVolume() const
{ {
m_boundingVolume.Set(Vector3f(0.f), m_size.x*Vector3f::Right() + m_size.y*Vector3f::Down()); m_boundingVolume.Set(Vector3f(0.f), m_size.x*Vector3f::Right() + m_size.y*Vector3f::Down());
} }
/*!
* \brief Updates the data of the sprite
*
* \param instanceData Data of the instance
*/
void Sprite::UpdateData(InstanceData* instanceData) const void Sprite::UpdateData(InstanceData* instanceData) const
{ {
instanceData->data.resize(4 * sizeof(VertexStruct_XYZ_Color_UV)); instanceData->data.resize(4 * sizeof(VertexStruct_XYZ_Color_UV));
@ -51,6 +74,13 @@ namespace Nz
*texCoordPtr++ = m_textureCoords.GetCorner(RectCorner_RightBottom); *texCoordPtr++ = m_textureCoords.GetCorner(RectCorner_RightBottom);
} }
/*!
* \brief Initializes the sprite librairies
* \return true If successful
*
* \remark Produces a NazaraError if the sprite library failed to be initialized
*/
bool Sprite::Initialize() bool Sprite::Initialize()
{ {
if (!SpriteLibrary::Initialize()) if (!SpriteLibrary::Initialize())
@ -62,6 +92,10 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Uninitializes the sprite librairies
*/
void Sprite::Uninitialize() void Sprite::Uninitialize()
{ {
SpriteLibrary::Uninitialize(); SpriteLibrary::Uninitialize();

View File

@ -13,6 +13,19 @@
namespace Nz namespace Nz
{ {
/*!
* \ingroup graphics
* \class Nz::TextSprite
* \brief Graphics class that represents the rendering of a sprite containing text
*/
/*!
* \brief Adds the text to the rendering queue
*
* \param renderQueue Queue to be added
* \param instanceData Data for the instance
*/
void TextSprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const void TextSprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{ {
if (!m_material) if (!m_material)
@ -26,11 +39,19 @@ namespace Nz
if (indices.count > 0) if (indices.count > 0)
{ {
const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<const VertexStruct_XYZ_Color_UV*>(instanceData.data.data()); const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<const VertexStruct_XYZ_Color_UV*>(instanceData.data.data());
renderQueue->AddSprites(instanceData.renderOrder, m_material, &vertices[indices.first*4], indices.count, overlay); renderQueue->AddSprites(instanceData.renderOrder, m_material, &vertices[indices.first * 4], indices.count, overlay);
} }
} }
} }
/*!
* \brief Updates the text
*
* \param drawer Drawer used to compose the text
*
* \remark Produces a NazaraAssert if atlas does not use a hardware storage
*/
void TextSprite::Update(const AbstractTextDrawer& drawer) void TextSprite::Update(const AbstractTextDrawer& drawer)
{ {
CallOnExit clearOnFail([this]() CallOnExit clearOnFail([this]()
@ -138,8 +159,8 @@ namespace Nz
// First, compute the uv coordinates from our atlas rect // First, compute the uv coordinates from our atlas rect
Vector2ui size(texture->GetSize()); Vector2ui size(texture->GetSize());
float invWidth = 1.f/size.x; float invWidth = 1.f / size.x;
float invHeight = 1.f/size.y; float invHeight = 1.f / size.y;
Rectf uvRect(glyph.atlasRect); Rectf uvRect(glyph.atlasRect);
uvRect.x *= invWidth; uvRect.x *= invWidth;
@ -155,9 +176,9 @@ namespace Nz
for (unsigned int j = 0; j < 4; ++j) for (unsigned int j = 0; j < 4; ++j)
{ {
// Remember that indices->count is a counter here, not a count value // Remember that indices->count is a counter here, not a count value
m_localVertices[indices->count*4 + j].color = glyph.color; m_localVertices[indices->count * 4 + j].color = glyph.color;
m_localVertices[indices->count*4 + j].position.Set(glyph.corners[j]); m_localVertices[indices->count * 4 + j].position.Set(glyph.corners[j]);
m_localVertices[indices->count*4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j])); m_localVertices[indices->count * 4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j]));
} }
// Increment the counter, go to next glyph // Increment the counter, go to next glyph
@ -172,15 +193,25 @@ namespace Nz
clearOnFail.Reset(); clearOnFail.Reset();
} }
/*
* \brief Makes the bounding volume of this text
*/
void TextSprite::MakeBoundingVolume() const void TextSprite::MakeBoundingVolume() const
{ {
Rectf bounds(m_localBounds); Rectf bounds(m_localBounds);
Vector2f max = bounds.GetMaximum(); Vector2f max = bounds.GetMaximum();
Vector2f min = bounds.GetMinimum(); Vector2f min = bounds.GetMinimum();
m_boundingVolume.Set(min.x*Vector3f::Right() + min.y*Vector3f::Down(), max.x*Vector3f::Right() + max.y*Vector3f::Down()); m_boundingVolume.Set(min.x * Vector3f::Right() + min.y * Vector3f::Down(), max.x * Vector3f::Right() + max.y * Vector3f::Down());
} }
/*!
* \brief Handle the invalidation of an atlas
*
* \param atlas Atlas being invalidated
*/
void TextSprite::OnAtlasInvalidated(const AbstractAtlas* atlas) void TextSprite::OnAtlasInvalidated(const AbstractAtlas* atlas)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -195,6 +226,14 @@ namespace Nz
Clear(); Clear();
} }
/*!
* \brief Handle the invalidation of an atlas layer
*
* \param atlas Atlas being invalidated
* \param oldLayer Pointer to the previous layer
* \param newLayer Pointer to the new layer
*/
void TextSprite::OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer) void TextSprite::OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer)
{ {
NazaraUnused(atlas); NazaraUnused(atlas);
@ -207,23 +246,23 @@ namespace Nz
} }
#endif #endif
// La texture d'un atlas vient d'être recréée (changement de taille) // The texture of an atlas have just been recreated (size change)
// nous devons ajuster les coordonnées de textures et la texture du rendu // we have to adjust the coordinates of the texture and the rendering texture
Texture* oldTexture = static_cast<Texture*>(oldLayer); Texture* oldTexture = static_cast<Texture*>(oldLayer);
Texture* newTexture = static_cast<Texture*>(newLayer); Texture* newTexture = static_cast<Texture*>(newLayer);
// Il est possible que nous n'utilisions pas la texture en question (l'atlas nous prévenant pour chacun de ses layers) // It is possible that we don't use the texture (the atlas warning us for each of its layers)
auto it = m_renderInfos.find(oldTexture); auto it = m_renderInfos.find(oldTexture);
if (it != m_renderInfos.end()) if (it != m_renderInfos.end())
{ {
// Nous utilisons bien cette texture, nous devons mettre à jour les coordonnées de texture // We indeed use this texture, we have to update its coordinates
RenderIndices indices = std::move(it->second); RenderIndices indices = std::move(it->second);
Vector2ui oldSize(oldTexture->GetSize()); Vector2ui oldSize(oldTexture->GetSize());
Vector2ui newSize(newTexture->GetSize()); Vector2ui newSize(newTexture->GetSize());
Vector2f scale = Vector2f(oldSize)/Vector2f(newSize); // ratio ancienne et nouvelle taille Vector2f scale = Vector2f(oldSize) / Vector2f(newSize); // ratio of the old one to the new one
// On va maintenant parcourir toutes les coordonnées de texture concernées pour les multiplier par ce ratio // Now we will iterate through each coordinates of the concerned texture to multiply them by the ratio
SparsePtr<Vector2f> texCoordPtr(&m_localVertices[indices.first].uv, sizeof(VertexStruct_XYZ_Color_UV)); SparsePtr<Vector2f> texCoordPtr(&m_localVertices[indices.first].uv, sizeof(VertexStruct_XYZ_Color_UV));
for (unsigned int i = 0; i < indices.count; ++i) for (unsigned int i = 0; i < indices.count; ++i)
{ {
@ -231,12 +270,18 @@ namespace Nz
m_localVertices[i*4 + j].uv *= scale; m_localVertices[i*4 + j].uv *= scale;
} }
// Nous enlevons l'ancienne texture et rajoutons la nouvelle à sa place (pour les mêmes indices) // We get rid off the old texture and we set the new one at the place (same for indices)
m_renderInfos.erase(it); m_renderInfos.erase(it);
m_renderInfos.insert(std::make_pair(newTexture, std::move(indices))); m_renderInfos.insert(std::make_pair(newTexture, std::move(indices)));
} }
} }
/*!
* \brief Updates the data of the sprite
*
* \param instanceData Data of the instance
*/
void TextSprite::UpdateData(InstanceData* instanceData) const void TextSprite::UpdateData(InstanceData* instanceData) const
{ {
instanceData->data.resize(m_localVertices.size() * sizeof(VertexStruct_XYZ_Color_UV)); instanceData->data.resize(m_localVertices.size() * sizeof(VertexStruct_XYZ_Color_UV));
@ -246,18 +291,18 @@ namespace Nz
SparsePtr<Vector3f> posPtr(&vertices[0].position, sizeof(VertexStruct_XYZ_Color_UV)); SparsePtr<Vector3f> posPtr(&vertices[0].position, sizeof(VertexStruct_XYZ_Color_UV));
SparsePtr<Vector2f> texCoordPtr(&vertices[0].uv, sizeof(VertexStruct_XYZ_Color_UV)); SparsePtr<Vector2f> texCoordPtr(&vertices[0].uv, sizeof(VertexStruct_XYZ_Color_UV));
// Nous allons maintenant initialiser les sommets finaux (ceux envoyés à la RenderQueue) // We will not initialize the final vertices (those send to the RenderQueue)
// à l'aide du repère, de la matrice et de notre attribut de couleur // With the help of the coordinates axis, the matrix and our color attribute
for (auto& pair : m_renderInfos) for (auto& pair : m_renderInfos)
{ {
RenderIndices& indices = pair.second; RenderIndices& indices = pair.second;
if (indices.count == 0) if (indices.count == 0)
continue; //< Ignore empty render indices continue; //< Ignore empty render indices
SparsePtr<Color> color = colorPtr + indices.first*4; SparsePtr<Color> color = colorPtr + indices.first * 4;
SparsePtr<Vector3f> pos = posPtr + indices.first*4; SparsePtr<Vector3f> pos = posPtr + indices.first * 4;
SparsePtr<Vector2f> uv = texCoordPtr + indices.first*4; SparsePtr<Vector2f> uv = texCoordPtr + indices.first * 4;
VertexStruct_XY_Color_UV* localVertex = &m_localVertices[indices.first*4]; VertexStruct_XY_Color_UV* localVertex = &m_localVertices[indices.first * 4];
for (unsigned int i = 0; i < indices.count; ++i) for (unsigned int i = 0; i < indices.count; ++i)
{ {
for (unsigned int j = 0; j < 4; ++j) for (unsigned int j = 0; j < 4; ++j)

View File

@ -11,6 +11,11 @@ namespace Nz
{ {
namespace namespace
{ {
/*!
* \brief Defines render states
* \return RenderStates for the color background
*/
RenderStates BuildRenderStates() RenderStates BuildRenderStates()
{ {
RenderStates states; RenderStates states;
@ -24,6 +29,18 @@ namespace Nz
} }
} }
/*!
* \ingroup graphics
* \class Nz::TextureBackground
* \brief Graphics class that represents a background with a texture
*/
/*!
* \brief Constructs a TextureBackground object with a texture
*
* \param texture Texture
*/
TextureBackground::TextureBackground(TextureRef texture) TextureBackground::TextureBackground(TextureRef texture)
{ {
m_uberShader = UberShaderLibrary::Get("Basic"); m_uberShader = UberShaderLibrary::Get("Basic");
@ -43,6 +60,12 @@ namespace Nz
SetTexture(std::move(texture)); SetTexture(std::move(texture));
} }
/*!
* \brief Draws this relatively to the viewer
*
* \param viewer Viewer for the background
*/
void TextureBackground::Draw(const AbstractViewer* viewer) const void TextureBackground::Draw(const AbstractViewer* viewer) const
{ {
NazaraUnused(viewer); NazaraUnused(viewer);
@ -62,6 +85,11 @@ namespace Nz
Renderer::DrawFullscreenQuad(); Renderer::DrawFullscreenQuad();
} }
/*!
* \brief Gets the background type
* \return Type of background
*/
BackgroundType TextureBackground::GetBackgroundType() const BackgroundType TextureBackground::GetBackgroundType() const
{ {
return BackgroundType_Texture; return BackgroundType_Texture;

View File

@ -0,0 +1,34 @@
#include <Nazara/Graphics/Billboard.hpp>
#include <Catch/catch.hpp>
SCENARIO("Billboard", "[GRAPHICS][BILLBOARD]")
{
GIVEN("A default billboard")
{
Nz::Billboard billboard;
WHEN("We assign it to another")
{
Nz::MaterialRef materialRef = Nz::Material::New();
materialRef->LoadFromFile("resources/Engine/Graphics/Nazara.png");
Nz::Color materialColor = materialRef->GetDiffuseColor();
Nz::BillboardRef otherBillboard = Nz::Billboard::New(materialRef);
billboard = *otherBillboard;
THEN("The old one has the same properties than the new one")
{
REQUIRE(billboard.GetColor() == materialColor);
REQUIRE(billboard.GetMaterial().Get() == materialRef.Get());
REQUIRE(billboard.GetRotation() == Approx(0.f));
REQUIRE(billboard.GetSize() == Nz::Vector2f(64.f, 64.f)); // Default sizes
}
THEN("We set it with our new material and ask for its real size")
{
billboard.SetMaterial(materialRef, true);
REQUIRE(billboard.GetSize() == Nz::Vector2f(765.f, 212.f)); // Nazara.png sizes
}
}
}
}

View File

@ -0,0 +1,20 @@
#include <Nazara/Graphics/ColorBackground.hpp>
#include <Catch/catch.hpp>
SCENARIO("ColorBackground", "[GRAPHICS][COLORBACKGROUND]")
{
GIVEN("A default color background")
{
Nz::ColorBackground colorBackground;
WHEN("We assign it a color")
{
colorBackground.SetColor(Nz::Color::Red);
THEN("We can get it")
{
REQUIRE(colorBackground.GetColor() == Nz::Color::Red);
}
}
}
}

View File

@ -0,0 +1,29 @@
#include <Nazara/Graphics/DeferredRenderTechnique.hpp>
#include <Catch/catch.hpp>
SCENARIO("DeferredRenderTechnique", "[GRAPHICS][DEFERREDRENDERTECHNIQUE]")
{
GIVEN("A default deferred render technique")
{
Nz::DeferredRenderTechnique deferredRenderTechnique;
WHEN("We can disable a pass")
{
REQUIRE(deferredRenderTechnique.IsPassEnabled(Nz::RenderPassType::RenderPassType_AA, 0));
deferredRenderTechnique.EnablePass(Nz::RenderPassType::RenderPassType_AA, 0, false);
THEN("It is disabled")
{
REQUIRE(!deferredRenderTechnique.IsPassEnabled(Nz::RenderPassType::RenderPassType_AA, 0));
}
AND_THEN("We reset it, it is disabled and not the same as the old one")
{
Nz::DeferredRenderPass* oldPass = deferredRenderTechnique.GetPass(Nz::RenderPassType::RenderPassType_AA, 0);
deferredRenderTechnique.ResetPass(Nz::RenderPassType::RenderPassType_AA, 0);
REQUIRE(!deferredRenderTechnique.IsPassEnabled(Nz::RenderPassType::RenderPassType_AA, 0));
REQUIRE(deferredRenderTechnique.GetPass(Nz::RenderPassType::RenderPassType_AA, 0) != oldPass);
}
}
}
}

View File

@ -0,0 +1,31 @@
#include <Nazara/Graphics/Light.hpp>
#include <Catch/catch.hpp>
SCENARIO("Light", "[GRAPHICS][LIGHT]")
{
GIVEN("Different light")
{
Nz::Light directionalLight(Nz::LightType_Directional);
Nz::Light pointLight(Nz::LightType_Point);
Nz::Light spotLight(Nz::LightType_Spot);
WHEN("We try to cull")
{
Nz::Frustumf frustum;
frustum.Build(90.f, 16.f / 9.f, 1.f, 1000.f, Nz::Vector3f::Zero(), Nz::Vector3f::UnitX());
Nz::Matrix4f Unit3InX = Nz::Matrix4f::Translate(Nz::Vector3f::UnitX() * 3.f);
Nz::Matrix4f rotationTowardsY = Unit3InX * Nz::Matrix4f::Rotate(Nz::EulerAnglesf(Nz::FromDegrees(90.f), 0.f, 0.f).ToQuaternion());
THEN("These results are expected")
{
REQUIRE(directionalLight.Cull(frustum, Unit3InX));
REQUIRE(pointLight.Cull(frustum, Unit3InX));
REQUIRE(!spotLight.Cull(frustum, Unit3InX));
REQUIRE(directionalLight.Cull(frustum, rotationTowardsY));
REQUIRE(pointLight.Cull(frustum, rotationTowardsY));
REQUIRE(!spotLight.Cull(frustum, rotationTowardsY));
}
}
}
}

View File

@ -0,0 +1,24 @@
#include <Nazara/Graphics/Model.hpp>
#include <Catch/catch.hpp>
SCENARIO("Model", "[GRAPHICS][MODEL]")
{
GIVEN("The standford dragon model")
{
WHEN("We get general informations")
{
THEN("These results are expected")
{
Nz::ModelRef model = Nz::Model::New();
REQUIRE(model->LoadFromFile("resources/Engine/Graphics/dragon_recon/dragon_vrip_res4.obj"));
REQUIRE(model->GetMaterialCount() == 2);
REQUIRE(model->GetSkin() == 0);
REQUIRE(model->GetSkinCount() == 1);
Nz::Material* material = model->GetMaterial(0);
REQUIRE(material->GetAmbientColor() == Nz::Color(128));
}
}
}
}

View File

@ -0,0 +1,29 @@
#include <Nazara/Graphics/ParticleDeclaration.hpp>
#include <Catch/catch.hpp>
SCENARIO("ParticleDeclaration", "[GRAPHICS][PARTICLEDECLARATION]")
{
GIVEN("A particle declaration of a model")
{
Nz::ParticleDeclaration* particleDeclaration = Nz::ParticleDeclaration::Get(Nz::ParticleLayout_Model);
WHEN("We disable a component")
{
bool enabled;
Nz::ComponentType type;
unsigned int offset;
particleDeclaration->GetComponent(Nz::ParticleComponent_Position, &enabled, &type, &offset);
REQUIRE(enabled);
unsigned int oldStride = particleDeclaration->GetStride();
particleDeclaration->DisableComponent(Nz::ParticleComponent_Position);
REQUIRE(oldStride != particleDeclaration->GetStride());
THEN("We can enable it and the stride is back")
{
particleDeclaration->EnableComponent(Nz::ParticleComponent_Position, type, offset);
REQUIRE(oldStride == particleDeclaration->GetStride());
}
}
}
}

View File

@ -0,0 +1,103 @@
#include <Nazara/Graphics/ParticleSystem.hpp>
#include <Catch/catch.hpp>
#include <Nazara/Core/SparsePtr.hpp>
#include <Nazara/Graphics/ParticleMapper.hpp>
class TestParticleController : public Nz::ParticleController
{
public:
// Be aware that the interval is [startId, endId] and NOT [startId, endId)
void Apply(Nz::ParticleSystem& system, Nz::ParticleMapper& mapper, unsigned int startId, unsigned int endId, float elapsedTime) override
{
Nz::SparsePtr<Nz::Vector3f> positionPtr = mapper.GetComponentPtr<Nz::Vector3f>(Nz::ParticleComponent_Position);
Nz::SparsePtr<Nz::Vector3f> velocityPtr = mapper.GetComponentPtr<Nz::Vector3f>(Nz::ParticleComponent_Velocity);
Nz::SparsePtr<float> lifePtr = mapper.GetComponentPtr<float>(Nz::ParticleComponent_Life);
for (unsigned int i = startId; i <= endId; ++i)
{
Nz::Vector3f& particlePosition = positionPtr[i];
Nz::Vector3f& particleVelocity = velocityPtr[i];
float& particleLife = lifePtr[i];
particleLife -= elapsedTime;
if (particleLife <= 0.f)
system.KillParticle(i);
}
}
};
class TestParticleEmitter : public Nz::ParticleEmitter
{
public:
~TestParticleEmitter() override = default;
void Emit(Nz::ParticleSystem& system, float elapsedTime) const override
{
system.GenerateParticles(GetEmissionCount());
}
private:
void SetupParticles(Nz::ParticleMapper& mapper, unsigned int count) const override
{
}
};
class TestParticleGenerator : public Nz::ParticleGenerator
{
public:
~TestParticleGenerator() override = default;
// Be aware that the interval is [startId, endId] and NOT [startId, endId)
void Generate(Nz::ParticleSystem& system, Nz::ParticleMapper& mapper, unsigned int startId, unsigned int endId) override
{
Nz::SparsePtr<Nz::Vector3f> positionPtr = mapper.GetComponentPtr<Nz::Vector3f>(Nz::ParticleComponent_Position);
Nz::SparsePtr<Nz::Vector3f> velocityPtr = mapper.GetComponentPtr<Nz::Vector3f>(Nz::ParticleComponent_Velocity);
Nz::SparsePtr<float> lifePtr = mapper.GetComponentPtr<float>(Nz::ParticleComponent_Life);
for (unsigned int i = startId; i <= endId; ++i)
{
Nz::Vector3f& particlePosition = positionPtr[i];
Nz::Vector3f& particleVelocity = velocityPtr[i];
float& particleLife = lifePtr[i];
particlePosition = Nz::Vector3f::Zero();
particleVelocity = Nz::Vector3f::UnitX();
particleLife = 1.3f;
}
}
};
SCENARIO("ParticleSystem", "[GRAPHICS][PARTICLESYSTEM]")
{
GIVEN("A particle system of maximum 10 billboards with its generators")
{
// These need to be alive longer than the particle system
TestParticleController particleController;
TestParticleGenerator particleGenerator;
Nz::ParticleSystem particleSystem(10, Nz::ParticleLayout_Billboard);
particleSystem.AddController(&particleController);
TestParticleEmitter particleEmitter;
particleEmitter.SetEmissionCount(10);
particleSystem.AddEmitter(&particleEmitter);
particleSystem.AddGenerator(&particleGenerator);
WHEN("We update to generate 10 particles")
{
particleSystem.Update(1.f);
THEN("There must be 10 particles")
{
REQUIRE(particleSystem.GetParticleCount() == 10);
}
AND_THEN("We update to make them die")
{
particleSystem.Update(2.f);
REQUIRE(particleSystem.GetParticleCount() == 0);
}
}
}
}

View File

@ -0,0 +1,47 @@
#include <Nazara/Graphics/RenderTechniques.hpp>
#include <Catch/catch.hpp>
#include <Nazara/Graphics/AbstractRenderTechnique.hpp>
#include <Nazara/Graphics/ForwardRenderTechnique.hpp>
SCENARIO("RenderTechniques", "[GRAPHICS][RENDERTECHNIQUES]")
{
GIVEN("Nothing")
{
WHEN("We try to get a technique")
{
THEN("We should get it")
{
std::unique_ptr<Nz::AbstractRenderTechnique> forwardByEnum(Nz::RenderTechniques::GetByEnum(Nz::RenderTechniqueType_BasicForward));
REQUIRE(forwardByEnum->GetType() == Nz::RenderTechniqueType_BasicForward);
std::unique_ptr<Nz::AbstractRenderTechnique> forwardByIndex(Nz::RenderTechniques::GetByIndex(1));
REQUIRE(forwardByIndex->GetType() == Nz::RenderTechniqueType_BasicForward);
std::unique_ptr<Nz::AbstractRenderTechnique> forwardByName(Nz::RenderTechniques::GetByName(Nz::RenderTechniques::ToString(Nz::RenderTechniqueType_BasicForward)));
REQUIRE(forwardByName->GetType() == Nz::RenderTechniqueType_BasicForward);
}
THEN("We can register a render technique")
{
unsigned int previousCount = Nz::RenderTechniques::GetCount();
Nz::RenderTechniques::Register("test", 23, []() -> Nz::AbstractRenderTechnique* {
return new Nz::ForwardRenderTechnique;
});
REQUIRE(previousCount < Nz::RenderTechniques::GetCount());
std::unique_ptr<Nz::AbstractRenderTechnique> forwardByRanking(Nz::RenderTechniques::GetByRanking(23));
REQUIRE(forwardByRanking->GetType() == Nz::RenderTechniqueType_BasicForward);
std::unique_ptr<Nz::AbstractRenderTechnique> forwardByName(Nz::RenderTechniques::GetByName("test"));
REQUIRE(forwardByName->GetType() == Nz::RenderTechniqueType_BasicForward);
Nz::RenderTechniques::Unregister("test");
REQUIRE(previousCount == Nz::RenderTechniques::GetCount());
}
}
}
}

View File

@ -0,0 +1,26 @@
#include <Nazara/Graphics/SkeletalModel.hpp>
#include <Catch/catch.hpp>
SCENARIO("SkeletalModel", "[GRAPHICS][SKELETALMODEL]")
{
GIVEN("A default skeletal model")
{
Nz::SkeletalModel skeletalModel;
Nz::AnimationRef animation = Nz::Animation::New();
WHEN("We can load the bob lamp")
{
REQUIRE(skeletalModel.LoadFromFile("resources/Engine/Graphics/Bob lamp/bob_lamp_update.md5mesh"));
REQUIRE(animation->LoadFromFile("resources/Engine/Graphics/Bob lamp/bob_lamp_update.md5anim"));
skeletalModel.SetAnimation(animation);
THEN("We can enable its animation")
{
REQUIRE(skeletalModel.HasAnimation());
skeletalModel.EnableAnimation(true);
skeletalModel.AdvanceAnimation(0.10f);
REQUIRE(skeletalModel.IsAnimationEnabled());
}
}
}
}

View File

@ -0,0 +1,25 @@
#include <Nazara/Graphics/SkyboxBackground.hpp>
#include <Catch/catch.hpp>
SCENARIO("SkyboxBackground", "[GRAPHICS][SKYBOXBACKGROUND]")
{
GIVEN("A skybox background with a loaded image")
{
Nz::TextureRef textureRef = Nz::Texture::New();
textureRef->LoadCubemapFromFile("resources/Engine/Graphics/skybox.png");
Nz::SkyboxBackgroundRef skyboxBackgroundRef = Nz::SkyboxBackground::New(textureRef);
WHEN("We assign it parameters")
{
skyboxBackgroundRef->SetMovementOffset(Nz::Vector3f::Unit());
skyboxBackgroundRef->SetMovementScale(1.f);
THEN("We can get it")
{
REQUIRE(skyboxBackgroundRef->GetMovementOffset() == Nz::Vector3f::Unit());
REQUIRE(skyboxBackgroundRef->GetMovementScale() == Approx(1.f));
REQUIRE(skyboxBackgroundRef->GetTexture().Get() == textureRef.Get());
}
}
}
}

View File

@ -0,0 +1,20 @@
#include <Nazara/Graphics/TextureBackground.hpp>
#include <Catch/catch.hpp>
SCENARIO("TextureBackground", "[GRAPHICS][TEXTUREBACKGROUND]")
{
GIVEN("A default texture background")
{
Nz::TextureRef textureRef = Nz::Texture::New();
textureRef->LoadFromFile("resources/Engine/Graphics/skybox.png");
Nz::TextureBackgroundRef textureBackgroundRef = Nz::TextureBackground::New(textureRef);
WHEN("We assign it parameters")
{
THEN("We can get it")
{
REQUIRE(textureBackgroundRef->GetTexture().Get() == textureRef.Get());
}
}
}
}

View File

@ -39,14 +39,14 @@ SCENARIO("Sphere", "[MATH][SPHERE]")
WHEN("We ask for distance") WHEN("We ask for distance")
{ {
THEN("These results are expected") THEN("These results are expected because we don't take into account the border")
{ {
REQUIRE(firstCenterAndUnit.Distance(Nz::Vector3f::UnitX()) == Approx(1.f)); REQUIRE(firstCenterAndUnit.Distance(Nz::Vector3f::UnitX() * 2.f) == Approx(1.f));
REQUIRE(firstCenterAndUnit.SquaredDistance(Nz::Vector3f::UnitX()) == Approx(1.f)); REQUIRE(firstCenterAndUnit.SquaredDistance(Nz::Vector3f::UnitX() * 2.f) == Approx(1.f));
Nz::Spheref tmp(Nz::Vector3f::UnitX(), 1.f); Nz::Spheref tmp(Nz::Vector3f::UnitX(), 1.f);
REQUIRE(tmp.Distance(Nz::Vector3f::UnitX() * 4.f) == Approx(3.f)); REQUIRE(tmp.Distance(Nz::Vector3f::UnitX() * 4.f) == Approx(2.f));
REQUIRE(tmp.SquaredDistance(Nz::Vector3f::UnitX() * 4.f) == Approx(9.f)); REQUIRE(tmp.SquaredDistance(Nz::Vector3f::UnitX() * 4.f) == Approx(4.f));
} }
} }
@ -84,7 +84,7 @@ SCENARIO("Sphere", "[MATH][SPHERE]")
THEN("Sphere must contain it and distance should be good") THEN("Sphere must contain it and distance should be good")
{ {
CHECK(firstCenterAndUnit.Contains(point)); CHECK(firstCenterAndUnit.Contains(point));
REQUIRE(firstCenterAndUnit.Distance(point) == 2.f); REQUIRE(firstCenterAndUnit.Distance(point) == 1.f);
} }
} }

View File

@ -1,2 +1,16 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_RUNNER
#include <Catch/catch.hpp> #include <Catch/catch.hpp>
#include <Nazara/Audio/Audio.hpp>
#include <Nazara/Core/Core.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Network/Network.hpp>
int main(int argc, char* const argv[])
{
Nz::Initializer<Nz::Audio, Nz::Core, Nz::Graphics, Nz::Network> modules;
int result = Catch::Session().run(argc, argv);
return result;
}

View File

@ -0,0 +1,24 @@
#############################
MD5 sample mesh and animation
#############################
INFORMATION & USAGE
===================
File includes *.blend source files and TGA format textures for MD5 animated mesh testing.
For extensive information and usage instructions visit http://www.katsbits.com/smforum/index.php?topic=178.0
- bob_lamp_update.blend contain mesh and armature as would be prior to preparation for export.
- bob_lamp_update_export contains triangulated mesh ready for export.
NOTES
=====
Included files are for use in **Blender 2.69** or above; opening files in older versions may result in errors dues to internal differences between Blender versions.
Files and media are provided "as is" without any warranties of functionality.
COPYRIGHT & DISTRIBUTION
========================
Copyright © 2014 KatsBits. All Rights Reserved.
For more information visit http://www.katsbits.com/ or email info@katsbits.com
For NON-COMMERCIAL USE ONLY. This file and/or its contents and/or associated materials may not be reproduced, duplicated, distributed or otherwise 'monetised' without prior consent.
Contact info@katsbits.com or visit http://copyright.katsbits.com/ for further details regarding this material and/or distribution/copyright.

View File

@ -0,0 +1,82 @@
skybox.png
https://commons.wikimedia.org/wiki/File:Skybox_example.png
Original file:
Skybox example.ogg (Ogg Vorbis sound file, length 1 min 3 s, 378 kbps)
Summary:
Description: English: An example of a skybox and how the faces can be aligned
Date: 8 June 2011
Source: Own work
Author: Creator:Arieee
Description: The Belgian national anthem (instrumental version) performed by the United States Navy Band. Direct link is at http://www.navyband.navy.mil/anthems/ANTHEMS/Belgium.mp3.
Date: 19 October 2004
Source: http://www.navyband.navy.mil/anthems/national_anthems.htm
Author: United States Navy Band (rendition), uploaded to Wikimedia by Keith Lehwald
Licencing:
This file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license.
You are free:
to share to copy, distribute and transmit the work
to remix to adapt the work
Under the following conditions:
attribution You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
share alike If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
-------------------------------------------------------------------------------------------------
Bob lamp
http://www.katsbits.com/download/models/md5-example.php
Original file:
bob_lamp_update.zip (Animated MD5 sample file)
Summary:
Description: Updated version of "Bob", a low-poly character mesh for general export and testing of MD5 mesh and animation - "*.md5mesh" and "*.md5anim". File and it's contents should be opened in Blender 2.69 or above to avoid compatibility issues with older versions of Blender and/or resulting MD5 exports (md5mesh & md5anim).
File includes two versions of the source file, one 'working' - mesh is intact with surfaces in 'quad' form; and one 'prepped' (exported) - mesh has been tessilated (triangulated) for export.
Date: Januari 2014
Source: http://www.katsbits.com/download/models/md5-example.php
Author: KatsBits
Licencing:
Please, refer to "Bob lamp/Readme.txt" file.
-------------------------------------------------------------------------------------------------
Standford dragon
http://graphics.stanford.edu/data/3Dscanrep/
Original file:
dragon_recon.tar.gz (PLY files)
Summary:
Dragon
Source: Stanford University Computer Graphics Laboratory
Scanner: Cyberware 3030 MS + spacetime analysis
Number of scans: ~70
Total size of scans: 2,748,318 points (about 5,500,000 triangles)
Reconstruction: vrip (conservatively decimated)
Size of reconstruction: 566,098 vertices, 1,132,830 triangles
Comments: contains numerous small holes
Date: 1996
Source: http://graphics.stanford.edu/data/3Dscanrep/
Author: Stanford University Computer Graphics Laboratory
Licencing:
Please be sure to acknowledge the source of the data and models you take from this repository. In each of the listings below, we have cited the source of the range data and reconstructed models. You are welcome to use the data and models for research purposes. You are also welcome to mirror or redistribute them for free. Finally, you may publish images made using these models, or the images on this web site, in a scholarly article or book - as long as credit is given to the Stanford Computer Graphics Laboratory. However, such models or images are not to be used for commercial purposes, nor should they appear in a product for sale (with the exception of scholarly journals or books), without our permission.
Please, refer to "dragon_recon/README" file.

View File

@ -0,0 +1,27 @@
Surface Reconstructions
Stanford Range Repository
Computer Graphics Laboratory
Stanford University
August 4, 1996
These files are the result of reconstructing a set of range images
using the "vrip" program. The first file is the high resolution
result, while the "_res*" files are decimated versions. Note that
these decimations were performed using a crude algorithm that does not
necessarily preserve mesh topology. While they are not beautiful,
they are suitable for interactive rendering.
Note that this model is a decimated version of the original which was
constructed at the voxel resolution of 0.35 mm. The original model
has no holes in it, however, the decimated model has some holes that
we detected with software, but not by inspection. Apparently, the
decimation software introduced these holes.
For more information, consult the web pages of the Stanford Graphics
Laboratory:
http://www-graphics.stanford.edu