// 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 #include #include #include #include #include #include #include #include #include #include #include namespace Nz { namespace { const UInt8 r_fragmentShader[] = { #include }; const UInt8 r_vertexShader[] = { #include }; } BasicMaterial::BasicMaterial(Material& material) : m_material(material) { // Most common case: don't fetch texture indexes as a little optimization const std::shared_ptr& materialSettings = material.GetSettings(); if (materialSettings == s_materialSettings) { m_conditionIndexes = s_conditionIndexes; m_textureIndexes = s_textureIndexes; m_uniformBlockIndex = s_uniformBlockIndex; m_uniformOffsets = s_uniformOffsets; } else { m_conditionIndexes.alphaTest = materialSettings->GetConditionIndex("AlphaTest"); m_conditionIndexes.hasAlphaMap = materialSettings->GetConditionIndex("HasAlphaMap"); m_conditionIndexes.hasDiffuseMap = materialSettings->GetConditionIndex("HasDiffuseMap"); 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::GetAlphaTestThreshold() const { NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform"); const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); return AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold); } Color BasicMaterial::GetDiffuseColor() const { NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); const float* colorPtr = AccessByOffset(bufferData.data(), 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::SetAlphaTestThreshold(float alphaThreshold) { NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform"); std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold) = alphaThreshold; } void BasicMaterial::SetDiffuseColor(const Color& diffuse) { NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); float* colorPtr = AccessByOffset(bufferData.data(), 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; } bool BasicMaterial::Initialize() { FieldOffsets fieldOffsets(StructLayout::Std140); s_uniformOffsets.alphaThreshold = fieldOffsets.AddField(StructFieldType::Float1); s_uniformOffsets.diffuseColor = fieldOffsets.AddField(StructFieldType::Float4); s_uniformOffsets.totalSize = fieldOffsets.GetSize(); MaterialSettings::Builder settings; std::vector 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 defaultValues(fieldOffsets.GetSize()); AccessByOffset(defaultValues.data(), s_uniformOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f); AccessByOffset(defaultValues.data(), s_uniformOffsets.alphaThreshold) = 0.2f; s_textureIndexes.alpha = settings.textures.size(); settings.textures.push_back({ 2, "Alpha", ImageType::E2D }); s_textureIndexes.diffuse = settings.textures.size(); settings.textures.push_back({ 1, "Diffuse", ImageType::E2D }); s_uniformBlockIndex = settings.uniformBlocks.size(); settings.uniformBlocks.push_back({ 0, "BasicSettings", fieldOffsets.GetSize(), std::move(variables), std::move(defaultValues) }); // Shaders auto& fragmentShader = settings.shaders[UnderlyingCast(ShaderStageType::Fragment)]; auto& vertexShader = settings.shaders[UnderlyingCast(ShaderStageType::Vertex)]; fragmentShader = std::make_shared(ShaderStageType::Fragment, ShaderAst::UnserializeShader(r_fragmentShader, sizeof(r_fragmentShader))); vertexShader = std::make_shared(ShaderStageType::Vertex, ShaderAst::UnserializeShader(r_vertexShader, sizeof(r_vertexShader))); // Conditions // HasDiffuseMap { std::array shaderConditions; shaderConditions.fill(0); shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_DIFFUSE_TEXTURE"); s_conditionIndexes.hasDiffuseMap = settings.conditions.size(); settings.conditions.push_back({ "HasDiffuseMap", shaderConditions }); } // HasAlphaMap { std::array shaderConditions; shaderConditions.fill(0); shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("HAS_ALPHA_TEXTURE"); s_conditionIndexes.hasAlphaMap = settings.conditions.size(); settings.conditions.push_back({ "HasAlphaMap", shaderConditions }); } // AlphaTest { std::array shaderConditions; shaderConditions.fill(0); shaderConditions[UnderlyingCast(ShaderStageType::Fragment)] = fragmentShader->GetOptionFlagByName("ALPHA_TEST"); s_conditionIndexes.alphaTest = settings.conditions.size(); settings.conditions.push_back({ "AlphaTest", shaderConditions }); } s_materialSettings = std::make_shared(std::move(settings)); return true; } void BasicMaterial::Uninitialize() { s_materialSettings.reset(); } std::shared_ptr BasicMaterial::s_materialSettings; std::size_t BasicMaterial::s_uniformBlockIndex; BasicMaterial::ConditionIndexes BasicMaterial::s_conditionIndexes; BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes; BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets; }