New Render queues (#161)
* Add new render queues proof of concept + scissoring support (WIP) * Graphics: Adapt basic sprites rendering to new render queue system * Graphics: Fix layers when rendering sprites * Graphics/RenderQueue: Fix sprite default overlay * Graphics: Enable scissor test by default * SDK/Widgets: Enable scissoring on widgets * Graphics: Handle almost everything with the new renderqueues system Todo: - Billboard rendering - Proper model rendering * Graphics/RenderQueue: Billboard drawing now works (WIP) At 1/4 of previous code performances due to individually process of billboards * Add new render queues proof of concept + scissoring support (WIP) * Graphics: Adapt basic sprites rendering to new render queue system * Graphics: Fix layers when rendering sprites * Graphics/RenderQueue: Fix sprite default overlay * Graphics: Enable scissor test by default * SDK/Widgets: Enable scissoring on widgets * Graphics: Handle almost everything with the new renderqueues system Todo: - Billboard rendering - Proper model rendering * Graphics/RenderQueue: Billboard drawing now works (WIP) At 1/4 of previous code performances due to individually process of billboards * Graphics/RenderQueues: Add full support for billboards * Graphics/RenderQueue: Cleanup and improve billboard rendering * Graphics/RenderQueue: Fix model drawing * Examples/Particles: Fix lighting on space station * Graphics: Cleanup forward render queue/technique * Fix compilation under Linux * Graphics/ForwardRenderTechnique: Fix case when scissoring is enabled on material but disabled on element * Add support for Deferred Shading * SDK/Widgets: Fix widget rendering * Graphics: Remove legacy code from render queues * Graphics: Fix some objects sometimes not showing up due to broken scissor box * Fix compilation error * Sdk/GraphicsGraphics: Fix bounding volume * SDK/World: Fix self-assignation * Update changelog for render queues
This commit is contained in:
947
src/Nazara/Graphics/BasicRenderQueue.cpp
Normal file
947
src/Nazara/Graphics/BasicRenderQueue.cpp
Normal file
@@ -0,0 +1,947 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/BasicRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Utility/VertexStruct.hpp>
|
||||
#include <limits>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
///TODO: Replace sinus/cosinus by a lookup table (which will lead to a speed up about 10x)
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::BasicRenderQueue
|
||||
* \brief Graphics class that represents a simple rendering queue
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
*colorPtr++,
|
||||
*positionPtr++,
|
||||
*sizePtr++,
|
||||
*sinCosPtr++
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = *colorPtr++;
|
||||
data->sinCos = *sinCosPtr++;
|
||||
data->size = *sizePtr++;
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
ComputeColor(*alphaPtr++),
|
||||
*positionPtr++,
|
||||
*sizePtr++,
|
||||
*sinCosPtr++
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = ComputeColor(*alphaPtr++);
|
||||
data->sinCos = *sinCosPtr++;
|
||||
data->size = *sizePtr++;
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
*colorPtr++,
|
||||
*positionPtr++,
|
||||
*sizePtr++,
|
||||
ComputeSinCos(*anglePtr++)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = *colorPtr++;
|
||||
data->sinCos = ComputeSinCos(*anglePtr++);
|
||||
data->size = *sizePtr++;
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
ComputeColor(*alphaPtr++),
|
||||
*positionPtr++,
|
||||
*sizePtr++,
|
||||
ComputeSinCos(*anglePtr++)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = ComputeColor(*alphaPtr++);
|
||||
data->sinCos = ComputeSinCos(*anglePtr++);
|
||||
data->size = *sizePtr++;
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
*colorPtr++,
|
||||
*positionPtr++,
|
||||
ComputeSize(*sizePtr++),
|
||||
*sinCosPtr++
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = *colorPtr++;
|
||||
data->sinCos = *sinCosPtr++;
|
||||
data->size = ComputeSize(*sizePtr++);
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
ComputeColor(*alphaPtr++),
|
||||
*positionPtr++,
|
||||
ComputeSize(*sizePtr++),
|
||||
*sinCosPtr++
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = ComputeColor(*alphaPtr++);
|
||||
data->sinCos = *sinCosPtr++;
|
||||
data->size = ComputeSize(*sizePtr++);
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
*colorPtr++,
|
||||
*positionPtr++,
|
||||
ComputeSize(*sizePtr++),
|
||||
ComputeSinCos(*anglePtr++)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = *colorPtr++;
|
||||
data->sinCos = ComputeSinCos(*anglePtr++);
|
||||
data->size = ComputeSize(*sizePtr++);
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
depthSortedBillboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
{
|
||||
ComputeColor(*alphaPtr++),
|
||||
*positionPtr++,
|
||||
ComputeSize(*sizePtr++),
|
||||
ComputeSinCos(*anglePtr++)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t billboardIndex = m_billboards.size();
|
||||
m_billboards.resize(billboardIndex + billboardCount);
|
||||
BillboardData* data = &m_billboards[billboardIndex];
|
||||
|
||||
for (std::size_t i = 0; i < billboardCount; ++i)
|
||||
{
|
||||
data->center = *positionPtr++;
|
||||
data->color = ComputeColor(*alphaPtr++);
|
||||
data->sinCos = ComputeSinCos(*anglePtr++);
|
||||
data->size = ComputeSize(*sizePtr++);
|
||||
data++;
|
||||
}
|
||||
|
||||
billboards.Insert({
|
||||
renderOrder,
|
||||
material,
|
||||
scissorRect,
|
||||
billboardCount,
|
||||
billboardIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable)
|
||||
{
|
||||
NazaraAssert(drawable, "Invalid material");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
customDrawables.Insert({
|
||||
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
|
||||
*
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
void BasicRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
Spheref obbSphere(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
depthSortedModels.Insert({
|
||||
renderOrder,
|
||||
meshData,
|
||||
material,
|
||||
transformMatrix,
|
||||
scissorRect,
|
||||
obbSphere
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
models.Insert({
|
||||
renderOrder,
|
||||
meshData,
|
||||
material,
|
||||
transformMatrix,
|
||||
scissorRect,
|
||||
obbSphere
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 BasicRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay /*= nullptr*/)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
depthSortedSprites.Insert({
|
||||
renderOrder,
|
||||
spriteCount,
|
||||
material,
|
||||
overlay,
|
||||
vertices,
|
||||
scissorRect
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
basicSprites.Insert({
|
||||
renderOrder,
|
||||
spriteCount,
|
||||
material,
|
||||
overlay,
|
||||
vertices,
|
||||
scissorRect
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears the queue
|
||||
*
|
||||
* \param fully Should everything be cleared or we can keep layers
|
||||
*/
|
||||
|
||||
void BasicRenderQueue::Clear(bool fully)
|
||||
{
|
||||
AbstractRenderQueue::Clear(fully);
|
||||
|
||||
basicSprites.Clear();
|
||||
billboards.Clear();
|
||||
depthSortedBillboards.Clear();
|
||||
depthSortedModels.Clear();
|
||||
depthSortedSprites.Clear();
|
||||
models.Clear();
|
||||
|
||||
m_pipelineCache.clear();
|
||||
m_materialCache.clear();
|
||||
m_overlayCache.clear();
|
||||
m_shaderCache.clear();
|
||||
m_textureCache.clear();
|
||||
m_vertexBufferCache.clear();
|
||||
|
||||
m_billboards.clear();
|
||||
m_renderLayers.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sorts the object according to the viewer position, furthest to nearest
|
||||
*
|
||||
* \param viewer Viewer of the scene
|
||||
*/
|
||||
|
||||
void BasicRenderQueue::Sort(const AbstractViewer* viewer)
|
||||
{
|
||||
m_layerCache.clear();
|
||||
for (int layer : m_renderLayers)
|
||||
m_layerCache.emplace(layer, m_layerCache.size());
|
||||
|
||||
auto GetOrInsert = [](auto& container, auto&& value)
|
||||
{
|
||||
auto it = container.find(value);
|
||||
if (it == container.end())
|
||||
it = container.emplace(value, container.size()).first;
|
||||
|
||||
return it->second;
|
||||
};
|
||||
|
||||
basicSprites.Sort([&](const SpriteChain& vertices)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Pipeline (8bits)
|
||||
// - Material (8bits)
|
||||
// - Shader? (8bits)
|
||||
// - Textures (8bits)
|
||||
// - Overlay (8bits)
|
||||
// - Scissor (4bits)
|
||||
// - Depth? (16bits)
|
||||
|
||||
UInt64 layerIndex = m_layerCache[vertices.layerIndex];
|
||||
UInt64 pipelineIndex = GetOrInsert(m_pipelineCache, vertices.material->GetPipeline());
|
||||
UInt64 materialIndex = GetOrInsert(m_materialCache, vertices.material);
|
||||
UInt64 shaderIndex = GetOrInsert(m_shaderCache, vertices.material->GetShader());
|
||||
UInt64 textureIndex = GetOrInsert(m_textureCache, vertices.material->GetDiffuseMap());
|
||||
UInt64 overlayIndex = GetOrInsert(m_overlayCache, vertices.overlay);
|
||||
UInt64 scissorIndex = 0; //< TODO
|
||||
UInt64 depthIndex = 0; //< TODO
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(pipelineIndex & 0xFF) << 52 |
|
||||
(materialIndex & 0xFF) << 44 |
|
||||
(shaderIndex & 0xFF) << 36 |
|
||||
(textureIndex & 0xFF) << 28 |
|
||||
(overlayIndex & 0xFF) << 20 |
|
||||
(scissorIndex & 0x0F) << 16 |
|
||||
(depthIndex & 0xFFFF) << 0;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
billboards.Sort([&](const BillboardChain& billboard)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Pipeline (8bits)
|
||||
// - Material (8bits)
|
||||
// - Shader? (8bits)
|
||||
// - Textures (8bits)
|
||||
// - ??? (8bits)
|
||||
// - Scissor (4bits)
|
||||
// - Depth? (16bits)
|
||||
|
||||
UInt64 layerIndex = m_layerCache[billboard.layerIndex];
|
||||
UInt64 pipelineIndex = GetOrInsert(m_pipelineCache, billboard.material->GetPipeline());
|
||||
UInt64 materialIndex = GetOrInsert(m_materialCache, billboard.material);
|
||||
UInt64 shaderIndex = GetOrInsert(m_shaderCache, billboard.material->GetShader());
|
||||
UInt64 textureIndex = GetOrInsert(m_textureCache, billboard.material->GetDiffuseMap());
|
||||
UInt64 unknownIndex = 0; //< ???
|
||||
UInt64 scissorIndex = 0; //< TODO
|
||||
UInt64 depthIndex = 0; //< TODO?
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(pipelineIndex & 0xFF) << 52 |
|
||||
(materialIndex & 0xFF) << 44 |
|
||||
(shaderIndex & 0xFF) << 36 |
|
||||
(textureIndex & 0xFF) << 28 |
|
||||
(unknownIndex & 0xFF) << 20 |
|
||||
(scissorIndex & 0x0F) << 16 |
|
||||
(depthIndex & 0xFFFF) << 0;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
customDrawables.Sort([&](const CustomDrawable& drawable)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
|
||||
UInt64 layerIndex = m_layerCache[drawable.layerIndex];
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60;
|
||||
|
||||
return index;
|
||||
|
||||
});
|
||||
|
||||
models.Sort([&](const Model& renderData)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Pipeline (8bits)
|
||||
// - Material (8bits)
|
||||
// - Shader? (8bits)
|
||||
// - Textures (8bits)
|
||||
// - Buffers (8bits)
|
||||
// - Scissor (4bits)
|
||||
// - Depth? (16bits)
|
||||
|
||||
UInt64 layerIndex = m_layerCache[renderData.layerIndex];
|
||||
UInt64 pipelineIndex = GetOrInsert(m_pipelineCache, renderData.material->GetPipeline());
|
||||
UInt64 materialIndex = GetOrInsert(m_materialCache, renderData.material);
|
||||
UInt64 shaderIndex = GetOrInsert(m_shaderCache, renderData.material->GetShader());
|
||||
UInt64 textureIndex = GetOrInsert(m_textureCache, renderData.material->GetDiffuseMap());
|
||||
UInt64 bufferIndex = GetOrInsert(m_vertexBufferCache, renderData.meshData.vertexBuffer);
|
||||
UInt64 scissorIndex = 0; //< TODO
|
||||
UInt64 depthIndex = 0; //< TODO
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(pipelineIndex & 0xFF) << 52 |
|
||||
(materialIndex & 0xFF) << 44 |
|
||||
(shaderIndex & 0xFF) << 36 |
|
||||
(textureIndex & 0xFF) << 28 |
|
||||
(bufferIndex & 0xFF) << 20 |
|
||||
(scissorIndex & 0x0F) << 16 |
|
||||
(depthIndex & 0xFFFF) << 0;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
static_assert(std::numeric_limits<float>::is_iec559, "The following sorting functions relies on IEEE 754 floatings-points");
|
||||
|
||||
#if defined(arm) && \
|
||||
((defined(__MAVERICK__) && defined(NAZARA_BIG_ENDIAN)) || \
|
||||
(!defined(__SOFTFP__) && !defined(__VFP_FP__) && !defined(__MAVERICK__)))
|
||||
#error The following code relies on native-endian IEEE-754 representation, which your platform does not guarantee
|
||||
#endif
|
||||
|
||||
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
||||
|
||||
depthSortedBillboards.Sort([&](const Billboard& billboard)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (28bits)
|
||||
|
||||
// Reinterpret depth as UInt32 (this will work as long as they're all either positive or negative,
|
||||
// a negative distance may happen with billboard behind the camera which we don't care about since they'll be rendered)
|
||||
float depth = nearPlane.Distance(billboard.data.center);
|
||||
|
||||
UInt64 layerIndex = m_layerCache[billboard.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(depthIndex & 0xFFFFFFFF) << 28;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
if (viewer->GetProjectionType() == ProjectionType_Orthogonal)
|
||||
{
|
||||
depthSortedModels.Sort([&](const Model& model)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (28bits)
|
||||
|
||||
float depth = nearPlane.Distance(model.obbSphere.GetPosition());
|
||||
|
||||
UInt64 layerIndex = m_layerCache[model.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(depthIndex & 0xFFFFFFFF) << 28;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
depthSortedSprites.Sort([&](const SpriteChain& spriteChain)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (28bits)
|
||||
|
||||
float depth = nearPlane.Distance(spriteChain.vertices[0].position);
|
||||
|
||||
UInt64 layerIndex = m_layerCache[spriteChain.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(depthIndex & 0xFFFFFFFF) << 28;
|
||||
|
||||
return index;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3f viewerPos = viewer->GetEyePosition();
|
||||
|
||||
depthSortedModels.Sort([&](const Model& model)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (28bits)
|
||||
|
||||
float depth = viewerPos.SquaredDistance(model.obbSphere.GetPosition());
|
||||
|
||||
UInt64 layerIndex = m_layerCache[model.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(depthIndex & 0xFFFFFFFF) << 28;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
depthSortedSprites.Sort([&](const SpriteChain& sprites)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (4bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (28bits)
|
||||
|
||||
float depth = viewerPos.SquaredDistance(sprites.vertices[0].position);
|
||||
|
||||
UInt64 layerIndex = m_layerCache[sprites.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 60 |
|
||||
(depthIndex & 0xFFFFFFFF) << 28;
|
||||
|
||||
return index;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,10 @@ namespace Nz
|
||||
* \param instanceData Data used for instance
|
||||
*/
|
||||
|
||||
void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
|
||||
void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const
|
||||
{
|
||||
Nz::Vector3f position = instanceData.transformMatrix.GetTranslation();
|
||||
renderQueue->AddBillboards(instanceData.renderOrder, GetMaterial(), 1, &position, &m_size, &m_sinCos, &m_color);
|
||||
renderQueue->AddBillboards(instanceData.renderOrder, GetMaterial(), 1, scissorRect, &position, &m_size, &m_sinCos, &m_color);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -5,16 +5,34 @@
|
||||
#include <Nazara/Graphics/DeferredGeometryPass.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/OffsetOf.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/DeferredRenderTechnique.hpp>
|
||||
#include <Nazara/Graphics/DeferredProxyRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Graphics/SceneData.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderTexture.hpp>
|
||||
#include <Nazara/Utility/VertexStruct.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct BillboardPoint
|
||||
{
|
||||
Color color;
|
||||
Vector3f position;
|
||||
Vector2f size;
|
||||
Vector2f sinCos; // must follow `size` (both will be sent as a Vector4f)
|
||||
Vector2f uv;
|
||||
};
|
||||
|
||||
UInt32 s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
||||
UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::DeferredGeometryPass
|
||||
@@ -25,8 +43,20 @@ namespace Nz
|
||||
* \brief Constructs a DeferredGeometryPass object by default
|
||||
*/
|
||||
|
||||
DeferredGeometryPass::DeferredGeometryPass()
|
||||
DeferredGeometryPass::DeferredGeometryPass() :
|
||||
m_vertexBuffer(BufferType_Vertex)
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
std::array<UInt8, 4> whitePixel = { { 255, 255, 255, 255 } };
|
||||
m_whiteTexture.Create(ImageType_2D, PixelFormatType_RGBA8, 1, 1);
|
||||
m_whiteTexture.Update(whitePixel.data());
|
||||
|
||||
m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
|
||||
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
|
||||
m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer);
|
||||
|
||||
m_clearShader = ShaderLibrary::Get("DeferredGBufferClear");
|
||||
m_clearStates.depthBuffer = true;
|
||||
m_clearStates.faceCulling = true;
|
||||
@@ -67,131 +97,27 @@ namespace Nz
|
||||
Renderer::SetMatrix(MatrixType_Projection, sceneData.viewer->GetProjectionMatrix());
|
||||
Renderer::SetMatrix(MatrixType_View, sceneData.viewer->GetViewMatrix());
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
BasicRenderQueue& renderQueue = *m_renderQueue->GetDeferredRenderQueue();
|
||||
|
||||
for (auto& layerPair : m_renderQueue->layers)
|
||||
{
|
||||
for (auto& pipelinePair : layerPair.second.opaqueModels)
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
renderQueue.Sort(sceneData.viewer);
|
||||
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
bool instancing = instancingEnabled && (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
if (!renderQueue.models.empty())
|
||||
DrawModels(sceneData, renderQueue, renderQueue.models);
|
||||
|
||||
UInt32 flags = ShaderFlags_Deferred;
|
||||
if (instancing)
|
||||
flags |= ShaderFlags_Instancing;
|
||||
if (!renderQueue.basicSprites.empty())
|
||||
DrawSprites(sceneData, renderQueue, renderQueue.basicSprites);
|
||||
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(flags);
|
||||
if (!renderQueue.billboards.empty())
|
||||
DrawBillboards(sceneData, renderQueue, renderQueue.billboards);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
if (!renderQueue.depthSortedModels.empty())
|
||||
DrawModels(sceneData, renderQueue, renderQueue.depthSortedModels);
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
if (!renderQueue.depthSortedSprites.empty())
|
||||
DrawSprites(sceneData, renderQueue, renderQueue.depthSortedSprites);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
DeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
if (!meshInstances.empty())
|
||||
{
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
if (!instances.empty())
|
||||
{
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
if (instancing)
|
||||
{
|
||||
// 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];
|
||||
std::size_t instanceCount = instances.size();
|
||||
std::size_t maxInstanceCount = instanceBuffer->GetVertexCount(); // The number of matrices that can be hold in the buffer
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
// We compute the number of instances that we will be able to show this time (Depending on the instance buffer size)
|
||||
std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// And we show
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!renderQueue.depthSortedBillboards.empty())
|
||||
DrawBillboards(sceneData, renderQueue, renderQueue.depthSortedBillboards);
|
||||
|
||||
return false; // We only fill the G-Buffer, the work texture are unchanged
|
||||
}
|
||||
@@ -266,13 +192,409 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredGeometryPass::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue<BasicRenderQueue::Billboard>& billboards) const
|
||||
{
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
|
||||
|
||||
/*!
|
||||
* \brief Gets the uniforms of a shader
|
||||
* \return Uniforms of the shader
|
||||
*
|
||||
* \param shader Shader to get uniforms from
|
||||
*/
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
Nz::BufferMapper<VertexBuffer> instanceBufferMapper;
|
||||
std::size_t billboardCount = 0;
|
||||
std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
|
||||
auto Commit = [&]()
|
||||
{
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
instanceBufferMapper.Unmap();
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
|
||||
billboardCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
const Texture* lastOverlay = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
for (const BasicRenderQueue::Billboard& billboard : billboards)
|
||||
{
|
||||
const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect;
|
||||
|
||||
if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
||||
{
|
||||
Commit();
|
||||
|
||||
const MaterialPipeline* pipeline = billboard.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (lastMaterial != billboard.material)
|
||||
{
|
||||
billboard.material->Apply(*pipelineInstance);
|
||||
lastMaterial = billboard.material;
|
||||
}
|
||||
|
||||
if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
if (!instanceBufferMapper.GetBuffer())
|
||||
instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite);
|
||||
|
||||
std::memcpy(static_cast<Nz::UInt8*>(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, &billboard.data, sizeof(BasicRenderQueue::BillboardData));
|
||||
if (++billboardCount >= maxBillboardPerDraw)
|
||||
Commit();
|
||||
}
|
||||
|
||||
Commit();
|
||||
}
|
||||
|
||||
void DeferredGeometryPass::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue<BasicRenderQueue::BillboardChain>& billboards) const
|
||||
{
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
|
||||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
Nz::BufferMapper<VertexBuffer> instanceBufferMapper;
|
||||
std::size_t billboardCount = 0;
|
||||
std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
|
||||
auto Commit = [&]()
|
||||
{
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
instanceBufferMapper.Unmap();
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
|
||||
billboardCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
const Texture* lastOverlay = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
for (const BasicRenderQueue::BillboardChain& billboard : billboards)
|
||||
{
|
||||
const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect;
|
||||
|
||||
if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
||||
{
|
||||
Commit();
|
||||
|
||||
const MaterialPipeline* pipeline = billboard.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (lastMaterial != billboard.material)
|
||||
{
|
||||
billboard.material->Apply(*pipelineInstance);
|
||||
lastMaterial = billboard.material;
|
||||
}
|
||||
|
||||
if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t billboardRemaining = billboard.billboardCount;
|
||||
const BasicRenderQueue::BillboardData* billboardData = renderQueue.GetBillboardData(billboard.billboardIndex);
|
||||
do
|
||||
{
|
||||
std::size_t renderedBillboardCount = std::min(billboardRemaining, maxBillboardPerDraw - billboardCount);
|
||||
billboardRemaining -= renderedBillboardCount;
|
||||
|
||||
if (!instanceBufferMapper.GetBuffer())
|
||||
instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite);
|
||||
|
||||
std::memcpy(static_cast<Nz::UInt8*>(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, billboardData, renderedBillboardCount * sizeof(BasicRenderQueue::BillboardData));
|
||||
billboardCount += renderedBillboardCount;
|
||||
billboardData += renderedBillboardCount;
|
||||
|
||||
if (billboardCount >= maxBillboardPerDraw)
|
||||
Commit();
|
||||
}
|
||||
while (billboardRemaining > 0);
|
||||
}
|
||||
|
||||
Commit();
|
||||
}
|
||||
|
||||
void DeferredGeometryPass::DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const Nz::RenderQueue<Nz::BasicRenderQueue::Model>& models) const
|
||||
{
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
///TODO: Reimplement instancing
|
||||
|
||||
for (const BasicRenderQueue::Model& model : models)
|
||||
{
|
||||
const MaterialPipeline* pipeline = model.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &model.material->GetPipeline()->Apply(ShaderFlags_Deferred);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (lastMaterial != model.material)
|
||||
{
|
||||
model.material->Apply(*pipelineInstance);
|
||||
lastMaterial = model.material;
|
||||
}
|
||||
|
||||
if (model.material->IsScissorTestEnabled())
|
||||
{
|
||||
const Nz::Recti& scissorRect = (model.scissorRect.width > 0) ? model.scissorRect : fullscreenScissorRect;
|
||||
if (scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (model.meshData.indexBuffer)
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = model.meshData.indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = model.meshData.vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
Renderer::SetIndexBuffer(model.meshData.indexBuffer);
|
||||
Renderer::SetVertexBuffer(model.meshData.vertexBuffer);
|
||||
|
||||
Renderer::SetMatrix(MatrixType_World, model.matrix);
|
||||
drawFunc(model.meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredGeometryPass::DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue<BasicRenderQueue::SpriteChain>& spriteList) const
|
||||
{
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
|
||||
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
||||
m_spriteChains.clear();
|
||||
|
||||
auto Commit = [&]()
|
||||
{
|
||||
std::size_t spriteChainCount = m_spriteChains.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
std::size_t spriteChain = 0; // Which chain of sprites are we treating
|
||||
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// 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());
|
||||
|
||||
std::size_t spriteCount = 0;
|
||||
|
||||
do
|
||||
{
|
||||
const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first;
|
||||
std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second;
|
||||
std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset);
|
||||
|
||||
std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count * 4;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChainSpriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
}
|
||||
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
}
|
||||
while (spriteChain < spriteChainCount);
|
||||
}
|
||||
|
||||
m_spriteChains.clear();
|
||||
};
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
const Texture* lastOverlay = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList)
|
||||
{
|
||||
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
|
||||
|
||||
if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
||||
{
|
||||
Commit();
|
||||
|
||||
const MaterialPipeline* pipeline = basicSprites.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
// Overlay texture unit
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (lastMaterial != basicSprites.material)
|
||||
{
|
||||
basicSprites.material->Apply(*pipelineInstance);
|
||||
|
||||
Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler());
|
||||
|
||||
lastMaterial = basicSprites.material;
|
||||
}
|
||||
|
||||
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : &m_whiteTexture;
|
||||
if (overlayTexture != lastOverlay)
|
||||
{
|
||||
Renderer::SetTexture(overlayTextureUnit, overlayTexture);
|
||||
lastOverlay = overlayTexture;
|
||||
}
|
||||
|
||||
if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount);
|
||||
}
|
||||
|
||||
Commit();
|
||||
}
|
||||
|
||||
const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const
|
||||
{
|
||||
@@ -303,4 +625,73 @@ namespace Nz
|
||||
{
|
||||
m_shaderUniforms.erase(shader);
|
||||
}
|
||||
|
||||
bool DeferredGeometryPass::Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0);
|
||||
|
||||
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 + 2;
|
||||
*indices++ = i * 4 + 3;
|
||||
*indices++ = i * 4 + 1;
|
||||
}
|
||||
|
||||
mapper.Unmap(); // No point to keep the buffer open any longer
|
||||
|
||||
// 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, 0);
|
||||
|
||||
float vertices[2 * 4] = {
|
||||
-0.5f, -0.5f,
|
||||
0.5f, -0.5f,
|
||||
-0.5f, 0.5f,
|
||||
0.5f, 0.5f,
|
||||
};
|
||||
|
||||
s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices));
|
||||
|
||||
// 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)); // Includes sincos
|
||||
|
||||
// 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(BasicRenderQueue::BillboardData, center));
|
||||
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(BasicRenderQueue::BillboardData, size)); // Englobe sincos
|
||||
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(BasicRenderQueue::BillboardData, color));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError("Failed to initialise: " + String(e.what()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeferredGeometryPass::Uninitialize()
|
||||
{
|
||||
s_quadIndexBuffer.Reset();
|
||||
s_quadVertexBuffer.Reset();
|
||||
}
|
||||
|
||||
IndexBuffer DeferredGeometryPass::s_quadIndexBuffer;
|
||||
VertexBuffer DeferredGeometryPass::s_quadVertexBuffer;
|
||||
VertexDeclaration DeferredGeometryPass::s_billboardInstanceDeclaration;
|
||||
VertexDeclaration DeferredGeometryPass::s_billboardVertexDeclaration;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <Nazara/Graphics/DeferredPhongLightingPass.hpp>
|
||||
#include <Nazara/Core/Primitive.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/DeferredRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/DeferredProxyRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/SceneData.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderTexture.hpp>
|
||||
|
||||
261
src/Nazara/Graphics/DeferredProxyRenderQueue.cpp
Normal file
261
src/Nazara/Graphics/DeferredProxyRenderQueue.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/DeferredProxyRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/BasicRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::DeferredProxyRenderQueue
|
||||
* \brief Graphics class sorting the objects into a deferred and forward render queue (depending on blending)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr);
|
||||
else
|
||||
m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, 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 DeferredProxyRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable)
|
||||
{
|
||||
m_forwardRenderQueue->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 DeferredProxyRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix, scissorRect);
|
||||
else
|
||||
m_forwardRenderQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix, scissorRect);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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 DeferredProxyRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (!material->IsBlendingEnabled())
|
||||
m_deferredRenderQueue->AddSprites(renderOrder, material, vertices, spriteCount, scissorRect, overlay);
|
||||
else
|
||||
m_forwardRenderQueue->AddSprites(renderOrder, material, vertices, spriteCount, scissorRect, overlay);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears the queue
|
||||
*
|
||||
* \param fully Should everything be cleared or we can keep layers
|
||||
*/
|
||||
|
||||
void DeferredProxyRenderQueue::Clear(bool fully)
|
||||
{
|
||||
AbstractRenderQueue::Clear(fully);
|
||||
|
||||
m_deferredRenderQueue->Clear(fully);
|
||||
m_forwardRenderQueue->Clear(fully);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/DeferredRenderPass.hpp>
|
||||
#include <Nazara/Graphics/DeferredProxyRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/DeferredRenderTechnique.hpp>
|
||||
#include <Nazara/Graphics/DeferredRenderQueue.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Nz
|
||||
void DeferredRenderPass::Initialize(DeferredRenderTechnique* technique)
|
||||
{
|
||||
m_deferredTechnique = technique;
|
||||
m_renderQueue = static_cast<DeferredRenderQueue*>(technique->GetRenderQueue());
|
||||
m_renderQueue = static_cast<DeferredProxyRenderQueue*>(technique->GetRenderQueue());
|
||||
|
||||
m_depthStencilTexture = technique->GetDepthStencilTexture();
|
||||
|
||||
|
||||
@@ -1,410 +0,0 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/DeferredRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
///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 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->IsBlendingEnabled() || material->IsDepthSortingEnabled()) //< Fixme: Deferred Shading should be able to handle depth sorting
|
||||
// Deferred Shading cannot handle blended objects, put them in the forward list
|
||||
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
|
||||
else
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels;
|
||||
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = opaqueModels.find(materialPipeline);
|
||||
if (pipelineIt == opaqueModels.end())
|
||||
{
|
||||
BatchedMaterialEntry materialEntry;
|
||||
pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedMaterialEntry& materialEntry = pipelineIt->second;
|
||||
MeshMaterialBatches& materialMap = materialEntry.materialMap;
|
||||
|
||||
auto materialIt = materialMap.find(material);
|
||||
if (materialIt == materialMap.end())
|
||||
{
|
||||
BatchedModelEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &DeferredRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedModelEntry& entry = materialIt->second;
|
||||
entry.enabled = true;
|
||||
|
||||
MeshInstanceContainer& meshMap = entry.meshMap;
|
||||
|
||||
auto it2 = meshMap.find(meshData);
|
||||
if (it2 == meshMap.end())
|
||||
{
|
||||
MeshInstanceEntry instanceEntry;
|
||||
if (meshData.indexBuffer)
|
||||
instanceEntry.indexBufferReleaseSlot.Connect(meshData.indexBuffer->OnIndexBufferRelease, this, &DeferredRenderQueue::OnIndexBufferInvalidation);
|
||||
|
||||
instanceEntry.vertexBufferReleaseSlot.Connect(meshData.vertexBuffer->OnVertexBufferRelease, this, &DeferredRenderQueue::OnVertexBufferInvalidation);
|
||||
|
||||
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
|
||||
}
|
||||
|
||||
std::vector<Matrix4f>& instances = it2->second.instances;
|
||||
instances.push_back(transformMatrix);
|
||||
|
||||
materialEntry.maxInstanceCount = std::max(materialEntry.maxInstanceCount, instances.size());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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, std::size_t 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);
|
||||
|
||||
if (fully)
|
||||
layers.clear();
|
||||
else
|
||||
{
|
||||
for (auto it = layers.begin(); it != layers.end();)
|
||||
{
|
||||
Layer& layer = it->second;
|
||||
if (layer.clearCount++ >= 100)
|
||||
it = layers.erase(it);
|
||||
else
|
||||
{
|
||||
for (auto& pipelinePair : layer.opaqueModels)
|
||||
{
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
meshEntry.instances.clear();
|
||||
}
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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 DeferredRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.indexBuffer == indexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a material
|
||||
*
|
||||
* \param material Material being invalidated
|
||||
*/
|
||||
|
||||
void DeferredRenderQueue::OnMaterialInvalidation(const Material* material)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a vertex buffer
|
||||
*
|
||||
* \param vertexBuffer Vertex buffer being invalidated
|
||||
*/
|
||||
|
||||
void DeferredRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.vertexBuffer == vertexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ namespace Nz
|
||||
*/
|
||||
|
||||
DeferredRenderTechnique::DeferredRenderTechnique() :
|
||||
m_renderQueue(static_cast<ForwardRenderQueue*>(m_forwardTechnique.GetRenderQueue())),
|
||||
m_renderQueue(&m_deferredRenderQueue, static_cast<BasicRenderQueue*>(m_forwardTechnique.GetRenderQueue())),
|
||||
m_GBufferSize(0U)
|
||||
{
|
||||
m_depthStencilTexture = Texture::New();
|
||||
@@ -455,35 +455,35 @@ namespace Nz
|
||||
switch (renderPass)
|
||||
{
|
||||
case RenderPassType_AA:
|
||||
smartPtr.reset(new DeferredFXAAPass);
|
||||
smartPtr = std::make_unique<DeferredFXAAPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_Bloom:
|
||||
smartPtr.reset(new DeferredBloomPass);
|
||||
smartPtr = std::make_unique<DeferredBloomPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_DOF:
|
||||
smartPtr.reset(new DeferredDOFPass);
|
||||
smartPtr = std::make_unique<DeferredDOFPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_Final:
|
||||
smartPtr.reset(new DeferredFinalPass);
|
||||
smartPtr = std::make_unique<DeferredFinalPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_Fog:
|
||||
smartPtr.reset(new DeferredFogPass);
|
||||
smartPtr = std::make_unique<DeferredFogPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_Forward:
|
||||
smartPtr.reset(new DeferredForwardPass);
|
||||
smartPtr = std::make_unique<DeferredForwardPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_Geometry:
|
||||
smartPtr.reset(new DeferredGeometryPass);
|
||||
smartPtr = std::make_unique<DeferredGeometryPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_Lighting:
|
||||
smartPtr.reset(new DeferredPhongLightingPass);
|
||||
smartPtr = std::make_unique<DeferredPhongLightingPass>();
|
||||
break;
|
||||
|
||||
case RenderPassType_SSAO:
|
||||
@@ -701,6 +701,12 @@ namespace Nz
|
||||
NazaraWarning("Failed to register gaussian blur shader, certain features will not work: " + error);
|
||||
}
|
||||
|
||||
if (!DeferredGeometryPass::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize geometry pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -710,6 +716,8 @@ namespace Nz
|
||||
|
||||
void DeferredRenderTechnique::Uninitialize()
|
||||
{
|
||||
DeferredGeometryPass::Uninitialize();
|
||||
|
||||
ShaderLibrary::Unregister("DeferredGBufferClear");
|
||||
ShaderLibrary::Unregister("DeferredDirectionnalLight");
|
||||
ShaderLibrary::Unregister("DeferredPointSpotLight");
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -56,7 +56,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -73,7 +73,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -86,7 +86,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -103,7 +103,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -116,7 +116,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -133,7 +133,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -146,7 +146,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -163,7 +163,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -176,7 +176,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -193,7 +193,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -206,7 +206,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -223,7 +223,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -236,7 +236,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -253,7 +253,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -266,11 +266,11 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
|
||||
BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a direcitonal light to the queue
|
||||
* \brief Adds a directional light to the queue
|
||||
*
|
||||
* \param light Light to add
|
||||
*
|
||||
@@ -295,7 +295,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
|
||||
void DepthRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -309,7 +309,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddMesh(0, material, meshData, meshAABB, transformMatrix);
|
||||
BasicRenderQueue::AddMesh(0, material, meshData, meshAABB, transformMatrix, scissorRect);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -352,7 +352,7 @@ namespace Nz
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay)
|
||||
void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay /*= nullptr*/)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
NazaraUnused(renderOrder);
|
||||
@@ -366,7 +366,7 @@ namespace Nz
|
||||
else
|
||||
material = m_baseMaterial;
|
||||
|
||||
ForwardRenderQueue::AddSprites(0, material, vertices, spriteCount, overlay);
|
||||
BasicRenderQueue::AddSprites(0, material, vertices, spriteCount, scissorRect, overlay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
#include <Nazara/Graphics/DepthRenderTechnique.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/OffsetOf.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/Drawable.hpp>
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Graphics/SceneData.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Utility/BufferMapper.hpp>
|
||||
#include <Nazara/Utility/VertexStruct.hpp>
|
||||
#include <limits>
|
||||
@@ -83,22 +85,28 @@ namespace Nz
|
||||
|
||||
bool DepthRenderTechnique::Draw(const SceneData& sceneData) const
|
||||
{
|
||||
for (auto& pair : m_renderQueue.layers)
|
||||
{
|
||||
ForwardRenderQueue::Layer& layer = pair.second;
|
||||
m_renderQueue.Sort(sceneData.viewer);
|
||||
|
||||
if (!layer.opaqueModels.empty())
|
||||
DrawOpaqueModels(sceneData, layer);
|
||||
if (!m_renderQueue.models.empty())
|
||||
DrawModels(sceneData, m_renderQueue, m_renderQueue.models);
|
||||
|
||||
if (!layer.opaqueSprites.empty())
|
||||
DrawBasicSprites(sceneData, layer);
|
||||
if (!m_renderQueue.basicSprites.empty())
|
||||
DrawSprites(sceneData, m_renderQueue, m_renderQueue.basicSprites);
|
||||
|
||||
if (!layer.billboards.empty())
|
||||
DrawBillboards(sceneData, layer);
|
||||
if (!m_renderQueue.billboards.empty())
|
||||
DrawBillboards(sceneData, m_renderQueue, m_renderQueue.billboards);
|
||||
|
||||
for (const Drawable* drawable : layer.otherDrawables)
|
||||
drawable->Draw();
|
||||
}
|
||||
if (!m_renderQueue.depthSortedModels.empty())
|
||||
DrawModels(sceneData, m_renderQueue, m_renderQueue.depthSortedModels);
|
||||
|
||||
if (!m_renderQueue.depthSortedSprites.empty())
|
||||
DrawSprites(sceneData, m_renderQueue, m_renderQueue.depthSortedSprites);
|
||||
|
||||
if (!m_renderQueue.depthSortedBillboards.empty())
|
||||
DrawBillboards(sceneData, m_renderQueue, m_renderQueue.depthSortedBillboards);
|
||||
|
||||
if (!m_renderQueue.customDrawables.empty())
|
||||
DrawCustomDrawables(sceneData, m_renderQueue, m_renderQueue.customDrawables);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -175,9 +183,9 @@ namespace Nz
|
||||
|
||||
// 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
|
||||
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));
|
||||
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(BasicRenderQueue::BillboardData, center));
|
||||
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(BasicRenderQueue::BillboardData, size)); // Englobe sincos
|
||||
s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(BasicRenderQueue::BillboardData, color));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@@ -197,411 +205,406 @@ namespace Nz
|
||||
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
|
||||
|
||||
void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue<BasicRenderQueue::Billboard>& billboards) const
|
||||
{
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
|
||||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
Nz::BufferMapper<VertexBuffer> instanceBufferMapper;
|
||||
std::size_t billboardCount = 0;
|
||||
std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
|
||||
auto Commit = [&]()
|
||||
{
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
instanceBufferMapper.Unmap();
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
|
||||
billboardCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
const Texture* lastOverlay = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
for (const BasicRenderQueue::Billboard& billboard : billboards)
|
||||
{
|
||||
const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect;
|
||||
|
||||
if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
||||
{
|
||||
Commit();
|
||||
|
||||
const MaterialPipeline* pipeline = billboard.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (lastMaterial != billboard.material)
|
||||
{
|
||||
billboard.material->Apply(*pipelineInstance);
|
||||
lastMaterial = billboard.material;
|
||||
}
|
||||
|
||||
if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
if (!instanceBufferMapper.GetBuffer())
|
||||
instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite);
|
||||
|
||||
std::memcpy(static_cast<Nz::UInt8*>(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, &billboard.data, sizeof(BasicRenderQueue::BillboardData));
|
||||
if (++billboardCount >= maxBillboardPerDraw)
|
||||
Commit();
|
||||
}
|
||||
|
||||
Commit();
|
||||
}
|
||||
|
||||
void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue<BasicRenderQueue::BillboardChain>& billboards) const
|
||||
{
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
|
||||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
Nz::BufferMapper<VertexBuffer> instanceBufferMapper;
|
||||
std::size_t billboardCount = 0;
|
||||
std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
|
||||
auto Commit = [&]()
|
||||
{
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
instanceBufferMapper.Unmap();
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
|
||||
billboardCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
const Texture* lastOverlay = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
for (const BasicRenderQueue::BillboardChain& billboard : billboards)
|
||||
{
|
||||
const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect;
|
||||
|
||||
if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
||||
{
|
||||
Commit();
|
||||
|
||||
const MaterialPipeline* pipeline = billboard.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (lastMaterial != billboard.material)
|
||||
{
|
||||
billboard.material->Apply(*pipelineInstance);
|
||||
lastMaterial = billboard.material;
|
||||
}
|
||||
|
||||
if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t billboardRemaining = billboard.billboardCount;
|
||||
const BasicRenderQueue::BillboardData* billboardData = renderQueue.GetBillboardData(billboard.billboardIndex);
|
||||
do
|
||||
{
|
||||
std::size_t renderedBillboardCount = std::min(billboardRemaining, maxBillboardPerDraw - billboardCount);
|
||||
billboardRemaining -= renderedBillboardCount;
|
||||
|
||||
if (!instanceBufferMapper.GetBuffer())
|
||||
instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite);
|
||||
|
||||
std::memcpy(static_cast<Nz::UInt8*>(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, billboardData, renderedBillboardCount * sizeof(BasicRenderQueue::BillboardData));
|
||||
billboardCount += renderedBillboardCount;
|
||||
billboardData += renderedBillboardCount;
|
||||
|
||||
if (billboardCount >= maxBillboardPerDraw)
|
||||
Commit();
|
||||
}
|
||||
while (billboardRemaining > 0);
|
||||
}
|
||||
|
||||
Commit();
|
||||
}
|
||||
|
||||
void DepthRenderTechnique::DrawCustomDrawables(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue<BasicRenderQueue::CustomDrawable>& customDrawables) const
|
||||
{
|
||||
for (const BasicRenderQueue::CustomDrawable& customDrawable : customDrawables)
|
||||
customDrawable.drawable->Draw();
|
||||
}
|
||||
|
||||
void DepthRenderTechnique::DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const Nz::RenderQueue<Nz::BasicRenderQueue::Model>& models) const
|
||||
{
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
///TODO: Reimplement instancing
|
||||
|
||||
for (const BasicRenderQueue::Model& model : models)
|
||||
{
|
||||
const MaterialPipeline* pipeline = model.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &model.material->GetPipeline()->Apply(ShaderFlags_Deferred);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (lastMaterial != model.material)
|
||||
{
|
||||
model.material->Apply(*pipelineInstance);
|
||||
lastMaterial = model.material;
|
||||
}
|
||||
|
||||
if (model.material->IsScissorTestEnabled())
|
||||
{
|
||||
const Nz::Recti& scissorRect = (model.scissorRect.width > 0) ? model.scissorRect : fullscreenScissorRect;
|
||||
if (scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (model.meshData.indexBuffer)
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = model.meshData.indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = model.meshData.vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
Renderer::SetIndexBuffer(model.meshData.indexBuffer);
|
||||
Renderer::SetVertexBuffer(model.meshData.vertexBuffer);
|
||||
|
||||
Renderer::SetMatrix(MatrixType_World, model.matrix);
|
||||
drawFunc(model.meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DepthRenderTechnique::DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue<BasicRenderQueue::SpriteChain>& spriteList) const
|
||||
{
|
||||
const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
|
||||
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
|
||||
|
||||
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
for (auto& pipelinePair : layer.opaqueSprites)
|
||||
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
|
||||
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
||||
m_spriteChains.clear();
|
||||
|
||||
auto Commit = [&]()
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.enabled)
|
||||
std::size_t spriteChainCount = m_spriteChains.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||
std::size_t spriteChain = 0; // Which chain of sprites are we treating
|
||||
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
do
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
// 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());
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
std::size_t spriteCount = 0;
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
do
|
||||
{
|
||||
unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
|
||||
material->Apply(pipelineInstance);
|
||||
const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first;
|
||||
std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second;
|
||||
std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset);
|
||||
|
||||
std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
|
||||
vertices += count * 4;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChainSpriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
}
|
||||
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
}
|
||||
while (spriteChain < spriteChainCount);
|
||||
}
|
||||
|
||||
m_spriteChains.clear();
|
||||
};
|
||||
|
||||
const Material* lastMaterial = nullptr;
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
const Texture* lastOverlay = nullptr;
|
||||
Recti lastScissorRect = Recti(-1, -1);
|
||||
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
|
||||
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList)
|
||||
{
|
||||
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
|
||||
|
||||
if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
||||
{
|
||||
Commit();
|
||||
|
||||
const MaterialPipeline* pipeline = basicSprites.material->GetPipeline();
|
||||
if (lastPipeline != pipeline)
|
||||
{
|
||||
pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
|
||||
// Overlay texture unit
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
||||
|
||||
Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler());
|
||||
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
{
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
|
||||
std::size_t spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
Renderer::SetTexture(overlayTextureUnit, (overlay) ? overlay : &m_whiteTexture);
|
||||
|
||||
std::size_t spriteChain = 0; // Which chain of sprites are we treating
|
||||
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
do
|
||||
{
|
||||
// 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());
|
||||
|
||||
std::size_t spriteCount = 0;
|
||||
std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
||||
do
|
||||
{
|
||||
ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
|
||||
std::size_t 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;
|
||||
|
||||
spriteCount += count;
|
||||
spriteChainOffset += count;
|
||||
|
||||
// Have we treated the entire chain ?
|
||||
if (spriteChainOffset == currentChain.spriteCount)
|
||||
{
|
||||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
} while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
} while (spriteChain < spriteChainCount);
|
||||
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// We set it back to zero
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
if (Renderer::HasCapability(RendererCap_Instancing))
|
||||
{
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
|
||||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
std::size_t billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
material->Apply(pipelineInstance);
|
||||
if (lastMaterial != basicSprites.material)
|
||||
{
|
||||
basicSprites.material->Apply(*pipelineInstance);
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
{
|
||||
std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler());
|
||||
|
||||
instanceBuffer->Fill(data, 0, renderedBillboardCount);
|
||||
data += renderedBillboardCount;
|
||||
lastMaterial = basicSprites.material;
|
||||
}
|
||||
|
||||
Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4);
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : &m_whiteTexture;
|
||||
if (overlayTexture != lastOverlay)
|
||||
{
|
||||
Renderer::SetTexture(overlayTextureUnit, overlayTexture);
|
||||
lastOverlay = overlayTexture;
|
||||
}
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
|
||||
{
|
||||
Renderer::SetScissorRect(scissorRect);
|
||||
lastScissorRect = scissorRect;
|
||||
}
|
||||
}
|
||||
|
||||
m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||
Renderer::SetVertexBuffer(&m_billboardPointBuffer);
|
||||
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
std::size_t maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
std::size_t billboardCount = billboardVector.size();
|
||||
do
|
||||
{
|
||||
std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
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)
|
||||
{
|
||||
const ForwardRenderQueue::BillboardData& billboard = *data++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 1.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 1.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(0.f, 0.f);
|
||||
vertices++;
|
||||
|
||||
vertices->color = billboard.color;
|
||||
vertices->position = billboard.center;
|
||||
vertices->sinCos = billboard.sinCos;
|
||||
vertices->size = billboard.size;
|
||||
vertices->uv.Set(1.f, 0.f);
|
||||
vertices++;
|
||||
}
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6);
|
||||
}
|
||||
while (billboardCount > 0);
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& pipelinePair : layer.opaqueModels)
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply((instancing) ? ShaderFlags_Instancing : 0);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
if (!instances.empty())
|
||||
{
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
// Handle draw call before rendering loop
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
if (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];
|
||||
std::size_t instanceCount = instances.size();
|
||||
std::size_t maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
// We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size)
|
||||
std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
// We fill the instancing buffer with our world matrices
|
||||
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount);
|
||||
instanceMatrices += renderedInstanceCount;
|
||||
|
||||
// And we draw
|
||||
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
instances.clear();
|
||||
}
|
||||
}
|
||||
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
Commit();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -1,931 +0,0 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Utility/VertexStruct.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
///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 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");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = *colorPtr++;
|
||||
billboardData->sinCos = *sinCosPtr++;
|
||||
billboardData->size = *sizePtr++;
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = Color(255, 255, 255, static_cast<UInt8>(255.f * (*alphaPtr++)));
|
||||
billboardData->sinCos = *sinCosPtr++;
|
||||
billboardData->size = *sizePtr++;
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
float sin = std::sin(ToRadians(*anglePtr));
|
||||
float cos = std::cos(ToRadians(*anglePtr));
|
||||
anglePtr++;
|
||||
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = *colorPtr++;
|
||||
billboardData->sinCos.Set(sin, cos);
|
||||
billboardData->size = *sizePtr++;
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
float sin = std::sin(ToRadians(*anglePtr));
|
||||
float cos = std::cos(ToRadians(*anglePtr));
|
||||
anglePtr++;
|
||||
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = Color(255, 255, 255, static_cast<UInt8>(255.f * (*alphaPtr++)));
|
||||
billboardData->sinCos.Set(sin, cos);
|
||||
billboardData->size = *sizePtr++;
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = *colorPtr++;
|
||||
billboardData->sinCos = *sinCosPtr++;
|
||||
billboardData->size.Set(*sizePtr++);
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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");
|
||||
|
||||
Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
|
||||
|
||||
if (!sinCosPtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = Color(255, 255, 255, static_cast<UInt8>(255.f * (*alphaPtr++)));
|
||||
billboardData->sinCos = *sinCosPtr++;
|
||||
billboardData->size.Set(*sizePtr++);
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
float sin = std::sin(ToRadians(*anglePtr));
|
||||
float cos = std::cos(ToRadians(*anglePtr));
|
||||
anglePtr++;
|
||||
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = *colorPtr++;
|
||||
billboardData->sinCos.Set(sin, cos);
|
||||
billboardData->size.Set(*sizePtr++);
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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");
|
||||
|
||||
float defaultRotation = 0.f;
|
||||
|
||||
if (!anglePtr)
|
||||
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); // Same
|
||||
|
||||
BillboardData* billboardData = GetBillboardData(renderOrder, material, count);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
float sin = std::sin(ToRadians(*anglePtr));
|
||||
float cos = std::cos(ToRadians(*anglePtr));
|
||||
anglePtr++;
|
||||
|
||||
billboardData->center = *positionPtr++;
|
||||
billboardData->color = Color(255, 255, 255, static_cast<UInt8>(255.f * (*alphaPtr++)));
|
||||
billboardData->sinCos.Set(sin, cos);
|
||||
billboardData->size.Set(*sizePtr++);
|
||||
billboardData++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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
|
||||
if (!drawable)
|
||||
{
|
||||
NazaraError("Invalid drawable");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto& otherDrawables = GetLayer(renderOrder).otherDrawables;
|
||||
|
||||
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->IsDepthSortingEnabled())
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& transparentMeshes = currentLayer.depthSortedMeshes;
|
||||
auto& transparentData = currentLayer.depthSortedMeshData;
|
||||
|
||||
// The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them)
|
||||
std::size_t index = transparentData.size();
|
||||
transparentData.resize(index+1);
|
||||
|
||||
UnbatchedModelData& data = transparentData.back();
|
||||
data.material = material;
|
||||
data.meshData = meshData;
|
||||
data.obbSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
|
||||
data.transformMatrix = transformMatrix;
|
||||
|
||||
transparentMeshes.push_back(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels;
|
||||
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = opaqueModels.find(materialPipeline);
|
||||
if (pipelineIt == opaqueModels.end())
|
||||
{
|
||||
BatchedMaterialEntry materialEntry;
|
||||
pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedMaterialEntry& materialEntry = pipelineIt->second;
|
||||
MeshMaterialBatches& materialMap = materialEntry.materialMap;
|
||||
|
||||
auto materialIt = materialMap.find(material);
|
||||
if (materialIt == materialMap.end())
|
||||
{
|
||||
BatchedModelEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedModelEntry& entry = materialIt->second;
|
||||
entry.enabled = true;
|
||||
|
||||
MeshInstanceContainer& meshMap = entry.meshMap;
|
||||
|
||||
auto it2 = meshMap.find(meshData);
|
||||
if (it2 == meshMap.end())
|
||||
{
|
||||
MeshInstanceEntry instanceEntry;
|
||||
instanceEntry.squaredBoundingSphere = meshAABB.GetSquaredBoundingSphere();
|
||||
|
||||
if (meshData.indexBuffer)
|
||||
instanceEntry.indexBufferReleaseSlot.Connect(meshData.indexBuffer->OnIndexBufferRelease, this, &ForwardRenderQueue::OnIndexBufferInvalidation);
|
||||
|
||||
instanceEntry.vertexBufferReleaseSlot.Connect(meshData.vertexBuffer->OnVertexBufferRelease, this, &ForwardRenderQueue::OnVertexBufferInvalidation);
|
||||
|
||||
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
|
||||
}
|
||||
|
||||
std::vector<Matrix4f>& instances = it2->second.instances;
|
||||
instances.push_back(transformMatrix);
|
||||
|
||||
materialEntry.maxInstanceCount = std::max(materialEntry.maxInstanceCount, instances.size());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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, std::size_t spriteCount, const Texture* overlay)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
auto& transparentSprites = currentLayer.depthSortedSprites;
|
||||
auto& transparentData = currentLayer.depthSortedSpriteData;
|
||||
|
||||
// The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them)
|
||||
std::size_t index = transparentData.size();
|
||||
transparentData.resize(index + 1);
|
||||
|
||||
UnbatchedSpriteData& data = transparentData.back();
|
||||
data.material = material;
|
||||
data.overlay = overlay;
|
||||
data.spriteCount = spriteCount;
|
||||
data.vertices = vertices;
|
||||
|
||||
transparentSprites.push_back(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpritePipelineBatches& sprites = currentLayer.opaqueSprites;
|
||||
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = sprites.find(materialPipeline);
|
||||
if (pipelineIt == sprites.end())
|
||||
{
|
||||
BatchedSpritePipelineEntry materialEntry;
|
||||
pipelineIt = sprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second;
|
||||
pipelineEntry.enabled = true;
|
||||
|
||||
SpriteMaterialBatches& materialMap = pipelineEntry.materialMap;
|
||||
|
||||
auto matIt = materialMap.find(material);
|
||||
if (matIt == materialMap.end())
|
||||
{
|
||||
BatchedBasicSpriteEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
matIt = materialMap.insert(SpriteMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedBasicSpriteEntry& entry = matIt->second;
|
||||
entry.enabled = true;
|
||||
|
||||
auto& overlayMap = entry.overlayMap;
|
||||
|
||||
auto overlayIt = overlayMap.find(overlay);
|
||||
if (overlayIt == overlayMap.end())
|
||||
{
|
||||
BatchedSpriteEntry overlayEntry;
|
||||
if (overlay)
|
||||
overlayEntry.textureReleaseSlot.Connect(overlay->OnTextureRelease, this, &ForwardRenderQueue::OnTextureInvalidation);
|
||||
|
||||
overlayIt = overlayMap.insert(std::make_pair(overlay, std::move(overlayEntry))).first;
|
||||
}
|
||||
|
||||
auto& spriteVector = overlayIt->second.spriteChains;
|
||||
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);
|
||||
|
||||
if (fully)
|
||||
layers.clear();
|
||||
else
|
||||
{
|
||||
for (auto it = layers.begin(); it != layers.end();)
|
||||
{
|
||||
Layer& layer = it->second;
|
||||
if (layer.clearCount++ >= 100)
|
||||
layers.erase(it++);
|
||||
else
|
||||
{
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
billboardVector.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pipelineEntry.enabled = false;
|
||||
}
|
||||
|
||||
for (auto& pipelinePair : layer.opaqueSprites)
|
||||
{
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
{
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& pipelinePair : layer.opaqueModels)
|
||||
{
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
auto& matEntry = materialPair.second;
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
auto& meshEntry = meshIt.second;
|
||||
meshEntry.instances.clear();
|
||||
}
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
layer.depthSortedMeshes.clear();
|
||||
layer.depthSortedMeshData.clear();
|
||||
layer.depthSortedSpriteData.clear();
|
||||
layer.depthSortedSprites.clear();
|
||||
layer.otherDrawables.clear();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sorts the object according to the viewer position, furthest to nearest
|
||||
*
|
||||
* \param viewer Viewer of the scene
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::Sort(const AbstractViewer* viewer)
|
||||
{
|
||||
if (viewer->GetProjectionType() == ProjectionType_Orthogonal)
|
||||
SortForOrthographic(viewer);
|
||||
else
|
||||
SortForPerspective(viewer);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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;
|
||||
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = billboards.find(materialPipeline);
|
||||
if (pipelineIt == billboards.end())
|
||||
{
|
||||
BatchedBillboardPipelineEntry pipelineEntry;
|
||||
pipelineIt = billboards.insert(BillboardPipelineBatches::value_type(materialPipeline, std::move(pipelineEntry))).first;
|
||||
}
|
||||
BatchedBillboardPipelineEntry& pipelineEntry = pipelineIt->second;
|
||||
pipelineEntry.enabled = true;
|
||||
|
||||
BatchedBillboardContainer& materialMap = pipelineEntry.materialMap;
|
||||
|
||||
auto it = materialMap.find(material);
|
||||
if (it == materialMap.end())
|
||||
{
|
||||
BatchedBillboardEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = materialMap.insert(BatchedBillboardContainer::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedBillboardEntry& entry = it->second;
|
||||
|
||||
auto& billboardVector = entry.billboards;
|
||||
std::size_t 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;
|
||||
}
|
||||
|
||||
void ForwardRenderQueue::SortBillboards(Layer& layer, const Planef& nearPlane)
|
||||
{
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
for (auto& matPair : pipelinePair.second.materialMap)
|
||||
{
|
||||
const Material* mat = matPair.first;
|
||||
|
||||
if (mat->IsDepthSortingEnabled())
|
||||
{
|
||||
BatchedBillboardEntry& entry = matPair.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
std::sort(billboardVector.begin(), billboardVector.end(), [&nearPlane] (const BillboardData& data1, const BillboardData& data2)
|
||||
{
|
||||
return nearPlane.Distance(data1.center) > nearPlane.Distance(data2.center);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ForwardRenderQueue::SortForOrthographic(const AbstractViewer * viewer)
|
||||
{
|
||||
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
||||
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2)
|
||||
{
|
||||
const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere;
|
||||
const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere;
|
||||
|
||||
return nearPlane.Distance(sphere1.GetPosition()) < nearPlane.Distance(sphere2.GetPosition());
|
||||
});
|
||||
|
||||
std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2)
|
||||
{
|
||||
const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position;
|
||||
const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position;
|
||||
|
||||
return nearPlane.Distance(pos1) < nearPlane.Distance(pos2);
|
||||
});
|
||||
|
||||
SortBillboards(layer, nearPlane);
|
||||
}
|
||||
}
|
||||
|
||||
void ForwardRenderQueue::SortForPerspective(const AbstractViewer* viewer)
|
||||
{
|
||||
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
||||
Vector3f viewerPos = viewer->GetEyePosition();
|
||||
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2)
|
||||
{
|
||||
const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere;
|
||||
const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere;
|
||||
|
||||
return viewerPos.SquaredDistance(sphere1.GetPosition()) > viewerPos.SquaredDistance(sphere2.GetPosition());
|
||||
});
|
||||
|
||||
std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2)
|
||||
{
|
||||
const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position;
|
||||
const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position;
|
||||
|
||||
return viewerPos.SquaredDistance(pos1) > viewerPos.SquaredDistance(pos2);
|
||||
});
|
||||
|
||||
SortBillboards(layer, nearPlane);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of an index buffer
|
||||
*
|
||||
* \param indexBuffer Index buffer being invalidated
|
||||
*/
|
||||
void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.indexBuffer == indexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a material
|
||||
*
|
||||
* \param material Material being invalidated
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::OnMaterialInvalidation(const Material* material)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& pipelineEntry : layer.opaqueSprites)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
|
||||
for (auto& pipelineEntry : layer.billboards)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a texture
|
||||
*
|
||||
* \param texture Texture being invalidated
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::OnTextureInvalidation(const Texture* texture)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto& pipelineEntry : layer.opaqueSprites)
|
||||
{
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
materialEntry.second.overlayMap.erase(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a vertex buffer
|
||||
*
|
||||
* \param vertexBuffer Vertex buffer being invalidated
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
if (renderData.vertexBuffer == vertexBuffer)
|
||||
it = meshes.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ForwardRenderQueue::MaterialComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
{
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
bool ForwardRenderQueue::MaterialPipelineComparator::operator()(const MaterialPipeline* pipeline1, const MaterialPipeline* pipeline2) const
|
||||
{
|
||||
const Shader* shader1 = pipeline1->GetInstance().renderPipeline.GetInfo().shader;
|
||||
const Shader* shader2 = pipeline2->GetInstance().renderPipeline.GetInfo().shader;
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
return pipeline1 < pipeline2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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;
|
||||
const Buffer* buffer2;
|
||||
|
||||
buffer1 = (data1.indexBuffer) ? data1.indexBuffer->GetBuffer() : nullptr;
|
||||
buffer2 = (data2.indexBuffer) ? data2.indexBuffer->GetBuffer() : nullptr;
|
||||
if (buffer1 != buffer2)
|
||||
return buffer1 < buffer2;
|
||||
|
||||
buffer1 = data1.vertexBuffer->GetBuffer();
|
||||
buffer2 = data2.vertexBuffer->GetBuffer();
|
||||
if (buffer1 != buffer2)
|
||||
return buffer1 < buffer2;
|
||||
|
||||
return data1.primitiveMode < data2.primitiveMode;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -188,17 +188,19 @@ namespace Nz
|
||||
MaterialPipelineInfo pipelineInfo;
|
||||
pipelineInfo.uberShader = UberShaderLibrary::Get("Basic");
|
||||
|
||||
// Basic 2D - No depth write/face culling
|
||||
// Basic 2D - No depth write/face culling with scissoring
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.scissorTest = true;
|
||||
|
||||
MaterialPipelineLibrary::Register("Basic2D", GetPipeline(pipelineInfo));
|
||||
|
||||
// Translucent 2D - Alpha blending with no depth write/face culling
|
||||
// Translucent 2D - Alpha blending with no depth write/face culling and scissoring
|
||||
pipelineInfo.blending = true;
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.depthSorting = true;
|
||||
pipelineInfo.scissorTest = true;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
@@ -210,6 +212,7 @@ namespace Nz
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.depthSorting = true;
|
||||
pipelineInfo.scissorTest = false;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Nz
|
||||
* \param instanceData Data used for this instance
|
||||
*/
|
||||
|
||||
void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
|
||||
void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const
|
||||
{
|
||||
unsigned int submeshCount = m_mesh->GetSubMeshCount();
|
||||
for (unsigned int i = 0; i < submeshCount; ++i)
|
||||
@@ -65,7 +65,7 @@ namespace Nz
|
||||
meshData.primitiveMode = mesh->GetPrimitiveMode();
|
||||
meshData.vertexBuffer = mesh->GetVertexBuffer();
|
||||
|
||||
renderQueue->AddMesh(instanceData.renderOrder, material, meshData, mesh->GetAABB(), instanceData.transformMatrix);
|
||||
renderQueue->AddMesh(instanceData.renderOrder, material, meshData, mesh->GetAABB(), instanceData.transformMatrix, scissorRect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
src/Nazara/Graphics/RenderQueue.cpp
Normal file
18
src/Nazara/Graphics/RenderQueue.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/RenderQueue.hpp>
|
||||
#include <Nazara/Core/TaskScheduler.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
void RenderQueueInternal::Sort()
|
||||
{
|
||||
std::sort(m_orderedRenderQueue.begin(), m_orderedRenderQueue.end(), [](const RenderDataPair& lhs, const RenderDataPair& rhs)
|
||||
{
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ namespace Nz
|
||||
* \param instanceData Data for the instance
|
||||
*/
|
||||
|
||||
void SkeletalModel::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
|
||||
void SkeletalModel::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const
|
||||
{
|
||||
if (!m_mesh)
|
||||
return;
|
||||
@@ -69,7 +69,7 @@ namespace Nz
|
||||
meshData.primitiveMode = mesh->GetPrimitiveMode();
|
||||
meshData.vertexBuffer = SkinningManager::GetBuffer(mesh, &m_skeleton);
|
||||
|
||||
renderQueue->AddMesh(instanceData.renderOrder, material, meshData, m_skeleton.GetAABB(), instanceData.transformMatrix);
|
||||
renderQueue->AddMesh(instanceData.renderOrder, material, meshData, m_skeleton.GetAABB(), instanceData.transformMatrix, scissorRect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ namespace Nz
|
||||
* \param instanceData Data for the instance
|
||||
*/
|
||||
|
||||
void Sprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
|
||||
void Sprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const
|
||||
{
|
||||
const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<const VertexStruct_XYZ_Color_UV*>(instanceData.data.data());
|
||||
renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), vertices, 1);
|
||||
renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), vertices, 1, scissorRect);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Nz
|
||||
* \param instanceData Data for the instance
|
||||
*/
|
||||
|
||||
void TextSprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
|
||||
void TextSprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const
|
||||
{
|
||||
for (auto& pair : m_renderInfos)
|
||||
{
|
||||
@@ -36,7 +36,7 @@ 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, GetMaterial(), &vertices[indices.first * 4], indices.count, overlay);
|
||||
renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), &vertices[indices.first * 4], indices.count, scissorRect, overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Nz
|
||||
* \param renderQueue Queue to be added
|
||||
* \param instanceData Data for the instance
|
||||
*/
|
||||
void TileMap::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
|
||||
void TileMap::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const
|
||||
{
|
||||
const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<const VertexStruct_XYZ_Color_UV*>(instanceData.data.data());
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Nz
|
||||
std::size_t spriteCount = 0;
|
||||
for (const Layer& layer : m_layers)
|
||||
{
|
||||
renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(matCount++), &vertices[spriteCount], layer.tiles.size());
|
||||
renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(matCount++), &vertices[spriteCount], layer.tiles.size(), scissorRect);
|
||||
|
||||
spriteCount += layer.tiles.size();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user