#include "EffekseerRendererGL.MaterialLoader.h" #include "EffekseerRendererGL.ModelRenderer.h" #include "EffekseerRendererGL.Shader.h" #include #include "../EffekseerMaterialCompiler/OpenGL/EffekseerMaterialCompilerGL.h" #include "Effekseer/Material/Effekseer.CompiledMaterial.h" #undef min namespace EffekseerRendererGL { static const int GL_InstanceCount = 10; void StoreVertexUniform(const ::Effekseer::MaterialFile& materialFile, const EffekseerRenderer::MaterialShaderParameterGenerator& generator, Effekseer::CustomVector& uniformLayout) { using namespace Effekseer::Backend; auto storeVector = [&](const char* name, int offset, int count = 1) { uniformLayout.emplace_back(UniformLayoutElement{ShaderStageType::Vertex, name, UniformBufferLayoutElementType::Vector4, count, offset}); }; auto storeMatrix = [&](const char* name, int offset, int count = 1) { uniformLayout.emplace_back(UniformLayoutElement{ShaderStageType::Vertex, name, UniformBufferLayoutElementType::Matrix44, count, offset}); }; storeMatrix("uMatCamera", generator.VertexCameraMatrixOffset); storeMatrix("uMatProjection", generator.VertexProjectionMatrixOffset); storeVector("mUVInversed", generator.VertexInversedFlagOffset); storeVector("predefined_uniform", generator.VertexPredefinedOffset); storeVector("cameraPosition", generator.VertexCameraPositionOffset); auto currentOffset = generator.VertexUserUniformOffset; for (int32_t ui = 0; ui < materialFile.GetUniformCount(); ui++) { storeVector(materialFile.GetUniformName(ui), currentOffset); currentOffset += sizeof(float) * 4; } for (size_t ui = 0; ui < materialFile.Gradients.size(); ui++) { for (int j = 0; j < 13; j++) { const auto name = materialFile.Gradients.at(ui).Name + "_" + std::to_string(j); storeVector(name.c_str(), currentOffset); currentOffset += sizeof(float) * 4; } } } void StoreModelVertexUniform(const ::Effekseer::MaterialFile& materialFile, const EffekseerRenderer::MaterialShaderParameterGenerator& generator, Effekseer::CustomVector& uniformLayout, bool instancing) { using namespace Effekseer::Backend; auto storeVector = [&](const char* name, int offset, int count = 1) { uniformLayout.emplace_back(UniformLayoutElement{ShaderStageType::Vertex, name, UniformBufferLayoutElementType::Vector4, count, offset}); }; auto storeMatrix = [&](const char* name, int offset, int count = 1) { uniformLayout.emplace_back(UniformLayoutElement{ShaderStageType::Vertex, name, UniformBufferLayoutElementType::Matrix44, count, offset}); }; storeMatrix("ProjectionMatrix", generator.VertexProjectionMatrixOffset); if (instancing) { storeMatrix("ModelMatrix", generator.VertexModelMatrixOffset, GL_InstanceCount); storeVector("UVOffset", generator.VertexModelUVOffset, GL_InstanceCount); storeVector("ModelColor", generator.VertexModelColorOffset, GL_InstanceCount); } else { storeMatrix("ModelMatrix", generator.VertexModelMatrixOffset); storeVector("UVOffset", generator.VertexModelUVOffset); storeVector("ModelColor", generator.VertexModelColorOffset); } storeVector("mUVInversed", generator.VertexInversedFlagOffset); storeVector("predefined_uniform", generator.VertexPredefinedOffset); storeVector("cameraPosition", generator.VertexCameraPositionOffset); if (instancing) { if (materialFile.GetCustomData1Count() > 0) { storeVector("customData1s", generator.VertexModelCustomData1Offset, GL_InstanceCount); } if (materialFile.GetCustomData2Count() > 0) { storeVector("customData2s", generator.VertexModelCustomData2Offset, GL_InstanceCount); } } else { if (materialFile.GetCustomData1Count() > 0) { storeVector("customData1", generator.VertexModelCustomData1Offset); } if (materialFile.GetCustomData2Count() > 0) { storeVector("customData2", generator.VertexModelCustomData2Offset); } } auto currentOffset = generator.VertexUserUniformOffset; for (int32_t ui = 0; ui < materialFile.GetUniformCount(); ui++) { storeVector(materialFile.GetUniformName(ui), currentOffset); currentOffset += sizeof(float) * 4; } for (size_t ui = 0; ui < materialFile.Gradients.size(); ui++) { for (int j = 0; j < 13; j++) { const auto name = materialFile.Gradients.at(ui).Name + "_" + std::to_string(j); storeVector(name.c_str(), currentOffset); currentOffset += sizeof(float) * 4; } } } void StorePixelUniform(const ::Effekseer::MaterialFile& materialFile, const EffekseerRenderer::MaterialShaderParameterGenerator& generator, Effekseer::CustomVector& uniformLayout, int shaderType) { using namespace Effekseer::Backend; auto storeVector = [&](const char* name, int offset, int count = 1) { uniformLayout.emplace_back(UniformLayoutElement{ShaderStageType::Pixel, name, UniformBufferLayoutElementType::Vector4, count, offset}); }; auto storeMatrix = [&](const char* name, int offset, int count = 1) { uniformLayout.emplace_back(UniformLayoutElement{ShaderStageType::Pixel, name, UniformBufferLayoutElementType::Matrix44, count, offset}); }; storeVector("mUVInversedBack", generator.PixelInversedFlagOffset); storeVector("predefined_uniform", generator.PixelPredefinedOffset); storeVector("cameraPosition", generator.PixelCameraPositionOffset); storeVector("reconstructionParam1", generator.PixelReconstructionParam1Offset); storeVector("reconstructionParam2", generator.PixelReconstructionParam2Offset); storeVector("lightDirection", generator.PixelLightDirectionOffset); storeVector("lightColor", generator.PixelLightColorOffset); storeVector("lightAmbientColor", generator.PixelLightAmbientColorOffset); if (materialFile.GetHasRefraction() && shaderType == 1) { storeMatrix("cameraMat", generator.PixelCameraMatrixOffset); } auto currentOffset = generator.PixelUserUniformOffset; for (int32_t ui = 0; ui < materialFile.GetUniformCount(); ui++) { storeVector(materialFile.GetUniformName(ui), currentOffset); currentOffset += sizeof(float) * 4; } for (size_t ui = 0; ui < materialFile.Gradients.size(); ui++) { for (int j = 0; j < 13; j++) { const auto name = materialFile.Gradients.at(ui).Name + "_" + std::to_string(j); storeVector(name.c_str(), currentOffset); currentOffset += sizeof(float) * 4; } } } Effekseer::CustomVector> StoreTextureLocations(const ::Effekseer::MaterialFile& materialFile) { Effekseer::CustomVector> texLoc; int32_t maxInd = -1; for (int32_t ti = 0; ti < materialFile.GetTextureCount(); ti++) { maxInd = Effekseer::Max(maxInd, materialFile.GetTextureIndex(ti)); } texLoc.resize(maxInd + 1); for (int32_t ti = 0; ti < materialFile.GetTextureCount(); ti++) { texLoc[materialFile.GetTextureIndex(ti)] = materialFile.GetTextureName(ti); } texLoc.emplace_back("efk_background"); texLoc.emplace_back("efk_depth"); return texLoc; } ::Effekseer::MaterialRef MaterialLoader::LoadAcutually(::Effekseer::MaterialFile& materialFile, ::Effekseer::CompiledMaterialBinary* binary) { if (binary == nullptr) { return nullptr; } auto deviceType = graphicsDevice_->GetDeviceType(); auto instancing = deviceType == OpenGLDeviceType::OpenGL3 || deviceType == OpenGLDeviceType::OpenGLES3; auto material = ::Effekseer::MakeRefPtr<::Effekseer::Material>(); material->IsSimpleVertex = materialFile.GetIsSimpleVertex(); material->IsRefractionRequired = materialFile.GetHasRefraction(); std::array shaderTypes; std::array shaderTypesModel; shaderTypes[0] = Effekseer::MaterialShaderType::Standard; shaderTypes[1] = Effekseer::MaterialShaderType::Refraction; shaderTypesModel[0] = Effekseer::MaterialShaderType::Model; shaderTypesModel[1] = Effekseer::MaterialShaderType::RefractionModel; int32_t shaderTypeCount = 1; if (materialFile.GetHasRefraction()) { shaderTypeCount = 2; } for (int32_t st = 0; st < shaderTypeCount; st++) { auto parameterGenerator = EffekseerRenderer::MaterialShaderParameterGenerator(materialFile, false, st, 1); Effekseer::CustomVector uniformLayoutElements; StoreVertexUniform(materialFile, parameterGenerator, uniformLayoutElements); StorePixelUniform(materialFile, parameterGenerator, uniformLayoutElements, st); auto uniformLayout = Effekseer::MakeRefPtr(StoreTextureLocations(materialFile), uniformLayoutElements); auto shader = Shader::CreateWithHeader(graphicsDevice_, {(const char*)binary->GetVertexShaderData(shaderTypes[st])}, {(const char*)binary->GetPixelShaderData(shaderTypes[st])}, uniformLayout, "CustomMaterial"); if (shader == nullptr) { std::cout << "Vertex shader error" << std::endl; std::cout << (const char*)binary->GetVertexShaderData(shaderTypesModel[st]) << std::endl; std::cout << "Pixel shader error" << std::endl; std::cout << (const char*)binary->GetPixelShaderData(shaderTypesModel[st]) << std::endl; return nullptr; } if (material->IsSimpleVertex) { const Effekseer::Backend::VertexLayoutElement vlElem[3] = { {Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT, "atPosition", "POSITION", 0}, {Effekseer::Backend::VertexLayoutFormat::R8G8B8A8_UNORM, "atColor", "NORMAL", 0}, {Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT, "atTexCoord", "TEXCOORD", 0}, }; auto vl = graphicsDevice_->CreateVertexLayout(vlElem, 3).DownCast(); shader->SetVertexLayout(vl); } else { Effekseer::Backend::VertexLayoutElement vlElem[8] = { {Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT, "atPosition", "POSITION", 0}, {Effekseer::Backend::VertexLayoutFormat::R8G8B8A8_UNORM, "atColor", "NORMAL", 0}, {Effekseer::Backend::VertexLayoutFormat::R8G8B8A8_UNORM, "atNormal", "NORMAL", 1}, {Effekseer::Backend::VertexLayoutFormat::R8G8B8A8_UNORM, "atTangent", "NORMAL", 2}, {Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT, "atTexCoord", "TEXCOORD", 0}, {Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT, "atTexCoord2", "TEXCOORD", 1}, {Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT, "", "TEXCOORD", 2}, {Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT, "", "TEXCOORD", 3}, }; auto getFormat = [](int32_t i) -> Effekseer::Backend::VertexLayoutFormat { if (i == 1) return Effekseer::Backend::VertexLayoutFormat::R32_FLOAT; if (i == 2) return Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT; if (i == 3) return Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT; if (i == 4) return Effekseer::Backend::VertexLayoutFormat::R32G32B32A32_FLOAT; assert(0); return Effekseer::Backend::VertexLayoutFormat::R32_FLOAT; }; int32_t offset = 40; int count = 6; int semanticIndex = 2; const char* customData1Name = "atCustomData1"; const char* customData2Name = "atCustomData2"; if (materialFile.GetCustomData1Count() > 0) { vlElem[count].Name = customData1Name; vlElem[count].Format = getFormat(materialFile.GetCustomData1Count()); vlElem[count].SemanticIndex = semanticIndex; semanticIndex++; count++; offset += sizeof(float) * materialFile.GetCustomData1Count(); } if (materialFile.GetCustomData2Count() > 0) { vlElem[count].Name = customData2Name; vlElem[count].Format = getFormat(materialFile.GetCustomData2Count()); vlElem[count].SemanticIndex = semanticIndex; semanticIndex++; count++; offset += sizeof(float) * materialFile.GetCustomData2Count(); } auto vl = graphicsDevice_->CreateVertexLayout(vlElem, count).DownCast(); shader->SetVertexLayout(vl); } shader->SetVertexConstantBufferSize(parameterGenerator.VertexShaderUniformBufferSize); shader->SetPixelConstantBufferSize(parameterGenerator.PixelShaderUniformBufferSize); material->TextureCount = std::min(materialFile.GetTextureCount(), Effekseer::UserTextureSlotMax); material->UniformCount = materialFile.GetUniformCount(); if (st == 0) { material->UserPtr = shader; } else { material->RefractionUserPtr = shader; } } for (int32_t st = 0; st < shaderTypeCount; st++) { auto parameterGenerator = EffekseerRenderer::MaterialShaderParameterGenerator(materialFile, true, st, instancing ? GL_InstanceCount : 1); Effekseer::CustomVector uniformLayoutElements; StoreModelVertexUniform(materialFile, parameterGenerator, uniformLayoutElements, instancing); StorePixelUniform(materialFile, parameterGenerator, uniformLayoutElements, st); auto uniformLayout = Effekseer::MakeRefPtr(StoreTextureLocations(materialFile), uniformLayoutElements); auto shader = Shader::CreateWithHeader(graphicsDevice_, {(const char*)binary->GetVertexShaderData(shaderTypesModel[st])}, {(const char*)binary->GetPixelShaderData(shaderTypesModel[st])}, uniformLayout, "CustomMaterial"); if (shader == nullptr) { std::cout << "Vertex shader error" << std::endl; std::cout << (const char*)binary->GetVertexShaderData(shaderTypesModel[st]) << std::endl; std::cout << "Pixel shader error" << std::endl; std::cout << (const char*)binary->GetPixelShaderData(shaderTypesModel[st]) << std::endl; return nullptr; } const Effekseer::Backend::VertexLayoutElement vlElem[6] = { {Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT, "a_Position", "POSITION", 0}, {Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT, "a_Normal", "NORMAL", 1}, {Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT, "a_Binormal", "NORMAL", 1}, {Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT, "a_Tangent", "NORMAL", 2}, {Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT, "a_TexCoord", "TEXCOORD", 0}, {Effekseer::Backend::VertexLayoutFormat::R8G8B8A8_UNORM, "a_Color", "NORMAL", 3}, }; auto vl = graphicsDevice_->CreateVertexLayout(vlElem, 6).DownCast(); shader->SetVertexLayout(vl); shader->SetVertexConstantBufferSize(parameterGenerator.VertexShaderUniformBufferSize); shader->SetPixelConstantBufferSize(parameterGenerator.PixelShaderUniformBufferSize); if (st == 0) { material->ModelUserPtr = shader; } else { material->RefractionModelUserPtr = shader; } } material->CustomData1 = materialFile.GetCustomData1Count(); material->CustomData2 = materialFile.GetCustomData2Count(); material->TextureCount = std::min(materialFile.GetTextureCount(), Effekseer::UserTextureSlotMax); material->UniformCount = materialFile.GetUniformCount(); material->ShadingModel = materialFile.GetShadingModel(); for (int32_t i = 0; i < material->TextureCount; i++) { material->TextureWrapTypes.at(i) = materialFile.GetTextureWrap(i); } return material; } MaterialLoader::MaterialLoader(Backend::GraphicsDeviceRef graphicsDevice, ::Effekseer::FileInterfaceRef fileInterface, bool canLoadFromCache) : fileInterface_(fileInterface) , canLoadFromCache_(canLoadFromCache) { if (fileInterface == nullptr) { fileInterface_ = Effekseer::MakeRefPtr(); } graphicsDevice_ = graphicsDevice; } MaterialLoader ::~MaterialLoader() { } ::Effekseer::MaterialRef MaterialLoader::Load(const char16_t* path) { // code file if (canLoadFromCache_) { auto binaryPath = std::u16string(path) + u"d"; auto reader = fileInterface_->TryOpenRead(binaryPath.c_str()); if (reader != nullptr) { size_t size = reader->GetLength(); std::vector data; data.resize(size); reader->Read(data.data(), size); auto material = Load(data.data(), (int32_t)size, ::Effekseer::MaterialFileType::Compiled); if (material != nullptr) { return material; } } } // code file { auto reader = fileInterface_->OpenRead(path); if (reader != nullptr) { size_t size = reader->GetLength(); std::vector data; data.resize(size); reader->Read(data.data(), size); auto material = Load(data.data(), (int32_t)size, ::Effekseer::MaterialFileType::Code); return material; } } return nullptr; } ::Effekseer::MaterialRef MaterialLoader::Load(const void* data, int32_t size, Effekseer::MaterialFileType fileType) { if (fileType == Effekseer::MaterialFileType::Compiled) { auto compiled = Effekseer::CompiledMaterial(); if (!compiled.Load(static_cast(data), size)) { return nullptr; } if (!compiled.GetHasValue(::Effekseer::CompiledMaterialPlatformType::OpenGL)) { return nullptr; } // compiled Effekseer::MaterialFile materialFile; if (!materialFile.Load((const uint8_t*)compiled.GetOriginalData().data(), static_cast(compiled.GetOriginalData().size()))) { std::cout << "Error : Invalid material is loaded." << std::endl; return nullptr; } auto binary = compiled.GetBinary(::Effekseer::CompiledMaterialPlatformType::OpenGL); return LoadAcutually(materialFile, binary); } else { Effekseer::MaterialFile materialFile; if (!materialFile.Load((const uint8_t*)data, size)) { std::cout << "Error : Invalid material is loaded." << std::endl; return nullptr; } auto compiler = ::Effekseer::CreateUniqueReference(new Effekseer::MaterialCompilerGL()); auto binary = ::Effekseer::CreateUniqueReference(compiler->Compile(&materialFile)); return LoadAcutually(materialFile, binary.get()); } } void MaterialLoader::Unload(::Effekseer::MaterialRef data) { if (data == nullptr) return; auto shader = reinterpret_cast(data->UserPtr); auto modelShader = reinterpret_cast(data->ModelUserPtr); auto refractionShader = reinterpret_cast(data->RefractionUserPtr); auto refractionModelShader = reinterpret_cast(data->RefractionModelUserPtr); ES_SAFE_DELETE(shader); ES_SAFE_DELETE(modelShader); ES_SAFE_DELETE(refractionShader); ES_SAFE_DELETE(refractionModelShader); data->UserPtr = nullptr; data->ModelUserPtr = nullptr; data->RefractionUserPtr = nullptr; data->RefractionModelUserPtr = nullptr; } } // namespace EffekseerRendererGL