#include "EffekseerRendererLLGI.MaterialLoader.h" #include "EffekseerRendererLLGI.ModelRenderer.h" #include "EffekseerRendererLLGI.Shader.h" #include #include #include "Effekseer/Material/Effekseer.CompiledMaterial.h" #undef min namespace EffekseerRendererLLGI { static const int LLGI_InstanceCount = 40; void MaterialLoader::Deserialize(uint8_t* data, uint32_t datasize, LLGI::CompilerResult& result) { if (datasize < 4) return; uint32_t count = 0; uint32_t offset = 0; memcpy(&count, data + offset, sizeof(int32_t)); offset += sizeof(uint32_t); result.Binary.resize(count); for (uint32_t i = 0; i < count; i++) { uint32_t size = 0; memcpy(&size, data + offset, sizeof(int32_t)); offset += sizeof(uint32_t); result.Binary[i].resize(size); memcpy(result.Binary[i].data(), data + offset, size); offset += size; } } MaterialLoader::MaterialLoader(Backend::GraphicsDevice* graphicsDevice, ::Effekseer::FileInterfaceRef fileInterface, ::Effekseer::CompiledMaterialPlatformType platformType, ::Effekseer::MaterialCompiler* materialCompiler) : fileInterface_(fileInterface) , platformType_(platformType) , materialCompiler_(materialCompiler) { if (fileInterface == nullptr) { fileInterface_ = Effekseer::MakeRefPtr(); } graphicsDevice_ = graphicsDevice; ES_SAFE_ADDREF(graphicsDevice_); ES_SAFE_ADDREF(materialCompiler_); } MaterialLoader ::~MaterialLoader() { ES_SAFE_RELEASE(materialCompiler_); ES_SAFE_RELEASE(graphicsDevice_); } ::Effekseer::MaterialRef MaterialLoader::Load(const char16_t* path) { // code file { auto binaryPath = std::u16string(path) + u"d"; auto reader = fileInterface_->OpenRead(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 if (materialCompiler_ != nullptr) { 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::LoadAcutually(::Effekseer::MaterialFile& materialFile, ::Effekseer::CompiledMaterialBinary* binary) { if (binary == nullptr) { return nullptr; } 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++) { Shader* shader = nullptr; auto parameterGenerator = EffekseerRenderer::MaterialShaderParameterGenerator(materialFile, false, st, LLGI_InstanceCount); if (material->IsSimpleVertex) { LLGI::CompilerResult resultVS; LLGI::CompilerResult resultPS; Deserialize((uint8_t*)binary->GetVertexShaderData(shaderTypes[st]), binary->GetVertexShaderSize(shaderTypes[st]), resultVS); Deserialize((uint8_t*)binary->GetPixelShaderData(shaderTypes[st]), binary->GetPixelShaderSize(shaderTypes[st]), resultPS); std::array dataVS; std::array dataPS; for (size_t i = 0; i < resultVS.Binary.size(); i++) { dataVS[i].Data = resultVS.Binary[i].data(); dataVS[i].Size = static_cast(resultVS.Binary[i].size()); } for (size_t i = 0; i < resultPS.Binary.size(); i++) { dataPS[i].Data = resultPS.Binary[i].data(); dataPS[i].Size = static_cast(resultPS.Binary[i].size()); } // Pos(3) Color(1) UV(2) std::vector layouts; layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32B32_FLOAT, "POSITION", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R8G8B8A8_UNORM, "NORMAL", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32_FLOAT, "TEXCOORD", 0}); shader = Shader::Create(graphicsDevice_, dataVS.data(), (int32_t)resultVS.Binary.size(), dataPS.data(), (int32_t)resultPS.Binary.size(), "MaterialStandardRenderer", layouts, true); } else { LLGI::CompilerResult resultVS; LLGI::CompilerResult resultPS; Deserialize((uint8_t*)binary->GetVertexShaderData(shaderTypes[st]), binary->GetVertexShaderSize(shaderTypes[st]), resultVS); Deserialize((uint8_t*)binary->GetPixelShaderData(shaderTypes[st]), binary->GetPixelShaderSize(shaderTypes[st]), resultPS); std::array dataVS; std::array dataPS; for (size_t i = 0; i < resultVS.Binary.size(); i++) { dataVS[i].Data = resultVS.Binary[i].data(); dataVS[i].Size = static_cast(resultVS.Binary[i].size()); } for (size_t i = 0; i < resultPS.Binary.size(); i++) { dataPS[i].Data = resultPS.Binary[i].data(); dataPS[i].Size = static_cast(resultPS.Binary[i].size()); } // Pos(3) Color(1) Normal(1) Tangent(1) UV(2) UV(2) std::vector layouts; layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32B32_FLOAT, "POSITION", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R8G8B8A8_UNORM, "NORMAL", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R8G8B8A8_UNORM, "NORMAL", 1}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R8G8B8A8_UNORM, "NORMAL", 2}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32_FLOAT, "TEXCOORD", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32_FLOAT, "TEXCOORD", 1}); int32_t offset = 40; int count = 6; int index = 2; auto getFormat = [](int32_t i) -> LLGI::VertexLayoutFormat { if (i == 2) return LLGI::VertexLayoutFormat::R32G32_FLOAT; if (i == 3) return LLGI::VertexLayoutFormat::R32G32B32_FLOAT; if (i == 4) return LLGI::VertexLayoutFormat::R32G32B32A32_FLOAT; assert(false); return LLGI::VertexLayoutFormat::R32_FLOAT; }; if (materialFile.GetCustomData1Count() > 0) { layouts.push_back(VertexLayout{getFormat(materialFile.GetCustomData1Count()), "TEXCOORD", index}); index++; count++; offset += sizeof(float) * materialFile.GetCustomData1Count(); } if (materialFile.GetCustomData2Count() > 0) { layouts.push_back(VertexLayout{getFormat(materialFile.GetCustomData2Count()), "TEXCOORD", index}); index++; count++; offset += sizeof(float) * materialFile.GetCustomData2Count(); } shader = Shader::Create(graphicsDevice_, dataVS.data(), (int32_t)resultVS.Binary.size(), dataPS.data(), (int32_t)resultPS.Binary.size(), "MaterialStandardRenderer", layouts, true); } if (shader == nullptr) return nullptr; auto vertexUniformSize = parameterGenerator.VertexShaderUniformBufferSize; auto pixelUniformSize = parameterGenerator.PixelShaderUniformBufferSize; shader->SetVertexConstantBufferSize(vertexUniformSize); shader->SetPixelConstantBufferSize(pixelUniformSize); material->TextureCount = materialFile.GetTextureCount(); material->UniformCount = materialFile.GetUniformCount(); if (st == 0) { material->UserPtr = shader; } else { material->RefractionUserPtr = shader; } } for (int32_t st = 0; st < shaderTypeCount; st++) { LLGI::CompilerResult resultVS; LLGI::CompilerResult resultPS; Deserialize( (uint8_t*)binary->GetVertexShaderData(shaderTypesModel[st]), binary->GetVertexShaderSize(shaderTypesModel[st]), resultVS); Deserialize((uint8_t*)binary->GetPixelShaderData(shaderTypesModel[st]), binary->GetPixelShaderSize(shaderTypesModel[st]), resultPS); std::array dataVS; std::array dataPS; for (size_t i = 0; i < resultVS.Binary.size(); i++) { dataVS[i].Data = resultVS.Binary[i].data(); dataVS[i].Size = static_cast(resultVS.Binary[i].size()); } for (size_t i = 0; i < resultPS.Binary.size(); i++) { dataPS[i].Data = resultPS.Binary[i].data(); dataPS[i].Size = static_cast(resultPS.Binary[i].size()); } auto parameterGenerator = EffekseerRenderer::MaterialShaderParameterGenerator(materialFile, true, st, LLGI_InstanceCount); std::vector layouts; layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32B32_FLOAT, "POSITION", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32B32_FLOAT, "NORMAL", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32B32_FLOAT, "NORMAL", 1}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32B32_FLOAT, "NORMAL", 2}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R32G32_FLOAT, "TEXCOORD", 0}); layouts.push_back(VertexLayout{LLGI::VertexLayoutFormat::R8G8B8A8_UNORM, "NORMAL", 3}); // compile std::string log; auto shader = Shader::Create(graphicsDevice_, dataVS.data(), (int32_t)resultVS.Binary.size(), dataPS.data(), (int32_t)resultPS.Binary.size(), "MaterialStandardModelRenderer", layouts, true); if (shader == nullptr) return nullptr; auto vertexUniformSize = parameterGenerator.VertexShaderUniformBufferSize; auto pixelUniformSize = parameterGenerator.PixelShaderUniformBufferSize; shader->SetVertexConstantBufferSize(vertexUniformSize); shader->SetPixelConstantBufferSize(pixelUniformSize); 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; } ::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(platformType_)) { 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(platformType_); return LoadAcutually(materialFile, binary); } else { if (materialCompiler_ == nullptr) { return nullptr; } Effekseer::MaterialFile materialFile; if (!materialFile.Load((const uint8_t*)data, size)) { std::cout << "Error : Invalid material is loaded." << std::endl; return nullptr; } auto binary = ::Effekseer::CreateUniqueReference(materialCompiler_->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 EffekseerRendererLLGI