NazaraEngine/src/Nazara/Graphics/Material.cpp

117 lines
3.3 KiB
C++

// 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/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/UploadPool.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 Constructs a Material object with default states
*
* \see Reset
*/
Material::Material(std::shared_ptr<const MaterialSettings> settings) :
m_settings(std::move(settings)),
m_enabledConditions(0),
m_pipelineUpdated(false),
m_shadowCastingEnabled(true)
{
m_pipelineInfo.settings = m_settings;
const auto& shaders = m_settings->GetShaders();
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
m_pipelineInfo.shaders[i].uberShader = shaders[i];
m_textures.resize(m_settings->GetTextures().size());
m_uniformBuffers.reserve(m_settings->GetUniformBlocks().size());
for (const auto& uniformBufferInfo : m_settings->GetUniformBlocks())
{
auto& uniformBuffer = m_uniformBuffers.emplace_back();
uniformBuffer.buffer = Graphics::Instance()->GetRenderDevice().InstantiateBuffer(Nz::BufferType_Uniform);
if (!uniformBuffer.buffer->Initialize(uniformBufferInfo.blockSize, BufferUsage_Dynamic))
throw std::runtime_error("failed to initialize UBO memory");
assert(uniformBufferInfo.defaultValues.size() <= uniformBufferInfo.blockSize);
uniformBuffer.buffer->Fill(uniformBufferInfo.defaultValues.data(), 0, uniformBufferInfo.defaultValues.size());
uniformBuffer.data.resize(uniformBufferInfo.blockSize);
std::memcpy(uniformBuffer.data.data(), uniformBufferInfo.defaultValues.data(), uniformBufferInfo.defaultValues.size());
}
}
void Material::UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder)
{
for (auto& ubo : m_uniformBuffers)
{
if (ubo.dataInvalidated)
{
auto& allocation = uploadPool.Allocate(ubo.data.size());
std::memcpy(allocation.mappedPtr, ubo.data.data(), ubo.data.size());
builder.CopyBuffer(allocation, ubo.buffer.get());
ubo.dataInvalidated = false;
}
}
}
void Material::UpdateShaderBinding(ShaderBinding& shaderBinding) const
{
// TODO: Use StackVector
std::vector<ShaderBinding::Binding> bindings;
std::size_t bindingIndex = 0;
for (const auto& textureSlot : m_textures)
{
if (!textureSlot.sampler)
{
TextureSamplerCache& samplerCache = Graphics::Instance()->GetSamplerCache();
textureSlot.sampler = samplerCache.Get(textureSlot.samplerInfo);
}
//TODO: Use "missing" texture
if (textureSlot.texture)
{
bindings.push_back({
bindingIndex,
ShaderBinding::TextureBinding {
textureSlot.texture.get(), textureSlot.sampler.get()
}
});
}
bindingIndex++;
}
for (const auto& ubo : m_uniformBuffers)
{
bindings.push_back({
bindingIndex++,
ShaderBinding::UniformBufferBinding {
ubo.buffer.get(), 0, ubo.buffer->GetSize()
}
});
}
shaderBinding.Update(bindings.data(), bindings.size());
}
}