/* Crafter.Build Copyright (C) 2025 Catcrafts This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #include #include #include #include #include #include #include "DirStackFileIncluder.h" #include #include module Crafter.Build; using namespace Crafter::Build; Shader::Shader(fs::path path, std::string entrypoint, EShLanguage type): path(path), entrypoint(entrypoint), type(type) { } void Shader::Compile(fs::path outputDir) { glslang::InitializeProcess(); EShMessages messages = static_cast(EShMsgDefault | EShMsgVulkanRules | EShMsgSpvRules); std::ifstream fileStream(path, std::ios::in | std::ios::binary); if (!fileStream) { throw std::ios_base::failure("Failed to open file: " + path.string()); } std::ostringstream contents; contents << fileStream.rdbuf(); std::string src = contents.str(); const char *file_name_list[1] = {""}; const char *shader_source = reinterpret_cast(src.data()); glslang::TShader shader(type); shader.setStringsWithLengthsAndNames(&shader_source, nullptr, file_name_list, 1); shader.setEntryPoint(entrypoint.c_str()); shader.setSourceEntryPoint(entrypoint.c_str()); shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4); DirStackFileIncluder includeDir; includeDir.pushExternalLocalDirectory(path.parent_path().generic_string()); std::string info_log; if (!shader.parse(GetDefaultResources(), 100, false, messages, includeDir)) { info_log = std::string(shader.getInfoLog()) + std::string(shader.getInfoDebugLog()); } // Add shader to new program object. glslang::TProgram program; program.addShader(&shader); // Link program. if (!program.link(messages)) { info_log = std::string(program.getInfoLog()) + std::string(program.getInfoDebugLog()); } // Save any info log that was generated. if (shader.getInfoLog()) { info_log += std::string(shader.getInfoLog()) + std::string(shader.getInfoDebugLog()); } if (program.getInfoLog()) { info_log += std::string(program.getInfoLog()) + std::string(program.getInfoDebugLog()); } glslang::TIntermediate* intermediate = program.getIntermediate(type); if (!intermediate) { info_log += "Failed to get shared intermediate code."; } spv::SpvBuildLogger logger; std::vector spirv; std::cout << info_log; glslang::GlslangToSpv(*intermediate, spirv, &logger); std::cout << logger.getAllMessages(); glslang::FinalizeProcess(); path.replace_extension("spirv"); std::ofstream file(outputDir/path, std::ios::binary); file.write(reinterpret_cast(spirv.data()), spirv.size() * sizeof(std::uint32_t)); }