#include "utils.h" #include #define MAX_SHADER_SIZE 8 // TODO: Compute? // Would probably require a different path altogther // due to how those shaders are compiled tho typedef enum{ VERTEX = 0, FRAGMENT = 1 }ShaderStep; // This returns *allocated* memory, // should be manually free()'ed or some kind of arena used. static char* shader_block_preprocess(const char* shader_source, ShaderStep shader_step) { static const char* start_markers[2] = {"@vertex", "@fragment"}; static const char* end_markers[2] = {"@vs_end", "@fs_end"}; static const char* version_statement = "#version 330\n"; char* parsed_total = NULL; i32 start_idx = TextFindIndex(shader_source, start_markers[shader_step]); if (start_idx == BLANK_DEFAULT){ TRACELOG(LOG_ERROR, "%s could not be found.", start_markers[shader_step]); goto parse_err; } start_idx += TextLength(start_markers[shader_step]); i32 end_idx = TextFindIndex(shader_source, end_markers[shader_step]); if (end_idx == BLANK_DEFAULT){ TRACELOG(LOG_ERROR, "%s could not be found. Don't forget to end blocks!", end_markers[shader_step]); goto parse_err; } i32 block_sz = end_idx - start_idx; const char* block = TextSubtext(shader_source, start_idx, block_sz); i32 total_block_size = block_sz + TextLength(version_statement); parsed_total = (char*)RL_MALLOC(total_block_size + NULL_TERM_SZ); i32 cursor = 0; TextAppend(parsed_total, version_statement, &cursor); TextAppend(parsed_total, block, &cursor); parse_err: return parsed_total; } static Shader load_joined_shader(const char* path) { Shader something = (Shader){0}; char* shr = LoadFileText(path); char* vs = shader_block_preprocess(shr, VERTEX); if(vs == NULL){ TRACELOG(LOG_ERROR, "Unsuccessful vertex shader parse for %s", path); goto vertex_err; } char* fs = shader_block_preprocess(shr, FRAGMENT); if(fs == NULL){ TRACELOG(LOG_ERROR, "Unsuccessful fragment shader parse for %s", path); goto frag_err; } something = LoadShaderFromMemory(vs, fs); RL_FREE(fs); frag_err: RL_FREE(vs); vertex_err: UnloadFileText(shr); return something; } static Shader shader_slots[MAX_SHADER_SIZE] = {0}; static i32 shader_modtimes[MAX_SHADER_SIZE] = {0}; static const char* shader_paths[MAX_SHADER_SIZE] = {0}; void init_shader_sys(void) { for(i32 i = 0; i < MAX_SHADER_SIZE; ++i){ shader_slots[i] = (Shader){0}; shader_modtimes[i] = BLANK_DEFAULT; shader_paths[i] = NULL; } } i32 load_new_shader(const char* path) { i32 current_idx = BLANK_DEFAULT; for(i32 i = 0; i < MAX_SHADER_SIZE; ++i){ if(shader_slots[i].id <= 0){ current_idx = i; shader_slots[current_idx] = load_joined_shader(path); shader_modtimes[current_idx] = GetFileModTime(path); shader_paths[current_idx] = path; break; } } //TODO: Handle slots a bit better. if(current_idx == BLANK_DEFAULT) TRACELOG(LOG_WARNING, "Warning: No more empty shader slots.\n"); return current_idx; } void set_active_shader(i32 idx) { if(idx < 0 || idx >= MAX_SHADER_SIZE) TRACELOG(LOG_WARNING,"Bounds check: Attempted to set shader at non-existent index %i.\n", idx); else BeginShaderMode(shader_slots[idx]); } void update_shaders(void) { for(i32 i = 0; i < MAX_SHADER_SIZE; ++i){ if(shader_slots[i].id > 0){ i32 current_mod = GetFileModTime(shader_paths[i]); if(current_mod != shader_modtimes[i]){ shader_modtimes[i] = current_mod; Shader attempt = load_joined_shader(shader_paths[i]); if(IsShaderReady(attempt)){ UnloadShader(shader_slots[i]); shader_slots[i] = attempt; } } } } } void reset_active_shader(void) { EndShaderMode(); } void unload_shader(i32 idx) { if(idx < 0 || idx >= MAX_SHADER_SIZE){ TRACELOG(LOG_WARNING,"Bounds check: Attempted to unload shader at non-existent index %i.\n", idx); return; } UnloadShader(shader_slots[idx]); shader_slots[idx] = (Shader){0}; shader_modtimes[idx] = BLANK_DEFAULT; shader_paths[idx] = NULL; } void unload_active_shaders(void) { for(i32 i = 0; i < MAX_SHADER_SIZE; ++i){ if(shader_slots[i].id > 0) unload_shader(i); } }