WIP
This commit is contained in:
203
src/Nazara/Graphics/BasicMaterial.cpp
Normal file
203
src/Nazara/Graphics/BasicMaterial.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
// 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/BasicMaterial.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Utility/BufferMapper.hpp>
|
||||
#include <Nazara/Utility/FieldOffsets.hpp>
|
||||
#include <Nazara/Utility/MaterialData.hpp>
|
||||
#include <cassert>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr std::size_t AlphaMapBinding = 0;
|
||||
constexpr std::size_t DiffuseMapBinding = 1;
|
||||
constexpr std::size_t TextureOverlayBinding = 2;
|
||||
}
|
||||
|
||||
BasicMaterial::BasicMaterial(Material* material) :
|
||||
m_material(material)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
// Most common case: don't fetch texture indexes as a little optimization
|
||||
const std::shared_ptr<const MaterialSettings>& materialSettings = material->GetSettings();
|
||||
if (materialSettings == s_materialSettings)
|
||||
{
|
||||
m_textureIndexes = s_textureIndexes;
|
||||
m_uniformBlockIndex = s_uniformBlockIndex;
|
||||
m_uniformOffsets = s_uniformOffsets;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
|
||||
m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
|
||||
|
||||
m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("BasicSettings");
|
||||
|
||||
m_uniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold");
|
||||
m_uniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor");
|
||||
}
|
||||
}
|
||||
|
||||
float BasicMaterial::GetAlphaThreshold() const
|
||||
{
|
||||
NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_uniformBlockIndex), BufferAccess_ReadOnly);
|
||||
return *AccessByOffset<const float>(mapper.GetPointer(), m_uniformOffsets.alphaThreshold);
|
||||
}
|
||||
|
||||
Color BasicMaterial::GetDiffuseColor() const
|
||||
{
|
||||
NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_uniformBlockIndex), BufferAccess_ReadOnly);
|
||||
|
||||
const float* colorPtr = AccessByOffset<const float>(mapper.GetPointer(), m_uniformOffsets.diffuseColor);
|
||||
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
|
||||
}
|
||||
|
||||
void BasicMaterial::SetAlphaThreshold(float alphaThreshold)
|
||||
{
|
||||
NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_uniformBlockIndex), BufferAccess_WriteOnly);
|
||||
*AccessByOffset<float>(mapper.GetPointer(), m_uniformOffsets.alphaThreshold) = alphaThreshold;
|
||||
}
|
||||
|
||||
void BasicMaterial::SetDiffuseColor(const Color& diffuse)
|
||||
{
|
||||
NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_uniformBlockIndex), BufferAccess_WriteOnly);
|
||||
float* colorPtr = AccessByOffset<float>(mapper.GetPointer(), m_uniformOffsets.diffuseColor);
|
||||
colorPtr[0] = diffuse.r / 255.f;
|
||||
colorPtr[1] = diffuse.g / 255.f;
|
||||
colorPtr[2] = diffuse.b / 255.f;
|
||||
colorPtr[3] = diffuse.a / 255.f;
|
||||
}
|
||||
|
||||
const std::shared_ptr<MaterialSettings>& BasicMaterial::GetSettings()
|
||||
{
|
||||
return s_materialSettings;
|
||||
}
|
||||
|
||||
bool BasicMaterial::Initialize()
|
||||
{
|
||||
RenderPipelineLayoutInfo info;
|
||||
info.bindings.assign({
|
||||
{
|
||||
"MaterialAlphaMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
AlphaMapBinding
|
||||
},
|
||||
{
|
||||
"MaterialDiffuseMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
DiffuseMapBinding
|
||||
},
|
||||
{
|
||||
"TextureOverlay",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
TextureOverlayBinding
|
||||
}
|
||||
});
|
||||
|
||||
s_renderPipelineLayout = RenderPipelineLayout::New();
|
||||
s_renderPipelineLayout->Create(info);
|
||||
|
||||
FieldOffsets fieldOffsets(StructLayout_Std140);
|
||||
|
||||
s_uniformOffsets.diffuseColor = fieldOffsets.AddField(StructFieldType_Float4);
|
||||
s_uniformOffsets.alphaThreshold = fieldOffsets.AddField(StructFieldType_Float1);
|
||||
|
||||
MaterialSettings::PredefinedBinding predefinedBinding;
|
||||
predefinedBinding.fill(MaterialSettings::InvalidIndex);
|
||||
|
||||
std::vector<MaterialSettings::UniformVariable> variables;
|
||||
variables.assign({
|
||||
{
|
||||
"AlphaThreshold",
|
||||
s_uniformOffsets.alphaThreshold
|
||||
},
|
||||
{
|
||||
"DiffuseColor",
|
||||
s_uniformOffsets.diffuseColor
|
||||
}
|
||||
});
|
||||
|
||||
static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide");
|
||||
|
||||
std::vector<UInt8> defaultValues(fieldOffsets.GetSize());
|
||||
*AccessByOffset<Vector4f>(defaultValues.data(), s_uniformOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
|
||||
*AccessByOffset<float>(defaultValues.data(), s_uniformOffsets.alphaThreshold) = 0.2f;
|
||||
|
||||
std::vector<MaterialSettings::UniformBlock> uniformBlocks;
|
||||
s_uniformBlockIndex = uniformBlocks.size();
|
||||
uniformBlocks.assign({
|
||||
{
|
||||
"BasicSettings",
|
||||
fieldOffsets.GetSize(),
|
||||
"MaterialBasicSettings",
|
||||
std::move(variables),
|
||||
std::move(defaultValues)
|
||||
}
|
||||
});
|
||||
|
||||
std::vector<MaterialSettings::SharedUniformBlock> sharedUniformBlock;
|
||||
|
||||
predefinedBinding[PredefinedShaderBinding_UboInstanceData] = sharedUniformBlock.size();
|
||||
sharedUniformBlock.push_back(PredefinedInstanceData::GetUniformBlock());
|
||||
predefinedBinding[PredefinedShaderBinding_UboViewerData] = sharedUniformBlock.size();
|
||||
sharedUniformBlock.push_back(PredefinedViewerData::GetUniformBlock());
|
||||
|
||||
std::vector<MaterialSettings::Texture> textures;
|
||||
s_textureIndexes.alpha = textures.size();
|
||||
textures.push_back({
|
||||
"Alpha",
|
||||
ImageType_2D,
|
||||
"MaterialAlphaMap"
|
||||
});
|
||||
|
||||
s_textureIndexes.diffuse = textures.size();
|
||||
textures.push_back({
|
||||
"Diffuse",
|
||||
ImageType_2D,
|
||||
"MaterialDiffuseMap"
|
||||
});
|
||||
|
||||
predefinedBinding[PredefinedShaderBinding_TexOverlay] = textures.size();
|
||||
textures.push_back({
|
||||
"Overlay",
|
||||
ImageType_2D,
|
||||
"TextureOverlay"
|
||||
});
|
||||
|
||||
s_materialSettings = std::make_shared<MaterialSettings>(std::move(textures), std::move(uniformBlocks), std::move(sharedUniformBlock), predefinedBinding);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BasicMaterial::Uninitialize()
|
||||
{
|
||||
s_renderPipelineLayout.Reset();
|
||||
s_materialSettings.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialSettings> BasicMaterial::s_materialSettings;
|
||||
std::size_t BasicMaterial::s_uniformBlockIndex;
|
||||
RenderPipelineLayoutRef BasicMaterial::s_renderPipelineLayout;
|
||||
BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes;
|
||||
BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets;
|
||||
}
|
||||
956
src/Nazara/Graphics/BasicRenderQueue.cpp
Normal file
956
src/Nazara/Graphics/BasicRenderQueue.cpp
Normal file
@@ -0,0 +1,956 @@
|
||||
// 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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
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 Nz::Matrix4f& transformMatrix, std::size_t instanceIndex, const Recti& scissorRect)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
RegisterLayer(renderOrder);
|
||||
|
||||
Spheref obbSphere(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
|
||||
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
depthSortedModels.Insert({
|
||||
renderOrder,
|
||||
instanceIndex,
|
||||
meshData,
|
||||
material,
|
||||
scissorRect,
|
||||
obbSphere
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
models.Insert({
|
||||
renderOrder,
|
||||
instanceIndex,
|
||||
meshData,
|
||||
material,
|
||||
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 (16bits)
|
||||
// - Pipeline (8bits)
|
||||
// - Material (8bits)
|
||||
// - Shader? (8bits)
|
||||
// - Textures (8bits)
|
||||
// - Overlay (8bits)
|
||||
// - Scissor (4bits)
|
||||
// - ??? (4bits)
|
||||
|
||||
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 = 0;/* GetOrInsert(m_textureCache, vertices.material->GetDiffuseMap());*/
|
||||
UInt64 overlayIndex = GetOrInsert(m_overlayCache, vertices.overlay);
|
||||
UInt64 scissorIndex = 0; //< TODO
|
||||
|
||||
UInt64 index = (layerIndex & 0xFFFF) << 48 |
|
||||
(pipelineIndex & 0xFF) << 40 |
|
||||
(materialIndex & 0xFF) << 32 |
|
||||
(shaderIndex & 0xFF) << 24 |
|
||||
(textureIndex & 0xFF) << 16 |
|
||||
(overlayIndex & 0xFF) << 8 |
|
||||
(scissorIndex & 0x0F) << 4;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
billboards.Sort([&](const BillboardChain& billboard)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (16bits)
|
||||
// - Pipeline (8bits)
|
||||
// - Material (8bits)
|
||||
// - Shader? (8bits)
|
||||
// - Textures (8bits)
|
||||
// - Scissor (4bits)
|
||||
// - ??? (12bits)
|
||||
|
||||
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 = 0; /*GetOrInsert(m_textureCache, billboard.material->GetDiffuseMap())*/;
|
||||
UInt64 unknownIndex = 0; //< ???
|
||||
UInt64 scissorIndex = 0; //< TODO
|
||||
|
||||
UInt64 index = (layerIndex & 0xFFFF) << 48 |
|
||||
(pipelineIndex & 0xFF) << 40 |
|
||||
(materialIndex & 0xFF) << 32 |
|
||||
(shaderIndex & 0xFF) << 24 |
|
||||
(textureIndex & 0xFF) << 16 |
|
||||
(scissorIndex & 0x0F) << 12 |
|
||||
(unknownIndex & 0xFF) << 0;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
customDrawables.Sort([&](const CustomDrawable& drawable)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (16bits)
|
||||
|
||||
UInt64 layerIndex = m_layerCache[drawable.layerIndex];
|
||||
|
||||
UInt64 index = (layerIndex & 0xFFFF) << 48;
|
||||
|
||||
return index;
|
||||
|
||||
});
|
||||
|
||||
models.Sort([&](const Model& renderData)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (16bits)
|
||||
// - Pipeline (8bits)
|
||||
// - Material (8bits)
|
||||
// - Shader? (8bits)
|
||||
// - Textures (8bits)
|
||||
// - Buffers (8bits)
|
||||
// - Scissor (4bits)
|
||||
// - ??? (4bits)
|
||||
|
||||
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 = 0;/* 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 & 0xFFFF) << 48 |
|
||||
(pipelineIndex & 0xFF) << 40 |
|
||||
(materialIndex & 0xFF) << 32 |
|
||||
(shaderIndex & 0xFF) << 24 |
|
||||
(textureIndex & 0xFF) << 16 |
|
||||
(bufferIndex & 0xFF) << 8 |
|
||||
(scissorIndex & 0x0F) << 4;
|
||||
|
||||
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 (16bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (16bits)
|
||||
|
||||
// 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 not be rendered)
|
||||
float depth = nearPlane.Distance(billboard.data.center);
|
||||
|
||||
UInt64 layerIndex = m_layerCache[billboard.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0xFFFF) << 48 |
|
||||
(depthIndex & 0xFFFFFFFF) << 16;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
if (viewer->GetProjectionType() == ProjectionType_Orthogonal)
|
||||
{
|
||||
depthSortedModels.Sort([&](const Model& model)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (16bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (16bits)
|
||||
|
||||
float depth = nearPlane.Distance(model.obbSphere.GetPosition());
|
||||
|
||||
UInt64 layerIndex = m_layerCache[model.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0xFFFF) << 48 |
|
||||
(depthIndex & 0xFFFFFFFF) << 16;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
depthSortedSprites.Sort([&](const SpriteChain& spriteChain)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (16bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (16bits)
|
||||
|
||||
float depth = nearPlane.Distance(spriteChain.vertices[0].position);
|
||||
|
||||
UInt64 layerIndex = m_layerCache[spriteChain.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0xFFFF) << 48 |
|
||||
(depthIndex & 0xFFFFFFFF) << 16;
|
||||
|
||||
return index;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3f viewerPos = viewer->GetEyePosition();
|
||||
|
||||
depthSortedModels.Sort([&](const Model& model)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (16bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (16bits)
|
||||
|
||||
float depth = viewerPos.SquaredDistance(model.obbSphere.GetPosition());
|
||||
|
||||
UInt64 layerIndex = m_layerCache[model.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0x0F) << 48 |
|
||||
(depthIndex & 0xFFFFFFFF) << 16;
|
||||
|
||||
return index;
|
||||
});
|
||||
|
||||
depthSortedSprites.Sort([&](const SpriteChain& sprites)
|
||||
{
|
||||
// RQ index:
|
||||
// - Layer (16bits)
|
||||
// - Depth (32bits)
|
||||
// - ?? (16bits)
|
||||
|
||||
float depth = viewerPos.SquaredDistance(sprites.vertices[0].position);
|
||||
|
||||
UInt64 layerIndex = m_layerCache[sprites.layerIndex];
|
||||
UInt64 depthIndex = ~reinterpret_cast<UInt32&>(depth);
|
||||
|
||||
UInt64 index = (layerIndex & 0xFFFF) << 48 |
|
||||
(depthIndex & 0xFFFFFFFF) << 16;
|
||||
|
||||
return index;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
@@ -13,13 +14,29 @@ namespace Nz
|
||||
* \brief Audio class that represents the module initializer of Graphics
|
||||
*/
|
||||
|
||||
Graphics::Graphics(Config /*config*/) :
|
||||
Graphics::Graphics(Config config) :
|
||||
ModuleBase("Graphics", this)
|
||||
{
|
||||
}
|
||||
Renderer* renderer = Renderer::Instance();
|
||||
RendererImpl* rendererImpl = renderer->GetRendererImpl(); //< FIXME
|
||||
std::vector<RenderDeviceInfo> renderDeviceInfo = rendererImpl->QueryRenderDevices();
|
||||
if (renderDeviceInfo.empty())
|
||||
throw std::runtime_error("no render device available");
|
||||
|
||||
Graphics::~Graphics()
|
||||
{
|
||||
std::size_t bestRenderDeviceIndex = 0;
|
||||
for (std::size_t i = 0; i < renderDeviceInfo.size(); ++i)
|
||||
{
|
||||
const auto& deviceInfo = renderDeviceInfo[i];
|
||||
if (config.useDedicatedRenderDevice && deviceInfo.type == RenderDeviceType::Dedicated)
|
||||
{
|
||||
bestRenderDeviceIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_renderDevice = rendererImpl->InstanciateRenderDevice(bestRenderDeviceIndex);
|
||||
if (!m_renderDevice)
|
||||
throw std::runtime_error("failed to instantiate render device");
|
||||
}
|
||||
|
||||
Graphics* Graphics::s_instance = nullptr;
|
||||
|
||||
487
src/Nazara/Graphics/Material.cpp
Normal file
487
src/Nazara/Graphics/Material.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
// 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/Material.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Graphics/BasicMaterial.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Utility/MaterialData.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::Material
|
||||
* \brief Graphics class that represents a material
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the parameters for the material are correct
|
||||
* \return true If parameters are valid
|
||||
*/
|
||||
bool MaterialParams::IsValid() const
|
||||
{
|
||||
if (!UberShaderLibrary::Has(shaderName))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Material object with default states
|
||||
*
|
||||
* \see Reset
|
||||
*/
|
||||
Material::Material(std::shared_ptr<const MaterialSettings> settings) :
|
||||
m_settings(std::move(settings)),
|
||||
m_reflectionMode(ReflectionMode_Skybox),
|
||||
m_pipelineUpdated(false),
|
||||
m_shadowCastingEnabled(true),
|
||||
m_reflectionSize(256)
|
||||
{
|
||||
m_pipelineInfo.settings = m_settings;
|
||||
SetShader("Basic");
|
||||
|
||||
m_textures.resize(m_settings->GetTextures().size());
|
||||
|
||||
m_uniformBuffers.reserve(m_settings->GetUniformBlocks().size());
|
||||
for (const auto& uniformBufferInfo : m_settings->GetUniformBlocks())
|
||||
{
|
||||
//TODO: Use pools
|
||||
UniformBufferRef ubo = UniformBuffer::New(static_cast<UInt32>(uniformBufferInfo.blockSize), DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
ubo->Fill(uniformBufferInfo.defaultValues.data(), 0, uniformBufferInfo.defaultValues.size());
|
||||
|
||||
m_uniformBuffers.emplace_back(std::move(ubo));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies shader to the material
|
||||
*
|
||||
* \param instance Pipeline instance to update
|
||||
* \param textureUnit Unit for the texture GL_TEXTURE"i"
|
||||
* \param lastUsedUnit Optional argument to get the last texture unit
|
||||
*/
|
||||
void Material::Apply(const MaterialPipeline::Instance& instance) const
|
||||
{
|
||||
const Shader* shader = instance.renderPipeline.GetInfo().shader;
|
||||
|
||||
unsigned int bindingIndex = 0;
|
||||
|
||||
for (const MaterialTexture& textureData : m_textures)
|
||||
{
|
||||
auto it = instance.bindings.find(bindingIndex++);
|
||||
assert(it != instance.bindings.end());
|
||||
|
||||
unsigned int textureIndex = it->second;
|
||||
|
||||
Renderer::SetTexture(textureIndex, textureData.texture);
|
||||
Renderer::SetTextureSampler(textureIndex, textureData.sampler);
|
||||
}
|
||||
|
||||
for (const UniformBufferRef& ubo : m_uniformBuffers)
|
||||
{
|
||||
auto it = instance.bindings.find(bindingIndex++);
|
||||
assert(it != instance.bindings.end());
|
||||
|
||||
unsigned int uniformBufferIndex = it->second;
|
||||
|
||||
Renderer::SetUniformBuffer(uniformBufferIndex, ubo);
|
||||
}
|
||||
|
||||
/*if (instance.uniforms[MaterialUniform_AlphaThreshold] != -1)
|
||||
shader->SendFloat(instance.uniforms[MaterialUniform_AlphaThreshold], m_alphaThreshold);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Ambient] != -1)
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Ambient], m_ambientColor);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Diffuse] != -1)
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Diffuse], m_diffuseColor);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Shininess] != -1)
|
||||
shader->SendFloat(instance.uniforms[MaterialUniform_Shininess], m_shininess);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Specular] != -1)
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Specular], m_specularColor);*/
|
||||
|
||||
/*if (m_alphaMap && instance.uniforms[MaterialUniform_AlphaMap] != -1)
|
||||
{
|
||||
unsigned int textureUnit = s_textureUnits[TextureMap_Alpha];
|
||||
|
||||
Renderer::SetTexture(textureUnit, m_alphaMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
}
|
||||
|
||||
if (m_diffuseMap && instance.uniforms[MaterialUniform_DiffuseMap] != -1)
|
||||
{
|
||||
unsigned int textureUnit = s_textureUnits[TextureMap_Diffuse];
|
||||
|
||||
Renderer::SetTexture(textureUnit, m_diffuseMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
}
|
||||
|
||||
if (m_emissiveMap && instance.uniforms[MaterialUniform_EmissiveMap] != -1)
|
||||
{
|
||||
unsigned int textureUnit = s_textureUnits[TextureMap_Emissive];
|
||||
|
||||
Renderer::SetTexture(textureUnit, m_emissiveMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
}
|
||||
|
||||
if (m_heightMap && instance.uniforms[MaterialUniform_HeightMap] != -1)
|
||||
{
|
||||
unsigned int textureUnit = s_textureUnits[TextureMap_Height];
|
||||
|
||||
Renderer::SetTexture(textureUnit, m_heightMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
}
|
||||
|
||||
if (m_normalMap && instance.uniforms[MaterialUniform_NormalMap] != -1)
|
||||
{
|
||||
unsigned int textureUnit = s_textureUnits[TextureMap_Normal];
|
||||
|
||||
Renderer::SetTexture(textureUnit, m_normalMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
}
|
||||
|
||||
if (m_specularMap && instance.uniforms[MaterialUniform_SpecularMap] != -1)
|
||||
{
|
||||
unsigned int textureUnit = s_textureUnits[TextureMap_Specular];
|
||||
|
||||
Renderer::SetTexture(textureUnit, m_specularMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_specularSampler);
|
||||
}*/
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Builds the material from a parameter list
|
||||
*
|
||||
* \param matData Data information for the material
|
||||
* \param matParams Additional parameters for the material
|
||||
*/
|
||||
void Material::BuildFromParameters(const ParameterList& matData, const MaterialParams& matParams)
|
||||
{
|
||||
Color color;
|
||||
bool isEnabled;
|
||||
double dValue;
|
||||
long long iValue;
|
||||
String path;
|
||||
|
||||
ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled, true);
|
||||
|
||||
/*if (matData.GetDoubleParameter(MaterialData::AlphaThreshold, &dValue))
|
||||
SetAlphaThreshold(float(dValue));*/
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::AlphaTest, &isEnabled))
|
||||
EnableAlphaTest(isEnabled);
|
||||
|
||||
/*if (matData.GetColorParameter(MaterialData::AmbientColor, &color))
|
||||
SetAmbientColor(color);*/
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::CullingSide, &iValue))
|
||||
SetFaceCulling(static_cast<FaceSide>(iValue));
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::DepthFunc, &iValue))
|
||||
SetDepthFunc(static_cast<RendererComparison>(iValue));
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::DepthSorting, &isEnabled))
|
||||
EnableDepthSorting(isEnabled);
|
||||
|
||||
/*if (matData.GetColorParameter(MaterialData::DiffuseColor, &color))
|
||||
SetDiffuseColor(color);*/
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::DstBlend, &iValue))
|
||||
SetDstBlend(static_cast<BlendFunc>(iValue));
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::FaceFilling, &iValue))
|
||||
SetFaceFilling(static_cast<FaceFilling>(iValue));
|
||||
|
||||
if (matData.GetDoubleParameter(MaterialData::LineWidth, &dValue))
|
||||
SetLineWidth(float(dValue));
|
||||
|
||||
if (matData.GetDoubleParameter(MaterialData::PointSize, &dValue))
|
||||
SetPointSize(float(dValue));
|
||||
|
||||
/*if (matData.GetColorParameter(MaterialData::SpecularColor, &color))
|
||||
SetSpecularColor(color);
|
||||
|
||||
if (matData.GetDoubleParameter(MaterialData::Shininess, &dValue))
|
||||
SetShininess(float(dValue));*/
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::SrcBlend, &iValue))
|
||||
SetSrcBlend(static_cast<BlendFunc>(iValue));
|
||||
|
||||
// RendererParameter
|
||||
if (matData.GetBooleanParameter(MaterialData::Blending, &isEnabled))
|
||||
EnableBlending(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::ColorWrite, &isEnabled))
|
||||
EnableColorWrite(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::DepthBuffer, &isEnabled))
|
||||
EnableDepthBuffer(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::DepthWrite, &isEnabled))
|
||||
EnableDepthWrite(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::FaceCulling, &isEnabled))
|
||||
EnableFaceCulling(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::ScissorTest, &isEnabled))
|
||||
EnableScissorTest(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::StencilTest, &isEnabled))
|
||||
EnableStencilTest(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::VertexColor, &isEnabled))
|
||||
EnableVertexColor(isEnabled);
|
||||
|
||||
// Samplers
|
||||
/*if (matData.GetIntegerParameter(MaterialData::DiffuseAnisotropyLevel, &iValue))
|
||||
m_diffuseSampler.SetAnisotropyLevel(static_cast<UInt8>(iValue));
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::DiffuseFilter, &iValue))
|
||||
m_diffuseSampler.SetFilterMode(static_cast<SamplerFilter>(iValue));
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::DiffuseWrap, &iValue))
|
||||
m_diffuseSampler.SetWrapMode(static_cast<SamplerWrap>(iValue));
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::SpecularAnisotropyLevel, &iValue))
|
||||
m_specularSampler.SetAnisotropyLevel(static_cast<UInt8>(iValue));
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::SpecularFilter, &iValue))
|
||||
m_specularSampler.SetFilterMode(static_cast<SamplerFilter>(iValue));
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::SpecularWrap, &iValue))
|
||||
m_specularSampler.SetWrapMode(static_cast<SamplerWrap>(iValue));*/
|
||||
|
||||
// Stencil
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilCompare, &iValue))
|
||||
m_pipelineInfo.stencilCompare.front = static_cast<RendererComparison>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilFail, &iValue))
|
||||
m_pipelineInfo.stencilFail.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilPass, &iValue))
|
||||
m_pipelineInfo.stencilPass.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilZFail, &iValue))
|
||||
m_pipelineInfo.stencilDepthFail.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilMask, &iValue))
|
||||
m_pipelineInfo.stencilWriteMask.front = static_cast<UInt32>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilReference, &iValue))
|
||||
m_pipelineInfo.stencilReference.front = static_cast<unsigned int>(iValue);
|
||||
|
||||
// Stencil (back)
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilCompare, &iValue))
|
||||
m_pipelineInfo.stencilCompare.back = static_cast<RendererComparison>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilFail, &iValue))
|
||||
m_pipelineInfo.stencilFail.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilPass, &iValue))
|
||||
m_pipelineInfo.stencilPass.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilZFail, &iValue))
|
||||
m_pipelineInfo.stencilDepthFail.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilMask, &iValue))
|
||||
m_pipelineInfo.stencilWriteMask.back = static_cast<UInt32>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilReference, &iValue))
|
||||
m_pipelineInfo.stencilReference.back = static_cast<unsigned int>(iValue);
|
||||
|
||||
InvalidatePipeline();
|
||||
|
||||
// Textures
|
||||
/*if (matParams.loadAlphaMap && matData.GetStringParameter(MaterialData::AlphaTexturePath, &path))
|
||||
SetAlphaMap(path);
|
||||
|
||||
if (matParams.loadDiffuseMap && matData.GetStringParameter(MaterialData::DiffuseTexturePath, &path))
|
||||
SetDiffuseMap(path);
|
||||
|
||||
if (matParams.loadEmissiveMap && matData.GetStringParameter(MaterialData::EmissiveTexturePath, &path))
|
||||
SetEmissiveMap(path);
|
||||
|
||||
if (matParams.loadHeightMap && matData.GetStringParameter(MaterialData::HeightTexturePath, &path))
|
||||
SetHeightMap(path);
|
||||
|
||||
if (matParams.loadNormalMap && matData.GetStringParameter(MaterialData::NormalTexturePath, &path))
|
||||
SetNormalMap(path);
|
||||
|
||||
if (matParams.loadSpecularMap && matData.GetStringParameter(MaterialData::SpecularTexturePath, &path))
|
||||
SetSpecularMap(path);*/
|
||||
|
||||
SetShader(matParams.shaderName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Builds a ParameterList with material data
|
||||
*
|
||||
* \param matData Destination parameter list which will receive material data
|
||||
*/
|
||||
void Material::SaveToParameters(ParameterList* matData)
|
||||
{
|
||||
NazaraAssert(matData, "Invalid ParameterList");
|
||||
|
||||
matData->SetParameter(MaterialData::AlphaTest, IsAlphaTestEnabled());
|
||||
//matData->SetParameter(MaterialData::AlphaThreshold, GetAlphaThreshold());
|
||||
//matData->SetParameter(MaterialData::AmbientColor, GetAmbientColor());
|
||||
matData->SetParameter(MaterialData::CullingSide, static_cast<long long>(GetFaceCulling()));
|
||||
matData->SetParameter(MaterialData::DepthFunc, static_cast<long long>(GetDepthFunc()));
|
||||
matData->SetParameter(MaterialData::DepthSorting, IsDepthSortingEnabled());
|
||||
//matData->SetParameter(MaterialData::DiffuseColor, GetDiffuseColor());
|
||||
matData->SetParameter(MaterialData::DstBlend, static_cast<long long>(GetDstBlend()));
|
||||
matData->SetParameter(MaterialData::FaceFilling, static_cast<long long>(GetFaceFilling()));
|
||||
matData->SetParameter(MaterialData::LineWidth, GetLineWidth());
|
||||
matData->SetParameter(MaterialData::PointSize, GetPointSize());
|
||||
//matData->SetParameter(MaterialData::Shininess, GetShininess());
|
||||
//matData->SetParameter(MaterialData::SpecularColor, GetSpecularColor());
|
||||
matData->SetParameter(MaterialData::SrcBlend, static_cast<long long>(GetSrcBlend()));
|
||||
|
||||
// RendererParameter
|
||||
matData->SetParameter(MaterialData::Blending, IsBlendingEnabled());
|
||||
matData->SetParameter(MaterialData::ColorWrite, IsColorWriteEnabled());
|
||||
matData->SetParameter(MaterialData::DepthBuffer, IsDepthBufferEnabled());
|
||||
matData->SetParameter(MaterialData::DepthWrite, IsDepthWriteEnabled());
|
||||
matData->SetParameter(MaterialData::FaceCulling, IsFaceCullingEnabled());
|
||||
matData->SetParameter(MaterialData::ScissorTest, IsScissorTestEnabled());
|
||||
matData->SetParameter(MaterialData::StencilTest, IsStencilTestEnabled());
|
||||
matData->SetParameter(MaterialData::VertexColor, HasVertexColor());
|
||||
|
||||
// Samplers
|
||||
/*matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, static_cast<long long>(GetDiffuseSampler().GetAnisotropicLevel()));
|
||||
matData->SetParameter(MaterialData::DiffuseFilter, static_cast<long long>(GetDiffuseSampler().GetFilterMode()));
|
||||
matData->SetParameter(MaterialData::DiffuseWrap, static_cast<long long>(GetDiffuseSampler().GetWrapMode()));
|
||||
|
||||
matData->SetParameter(MaterialData::SpecularAnisotropyLevel, static_cast<long long>(GetSpecularSampler().GetAnisotropicLevel()));
|
||||
matData->SetParameter(MaterialData::SpecularFilter, static_cast<long long>(GetSpecularSampler().GetFilterMode()));
|
||||
matData->SetParameter(MaterialData::SpecularWrap, static_cast<long long>(GetSpecularSampler().GetWrapMode()));*/
|
||||
|
||||
// Stencil
|
||||
matData->SetParameter(MaterialData::StencilCompare, static_cast<long long>(GetPipelineInfo().stencilCompare.front));
|
||||
matData->SetParameter(MaterialData::StencilFail, static_cast<long long>(GetPipelineInfo().stencilFail.front));
|
||||
matData->SetParameter(MaterialData::StencilPass, static_cast<long long>(GetPipelineInfo().stencilPass.front));
|
||||
matData->SetParameter(MaterialData::StencilZFail, static_cast<long long>(GetPipelineInfo().stencilDepthFail.front));
|
||||
matData->SetParameter(MaterialData::StencilMask, static_cast<long long>(GetPipelineInfo().stencilWriteMask.front));
|
||||
matData->SetParameter(MaterialData::StencilReference, static_cast<long long>(GetPipelineInfo().stencilReference.front));
|
||||
|
||||
// Stencil (back)
|
||||
matData->SetParameter(MaterialData::BackFaceStencilCompare, static_cast<long long>(GetPipelineInfo().stencilCompare.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilFail, static_cast<long long>(GetPipelineInfo().stencilFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilPass, static_cast<long long>(GetPipelineInfo().stencilPass.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilZFail, static_cast<long long>(GetPipelineInfo().stencilDepthFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilMask, static_cast<long long>(GetPipelineInfo().stencilWriteMask.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilReference, static_cast<long long>(GetPipelineInfo().stencilReference.back));
|
||||
|
||||
// Textures
|
||||
/*if (HasAlphaMap())
|
||||
{
|
||||
const String& path = GetAlphaMap()->GetFilePath();
|
||||
if (!path.IsEmpty())
|
||||
matData->SetParameter(MaterialData::AlphaTexturePath, path);
|
||||
}
|
||||
|
||||
if (HasDiffuseMap())
|
||||
{
|
||||
const String& path = GetDiffuseMap()->GetFilePath();
|
||||
if (!path.IsEmpty())
|
||||
matData->SetParameter(MaterialData::DiffuseTexturePath, path);
|
||||
}
|
||||
|
||||
if (HasEmissiveMap())
|
||||
{
|
||||
const String& path = GetEmissiveMap()->GetFilePath();
|
||||
if (!path.IsEmpty())
|
||||
matData->SetParameter(MaterialData::EmissiveTexturePath, path);
|
||||
}
|
||||
|
||||
if (HasHeightMap())
|
||||
{
|
||||
const String& path = GetHeightMap()->GetFilePath();
|
||||
if (!path.IsEmpty())
|
||||
matData->SetParameter(MaterialData::HeightTexturePath, path);
|
||||
}
|
||||
|
||||
if (HasNormalMap())
|
||||
{
|
||||
const String& path = GetNormalMap()->GetFilePath();
|
||||
if (!path.IsEmpty())
|
||||
matData->SetParameter(MaterialData::NormalTexturePath, path);
|
||||
}
|
||||
|
||||
if (HasSpecularMap())
|
||||
{
|
||||
const String& path = GetSpecularMap()->GetFilePath();
|
||||
if (!path.IsEmpty())
|
||||
matData->SetParameter(MaterialData::SpecularTexturePath, path);
|
||||
}*/
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the material librairies
|
||||
* \return true If successful
|
||||
*
|
||||
* \remark Produces a NazaraError if the material library failed to be initialized
|
||||
*/
|
||||
bool Material::Initialize()
|
||||
{
|
||||
if (!MaterialLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MaterialManager::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_defaultMaterial = New(BasicMaterial::GetSettings());
|
||||
s_defaultMaterial->EnableFaceCulling(false);
|
||||
s_defaultMaterial->SetFaceFilling(FaceFilling_Line);
|
||||
MaterialLibrary::Register("Default", s_defaultMaterial);
|
||||
|
||||
unsigned int textureUnit = 0;
|
||||
|
||||
s_textureUnits[TextureMap_Diffuse] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Alpha] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Specular] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Normal] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Emissive] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Overlay] = textureUnit++;
|
||||
s_textureUnits[TextureMap_ReflectionCube] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Height] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Shadow2D_1] = textureUnit++;
|
||||
s_textureUnits[TextureMap_ShadowCube_1] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Shadow2D_2] = textureUnit++;
|
||||
s_textureUnits[TextureMap_ShadowCube_2] = textureUnit++;
|
||||
s_textureUnits[TextureMap_Shadow2D_3] = textureUnit++;
|
||||
s_textureUnits[TextureMap_ShadowCube_3] = textureUnit++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the material librairies
|
||||
*/
|
||||
void Material::Uninitialize()
|
||||
{
|
||||
s_defaultMaterial.Reset();
|
||||
|
||||
MaterialManager::Uninitialize();
|
||||
MaterialLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
std::array<int, TextureMap_Max + 1> Material::s_textureUnits;
|
||||
MaterialLibrary::LibraryMap Material::s_library;
|
||||
MaterialLoader::LoaderList Material::s_loaders;
|
||||
MaterialManager::ManagerMap Material::s_managerMap;
|
||||
MaterialManager::ManagerParams Material::s_managerParameters;
|
||||
MaterialRef Material::s_defaultMaterial = nullptr;
|
||||
}
|
||||
235
src/Nazara/Graphics/MaterialPipeline.cpp
Normal file
235
src/Nazara/Graphics/MaterialPipeline.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
// 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/MaterialPipeline.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Graphics/BasicMaterial.hpp>
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Graphics/MaterialSettings.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const UInt8 r_basicFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_basicVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.vert.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h>
|
||||
};
|
||||
|
||||
void OverrideShader(const String& path, String* source)
|
||||
{
|
||||
ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled);
|
||||
|
||||
File shaderFile(path, Nz::OpenMode_ReadOnly | Nz::OpenMode_Text);
|
||||
if (shaderFile.IsOpen())
|
||||
{
|
||||
StringStream shaderSource;
|
||||
|
||||
while (!shaderFile.EndOfFile())
|
||||
{
|
||||
shaderSource << shaderFile.ReadLine();
|
||||
shaderSource << '\n';
|
||||
}
|
||||
|
||||
*source = shaderSource;
|
||||
|
||||
NazaraNotice(path + " will be used to override built-in shader");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::MaterialPipeline
|
||||
*
|
||||
* \brief Graphics class used to contains all rendering states that are not allowed to change individually on rendering devices
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to a MaterialPipeline built with MaterialPipelineInfo
|
||||
*
|
||||
* This function is using a cache, calling it multiples times with the same MaterialPipelineInfo will returns references to a single MaterialPipeline
|
||||
*
|
||||
* \param pipelineInfo Pipeline informations used to build/retrieve a MaterialPipeline object
|
||||
*/
|
||||
MaterialPipelineRef MaterialPipeline::GetPipeline(const MaterialPipelineInfo& pipelineInfo)
|
||||
{
|
||||
auto it = s_pipelineCache.find(pipelineInfo);
|
||||
if (it == s_pipelineCache.end())
|
||||
it = s_pipelineCache.insert(it, PipelineCache::value_type(pipelineInfo, New(pipelineInfo)));
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void MaterialPipeline::GenerateRenderPipeline(UInt32 flags) const
|
||||
{
|
||||
NazaraAssert(m_pipelineInfo.settings, "Material pipeline has no settings");
|
||||
NazaraAssert(m_pipelineInfo.uberShader, "Material pipeline has no uber shader");
|
||||
|
||||
const auto& textures = m_pipelineInfo.settings->GetTextures();
|
||||
|
||||
ParameterList list;
|
||||
for (std::size_t i = 0, texCount = textures.size(); i < texCount; ++i)
|
||||
{
|
||||
const auto& texture = textures[i];
|
||||
String parameterName = "HAS_" + texture.name.ToUpper() + "_TEXTURE";
|
||||
|
||||
list.SetParameter(parameterName, (m_pipelineInfo.textures & (1 << i)) != 0);
|
||||
}
|
||||
|
||||
list.SetParameter("ALPHA_TEST", m_pipelineInfo.alphaTest);
|
||||
list.SetParameter("REFLECTION_MAPPING", m_pipelineInfo.reflectionMapping);
|
||||
list.SetParameter("SHADOW_MAPPING", m_pipelineInfo.shadowReceive);
|
||||
list.SetParameter("TEXTURE_MAPPING", m_pipelineInfo.textures != 0 ||
|
||||
m_pipelineInfo.reflectionMapping || flags & ShaderFlags_TextureOverlay);
|
||||
list.SetParameter("TRANSFORM", true);
|
||||
|
||||
list.SetParameter("FLAG_BILLBOARD", static_cast<bool>((flags & ShaderFlags_Billboard) != 0));
|
||||
list.SetParameter("FLAG_DEFERRED", static_cast<bool>((flags & ShaderFlags_Deferred) != 0));
|
||||
list.SetParameter("FLAG_INSTANCING", static_cast<bool>((flags & ShaderFlags_Instancing) != 0));
|
||||
list.SetParameter("FLAG_TEXTUREOVERLAY", static_cast<bool>((flags & ShaderFlags_TextureOverlay) != 0));
|
||||
list.SetParameter("FLAG_VERTEXCOLOR", m_pipelineInfo.hasVertexColor || static_cast<bool>((flags & ShaderFlags_VertexColor) != 0));
|
||||
|
||||
Instance& instance = m_instances[flags];
|
||||
instance.uberInstance = m_pipelineInfo.uberShader->Get(list);
|
||||
|
||||
RenderPipelineInfo renderPipelineInfo;
|
||||
static_cast<RenderStates&>(renderPipelineInfo).operator=(m_pipelineInfo); // Not my proudest line
|
||||
|
||||
renderPipelineInfo.shader = instance.uberInstance->GetShader();
|
||||
|
||||
instance.renderPipeline.Create(renderPipelineInfo);
|
||||
|
||||
// Send texture units (those never changes)
|
||||
const RenderPipelineLayout* pipelineLayout = m_pipelineInfo.pipelineLayout;
|
||||
if (!pipelineLayout)
|
||||
pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout();
|
||||
|
||||
instance.bindings = renderPipelineInfo.shader->ApplyLayout(pipelineLayout);
|
||||
|
||||
renderPipelineInfo.shader->SendInteger(renderPipelineInfo.shader->GetUniformLocation("ReflectionMap"), Material::GetTextureUnit(TextureMap_ReflectionCube));
|
||||
|
||||
renderPipelineInfo.shader->SendInteger(renderPipelineInfo.shader->GetUniformLocation("DirectionalSpotLightShadowMap[0]"), Material::GetTextureUnit(TextureMap_Shadow2D_1));
|
||||
renderPipelineInfo.shader->SendInteger(renderPipelineInfo.shader->GetUniformLocation("DirectionalSpotLightShadowMap[1]"), Material::GetTextureUnit(TextureMap_Shadow2D_2));
|
||||
renderPipelineInfo.shader->SendInteger(renderPipelineInfo.shader->GetUniformLocation("DirectionalSpotLightShadowMap[2]"), Material::GetTextureUnit(TextureMap_Shadow2D_3));
|
||||
|
||||
renderPipelineInfo.shader->SendInteger(renderPipelineInfo.shader->GetUniformLocation("PointLightShadowMap[0]"), Material::GetTextureUnit(TextureMap_ShadowCube_1));
|
||||
renderPipelineInfo.shader->SendInteger(renderPipelineInfo.shader->GetUniformLocation("PointLightShadowMap[1]"), Material::GetTextureUnit(TextureMap_ShadowCube_2));
|
||||
renderPipelineInfo.shader->SendInteger(renderPipelineInfo.shader->GetUniformLocation("PointLightShadowMap[2]"), Material::GetTextureUnit(TextureMap_ShadowCube_3));
|
||||
}
|
||||
|
||||
bool MaterialPipeline::Initialize()
|
||||
{
|
||||
// Basic shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_basicFragmentShader), sizeof(r_basicFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_basicVertexShader), sizeof(r_basicVertexShader));
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
OverrideShader("Shaders/Basic/core.frag", &fragmentShader);
|
||||
OverrideShader("Shaders/Basic/core.vert", &vertexShader);
|
||||
#endif
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY AUTO_TEXCOORDS HAS_ALPHA_TEXTURE HAS_DIFFUSE_TEXTURE TEXTURE_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("Basic", uberShader);
|
||||
}
|
||||
|
||||
if (!BasicMaterial::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize phong lighting materials");
|
||||
return false;
|
||||
}
|
||||
|
||||
// PhongLighting shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_phongLightingFragmentShader), sizeof(r_phongLightingFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_phongLightingVertexShader), sizeof(r_phongLightingVertexShader));
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
OverrideShader("Shaders/PhongLighting/core.frag", &fragmentShader);
|
||||
OverrideShader("Shaders/PhongLighting/core.vert", &vertexShader);
|
||||
#endif
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_TEST AUTO_TEXCOORDS HAS_ALPHA_TEXTURE HAS_DIFFUSE_TEXTURE HAS_EMISSIVE_TEXTURE HAS_NORMAL_TEXTURE HAS_HEIGHT_TEXTURE HAS_SPECULAR_TEXTURE REFLECTION_MAPPING SHADOW_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR HAS_NORMAL_TEXTURE SHADOW_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("PhongLighting", uberShader);
|
||||
}
|
||||
|
||||
if (!PhongLightingMaterial::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize phong lighting materials");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Once the base shaders are registered, we can now set some default materials
|
||||
MaterialPipelineInfo pipelineInfo;
|
||||
pipelineInfo.settings = BasicMaterial::GetSettings();
|
||||
pipelineInfo.uberShader = UberShaderLibrary::Get("Basic");
|
||||
|
||||
// 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 and scissoring
|
||||
pipelineInfo.blending = true;
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.depthSorting = false;
|
||||
pipelineInfo.scissorTest = true;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
MaterialPipelineLibrary::Register("Translucent2D", GetPipeline(pipelineInfo));
|
||||
|
||||
// Translucent 3D - Alpha blending with depth buffer and no depth write/face culling
|
||||
pipelineInfo.blending = true;
|
||||
pipelineInfo.depthBuffer = true;
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.depthSorting = true;
|
||||
pipelineInfo.scissorTest = false;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
MaterialPipelineLibrary::Register("Translucent3D", GetPipeline(pipelineInfo));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaterialPipeline::Uninitialize()
|
||||
{
|
||||
s_pipelineCache.clear();
|
||||
UberShaderLibrary::Unregister("PhongLighting");
|
||||
PhongLightingMaterial::Uninitialize();
|
||||
UberShaderLibrary::Unregister("Basic");
|
||||
BasicMaterial::Uninitialize();
|
||||
MaterialPipelineLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
MaterialPipelineLibrary::LibraryMap MaterialPipeline::s_library;
|
||||
MaterialPipeline::PipelineCache MaterialPipeline::s_pipelineCache;
|
||||
}
|
||||
331
src/Nazara/Graphics/PhongLightingMaterial.cpp
Normal file
331
src/Nazara/Graphics/PhongLightingMaterial.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
// 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/PhongLightingMaterial.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Utility/BufferMapper.hpp>
|
||||
#include <Nazara/Utility/FieldOffsets.hpp>
|
||||
#include <Nazara/Utility/MaterialData.hpp>
|
||||
#include <cassert>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr std::size_t AlphaMapBinding = 0;
|
||||
constexpr std::size_t DiffuseMapBinding = 1;
|
||||
constexpr std::size_t EmissiveMapBinding = 2;
|
||||
constexpr std::size_t HeightMapBinding = 3;
|
||||
constexpr std::size_t NormalMapBinding = 4;
|
||||
constexpr std::size_t SpecularMapBinding = 5;
|
||||
constexpr std::size_t TextureOverlayBinding = 6;
|
||||
}
|
||||
|
||||
PhongLightingMaterial::PhongLightingMaterial(Material* material) :
|
||||
m_material(material)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
// Most common case: don't fetch texture indexes as a little optimization
|
||||
const std::shared_ptr<const MaterialSettings>& materialSettings = material->GetSettings();
|
||||
if (materialSettings == s_materialSettings)
|
||||
{
|
||||
m_textureIndexes = s_textureIndexes;
|
||||
m_phongUniformIndex = s_phongUniformBlockIndex;
|
||||
m_phongUniformOffsets = s_phongUniformOffsets;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
|
||||
m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
|
||||
m_textureIndexes.emissive = materialSettings->GetTextureIndex("Emissive");
|
||||
m_textureIndexes.height = materialSettings->GetTextureIndex("Height");
|
||||
m_textureIndexes.normal = materialSettings->GetTextureIndex("Normal");
|
||||
m_textureIndexes.specular = materialSettings->GetTextureIndex("Specular");
|
||||
|
||||
m_phongUniformIndex = materialSettings->GetUniformBlockIndex("PhongSettings");
|
||||
|
||||
m_phongUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AlphaThreshold");
|
||||
m_phongUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AmbientColor");
|
||||
m_phongUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "DiffuseColor");
|
||||
m_phongUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "Shininess");
|
||||
m_phongUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "SpecularColor");
|
||||
}
|
||||
}
|
||||
|
||||
float PhongLightingMaterial::GetAlphaThreshold() const
|
||||
{
|
||||
NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly);
|
||||
return *AccessByOffset<const float>(mapper.GetPointer(), m_phongUniformOffsets.alphaThreshold);
|
||||
}
|
||||
|
||||
Color PhongLightingMaterial::GetAmbientColor() const
|
||||
{
|
||||
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly);
|
||||
|
||||
const float* colorPtr = AccessByOffset<const float>(mapper.GetPointer(), m_phongUniformOffsets.ambientColor);
|
||||
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
|
||||
}
|
||||
|
||||
Color PhongLightingMaterial::GetDiffuseColor() const
|
||||
{
|
||||
NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly);
|
||||
|
||||
const float* colorPtr = AccessByOffset<const float>(mapper.GetPointer(), m_phongUniformOffsets.diffuseColor);
|
||||
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
|
||||
}
|
||||
|
||||
float Nz::PhongLightingMaterial::GetShininess() const
|
||||
{
|
||||
NazaraAssert(HasShininess(), "Material has no shininess uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly);
|
||||
return *AccessByOffset<const float>(mapper.GetPointer(), m_phongUniformOffsets.shininess);
|
||||
}
|
||||
|
||||
Color PhongLightingMaterial::GetSpecularColor() const
|
||||
{
|
||||
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_ReadOnly);
|
||||
|
||||
const float* colorPtr = AccessByOffset<const float>(mapper.GetPointer(), m_phongUniformOffsets.specularColor);
|
||||
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
|
||||
}
|
||||
|
||||
void PhongLightingMaterial::SetAlphaThreshold(float alphaThreshold)
|
||||
{
|
||||
NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly);
|
||||
*AccessByOffset<float>(mapper.GetPointer(), m_phongUniformOffsets.alphaThreshold) = alphaThreshold;
|
||||
}
|
||||
|
||||
void PhongLightingMaterial::SetAmbientColor(const Color& ambient)
|
||||
{
|
||||
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly);
|
||||
float* colorPtr = AccessByOffset<float>(mapper.GetPointer(), m_phongUniformOffsets.ambientColor);
|
||||
colorPtr[0] = ambient.r / 255.f;
|
||||
colorPtr[1] = ambient.g / 255.f;
|
||||
colorPtr[2] = ambient.b / 255.f;
|
||||
colorPtr[3] = ambient.a / 255.f;
|
||||
}
|
||||
|
||||
void PhongLightingMaterial::SetDiffuseColor(const Color& diffuse)
|
||||
{
|
||||
NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly);
|
||||
float* colorPtr = AccessByOffset<float>(mapper.GetPointer(), m_phongUniformOffsets.diffuseColor);
|
||||
colorPtr[0] = diffuse.r / 255.f;
|
||||
colorPtr[1] = diffuse.g / 255.f;
|
||||
colorPtr[2] = diffuse.b / 255.f;
|
||||
colorPtr[3] = diffuse.a / 255.f;
|
||||
}
|
||||
|
||||
void PhongLightingMaterial::SetSpecularColor(const Color& diffuse)
|
||||
{
|
||||
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
|
||||
|
||||
BufferMapper<UniformBuffer> mapper(m_material->GetUniformBuffer(m_phongUniformIndex), BufferAccess_WriteOnly);
|
||||
float* colorPtr = AccessByOffset<float>(mapper.GetPointer(), m_phongUniformOffsets.specularColor);
|
||||
colorPtr[0] = diffuse.r / 255.f;
|
||||
colorPtr[1] = diffuse.g / 255.f;
|
||||
colorPtr[2] = diffuse.b / 255.f;
|
||||
colorPtr[3] = diffuse.a / 255.f;
|
||||
}
|
||||
|
||||
const std::shared_ptr<MaterialSettings>& PhongLightingMaterial::GetSettings()
|
||||
{
|
||||
return s_materialSettings;
|
||||
}
|
||||
|
||||
bool PhongLightingMaterial::Initialize()
|
||||
{
|
||||
RenderPipelineLayoutInfo info;
|
||||
info.bindings.assign({
|
||||
{
|
||||
"MaterialAlphaMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
AlphaMapBinding
|
||||
},
|
||||
{
|
||||
"MaterialDiffuseMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
DiffuseMapBinding
|
||||
},
|
||||
{
|
||||
"MaterialEmissiveMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
EmissiveMapBinding
|
||||
},
|
||||
{
|
||||
"MaterialHeightMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
HeightMapBinding
|
||||
},
|
||||
{
|
||||
"MaterialNormalMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
NormalMapBinding
|
||||
},
|
||||
{
|
||||
"MaterialSpecularMap",
|
||||
ShaderBindingType_Texture,
|
||||
ShaderStageType_Fragment,
|
||||
SpecularMapBinding
|
||||
}
|
||||
});
|
||||
|
||||
s_renderPipelineLayout = RenderPipelineLayout::New();
|
||||
s_renderPipelineLayout->Create(info);
|
||||
|
||||
std::vector<MaterialSettings::UniformBlock> uniformBlocks;
|
||||
|
||||
// MaterialPhongSettings
|
||||
FieldOffsets phongUniformStruct(StructLayout_Std140);
|
||||
|
||||
s_phongUniformOffsets.alphaThreshold = phongUniformStruct.AddField(StructFieldType_Float1);
|
||||
s_phongUniformOffsets.shininess = phongUniformStruct.AddField(StructFieldType_Float1);
|
||||
s_phongUniformOffsets.ambientColor = phongUniformStruct.AddField(StructFieldType_Float4);
|
||||
s_phongUniformOffsets.diffuseColor = phongUniformStruct.AddField(StructFieldType_Float4);
|
||||
s_phongUniformOffsets.specularColor = phongUniformStruct.AddField(StructFieldType_Float4);
|
||||
|
||||
MaterialSettings::PredefinedBinding predefinedBinding;
|
||||
predefinedBinding.fill(MaterialSettings::InvalidIndex);
|
||||
|
||||
std::vector<MaterialSettings::UniformVariable> phongVariables;
|
||||
phongVariables.assign({
|
||||
{
|
||||
"AlphaThreshold",
|
||||
s_phongUniformOffsets.alphaThreshold
|
||||
},
|
||||
{
|
||||
"Shininess",
|
||||
s_phongUniformOffsets.shininess
|
||||
},
|
||||
{
|
||||
"AmbientColor",
|
||||
s_phongUniformOffsets.ambientColor
|
||||
},
|
||||
{
|
||||
"DiffuseColor",
|
||||
s_phongUniformOffsets.diffuseColor
|
||||
},
|
||||
{
|
||||
"SpecularColor",
|
||||
s_phongUniformOffsets.specularColor
|
||||
}
|
||||
});
|
||||
|
||||
static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide");
|
||||
|
||||
std::vector<UInt8> defaultValues(phongUniformStruct.GetSize());
|
||||
*AccessByOffset<Vector4f>(defaultValues.data(), s_phongUniformOffsets.ambientColor) = Vector4f(0.5f, 0.5f, 0.5f, 1.f);
|
||||
*AccessByOffset<Vector4f>(defaultValues.data(), s_phongUniformOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
|
||||
*AccessByOffset<Vector4f>(defaultValues.data(), s_phongUniformOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
|
||||
*AccessByOffset<float>(defaultValues.data(), s_phongUniformOffsets.alphaThreshold) = 0.2f;
|
||||
*AccessByOffset<float>(defaultValues.data(), s_phongUniformOffsets.shininess) = 50.f;
|
||||
|
||||
s_phongUniformBlockIndex = uniformBlocks.size();
|
||||
uniformBlocks.push_back({
|
||||
"PhongSettings",
|
||||
phongUniformStruct.GetSize(),
|
||||
"MaterialPhongSettings",
|
||||
std::move(phongVariables),
|
||||
std::move(defaultValues)
|
||||
});
|
||||
|
||||
std::vector<MaterialSettings::SharedUniformBlock> sharedUniformBlock;
|
||||
predefinedBinding[PredefinedShaderBinding_UboInstanceData] = sharedUniformBlock.size();
|
||||
sharedUniformBlock.push_back(PredefinedInstanceData::GetUniformBlock());
|
||||
predefinedBinding[PredefinedShaderBinding_UboLighData] = sharedUniformBlock.size();
|
||||
sharedUniformBlock.push_back(PredefinedLightData::GetUniformBlock());
|
||||
predefinedBinding[PredefinedShaderBinding_UboViewerData] = sharedUniformBlock.size();
|
||||
sharedUniformBlock.push_back(PredefinedViewerData::GetUniformBlock());
|
||||
|
||||
std::vector<MaterialSettings::Texture> textures;
|
||||
s_textureIndexes.alpha = textures.size();
|
||||
textures.push_back({
|
||||
"Alpha",
|
||||
ImageType_2D,
|
||||
"MaterialAlphaMap"
|
||||
});
|
||||
|
||||
s_textureIndexes.diffuse = textures.size();
|
||||
textures.push_back({
|
||||
"Diffuse",
|
||||
ImageType_2D,
|
||||
"MaterialDiffuseMap"
|
||||
});
|
||||
|
||||
s_textureIndexes.emissive = textures.size();
|
||||
textures.push_back({
|
||||
"Emissive",
|
||||
ImageType_2D,
|
||||
"MaterialEmissiveMap"
|
||||
});
|
||||
|
||||
s_textureIndexes.height = textures.size();
|
||||
textures.push_back({
|
||||
"Height",
|
||||
ImageType_2D,
|
||||
"MaterialHeightMap"
|
||||
});
|
||||
|
||||
s_textureIndexes.normal = textures.size();
|
||||
textures.push_back({
|
||||
"Normal",
|
||||
ImageType_2D,
|
||||
"MaterialNormalMap"
|
||||
});
|
||||
|
||||
s_textureIndexes.specular = textures.size();
|
||||
textures.push_back({
|
||||
"Specular",
|
||||
ImageType_2D,
|
||||
"MaterialSpecularMap"
|
||||
});
|
||||
|
||||
predefinedBinding[PredefinedShaderBinding_TexOverlay] = textures.size();
|
||||
textures.push_back({
|
||||
"Overlay",
|
||||
ImageType_2D,
|
||||
"TextureOverlay"
|
||||
});
|
||||
|
||||
s_materialSettings = std::make_shared<MaterialSettings>(std::move(textures), std::move(uniformBlocks), std::move(sharedUniformBlock), predefinedBinding);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PhongLightingMaterial::Uninitialize()
|
||||
{
|
||||
s_renderPipelineLayout.Reset();
|
||||
s_materialSettings.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialSettings> PhongLightingMaterial::s_materialSettings;
|
||||
std::size_t PhongLightingMaterial::s_phongUniformBlockIndex;
|
||||
RenderPipelineLayoutRef PhongLightingMaterial::s_renderPipelineLayout;
|
||||
PhongLightingMaterial::TextureIndexes PhongLightingMaterial::s_textureIndexes;
|
||||
PhongLightingMaterial::PhongUniformOffsets PhongLightingMaterial::s_phongUniformOffsets;
|
||||
}
|
||||
167
src/Nazara/Graphics/PredefinedShaderStructs.cpp
Normal file
167
src/Nazara/Graphics/PredefinedShaderStructs.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
// 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/PredefinedShaderStructs.hpp>
|
||||
#include <Nazara/Utility/FieldOffsets.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
PredefinedLightData PredefinedLightData::GetOffset()
|
||||
{
|
||||
PredefinedLightData lightData;
|
||||
|
||||
FieldOffsets lightStruct(StructLayout_Std140);
|
||||
lightData.innerOffsets.type = lightStruct.AddField(StructFieldType_Int1);
|
||||
lightData.innerOffsets.color = lightStruct.AddField(StructFieldType_Float4);
|
||||
lightData.innerOffsets.factor = lightStruct.AddField(StructFieldType_Float2);
|
||||
lightData.innerOffsets.parameter1 = lightStruct.AddField(StructFieldType_Float4);
|
||||
lightData.innerOffsets.parameter2 = lightStruct.AddField(StructFieldType_Float4);
|
||||
lightData.innerOffsets.parameter3 = lightStruct.AddField(StructFieldType_Float2);
|
||||
lightData.innerOffsets.shadowMappingFlag = lightStruct.AddField(StructFieldType_Bool1);
|
||||
|
||||
lightData.innerOffsets.totalSize = lightStruct.GetSize();
|
||||
|
||||
FieldOffsets lightDataStruct(StructLayout_Std140);
|
||||
for (std::size_t& lightOffset : lightData.lightArray)
|
||||
lightOffset = lightDataStruct.AddStruct(lightStruct);
|
||||
|
||||
lightData.lightArraySize = lightDataStruct.GetSize();
|
||||
|
||||
return lightData;
|
||||
}
|
||||
|
||||
MaterialSettings::SharedUniformBlock PredefinedLightData::GetUniformBlock()
|
||||
{
|
||||
PredefinedLightData lightData = GetOffset();
|
||||
|
||||
std::vector<MaterialSettings::UniformVariable> lightDataVariables;
|
||||
for (std::size_t i = 0; i < lightData.lightArray.size(); ++i)
|
||||
{
|
||||
lightDataVariables.push_back({
|
||||
"LightData[" + std::to_string(i) + "]",
|
||||
lightData.lightArray[i]
|
||||
});
|
||||
}
|
||||
|
||||
MaterialSettings::SharedUniformBlock uniformBlock = {
|
||||
"Light",
|
||||
"LightData",
|
||||
std::move(lightDataVariables)
|
||||
};
|
||||
|
||||
return uniformBlock;
|
||||
}
|
||||
|
||||
PredefinedInstanceData PredefinedInstanceData::GetOffset()
|
||||
{
|
||||
FieldOffsets viewerStruct(StructLayout_Std140);
|
||||
|
||||
PredefinedInstanceData instanceData;
|
||||
instanceData.worldMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
instanceData.invWorldMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
|
||||
instanceData.totalSize = viewerStruct.GetSize();
|
||||
|
||||
return instanceData;
|
||||
}
|
||||
|
||||
MaterialSettings::SharedUniformBlock PredefinedInstanceData::GetUniformBlock()
|
||||
{
|
||||
PredefinedInstanceData instanceData = GetOffset();
|
||||
|
||||
std::vector<MaterialSettings::UniformVariable> instanceDataVariables;
|
||||
instanceDataVariables.assign({
|
||||
{
|
||||
"WorldMatrix",
|
||||
instanceData.worldMatrixOffset
|
||||
},
|
||||
{
|
||||
"InvWorldMatrix",
|
||||
instanceData.invWorldMatrixOffset
|
||||
},
|
||||
});
|
||||
|
||||
MaterialSettings::SharedUniformBlock uniformBlock = {
|
||||
"Instance",
|
||||
"InstanceData",
|
||||
std::move(instanceDataVariables)
|
||||
};
|
||||
|
||||
return uniformBlock;
|
||||
}
|
||||
|
||||
PredefinedViewerData PredefinedViewerData::GetOffset()
|
||||
{
|
||||
FieldOffsets viewerStruct(StructLayout_Std140);
|
||||
|
||||
PredefinedViewerData viewerData;
|
||||
viewerData.projMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
viewerData.invProjMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
viewerData.viewMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
viewerData.invViewMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
viewerData.viewProjMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
viewerData.invViewProjMatrixOffset = viewerStruct.AddMatrix(StructFieldType_Float1, 4, 4, true);
|
||||
viewerData.targetSizeOffset = viewerStruct.AddField(StructFieldType_Float2);
|
||||
viewerData.invTargetSizeOffset = viewerStruct.AddField(StructFieldType_Float2);
|
||||
viewerData.eyePositionOffset = viewerStruct.AddField(StructFieldType_Float3);
|
||||
|
||||
viewerData.totalSize = viewerStruct.GetSize();
|
||||
|
||||
return viewerData;
|
||||
}
|
||||
|
||||
MaterialSettings::SharedUniformBlock PredefinedViewerData::GetUniformBlock()
|
||||
{
|
||||
PredefinedViewerData viewerData = GetOffset();
|
||||
|
||||
std::vector<MaterialSettings::UniformVariable> viewerDataVariables;
|
||||
viewerDataVariables.assign({
|
||||
{
|
||||
"ProjMatrix",
|
||||
viewerData.projMatrixOffset
|
||||
},
|
||||
{
|
||||
"InvProjMatrix",
|
||||
viewerData.invProjMatrixOffset
|
||||
},
|
||||
{
|
||||
"ViewMatrix",
|
||||
viewerData.viewMatrixOffset
|
||||
},
|
||||
{
|
||||
"InvViewMatrix",
|
||||
viewerData.invViewMatrixOffset
|
||||
},
|
||||
{
|
||||
"ViewProjMatrix",
|
||||
viewerData.viewProjMatrixOffset
|
||||
},
|
||||
{
|
||||
"InvViewProjMatrix",
|
||||
viewerData.invViewProjMatrixOffset
|
||||
},
|
||||
{
|
||||
"TargetSize",
|
||||
viewerData.targetSizeOffset
|
||||
},
|
||||
{
|
||||
"InvTargetSize",
|
||||
viewerData.invTargetSizeOffset
|
||||
},
|
||||
{
|
||||
"EyePosition",
|
||||
viewerData.eyePositionOffset
|
||||
}
|
||||
});
|
||||
|
||||
MaterialSettings::SharedUniformBlock uniformBlock = {
|
||||
"Viewer",
|
||||
"ViewerData",
|
||||
std::move(viewerDataVariables)
|
||||
};
|
||||
|
||||
return uniformBlock;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user