Documentation for module: Graphics
Former-commit-id: 1757c33318443aade1dc38e16d053240d7dc885c
This commit is contained in:
@@ -7,6 +7,14 @@
|
||||
|
||||
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;
|
||||
|
||||
BackgroundLibrary::LibraryMap AbstractBackground::s_library;
|
||||
|
||||
@@ -7,23 +7,55 @@
|
||||
|
||||
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;
|
||||
|
||||
/*!
|
||||
* \brief Adds a directional light to the rendering queue
|
||||
*
|
||||
* \param light Directional light
|
||||
*/
|
||||
|
||||
void AbstractRenderQueue::AddDirectionalLight(const DirectionalLight& light)
|
||||
{
|
||||
directionalLights.push_back(light);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a point light to the rendering queue
|
||||
*
|
||||
* \param light Point light
|
||||
*/
|
||||
|
||||
void AbstractRenderQueue::AddPointLight(const PointLight& light)
|
||||
{
|
||||
pointLights.push_back(light);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a spot light to the rendering queue
|
||||
*
|
||||
* \param light Spot light
|
||||
*/
|
||||
|
||||
void AbstractRenderQueue::AddSpotLight(const SpotLight& light)
|
||||
{
|
||||
spotLights.push_back(light);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears the rendering queue
|
||||
*
|
||||
* \param fully Should everything be cleared ?
|
||||
*/
|
||||
|
||||
void AbstractRenderQueue::Clear(bool fully)
|
||||
{
|
||||
NazaraUnused(fully);
|
||||
|
||||
@@ -10,6 +10,18 @@
|
||||
|
||||
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() :
|
||||
m_instancingEnabled(true)
|
||||
{
|
||||
@@ -17,16 +29,34 @@ namespace Nz
|
||||
|
||||
AbstractRenderTechnique::~AbstractRenderTechnique() = default;
|
||||
|
||||
/*!
|
||||
* \brief Enables the instancing
|
||||
*
|
||||
* \param instancing Should instancing be enabled
|
||||
*
|
||||
* \remark This may improve performances
|
||||
*/
|
||||
|
||||
void AbstractRenderTechnique::EnableInstancing(bool instancing)
|
||||
{
|
||||
m_instancingEnabled = instancing;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the name of the actual technique
|
||||
* \return Name of the technique being used
|
||||
*/
|
||||
|
||||
String AbstractRenderTechnique::GetName() const
|
||||
{
|
||||
return RenderTechniques::ToString(GetType());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the instancing is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
bool AbstractRenderTechnique::IsInstancingEnabled() const
|
||||
{
|
||||
return m_instancingEnabled;
|
||||
|
||||
@@ -7,5 +7,13 @@
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,19 @@
|
||||
|
||||
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
|
||||
{
|
||||
if (!m_material)
|
||||
@@ -20,11 +33,15 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -11,6 +11,11 @@ namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
/*!
|
||||
* \brief Defines render states
|
||||
* \return RenderStates for the color background
|
||||
*/
|
||||
|
||||
RenderStates BuildRenderStates()
|
||||
{
|
||||
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) :
|
||||
m_color(color)
|
||||
{
|
||||
@@ -38,6 +55,12 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
NazaraUnused(viewer);
|
||||
@@ -55,16 +78,32 @@ namespace Nz
|
||||
Renderer::DrawFullscreenQuad();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the background type
|
||||
* \return Type of background
|
||||
*/
|
||||
|
||||
BackgroundType ColorBackground::GetBackgroundType() const
|
||||
{
|
||||
return BackgroundType_Color;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the color of the background
|
||||
* \return Background color
|
||||
*/
|
||||
|
||||
Color ColorBackground::GetColor() const
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the color of the background
|
||||
*
|
||||
* \param color Background color
|
||||
*/
|
||||
|
||||
void ColorBackground::SetColor(const Color& color)
|
||||
{
|
||||
m_color = color;
|
||||
|
||||
@@ -9,6 +9,16 @@
|
||||
|
||||
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() :
|
||||
m_uniformUpdated(false),
|
||||
m_brightLuminance(0.8f),
|
||||
@@ -32,26 +42,55 @@ namespace Nz
|
||||
|
||||
DeferredBloomPass::~DeferredBloomPass() = default;
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of pass for blur
|
||||
* \return Number of pass for blur
|
||||
*/
|
||||
|
||||
unsigned int DeferredBloomPass::GetBlurPassCount() const
|
||||
{
|
||||
return m_blurPassCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the coefficiant for luminosity
|
||||
* \return Luminosity of bright elements
|
||||
*/
|
||||
|
||||
float DeferredBloomPass::GetBrightLuminance() const
|
||||
{
|
||||
return m_brightLuminance;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the coefficiant for the middle grey
|
||||
* \return Luminosity of grey elements
|
||||
*/
|
||||
|
||||
float DeferredBloomPass::GetBrightMiddleGrey() const
|
||||
{
|
||||
return m_brightMiddleGrey;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the coefficiant for things to be bright
|
||||
* \return Threshold for bright elements
|
||||
*/
|
||||
|
||||
float DeferredBloomPass::GetBrightThreshold() const
|
||||
{
|
||||
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
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -65,7 +104,16 @@ namespace Nz
|
||||
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);
|
||||
|
||||
@@ -91,7 +139,7 @@ namespace Nz
|
||||
Renderer::DrawFullscreenQuad();
|
||||
|
||||
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);
|
||||
|
||||
@@ -124,6 +172,13 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resizes the texture sizes
|
||||
* \return true If successful
|
||||
*
|
||||
* \param dimensions Dimensions for the compute texture
|
||||
*/
|
||||
|
||||
bool DeferredBloomPass::Resize(const Vector2ui& dimensions)
|
||||
{
|
||||
DeferredRenderPass::Resize(dimensions);
|
||||
@@ -131,7 +186,7 @@ namespace Nz
|
||||
m_bloomRTT.Create(true);
|
||||
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.Unlock();
|
||||
@@ -145,23 +200,47 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the number of pass for blur
|
||||
*
|
||||
* \param passCount Number of pass for blur
|
||||
*/
|
||||
|
||||
void DeferredBloomPass::SetBlurPassCount(unsigned int passCount)
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_brightLuminance = luminance;
|
||||
m_uniformUpdated = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the coefficiant for the middle grey
|
||||
*
|
||||
* \param middleGrey Luminosity of grey elements
|
||||
*/
|
||||
|
||||
void DeferredBloomPass::SetBrightMiddleGrey(float middleGrey)
|
||||
{
|
||||
m_brightMiddleGrey = middleGrey;
|
||||
m_uniformUpdated = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the coefficiant for things to be bright
|
||||
*
|
||||
* \param threshold Threshold for bright elements
|
||||
*/
|
||||
|
||||
void DeferredBloomPass::SetBrightThreshold(float threshold)
|
||||
{
|
||||
m_brightThreshold = threshold;
|
||||
|
||||
@@ -13,6 +13,10 @@ namespace Nz
|
||||
{
|
||||
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/
|
||||
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()
|
||||
{
|
||||
m_dofShader = BuildDepthOfFieldShader();
|
||||
@@ -118,7 +132,16 @@ namespace Nz
|
||||
|
||||
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);
|
||||
|
||||
@@ -162,6 +185,13 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resizes the texture sizes
|
||||
* \return true If successful
|
||||
*
|
||||
* \param dimensions Dimensions for the compute texture
|
||||
*/
|
||||
|
||||
bool DeferredDOFPass::Resize(const Vector2ui& dimensions)
|
||||
{
|
||||
DeferredRenderPass::Resize(dimensions);
|
||||
@@ -181,5 +211,5 @@ namespace Nz
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
|
||||
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()
|
||||
{
|
||||
m_fxaaShader = ShaderLibrary::Get("DeferredFXAA");
|
||||
@@ -23,7 +33,16 @@ namespace Nz
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
|
||||
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()
|
||||
{
|
||||
m_pointSampler.SetAnisotropyLevel(1);
|
||||
@@ -34,7 +44,16 @@ namespace Nz
|
||||
|
||||
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");
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
/*!
|
||||
* \brief Builds the shader for the fog
|
||||
* \return Reference to the shader newly created
|
||||
*/
|
||||
|
||||
ShaderRef BuildFogShader()
|
||||
{
|
||||
/*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()
|
||||
{
|
||||
m_pointSampler.SetAnisotropyLevel(1);
|
||||
@@ -131,7 +146,16 @@ namespace Nz
|
||||
|
||||
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");
|
||||
|
||||
|
||||
@@ -13,9 +13,21 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::DeferredForwardPass
|
||||
* \brief Graphics class that represents the forward pass in deferred rendering
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
DeferredRenderPass::Initialize(technique);
|
||||
@@ -23,7 +35,16 @@ namespace Nz
|
||||
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");
|
||||
NazaraUnused(workTexture);
|
||||
|
||||
@@ -18,6 +18,16 @@
|
||||
|
||||
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()
|
||||
{
|
||||
m_clearShader = ShaderLibrary::Get("DeferredGBufferClear");
|
||||
@@ -31,7 +41,16 @@ namespace Nz
|
||||
|
||||
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");
|
||||
NazaraUnused(firstWorkTexture);
|
||||
@@ -72,22 +91,22 @@ namespace Nz
|
||||
|
||||
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;
|
||||
if (useInstancing)
|
||||
flags |= ShaderFlags_Instancing;
|
||||
|
||||
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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
// Ambient color for the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
@@ -105,7 +124,7 @@ namespace Nz
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
@@ -128,33 +147,33 @@ namespace Nz
|
||||
|
||||
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();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
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);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// Et on affiche
|
||||
// And we show
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sans instancing, on doit effectuer un draw call pour chaque instance
|
||||
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
|
||||
// À cause du temps de modification du buffer d'instancing
|
||||
// Without instancing, we must do one draw call for each instance
|
||||
// This may be faster than instancing under a threshold
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
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.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)
|
||||
{
|
||||
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
|
||||
{
|
||||
auto it = m_shaderUniforms.find(shader);
|
||||
@@ -260,6 +293,12 @@ namespace Nz
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a shader
|
||||
*
|
||||
* \param shader Shader being invalidated
|
||||
*/
|
||||
|
||||
void DeferredGeometryPass::OnShaderInvalidated(const Shader* shader) const
|
||||
{
|
||||
m_shaderUniforms.erase(shader);
|
||||
|
||||
@@ -13,6 +13,16 @@
|
||||
|
||||
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() :
|
||||
m_lightMeshesDrawing(false)
|
||||
{
|
||||
@@ -21,7 +31,7 @@ namespace Nz
|
||||
m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient");
|
||||
|
||||
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.factors = m_directionalLightShader->GetUniformLocation("LightFactors");
|
||||
m_directionalLightUniforms.locations.parameters1 = m_directionalLightShader->GetUniformLocation("LightDirection");
|
||||
@@ -56,16 +66,36 @@ namespace Nz
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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.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);
|
||||
|
||||
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_DepthBuffer, true);
|
||||
Renderer::Enable(RendererParameter_FaceCulling, false);
|
||||
@@ -166,7 +196,7 @@ namespace Nz
|
||||
|
||||
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_DepthBuffer, false);
|
||||
Renderer::Enable(RendererParameter_FaceCulling, true);
|
||||
@@ -192,7 +222,7 @@ namespace Nz
|
||||
Renderer::SetShader(shader);
|
||||
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);
|
||||
|
||||
Renderer::SetMatrix(MatrixType_World, lightMatrix);
|
||||
@@ -230,7 +260,7 @@ namespace Nz
|
||||
|
||||
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_DepthBuffer, true);
|
||||
Renderer::Enable(RendererParameter_FaceCulling, false);
|
||||
@@ -240,7 +270,7 @@ namespace Nz
|
||||
|
||||
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_DepthBuffer, false);
|
||||
Renderer::Enable(RendererParameter_FaceCulling, true);
|
||||
|
||||
@@ -9,6 +9,16 @@
|
||||
|
||||
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() :
|
||||
m_enabled(true)
|
||||
{
|
||||
@@ -16,11 +26,23 @@ namespace Nz
|
||||
|
||||
DeferredRenderPass::~DeferredRenderPass() = default;
|
||||
|
||||
/*!
|
||||
* \brief Enables the deferred rendering
|
||||
*
|
||||
* \param enable Should deferred rendering be activated
|
||||
*/
|
||||
|
||||
void DeferredRenderPass::Enable(bool enable)
|
||||
{
|
||||
m_enabled = enable;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the deferred forward pass which needs the deferred technique
|
||||
*
|
||||
* \param technique Rendering technique
|
||||
*/
|
||||
|
||||
void DeferredRenderPass::Initialize(DeferredRenderTechnique* technique)
|
||||
{
|
||||
m_deferredTechnique = technique;
|
||||
@@ -37,11 +59,23 @@ namespace Nz
|
||||
m_workTextures[i] = technique->GetWorkTexture(i);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the deferred rendering is enabled
|
||||
* \return true If it the case
|
||||
*/
|
||||
|
||||
bool DeferredRenderPass::IsEnabled() const
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_dimensions = dimensions;
|
||||
|
||||
@@ -8,69 +8,207 @@
|
||||
#include <Nazara/Graphics/Light.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
|
||||
{
|
||||
/*!
|
||||
* \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) :
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
else
|
||||
{
|
||||
@@ -103,21 +241,37 @@ namespace Nz
|
||||
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;
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
AbstractRenderQueue::Clear(fully);
|
||||
@@ -137,6 +291,13 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
auto it = layers.find(i);
|
||||
@@ -149,6 +310,12 @@ namespace Nz
|
||||
return layer;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of an index buffer
|
||||
*
|
||||
* \param indexBuffer Index buffer being invalidated
|
||||
*/
|
||||
|
||||
void DeferredRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
@@ -221,6 +408,14 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
const Buffer* buffer1;
|
||||
|
||||
@@ -77,7 +77,18 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
@@ -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() :
|
||||
m_renderQueue(static_cast<ForwardRenderQueue*>(m_forwardTechnique.GetRenderQueue())),
|
||||
m_GBufferSize(0U)
|
||||
@@ -204,11 +227,27 @@ namespace Nz
|
||||
|
||||
DeferredRenderTechnique::~DeferredRenderTechnique() = default;
|
||||
|
||||
/*!
|
||||
* \brief Clears the data
|
||||
*
|
||||
* \param sceneData Data of the scene
|
||||
*/
|
||||
|
||||
void DeferredRenderTechnique::Clear(const SceneData& sceneData) const
|
||||
{
|
||||
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
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
@@ -242,6 +281,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -271,16 +332,34 @@ namespace Nz
|
||||
return m_GBuffer[i];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the rendering texture of the G-buffer
|
||||
* \return Pointer to the rendering buffer
|
||||
*/
|
||||
|
||||
RenderTexture* DeferredRenderTechnique::GetGBufferRTT() const
|
||||
{
|
||||
return &m_GBufferRTT;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the forward technique
|
||||
* \return Constant pointer to the forward technique
|
||||
*/
|
||||
|
||||
const ForwardRenderTechnique* DeferredRenderTechnique::GetForwardTechnique() const
|
||||
{
|
||||
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)
|
||||
{
|
||||
auto it = m_passes.find(renderPass);
|
||||
@@ -294,21 +373,45 @@ namespace Nz
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the render queue
|
||||
* \return Pointer to the render queue
|
||||
*/
|
||||
|
||||
AbstractRenderQueue* DeferredRenderTechnique::GetRenderQueue()
|
||||
{
|
||||
return &m_renderQueue;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the type of the current technique
|
||||
* \return Type of the render technique
|
||||
*/
|
||||
|
||||
RenderTechniqueType DeferredRenderTechnique::GetType() const
|
||||
{
|
||||
return RenderTechniqueType_DeferredShading;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the render texture used to work
|
||||
* \return Pointer to the rendering texture
|
||||
*/
|
||||
|
||||
RenderTexture* DeferredRenderTechnique::GetWorkRTT() const
|
||||
{
|
||||
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
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -322,6 +425,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
auto it = m_passes.find(renderPass);
|
||||
@@ -335,9 +446,17 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -386,6 +505,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
if (pass)
|
||||
@@ -400,12 +527,26 @@ namespace Nz
|
||||
m_passes[relativeTo].erase(position);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the technique is supported
|
||||
* \return true if it is the case
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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
|
||||
{
|
||||
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()
|
||||
{
|
||||
const char vertexSource_Basic[] =
|
||||
@@ -560,6 +708,10 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the deferred render technique
|
||||
*/
|
||||
|
||||
void DeferredRenderTechnique::Uninitialize()
|
||||
{
|
||||
ShaderLibrary::Unregister("DeferredGBufferClear");
|
||||
@@ -571,6 +723,14 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
return RenderPassPriority[pass1] < RenderPassPriority[pass2];
|
||||
|
||||
@@ -9,6 +9,16 @@
|
||||
|
||||
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()
|
||||
{
|
||||
// Material
|
||||
@@ -18,6 +28,19 @@ namespace Nz
|
||||
//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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -34,6 +57,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -50,6 +87,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -66,6 +117,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -82,6 +147,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -98,6 +177,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -114,6 +207,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -130,6 +237,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -146,6 +267,20 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -162,12 +297,32 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(false, "Depth render queue doesn't handle lights");
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -185,18 +340,46 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(false, "Depth render queue doesn't handle lights");
|
||||
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)
|
||||
{
|
||||
NazaraAssert(false, "Depth render queue doesn't handle lights");
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
@@ -37,6 +37,16 @@ namespace Nz
|
||||
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() :
|
||||
m_vertexBuffer(BufferType_Vertex)
|
||||
{
|
||||
@@ -48,6 +58,12 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
Renderer::Enable(RendererParameter_DepthBuffer, true);
|
||||
@@ -59,6 +75,13 @@ namespace Nz
|
||||
// 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
|
||||
{
|
||||
for (auto& pair : m_renderQueue.layers)
|
||||
@@ -81,16 +104,33 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the render queue
|
||||
* \return Pointer to the render queue
|
||||
*/
|
||||
|
||||
AbstractRenderQueue* DepthRenderTechnique::GetRenderQueue()
|
||||
{
|
||||
return &m_renderQueue;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the type of the current technique
|
||||
* \return Type of the render technique
|
||||
*/
|
||||
|
||||
RenderTechniqueType DepthRenderTechnique::GetType() const
|
||||
{
|
||||
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()
|
||||
{
|
||||
try
|
||||
@@ -149,12 +189,23 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the depth render technique
|
||||
*/
|
||||
|
||||
void DepthRenderTechnique::Uninitialize()
|
||||
{
|
||||
s_quadIndexBuffer.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
|
||||
{
|
||||
const Shader* lastShader = nullptr;
|
||||
@@ -180,7 +231,7 @@ namespace Nz
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
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;
|
||||
if (overlay)
|
||||
flags |= ShaderFlags_TextureOverlay;
|
||||
@@ -195,26 +246,26 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Overlay
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous
|
||||
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// On ouvre le buffer en écriture
|
||||
// We open the buffer in writing mode
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||
VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
@@ -232,7 +283,7 @@ namespace Nz
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Avons-nous traité la chaîne entière ?
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChain.spriteCount)
|
||||
{
|
||||
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
|
||||
{
|
||||
const Shader* lastShader = nullptr;
|
||||
@@ -278,16 +336,16 @@ namespace Nz
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
|
||||
lastShader = shader;
|
||||
@@ -325,16 +383,16 @@ namespace Nz
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
|
||||
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
|
||||
{
|
||||
const Shader* lastShader = nullptr;
|
||||
@@ -415,14 +480,14 @@ namespace Nz
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
lastShader = shader;
|
||||
}
|
||||
@@ -441,7 +506,7 @@ namespace Nz
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
@@ -464,33 +529,33 @@ namespace Nz
|
||||
|
||||
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();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
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);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// Et on affiche
|
||||
// And we draw
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sans instancing, on doit effectuer un draw call pour chaque instance
|
||||
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
|
||||
// À cause du temps de modification du buffer d'instancing
|
||||
// Without instancing, we must do a draw call for each instance
|
||||
// This may be faster than instancing under a certain number
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
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.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
|
||||
{
|
||||
auto it = m_shaderUniforms.find(shader);
|
||||
@@ -527,6 +599,12 @@ namespace Nz
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a shader
|
||||
*
|
||||
* \param shader Shader being invalidated
|
||||
*/
|
||||
|
||||
void DepthRenderTechnique::OnShaderInvalidated(const Shader* shader) const
|
||||
{
|
||||
m_shaderUniforms.erase(shader);
|
||||
|
||||
@@ -7,5 +7,13 @@
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,29 @@
|
||||
#include <Nazara/Graphics/Light.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
|
||||
{
|
||||
/*!
|
||||
* \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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
@@ -32,37 +51,33 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
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)
|
||||
colorPtr.Reset(&Color::White, 0); // Pareil
|
||||
colorPtr.Reset(&Color::White, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
if (!alphaPtr)
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
colorPtr.Reset(&Color::White, 0); // Pareil
|
||||
colorPtr.Reset(&Color::White, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (!alphaPtr)
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
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)
|
||||
colorPtr.Reset(&Color::White, 0); // Pareil
|
||||
colorPtr.Reset(&Color::White, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
if (!alphaPtr)
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
colorPtr.Reset(&Color::White, 0); // Pareil
|
||||
colorPtr.Reset(&Color::White, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (!alphaPtr)
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Pareil
|
||||
alphaPtr.Reset(&defaultAlpha, 0); // Same
|
||||
|
||||
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);
|
||||
|
||||
BillboardData* billboardData = &billboardVector[prevSize];
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -399,15 +395,29 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (material->IsEnabled(RendererParameter_Blend))
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& transparentModels = currentLayer.transparentModels;
|
||||
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();
|
||||
transparentModelData.resize(index+1);
|
||||
|
||||
@@ -455,14 +465,28 @@ namespace Nz
|
||||
std::vector<Matrix4f>& instances = it2->second.instances;
|
||||
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)
|
||||
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)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& basicSprites = currentLayer.basicSprites;
|
||||
|
||||
@@ -494,6 +518,12 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
||||
Vector3f viewerPos = viewer->GetEyePosition();
|
||||
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)
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
auto it = layers.find(i);
|
||||
if (it == layers.end())
|
||||
it = layers.insert(std::make_pair(i, Layer())).first;
|
||||
|
||||
|
||||
Layer& layer = it->second;
|
||||
layer.clearCount = 0;
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of an index buffer
|
||||
*
|
||||
* \param indexBuffer Index buffer being invalidated
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
@@ -655,6 +760,14 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
@@ -675,6 +788,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
@@ -695,6 +816,14 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
const Buffer* buffer1;
|
||||
|
||||
@@ -33,10 +33,20 @@ namespace Nz
|
||||
Vector2f uv;
|
||||
};
|
||||
|
||||
unsigned int s_maxQuads = std::numeric_limits<UInt16>::max()/6;
|
||||
unsigned int s_vertexBufferSize = 4*1024*1024; // 4 MiB
|
||||
unsigned int s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
||||
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() :
|
||||
m_vertexBuffer(BufferType_Vertex),
|
||||
m_maxLightPassPerObject(3)
|
||||
@@ -49,6 +59,12 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
Renderer::Enable(RendererParameter_DepthBuffer, true);
|
||||
@@ -59,6 +75,15 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
@@ -88,55 +113,83 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
return m_maxLightPassPerObject;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the render queue
|
||||
* \return Pointer to the render queue
|
||||
*/
|
||||
|
||||
AbstractRenderQueue* ForwardRenderTechnique::GetRenderQueue()
|
||||
{
|
||||
return &m_renderQueue;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the type of the current technique
|
||||
* \return Type of the render technique
|
||||
*/
|
||||
|
||||
RenderTechniqueType ForwardRenderTechnique::GetType() const
|
||||
{
|
||||
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()
|
||||
{
|
||||
try
|
||||
{
|
||||
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);
|
||||
UInt16* indices = static_cast<UInt16*>(mapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < s_maxQuads; ++i)
|
||||
{
|
||||
*indices++ = i*4 + 0;
|
||||
*indices++ = i*4 + 2;
|
||||
*indices++ = i*4 + 1;
|
||||
*indices++ = i * 4 + 0;
|
||||
*indices++ = i * 4 + 2;
|
||||
*indices++ = i * 4 + 1;
|
||||
|
||||
*indices++ = i*4 + 2;
|
||||
*indices++ = i*4 + 3;
|
||||
*indices++ = i*4 + 1;
|
||||
*indices++ = i * 4 + 2;
|
||||
*indices++ = i * 4 + 3;
|
||||
*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)
|
||||
//Note: Les UV sont calculés dans le shader
|
||||
// Quad buffer (used for instancing of billboards and sprites)
|
||||
//Note: UV are computed in the shader
|
||||
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,
|
||||
@@ -145,14 +198,14 @@ namespace Nz
|
||||
|
||||
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_Position, ComponentType_Float3, NazaraOffsetOf(BillboardPoint, position));
|
||||
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
|
||||
// L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU
|
||||
// Declaration used when rendering the billboards with intancing
|
||||
// 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_InstanceData1, ComponentType_Float4, NazaraOffsetOf(ForwardRenderQueue::BillboardData, size)); // Englobe sincos
|
||||
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(ForwardRenderQueue::BillboardData, color));
|
||||
@@ -169,12 +222,23 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the forward render technique
|
||||
*/
|
||||
|
||||
void ForwardRenderTechnique::Uninitialize()
|
||||
{
|
||||
s_quadIndexBuffer.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
|
||||
{
|
||||
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
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
@@ -240,7 +313,7 @@ namespace Nz
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
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;
|
||||
if (overlay)
|
||||
flags |= ShaderFlags_TextureOverlay;
|
||||
@@ -255,46 +328,46 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Overlay
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous
|
||||
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// On ouvre le buffer en écriture
|
||||
// We open the buffer in writing mode
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
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
|
||||
{
|
||||
ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
|
||||
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
|
||||
|
||||
std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count*4;
|
||||
std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count * 4;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Avons-nous traité la chaîne entière ?
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChain.spriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
@@ -305,7 +378,7 @@ namespace Nz
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount*6);
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
}
|
||||
while (spriteChain < spriteChainCount);
|
||||
|
||||
@@ -313,12 +386,21 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
// On remet à zéro
|
||||
// We set it back to zero
|
||||
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
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
@@ -342,18 +424,18 @@ namespace Nz
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
@@ -391,32 +473,32 @@ namespace Nz
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
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());
|
||||
|
||||
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
|
||||
@@ -454,7 +536,7 @@ namespace Nz
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount*6);
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6);
|
||||
}
|
||||
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
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
@@ -483,25 +574,25 @@ namespace Nz
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
|
||||
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
|
||||
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
|
||||
// (Le deferred shading n'a pas ce problème)
|
||||
// We only use instancing when no light (other than directional) is active
|
||||
// This is because instancing is not compatible with the search of nearest lights
|
||||
// Deferred shading does not have this problem
|
||||
bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty();
|
||||
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;
|
||||
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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
@@ -521,7 +612,7 @@ namespace Nz
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
@@ -544,17 +635,17 @@ namespace Nz
|
||||
|
||||
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();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
// Avec l'instancing, impossible de sélectionner les lumières pour chaque objet
|
||||
// Du coup, il n'est activé que pour les lumières directionnelles
|
||||
// With instancing, impossible to select the lights for each object
|
||||
// So, it's only activated for directional lights
|
||||
unsigned int lightCount = m_renderQueue.directionalLights.size();
|
||||
unsigned int lightIndex = 0;
|
||||
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)
|
||||
{
|
||||
if (shaderUniforms->hasLightUniforms)
|
||||
@@ -564,10 +655,10 @@ namespace Nz
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
// Pour additionner le résultat des calculs de lumière
|
||||
// Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques
|
||||
// (Autrement dit, sans blending)
|
||||
// Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois
|
||||
// To add the result of light computations
|
||||
// We won't interfeer with materials parameters because we only render opaques objects
|
||||
// (A.K.A., without blending)
|
||||
// About the depth function, it must be applied only the first time
|
||||
Renderer::Enable(RendererParameter_Blend, true);
|
||||
Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One);
|
||||
Renderer::SetDepthFunc(RendererComparison_Equal);
|
||||
@@ -575,32 +666,32 @@ namespace Nz
|
||||
|
||||
// Sends the uniforms
|
||||
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);
|
||||
}
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
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);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// Et on affiche
|
||||
// And we draw
|
||||
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::SetDepthFunc(oldDepthFunc);
|
||||
}
|
||||
@@ -617,19 +708,19 @@ namespace Nz
|
||||
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
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)
|
||||
{
|
||||
lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U));
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
// Pour additionner le résultat des calculs de lumière
|
||||
// Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques
|
||||
// (Autrement dit, sans blending)
|
||||
// Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois
|
||||
// To add the result of light computations
|
||||
// We won't interfeer with materials parameters because we only render opaques objects
|
||||
// (A.K.A., without blending)
|
||||
// About the depth function, it must be applied only the first time
|
||||
Renderer::Enable(RendererParameter_Blend, true);
|
||||
Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One);
|
||||
Renderer::SetDepthFunc(RendererComparison_Equal);
|
||||
@@ -639,7 +730,7 @@ namespace Nz
|
||||
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i);
|
||||
|
||||
// Et on passe à l'affichage
|
||||
// And we draw
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
|
||||
@@ -649,9 +740,9 @@ namespace Nz
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sans instancing, on doit effectuer un draw call pour chaque instance
|
||||
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
|
||||
// À cause du temps de modification du buffer d'instancing
|
||||
// Without instancing, we must do a draw call for each instance
|
||||
// This may be faster than instancing under a certain number
|
||||
// Due to the time to modify the instancing buffer
|
||||
for (const Matrix4f& matrix : instances)
|
||||
{
|
||||
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.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
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
@@ -683,25 +783,25 @@ namespace Nz
|
||||
{
|
||||
const ForwardRenderQueue::TransparentModelData& modelData = layer.transparentModelData[index];
|
||||
|
||||
// Matériau
|
||||
// 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;
|
||||
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)
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position de la caméra
|
||||
// Position of the camera
|
||||
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)
|
||||
{
|
||||
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 VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
// Handle draw call before the rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
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
|
||||
{
|
||||
auto it = m_shaderUniforms.find(shader);
|
||||
@@ -795,6 +902,12 @@ namespace Nz
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a shader
|
||||
*
|
||||
* \param shader Shader being invalidated
|
||||
*/
|
||||
|
||||
void ForwardRenderTechnique::OnShaderInvalidated(const Shader* shader) const
|
||||
{
|
||||
m_shaderUniforms.erase(shader);
|
||||
|
||||
@@ -28,15 +28,29 @@
|
||||
|
||||
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()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
if (IsInitialized())
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Déjà initialisé
|
||||
return true; // Already initialized
|
||||
}
|
||||
|
||||
// Initialisation des dépendances
|
||||
// Initialisation of dependances
|
||||
if (!Renderer::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Renderer module");
|
||||
@@ -45,7 +59,7 @@ namespace Nz
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
|
||||
// Initialisation du module
|
||||
// Initialisation of the module
|
||||
CallOnExit onExit(Graphics::Uninitialize);
|
||||
|
||||
if (!Material::Initialize())
|
||||
@@ -96,7 +110,7 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loaders génériques
|
||||
// Generic loaders
|
||||
Loaders::RegisterMesh();
|
||||
Loaders::RegisterTexture();
|
||||
|
||||
@@ -133,43 +147,54 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the module is initialized
|
||||
* \return true if module is initialized
|
||||
*/
|
||||
|
||||
bool Graphics::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the Core module
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
*/
|
||||
|
||||
void Graphics::Uninitialize()
|
||||
{
|
||||
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)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Libération du module
|
||||
// Free of module
|
||||
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();
|
||||
if (defaultAtlas && defaultAtlas->GetStorage() & DataStorage_Hardware)
|
||||
{
|
||||
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)
|
||||
// du coup, si la police par défaut utilise un atlas hardware, on lui enlève.
|
||||
// Je n'aime pas cette solution mais je n'en ai pas de meilleure sous la main pour l'instant
|
||||
// The default police can make live one hardware atlas after the free of a module (which could be problematic)
|
||||
// So, if the default police use a hardware atlas, we stole it.
|
||||
// I don't like this solution, but I don't have any better
|
||||
if (!defaultAtlas.unique())
|
||||
{
|
||||
// Encore au moins une police utilise l'atlas
|
||||
// Still at least one police use the atlas
|
||||
Font* defaultFont = Font::GetDefault();
|
||||
defaultFont->SetAtlas(nullptr);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -195,7 +220,7 @@ namespace Nz
|
||||
|
||||
NazaraNotice("Uninitialized: Graphics module");
|
||||
|
||||
// Libération des dépendances
|
||||
// Free of dependances
|
||||
Renderer::Uninitialize();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,32 @@
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
std::unique_ptr<Texture> newTexture(new Texture);
|
||||
@@ -23,8 +44,8 @@ namespace Nz
|
||||
{
|
||||
Texture* oldTexture = static_cast<Texture*>(oldImage);
|
||||
|
||||
// Copie des anciennes données
|
||||
///TODO: Copie de texture à texture
|
||||
// Copy of old data
|
||||
///TODO: Copy from texture to texture
|
||||
Image image;
|
||||
if (!oldTexture->Download(&image))
|
||||
{
|
||||
@@ -43,8 +64,7 @@ namespace Nz
|
||||
}
|
||||
else
|
||||
{
|
||||
// Si on arrive ici c'est que la taille demandée est trop grande pour la carte graphique
|
||||
// ou que nous manquons de mémoire
|
||||
// If we are here, it is that the size is too big for the graphic card or we don't have enough
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,43 @@
|
||||
|
||||
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()
|
||||
{
|
||||
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
|
||||
{
|
||||
return frustum.Contains(instanceData.volume);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bounding volume
|
||||
* \return Bounding volume of the instanced
|
||||
*/
|
||||
|
||||
const BoundingVolumef& InstancedRenderable::GetBoundingVolume() const
|
||||
{
|
||||
EnsureBoundingVolumeUpdated();
|
||||
@@ -24,11 +51,30 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
NazaraAssert(instanceData, "Invalid instance data");
|
||||
|
||||
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
|
||||
{
|
||||
NazaraAssert(instanceData, "Invalid instance data");
|
||||
@@ -37,6 +83,14 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
NazaraAssert(instanceData, "Invalid instance data");
|
||||
|
||||
@@ -13,11 +13,23 @@
|
||||
#include <cstring>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
///TODO: Utilisation des UBOs
|
||||
///TODO: Use of UBOs
|
||||
///TODO: Scale ?
|
||||
|
||||
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) :
|
||||
m_type(type),
|
||||
m_shadowMapFormat(PixelFormatType_Depth16),
|
||||
@@ -34,6 +46,15 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
return new Light(*this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a default light
|
||||
* \return Pointer to newly allocated light
|
||||
*/
|
||||
|
||||
Light* Light::Create() const
|
||||
{
|
||||
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
|
||||
{
|
||||
switch (m_type)
|
||||
@@ -128,6 +169,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
switch (m_type)
|
||||
@@ -166,19 +221,19 @@ namespace Nz
|
||||
|
||||
case LightType_Spot:
|
||||
{
|
||||
// On forme une boite sur l'origine
|
||||
// We make a box center in the origin
|
||||
Boxf box(Vector3f::Zero());
|
||||
|
||||
// On calcule le reste des points
|
||||
Vector3f base(Vector3f::Forward()*m_radius);
|
||||
// We compute the other points
|
||||
Vector3f base(Vector3f::Forward() * m_radius);
|
||||
|
||||
// Il nous faut maintenant le rayon du cercle projeté à cette distance
|
||||
// Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente
|
||||
// Now we need the radius of the projected circle depending on the distance
|
||||
// Tangent = Opposite/Adjacent <=> Opposite = Adjacent * Tangent
|
||||
float radius = m_radius * m_outerAngleTangent;
|
||||
Vector3f lExtend = Vector3f::Left()*radius;
|
||||
Vector3f uExtend = Vector3f::Up()*radius;
|
||||
Vector3f lExtend = Vector3f::Left() * 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);
|
||||
@@ -194,6 +249,10 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the shadow map
|
||||
*/
|
||||
|
||||
void Light::UpdateShadowMap() const
|
||||
{
|
||||
if (m_shadowCastingEnabled)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
{
|
||||
if (!UberShaderLibrary::Has(shaderName))
|
||||
@@ -44,6 +55,15 @@ namespace Nz
|
||||
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 ShaderInstance& instance = m_shaders[shaderFlags];
|
||||
@@ -123,6 +143,13 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
Color color;
|
||||
@@ -283,6 +310,10 @@ namespace Nz
|
||||
SetShader(matParams.shaderName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the material, cleans everything
|
||||
*/
|
||||
|
||||
void Material::Reset()
|
||||
{
|
||||
OnMaterialReset(this);
|
||||
@@ -319,9 +350,15 @@ namespace Nz
|
||||
SetShader("Basic");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Copies the other material
|
||||
*
|
||||
* \param material Material to copy into this
|
||||
*/
|
||||
|
||||
void Material::Copy(const Material& material)
|
||||
{
|
||||
// Copie des états de base
|
||||
// Copy of base states
|
||||
m_alphaTestEnabled = material.m_alphaTestEnabled;
|
||||
m_alphaThreshold = material.m_alphaThreshold;
|
||||
m_ambientColor = material.m_ambientColor;
|
||||
@@ -337,7 +374,7 @@ namespace Nz
|
||||
m_states = material.m_states;
|
||||
m_transformEnabled = material.m_transformEnabled;
|
||||
|
||||
// Copie des références de texture
|
||||
// Copy of reference to the textures
|
||||
m_alphaMap = material.m_alphaMap;
|
||||
m_depthMaterial = material.m_depthMaterial;
|
||||
m_diffuseMap = material.m_diffuseMap;
|
||||
@@ -347,10 +384,16 @@ namespace Nz
|
||||
m_specularMap = material.m_specularMap;
|
||||
m_uberShader = material.m_uberShader;
|
||||
|
||||
// On copie les instances de shader par la même occasion
|
||||
std::memcpy(&m_shaders[0], &material.m_shaders[0], (ShaderFlags_Max+1)*sizeof(ShaderInstance));
|
||||
// We copy the instances of the shader too
|
||||
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
|
||||
{
|
||||
ParameterList list;
|
||||
@@ -396,6 +439,13 @@ namespace Nz
|
||||
#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()
|
||||
{
|
||||
if (!MaterialLibrary::Initialize())
|
||||
@@ -462,6 +512,10 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the material librairies
|
||||
*/
|
||||
|
||||
void Material::Uninitialize()
|
||||
{
|
||||
s_defaultMaterial.Reset();
|
||||
|
||||
@@ -12,11 +12,26 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::Model
|
||||
* \brief Graphics class that represents a model
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a ModelParameters object by default
|
||||
*/
|
||||
|
||||
ModelParameters::ModelParameters()
|
||||
{
|
||||
material.shaderName = "PhongLighting";
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the parameters for the model are correct
|
||||
* \return true If parameters are valid
|
||||
*/
|
||||
|
||||
bool ModelParameters::IsValid() const
|
||||
{
|
||||
if (loadMaterials && !material.IsValid())
|
||||
@@ -25,6 +40,10 @@ namespace Nz
|
||||
return mesh.IsValid();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Model object by default
|
||||
*/
|
||||
|
||||
Model::Model() :
|
||||
m_matCount(0),
|
||||
m_skin(0),
|
||||
@@ -32,11 +51,24 @@ namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls Reset
|
||||
*
|
||||
* \see Reset
|
||||
*/
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -78,9 +121,18 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -91,9 +143,21 @@ namespace Nz
|
||||
}
|
||||
#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
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -118,9 +182,20 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -137,49 +212,103 @@ namespace Nz
|
||||
}
|
||||
#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
|
||||
{
|
||||
return m_matCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the mesh
|
||||
* \return Current mesh
|
||||
*/
|
||||
|
||||
Mesh* Model::GetMesh() const
|
||||
{
|
||||
return m_mesh;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the skin
|
||||
* \return Current skin
|
||||
*/
|
||||
|
||||
unsigned int Model::GetSkin() const
|
||||
{
|
||||
return m_skin;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of skins
|
||||
* \return Current number of skins
|
||||
*/
|
||||
|
||||
unsigned int Model::GetSkinCount() const
|
||||
{
|
||||
return m_skinCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the model is animated
|
||||
* \return false
|
||||
*/
|
||||
|
||||
bool Model::IsAnimated() const
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return ModelLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the model, cleans everything
|
||||
*/
|
||||
|
||||
void Model::Reset()
|
||||
{
|
||||
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)
|
||||
{
|
||||
SubMesh* subMesh = m_mesh->GetSubMesh(subMeshName);
|
||||
@@ -208,7 +348,7 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int index = m_skin*m_matCount + matIndex;
|
||||
unsigned int index = m_skin * m_matCount + matIndex;
|
||||
|
||||
if (material)
|
||||
m_materials[index] = material;
|
||||
@@ -218,6 +358,16 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -228,7 +378,7 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int index = m_skin*m_matCount + matIndex;
|
||||
unsigned int index = m_skin * m_matCount + matIndex;
|
||||
|
||||
if (material)
|
||||
m_materials[index] = material;
|
||||
@@ -236,6 +386,19 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -260,7 +423,7 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int index = skinIndex*m_matCount + matIndex;
|
||||
unsigned int index = skinIndex * m_matCount + matIndex;
|
||||
|
||||
if (material)
|
||||
m_materials[index] = material;
|
||||
@@ -270,6 +433,18 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -286,7 +461,7 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int index = skinIndex*m_matCount + matIndex;
|
||||
unsigned int index = skinIndex * m_matCount + matIndex;
|
||||
|
||||
if (material)
|
||||
m_materials[index] = material;
|
||||
@@ -294,6 +469,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -323,6 +506,14 @@ namespace Nz
|
||||
InvalidateBoundingVolume();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the skin
|
||||
*
|
||||
* \param skin Skin to use
|
||||
*
|
||||
* \remark Produces a NazaraError if skin is invalid
|
||||
*/
|
||||
|
||||
void Model::SetSkin(unsigned int skin)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -336,6 +527,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -350,6 +549,10 @@ namespace Nz
|
||||
m_skinCount = skinCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Makes the bounding volume of this billboard
|
||||
*/
|
||||
|
||||
void Model::MakeBoundingVolume() const
|
||||
{
|
||||
if (m_mesh)
|
||||
|
||||
@@ -7,17 +7,44 @@
|
||||
|
||||
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) :
|
||||
RefCounted()
|
||||
{
|
||||
NazaraUnused(controller);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls OnParticleControllerRelease
|
||||
*
|
||||
* \see OnParticleControllerRelease
|
||||
*/
|
||||
|
||||
ParticleController::~ParticleController()
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (!ParticleControllerLibrary::Initialize())
|
||||
@@ -29,6 +56,10 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the particle controller librairies
|
||||
*/
|
||||
|
||||
void ParticleController::Uninitialize()
|
||||
{
|
||||
ParticleControllerLibrary::Uninitialize();
|
||||
|
||||
@@ -15,23 +15,54 @@
|
||||
|
||||
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() :
|
||||
m_stride(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a ParticleDeclaration object by assignation
|
||||
*
|
||||
* \param declaration ParticleDeclaration to copy into this
|
||||
*/
|
||||
|
||||
ParticleDeclaration::ParticleDeclaration(const ParticleDeclaration& declaration) :
|
||||
RefCounted(),
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
#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)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
@@ -91,6 +133,18 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
@@ -121,24 +175,51 @@ namespace Nz
|
||||
*offset = particleComponent.offset;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the stride of the declaration
|
||||
* \return Stride of the declaration
|
||||
*/
|
||||
|
||||
unsigned int ParticleDeclaration::GetStride() const
|
||||
{
|
||||
return m_stride;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the stride of the declaration
|
||||
*
|
||||
* \param stride Stride of the declaration
|
||||
*/
|
||||
|
||||
void ParticleDeclaration::SetStride(unsigned int 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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
@@ -152,6 +233,15 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
switch (type)
|
||||
@@ -177,6 +267,14 @@ namespace Nz
|
||||
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()
|
||||
{
|
||||
if (!ParticleDeclarationLibrary::Initialize())
|
||||
@@ -231,11 +329,15 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the particle declaration librairies
|
||||
*/
|
||||
|
||||
void ParticleDeclaration::Uninitialize()
|
||||
{
|
||||
ParticleDeclarationLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
ParticleDeclaration ParticleDeclaration::s_declarations[ParticleLayout_Max+1];
|
||||
ParticleDeclaration ParticleDeclaration::s_declarations[ParticleLayout_Max + 1];
|
||||
ParticleDeclarationLibrary::LibraryMap ParticleDeclaration::s_library;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,16 @@
|
||||
|
||||
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() :
|
||||
m_lagCompensationEnabled(false),
|
||||
m_emissionAccumulator(0.f),
|
||||
@@ -24,28 +34,35 @@ namespace Nz
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
m_emissionAccumulator += elapsedTime*m_emissionRate;
|
||||
// We accumulate the real part (to avoid that a high emission rate prevents particles to form)
|
||||
m_emissionAccumulator += elapsedTime * m_emissionRate;
|
||||
|
||||
float emissionCount = std::floor(m_emissionAccumulator); // Le nombre d'émissions de cette mise à jour
|
||||
m_emissionAccumulator -= emissionCount; // On enlève la partie entière
|
||||
float emissionCount = std::floor(m_emissionAccumulator); // The number of emissions in this update
|
||||
m_emissionAccumulator -= emissionCount; // We get rid off the integer part
|
||||
|
||||
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 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());
|
||||
if (particleCount == 0)
|
||||
return;
|
||||
|
||||
// Et on émet nos particules
|
||||
// And we emit our particles
|
||||
void* particles = system.GenerateParticles(particleCount);
|
||||
ParticleMapper mapper(particles, system.GetDeclaration());
|
||||
|
||||
@@ -53,40 +70,73 @@ namespace Nz
|
||||
|
||||
if (m_lagCompensationEnabled)
|
||||
{
|
||||
// On va maintenant appliquer les contrôleurs
|
||||
float invEmissionRate = 1.f/m_emissionRate;
|
||||
// We will now apply our controllers
|
||||
float invEmissionRate = 1.f / m_emissionRate;
|
||||
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)
|
||||
{
|
||||
m_lagCompensationEnabled = enable;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the emission count
|
||||
* \return Current emission count
|
||||
*/
|
||||
|
||||
unsigned int ParticleEmitter::GetEmissionCount() const
|
||||
{
|
||||
return m_emissionCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the emission rate
|
||||
* \return Current emission rate
|
||||
*/
|
||||
|
||||
float ParticleEmitter::GetEmissionRate() const
|
||||
{
|
||||
return m_emissionRate;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the lag compensation is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
bool ParticleEmitter::IsLagCompensationEnabled() const
|
||||
{
|
||||
return m_lagCompensationEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the emission count
|
||||
*
|
||||
* \param count Emission count
|
||||
*/
|
||||
|
||||
void ParticleEmitter::SetEmissionCount(unsigned int count)
|
||||
{
|
||||
m_emissionCount = count;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the emission rate
|
||||
*
|
||||
* \param rate Emission rate
|
||||
*/
|
||||
|
||||
void ParticleEmitter::SetEmissionRate(float rate)
|
||||
{
|
||||
m_emissionRate = rate;
|
||||
|
||||
@@ -7,17 +7,44 @@
|
||||
|
||||
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) :
|
||||
RefCounted()
|
||||
{
|
||||
NazaraUnused(generator);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls OnParticleGeneratorRelease
|
||||
*
|
||||
* \see OnParticleGeneratorRelease
|
||||
*/
|
||||
|
||||
ParticleGenerator::~ParticleGenerator()
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (!ParticleGeneratorLibrary::Initialize())
|
||||
@@ -29,6 +56,10 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the particle generator librairies
|
||||
*/
|
||||
|
||||
void ParticleGenerator::Uninitialize()
|
||||
{
|
||||
ParticleGeneratorLibrary::Uninitialize();
|
||||
|
||||
@@ -8,6 +8,19 @@
|
||||
|
||||
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) :
|
||||
m_declaration(declaration),
|
||||
m_ptr(static_cast<UInt8*>(buffer))
|
||||
|
||||
@@ -7,17 +7,42 @@
|
||||
|
||||
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) :
|
||||
RefCounted()
|
||||
{
|
||||
NazaraUnused(renderer);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls OnParticleRendererRelease
|
||||
*
|
||||
* \see OnParticleRendererRelease
|
||||
*/
|
||||
|
||||
ParticleRenderer::~ParticleRenderer()
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (!ParticleRendererLibrary::Initialize())
|
||||
@@ -29,6 +54,10 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the particle renderer librairies
|
||||
*/
|
||||
|
||||
void ParticleRenderer::Uninitialize()
|
||||
{
|
||||
ParticleRendererLibrary::Uninitialize();
|
||||
|
||||
@@ -13,25 +13,51 @@
|
||||
|
||||
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(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) :
|
||||
m_declaration(std::move(declaration)),
|
||||
m_processing(false),
|
||||
m_maxParticleCount(maxParticleCount),
|
||||
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);
|
||||
|
||||
m_particleSize = m_declaration->GetStride(); // La taille de chaque particule
|
||||
m_particleSize = m_declaration->GetStride(); // The size of each particle
|
||||
|
||||
ResizeBuffer();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a ParticleSystem object by assignation
|
||||
*
|
||||
* \param system ParticleSystem to copy into this
|
||||
*/
|
||||
|
||||
ParticleSystem::ParticleSystem(const ParticleSystem& system) :
|
||||
Renderable(system),
|
||||
m_controllers(system.m_controllers),
|
||||
@@ -47,12 +73,20 @@ namespace Nz
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
NazaraAssert(controller, "Invalid particle controller");
|
||||
@@ -60,6 +94,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(emitter, "Invalid particle emitter");
|
||||
@@ -67,6 +109,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraAssert(generator, "Invalid particle generator");
|
||||
@@ -74,6 +124,16 @@ namespace Nz
|
||||
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
|
||||
{
|
||||
NazaraAssert(m_renderer, "Invalid particle renderer");
|
||||
@@ -83,45 +143,63 @@ namespace Nz
|
||||
if (m_particleCount > 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_processing = true;
|
||||
|
||||
// Pour éviter un verrouillage en cas d'exception
|
||||
// To avoid a lock in case of exception
|
||||
CallOnExit onExit([this]()
|
||||
{
|
||||
m_processing = false;
|
||||
});
|
||||
|
||||
for (ParticleController* controller : m_controllers)
|
||||
controller->Apply(*this, mapper, 0, particleCount-1, elapsedTime);
|
||||
controller->Apply(*this, mapper, 0, particleCount - 1, elapsedTime);
|
||||
|
||||
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)
|
||||
{
|
||||
// On tue les particules depuis la dernière vers la première (en terme de place), le std::set étant trié 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,
|
||||
// sans cette solution certaines particules pourraient échapper à la mort
|
||||
// We kill them in reverse order, std::set sorting them via std::greater
|
||||
// The reason is simple, as the death of a particle means the move of the last particle in the buffer,
|
||||
// without this solution, certain particles could avoid the death
|
||||
for (unsigned int index : m_dyingParticles)
|
||||
KillParticle(index);
|
||||
}
|
||||
else
|
||||
KillParticles(); // Toutes les particules sont mortes, ceci est beaucoup plus rapide
|
||||
KillParticles(); // Every particles are dead, this is way faster
|
||||
|
||||
m_dyingParticles.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates one particle
|
||||
* \return Pointer to the particle memory buffer
|
||||
*/
|
||||
|
||||
void* ParticleSystem::CreateParticle()
|
||||
{
|
||||
return CreateParticles(1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates multiple particles
|
||||
* \return Pointer to the first particle memory buffer
|
||||
*/
|
||||
|
||||
void* ParticleSystem::CreateParticles(unsigned int count)
|
||||
{
|
||||
if (count == 0)
|
||||
@@ -133,14 +211,24 @@ namespace Nz
|
||||
unsigned int particlesIndex = m_particleCount;
|
||||
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()
|
||||
{
|
||||
return GenerateParticles(1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Generates multiple particles
|
||||
* \return Pointer to the first particle memory buffer
|
||||
*/
|
||||
|
||||
void* ParticleSystem::GenerateParticles(unsigned int count)
|
||||
{
|
||||
void* ptr = CreateParticles(count);
|
||||
@@ -149,57 +237,108 @@ namespace Nz
|
||||
|
||||
ParticleMapper mapper(ptr, m_declaration);
|
||||
for (ParticleGenerator* generator : m_generators)
|
||||
generator->Generate(*this, mapper, 0, count-1);
|
||||
generator->Generate(*this, mapper, 0, count - 1);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the particle declaration
|
||||
* \return Particle declaration
|
||||
*/
|
||||
|
||||
const ParticleDeclarationConstRef& ParticleSystem::GetDeclaration() const
|
||||
{
|
||||
return m_declaration;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the fixed step size
|
||||
* \return Current fixed step size
|
||||
*/
|
||||
|
||||
float ParticleSystem::GetFixedStepSize() const
|
||||
{
|
||||
return m_stepSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the maximum number of particles
|
||||
* \return Current maximum number
|
||||
*/
|
||||
|
||||
unsigned int ParticleSystem::GetMaxParticleCount() const
|
||||
{
|
||||
return m_maxParticleCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of particles
|
||||
* \return Current number
|
||||
*/
|
||||
|
||||
unsigned int ParticleSystem::GetParticleCount() const
|
||||
{
|
||||
return m_particleCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the size of particles
|
||||
* \return Current size
|
||||
*/
|
||||
|
||||
unsigned int ParticleSystem::GetParticleSize() const
|
||||
{
|
||||
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)
|
||||
{
|
||||
///FIXME: Vérifier index
|
||||
///FIXME: Verify the index
|
||||
|
||||
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);
|
||||
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)
|
||||
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()
|
||||
{
|
||||
m_particleCount = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes a controller to the particles
|
||||
*
|
||||
* \param controller Controller for the particles to remove
|
||||
*/
|
||||
|
||||
void ParticleSystem::RemoveController(ParticleController* controller)
|
||||
{
|
||||
auto it = std::find(m_controllers.begin(), m_controllers.end(), controller);
|
||||
@@ -207,6 +346,12 @@ namespace Nz
|
||||
m_controllers.erase(it);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes an emitter to the particles
|
||||
*
|
||||
* \param emitter Emitter for the particles to remove
|
||||
*/
|
||||
|
||||
void ParticleSystem::RemoveEmitter(ParticleEmitter* emitter)
|
||||
{
|
||||
auto it = std::find(m_emitters.begin(), m_emitters.end(), emitter);
|
||||
@@ -214,6 +359,12 @@ namespace Nz
|
||||
m_emitters.erase(it);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes a generator to the particles
|
||||
*
|
||||
* \param generator Generator for the particles to remove
|
||||
*/
|
||||
|
||||
void ParticleSystem::RemoveGenerator(ParticleGenerator* generator)
|
||||
{
|
||||
auto it = std::find(m_generators.begin(), m_generators.end(), generator);
|
||||
@@ -221,31 +372,55 @@ namespace Nz
|
||||
m_generators.erase(it);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the fixed step size
|
||||
*
|
||||
* \param stepSize Fixed step size
|
||||
*/
|
||||
|
||||
void ParticleSystem::SetFixedStepSize(float stepSize)
|
||||
{
|
||||
m_stepSize = stepSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the renderer of the particles
|
||||
*
|
||||
* \param renderer Renderer for the particles
|
||||
*/
|
||||
|
||||
void ParticleSystem::SetRenderer(ParticleRenderer* renderer)
|
||||
{
|
||||
m_renderer = renderer;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the system
|
||||
*
|
||||
* \param elapsedTime Delta time between the previous frame
|
||||
*/
|
||||
|
||||
void ParticleSystem::Update(float elapsedTime)
|
||||
{
|
||||
// Émission
|
||||
// Emission
|
||||
for (ParticleEmitter* emitter : m_emitters)
|
||||
emitter->Emit(*this, elapsedTime);
|
||||
|
||||
// Mise à jour
|
||||
// Update
|
||||
if (m_particleCount > 0)
|
||||
{
|
||||
///TODO: Mettre à jour en utilisant des threads
|
||||
///TODO: Update using threads
|
||||
ParticleMapper mapper(m_buffer.data(), m_declaration);
|
||||
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)
|
||||
{
|
||||
NazaraUnused(transformMatrix);
|
||||
@@ -253,6 +428,13 @@ namespace Nz
|
||||
// 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)
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
@@ -268,29 +450,39 @@ namespace Nz
|
||||
m_renderer = system.m_renderer;
|
||||
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_processing = false;
|
||||
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();
|
||||
|
||||
// On ne copie que les particules vivantes
|
||||
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize);
|
||||
// We only copy alive particles
|
||||
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount * m_particleSize);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Makes the bounding volume of this text
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resizes the internal buffer
|
||||
*
|
||||
* \remark Produces a NazaraError if resize did not work
|
||||
*/
|
||||
|
||||
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
|
||||
{
|
||||
m_buffer.resize(m_maxParticleCount*m_particleSize);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Nz
|
||||
"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
|
||||
{
|
||||
@@ -34,6 +34,22 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
@@ -47,6 +63,16 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -66,6 +92,16 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -89,6 +125,16 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
if (maxRanking < 0)
|
||||
@@ -119,11 +165,28 @@ namespace Nz
|
||||
return technique->factory();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of techniques available
|
||||
* \return Number of techniques
|
||||
*/
|
||||
|
||||
unsigned int RenderTechniques::GetCount()
|
||||
{
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -149,6 +212,15 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
@@ -162,6 +234,12 @@ namespace Nz
|
||||
return techniquesName[renderTechnique];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Unregisters a technique
|
||||
*
|
||||
* \param name Name of the technique
|
||||
*/
|
||||
|
||||
void RenderTechniques::Unregister(const String& name)
|
||||
{
|
||||
s_renderTechniques.erase(name);
|
||||
|
||||
@@ -7,8 +7,24 @@
|
||||
|
||||
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;
|
||||
|
||||
/*!
|
||||
* \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
|
||||
{
|
||||
NazaraUnused(transformMatrix);
|
||||
@@ -16,6 +32,11 @@ namespace Nz
|
||||
return frustum.Contains(m_boundingVolume);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bounding volume
|
||||
* \return Bounding volume of the renderable element
|
||||
*/
|
||||
|
||||
const BoundingVolumef& Renderable::GetBoundingVolume() const
|
||||
{
|
||||
EnsureBoundingVolumeUpdated();
|
||||
@@ -23,6 +44,12 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
m_boundingVolume.Update(transformMatrix);
|
||||
|
||||
@@ -14,6 +14,17 @@
|
||||
|
||||
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
|
||||
{
|
||||
if (!ModelParameters::IsValid())
|
||||
@@ -25,12 +36,23 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a SkeletalModel object by default
|
||||
*/
|
||||
|
||||
SkeletalModel::SkeletalModel() :
|
||||
m_currentSequence(nullptr),
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -67,7 +97,7 @@ namespace Nz
|
||||
m_interpolation -= 1.f;
|
||||
|
||||
unsigned lastFrame = m_currentSequence->firstFrame + m_currentSequence->frameCount - 1;
|
||||
if (m_nextFrame+1 > lastFrame)
|
||||
if (m_nextFrame + 1 > lastFrame)
|
||||
{
|
||||
if (m_animation->IsLoopPointInterpolationEnabled())
|
||||
{
|
||||
@@ -77,7 +107,7 @@ namespace Nz
|
||||
else
|
||||
{
|
||||
m_currentFrame = m_currentSequence->firstFrame;
|
||||
m_nextFrame = m_currentFrame+1;
|
||||
m_nextFrame = m_currentFrame + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -92,26 +122,52 @@ namespace Nz
|
||||
InvalidateBoundingVolume();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clones this skeletal model
|
||||
* \return Pointer to newly allocated SkeletalModel
|
||||
*/
|
||||
|
||||
SkeletalModel* SkeletalModel::Clone() const
|
||||
{
|
||||
return new SkeletalModel(*this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a default skeletal model
|
||||
* \return Pointer to newly allocated SkeletalModel
|
||||
*/
|
||||
|
||||
SkeletalModel* SkeletalModel::Create() const
|
||||
{
|
||||
return new SkeletalModel;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables the animation of the model
|
||||
*
|
||||
* \param animation Should the model be animated
|
||||
*/
|
||||
|
||||
void SkeletalModel::EnableAnimation(bool animation)
|
||||
{
|
||||
m_animationEnabled = animation;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the animation of the model
|
||||
* \return Pointer to the animation
|
||||
*/
|
||||
|
||||
Animation* SkeletalModel::GetAnimation() const
|
||||
{
|
||||
return m_animation;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the skeleton of the model
|
||||
* \return Pointer to the skeleton
|
||||
*/
|
||||
|
||||
Skeleton* SkeletalModel::GetSkeleton()
|
||||
{
|
||||
InvalidateBoundingVolume();
|
||||
@@ -119,41 +175,96 @@ namespace Nz
|
||||
return &m_skeleton;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the skeleton of the model
|
||||
* \return Constant pointer to the skeleton
|
||||
*/
|
||||
|
||||
const Skeleton* SkeletalModel::GetSkeleton() const
|
||||
{
|
||||
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
|
||||
{
|
||||
return m_animation != nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the skeleton is animated
|
||||
* \return true
|
||||
*
|
||||
* \see HasAnimation, IsAnimationEnabled
|
||||
*/
|
||||
|
||||
bool SkeletalModel::IsAnimated() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the skeleton is currently animated
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \see HasAnimation, IsAnimated
|
||||
*/
|
||||
|
||||
bool SkeletalModel::IsAnimationEnabled() const
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return SkeletalModelLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the model
|
||||
*/
|
||||
|
||||
void SkeletalModel::Reset()
|
||||
{
|
||||
Model::Reset();
|
||||
@@ -161,6 +272,16 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -204,6 +325,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -224,13 +353,23 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
///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 (!m_animation)
|
||||
{
|
||||
@@ -240,11 +379,13 @@ namespace Nz
|
||||
#endif
|
||||
|
||||
const Sequence* currentSequence = m_animation->GetSequence(sequenceName);
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!currentSequence)
|
||||
{
|
||||
NazaraError("Sequence not found");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_currentSequence = currentSequence;
|
||||
m_nextFrame = m_currentSequence->firstFrame;
|
||||
@@ -252,6 +393,15 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -275,13 +425,22 @@ namespace Nz
|
||||
m_nextFrame = m_currentSequence->firstFrame;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Makes the bounding volume of this text
|
||||
*/
|
||||
|
||||
void SkeletalModel::MakeBoundingVolume() const
|
||||
{
|
||||
m_boundingVolume.Set(m_skeleton.GetAABB());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the model
|
||||
*/
|
||||
|
||||
void SkeletalModel::Update()
|
||||
{
|
||||
///TODO
|
||||
/*if (m_animationEnabled && m_animation)
|
||||
AdvanceAnimation(m_scene->GetUpdateTime());*/
|
||||
}
|
||||
|
||||
@@ -46,6 +46,13 @@ namespace Nz
|
||||
SkeletonMap s_cache;
|
||||
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)
|
||||
{
|
||||
@@ -60,6 +67,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
BufferMapper<VertexBuffer> inputMapper(mesh->GetVertexBuffer(), BufferAccess_ReadOnly);
|
||||
@@ -70,8 +85,8 @@ namespace Nz
|
||||
skinningData.outputVertex = static_cast<MeshVertex*>(outputMapper.GetPointer());
|
||||
skinningData.joints = skeleton->GetJoints();
|
||||
|
||||
// Afin d'empêcher les différents threads de vouloir mettre à jour la même matrice en même temps,
|
||||
// on se charge de la mettre à jour avant de les lancer
|
||||
// To avoid different threads to update the same matrix at the same time
|
||||
// We try to update them before launching the tasks
|
||||
unsigned int jointCount = skeleton->GetJointCount();
|
||||
for (unsigned int i = 0; i < jointCount; ++i)
|
||||
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)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
@@ -149,6 +181,10 @@ namespace Nz
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Skins the skeletal mesh
|
||||
*/
|
||||
|
||||
void SkinningManager::Skin()
|
||||
{
|
||||
for (QueueData& data : s_skinningQueue)
|
||||
@@ -157,6 +193,11 @@ namespace Nz
|
||||
s_skinningQueue.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the skinning librairies
|
||||
* \return true
|
||||
*/
|
||||
|
||||
bool SkinningManager::Initialize()
|
||||
{
|
||||
///TODO: GPU Skinning
|
||||
@@ -165,9 +206,15 @@ namespace Nz
|
||||
else
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
for (auto& pair : s_cache.at(skeleton).meshMap)
|
||||
pair.second.updated = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the release of a skeletal mesh
|
||||
*
|
||||
* \param skeleton SkeletalMesh being released
|
||||
*/
|
||||
|
||||
void SkinningManager::OnSkeletonRelease(const Skeleton* skeleton)
|
||||
{
|
||||
s_cache.erase(skeleton);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the skinning librairies
|
||||
*/
|
||||
|
||||
void SkinningManager::Uninitialize()
|
||||
{
|
||||
s_cache.clear();
|
||||
|
||||
@@ -22,6 +22,18 @@ namespace Nz
|
||||
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) :
|
||||
m_movementOffset(Vector3f::Zero()),
|
||||
m_movementScale(0.f)
|
||||
@@ -31,6 +43,12 @@ namespace Nz
|
||||
SetTexture(std::move(cubemapTexture));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Draws this relatively to the viewer
|
||||
*
|
||||
* \param viewer Viewer for the background
|
||||
*/
|
||||
|
||||
void SkyboxBackground::Draw(const AbstractViewer* viewer) const
|
||||
{
|
||||
Matrix4f skyboxMatrix(viewer->GetViewMatrix());
|
||||
@@ -65,14 +83,26 @@ namespace Nz
|
||||
Renderer::SetMatrix(MatrixType_View, viewer->GetViewMatrix());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the background type
|
||||
* \return Type of background
|
||||
*/
|
||||
|
||||
BackgroundType SkyboxBackground::GetBackgroundType() const
|
||||
{
|
||||
return BackgroundType_Skybox;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the skybox
|
||||
* \return true If successful
|
||||
*
|
||||
* \remark Produces a NazaraError if initialization failed
|
||||
*/
|
||||
|
||||
bool SkyboxBackground::Initialize()
|
||||
{
|
||||
const UInt16 indices[6*6] =
|
||||
const UInt16 indices[6 * 6] =
|
||||
{
|
||||
0, 1, 2, 0, 2, 3,
|
||||
3, 2, 6, 3, 6, 7,
|
||||
@@ -170,6 +200,10 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the skybox
|
||||
*/
|
||||
|
||||
void SkyboxBackground::Uninitialize()
|
||||
{
|
||||
s_indexBuffer.Reset();
|
||||
|
||||
@@ -11,6 +11,19 @@
|
||||
|
||||
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
|
||||
{
|
||||
if (!m_material)
|
||||
@@ -20,11 +33,21 @@ namespace Nz
|
||||
renderQueue->AddSprites(instanceData.renderOrder, m_material, vertices, 1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Makes the bounding volume of this text
|
||||
*/
|
||||
|
||||
void Sprite::MakeBoundingVolume() const
|
||||
{
|
||||
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
|
||||
{
|
||||
instanceData->data.resize(4 * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
@@ -51,6 +74,13 @@ namespace Nz
|
||||
*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()
|
||||
{
|
||||
if (!SpriteLibrary::Initialize())
|
||||
@@ -62,6 +92,10 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the sprite librairies
|
||||
*/
|
||||
|
||||
void Sprite::Uninitialize()
|
||||
{
|
||||
SpriteLibrary::Uninitialize();
|
||||
|
||||
@@ -13,6 +13,19 @@
|
||||
|
||||
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
|
||||
{
|
||||
if (!m_material)
|
||||
@@ -26,11 +39,19 @@ namespace Nz
|
||||
if (indices.count > 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
CallOnExit clearOnFail([this]()
|
||||
@@ -138,8 +159,8 @@ namespace Nz
|
||||
|
||||
// First, compute the uv coordinates from our atlas rect
|
||||
Vector2ui size(texture->GetSize());
|
||||
float invWidth = 1.f/size.x;
|
||||
float invHeight = 1.f/size.y;
|
||||
float invWidth = 1.f / size.x;
|
||||
float invHeight = 1.f / size.y;
|
||||
|
||||
Rectf uvRect(glyph.atlasRect);
|
||||
uvRect.x *= invWidth;
|
||||
@@ -155,9 +176,9 @@ namespace Nz
|
||||
for (unsigned int j = 0; j < 4; ++j)
|
||||
{
|
||||
// Remember that indices->count is a counter here, not a count value
|
||||
m_localVertices[indices->count*4 + j].color = glyph.color;
|
||||
m_localVertices[indices->count*4 + j].position.Set(glyph.corners[j]);
|
||||
m_localVertices[indices->count*4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j]));
|
||||
m_localVertices[indices->count * 4 + j].color = glyph.color;
|
||||
m_localVertices[indices->count * 4 + j].position.Set(glyph.corners[j]);
|
||||
m_localVertices[indices->count * 4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j]));
|
||||
}
|
||||
|
||||
// Increment the counter, go to next glyph
|
||||
@@ -172,15 +193,25 @@ namespace Nz
|
||||
clearOnFail.Reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Makes the bounding volume of this text
|
||||
*/
|
||||
|
||||
void TextSprite::MakeBoundingVolume() const
|
||||
{
|
||||
Rectf bounds(m_localBounds);
|
||||
Vector2f max = bounds.GetMaximum();
|
||||
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)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
@@ -195,6 +226,14 @@ namespace Nz
|
||||
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)
|
||||
{
|
||||
NazaraUnused(atlas);
|
||||
@@ -207,23 +246,23 @@ namespace Nz
|
||||
}
|
||||
#endif
|
||||
|
||||
// La texture d'un atlas vient d'être recréée (changement de taille)
|
||||
// nous devons ajuster les coordonnées de textures et la texture du rendu
|
||||
// The texture of an atlas have just been recreated (size change)
|
||||
// we have to adjust the coordinates of the texture and the rendering texture
|
||||
Texture* oldTexture = static_cast<Texture*>(oldLayer);
|
||||
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);
|
||||
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);
|
||||
|
||||
Vector2ui oldSize(oldTexture->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));
|
||||
for (unsigned int i = 0; i < indices.count; ++i)
|
||||
{
|
||||
@@ -231,12 +270,18 @@ namespace Nz
|
||||
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.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
|
||||
{
|
||||
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<Vector2f> texCoordPtr(&vertices[0].uv, sizeof(VertexStruct_XYZ_Color_UV));
|
||||
|
||||
// Nous allons maintenant initialiser les sommets finaux (ceux envoyés à la RenderQueue)
|
||||
// à l'aide du repère, de la matrice et de notre attribut de couleur
|
||||
// We will not initialize the final vertices (those send to the RenderQueue)
|
||||
// With the help of the coordinates axis, the matrix and our color attribute
|
||||
for (auto& pair : m_renderInfos)
|
||||
{
|
||||
RenderIndices& indices = pair.second;
|
||||
if (indices.count == 0)
|
||||
continue; //< Ignore empty render indices
|
||||
|
||||
SparsePtr<Color> color = colorPtr + indices.first*4;
|
||||
SparsePtr<Vector3f> pos = posPtr + indices.first*4;
|
||||
SparsePtr<Vector2f> uv = texCoordPtr + indices.first*4;
|
||||
VertexStruct_XY_Color_UV* localVertex = &m_localVertices[indices.first*4];
|
||||
SparsePtr<Color> color = colorPtr + indices.first * 4;
|
||||
SparsePtr<Vector3f> pos = posPtr + indices.first * 4;
|
||||
SparsePtr<Vector2f> uv = texCoordPtr + 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 j = 0; j < 4; ++j)
|
||||
|
||||
@@ -11,6 +11,11 @@ namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
/*!
|
||||
* \brief Defines render states
|
||||
* \return RenderStates for the color background
|
||||
*/
|
||||
|
||||
RenderStates BuildRenderStates()
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_uberShader = UberShaderLibrary::Get("Basic");
|
||||
@@ -43,6 +60,12 @@ namespace Nz
|
||||
SetTexture(std::move(texture));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Draws this relatively to the viewer
|
||||
*
|
||||
* \param viewer Viewer for the background
|
||||
*/
|
||||
|
||||
void TextureBackground::Draw(const AbstractViewer* viewer) const
|
||||
{
|
||||
NazaraUnused(viewer);
|
||||
@@ -62,6 +85,11 @@ namespace Nz
|
||||
Renderer::DrawFullscreenQuad();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the background type
|
||||
* \return Type of background
|
||||
*/
|
||||
|
||||
BackgroundType TextureBackground::GetBackgroundType() const
|
||||
{
|
||||
return BackgroundType_Texture;
|
||||
|
||||
Reference in New Issue
Block a user