6#define WIN32_LEAN_AND_MEAN
9#include "hellfire/graphics/managers/ShaderManager.h"
15#include "hellfire/graphics/material/Material.h"
16#include "../backends/opengl/glsl.h"
17#include "hellfire/graphics/texture/Texture.h"
26 std::string processed = source;
27 std::regex include_regex(
"#include\\s+\"([^\"]+)\"");
30 while (std::regex_search(processed, match, include_regex)) {
31 std::string include_relative_path = match[1].str();
32 std::string include_full_path = base_path + include_relative_path;
38 processed = processed.replace(match.position(), match.length(), include_content);
49 std::ifstream file(path);
50 if (!file.is_open()) {
51 throw std::runtime_error(
"Failed to open include file: " + path);
54 std::string content((std::istreambuf_iterator(file)),
55 std::istreambuf_iterator<
char>());
66 size_t last_slash = file_path.find_last_of(
"/\\");
67 if (last_slash != std::string::npos) {
68 return file_path.substr(0, last_slash + 1);
74 const std::unordered_set<std::string> &defines) {
75 std::istringstream stream(source);
76 std::ostringstream result;
79 stack<
bool> condition_stack;
80 condition_stack.push(
true);
82 while (std::getline(stream, line)) {
83 std::string trimmed =
trim(line
);
85 if (trimmed.substr(0, 7) ==
"#ifdef ") {
86 std::string define_name = trimmed.substr(7);
87 bool condition = defines.count(
trim(define_name
)) > 0;
88 condition_stack.push(condition_stack.top() && condition);
92 if (trimmed.substr(0, 8) ==
"#ifndef ") {
93 std::string define_name = trimmed.substr(8);
94 bool condition = defines.count(
trim(define_name
)) == 0;
95 condition_stack.push(condition_stack.top() && condition);
99 if (trimmed ==
"#endif") {
100 if (condition_stack.size() > 1) {
101 condition_stack.pop();
107 if (condition_stack.top()) {
108 result << line <<
"\n";
116 size_t start = str.find_first_not_of(
" \t");
117 if (start == std::string::npos)
return "";
118 size_t end = str.find_last_not_of(
" \t");
119 return str.substr(start, end - start + 1);
124 std::string base_path;
126 char exePath[MAX_PATH];
127 GetModuleFileNameA(
nullptr, exePath, MAX_PATH);
128 base_path = std::string(exePath);
129 base_path = base_path.substr(0, base_path.find_last_of(
"\\/")) +
"/";
132 std::string abs_path = path;
133 std::cout <<
"Loading shader from: " << abs_path << std::endl;
137 throw std::runtime_error(
"Failed to read shader file: " + abs_path);
140 std::string content(file_content);
141 delete[] file_content;
148 for (
const auto &define: defines) {
155 std::string cleaned = content;
158 std::string bom =
"\xEF\xBB\xBF";
162 int removedCount = 0;
163 while ((pos = cleaned.find(bom, pos)) != std::string::npos) {
164 cleaned.erase(pos, bom.length());
168 if (removedCount > 0) {
169 std::cout <<
"Removed " << removedCount <<
" BOM sequences from: " << filepath << std::endl;
205 }
catch (
const std::exception &e) {
206 std::cerr <<
"Error loading shader: " << e.what() << std::endl;
219 variant
.defines = shader_info->defines;
242 if (material.get_property<
Texture *>(
"diffuseTexture",
nullptr)) {
243 defines.insert(
"HAS_DIFFUSE_TEXTURE");
245 if (material.get_property<
Texture *>(
"normalTexture",
nullptr)) {
246 defines.insert(
"HAS_NORMAL_TEXTURE");
248 if (material.get_property<
Texture *>(
"specularTexture",
nullptr)) {
249 defines.insert(
"HAS_SPECULAR_TEXTURE");
251 if (material.get_property<
Texture *>(
"emissionTexture",
nullptr)) {
252 defines.insert(
"HAS_EMISSION_TEXTURE");
254 if (material.get_property<
Texture *>(
"roughnessTexture",
nullptr)) {
255 defines.insert(
"HAS_ROUGHNESS_TEXTURE");
257 if (material.get_property<
Texture *>(
"metallicTexture",
nullptr)) {
258 defines.insert(
"HAS_METALLIC_TEXTURE");
269 if (program_id != 0) {
271 std::string cache_key = vertex_path +
"|" + fragment_path;
276 }
catch (
const std::exception &e) {
277 std::cerr <<
"Error loading shaders: " << e.what() << std::endl;
286 for (
const auto &[key, shader_id]: compiled_shaders_) {
287 glDeleteProgram(shader_id);
293 std::vector<uint32_t> shader_ids;
296 shader_ids.push_back(id);
302 const char *vertex_src = vertex_source.c_str();
303 const char *fragment_src = fragment_source.c_str();
305 GLuint vertex_shader = glsl::makeVertexShader(vertex_src);
306 if (vertex_shader == 0) {
307 std::cerr <<
"Failed to compile vertex shader" << std::endl;
311 GLuint fragment_shader = glsl::makeFragmentShader(fragment_src);
312 if (fragment_shader == 0) {
313 std::cerr <<
"Failed to compile fragment shader" << std::endl;
314 glDeleteShader(vertex_shader);
318 uint32_t program_id = glsl::makeShaderProgram(vertex_shader, fragment_shader);
321 glDeleteShader(vertex_shader);
322 glDeleteShader(fragment_shader);
324 if (program_id == 0) {
325 std::cerr <<
"Failed to link shader program" << std::endl;
static char * readFile(const char *filename)
void set_compiled_shader_id(uint32_t shader_id)
bool has_custom_shader() const
const ShaderInfo * get_shader_info() const
std::vector< uint32_t > get_all_shader_ids() const
std::string process_defines(const std::string &source, const std::unordered_set< std::string > &defines)
std::unordered_map< std::string, std::string > include_cache_
std::unordered_map< std::string, uint32_t > compiled_shaders_
uint32_t load_shader_from_files(const std::string &vertex_path, const std::string &fragment_path)
std::string trim(const std::string &str)
void add_automatic_defines(const Material &material, std::unordered_set< std::string > &defines)
uint32_t load_shader(const ShaderVariant &variant)
std::string get_directory_from_path(const std::string &file_path)
std::string process_includes(const std::string &source, const std::string &base_path="shaders/")
std::string clean_shader_content(const std::string &content, const std::string &filepath)
uint32_t compile_shader_program(const std::string &vertex_source, const std::string &fragment_source)
std::string load_shader_file(const std::string &path)
uint32_t get_shader_for_material(Material &material)
uint32_t get_shader(const std::string &key) const
std::string load_include_file(const std::string &path, const std::string &base_path)
std::string fragment_path
std::unordered_set< std::string > defines
std::string get_key() const
std::string fragment_path