// Defines #define MAX_SHADER_SIZE 8 static const s8 version_st = String("#version 330\n"); static const s8 type_markers[2] = {String("#define VERTEX_SHADER 1\n"), String("#define FRAG_SHADER 1\n")}; static const s8 line_st = String("#line 1\n"); // Internal Functions // // 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 s8 shader_block_preprocess(const s8 source, const ShaderStep shader_step) { size total = version_st.len + type_markers[shader_step].len + line_st.len + source.len; s8 parsed_total = create_s8(total + NULL_TERM_SZ); size cursor = 0; add_s8(parsed_total, version_st, &cursor); add_s8(parsed_total, type_markers[shader_step], &cursor); add_s8(parsed_total, line_st, &cursor); add_s8(parsed_total, source, &cursor); parsed_total.buf[cursor] = NULL_TERM; return parsed_total; } static Shader load_joined_shader(const s8 path) { Shader something = (Shader){0}; s8 file = load_file_text(path); if(file.len == 0) goto oops; s8 vs = shader_block_preprocess(file, VERTEX); s8 fs = shader_block_preprocess(file, FRAGMENT); something = LoadShaderFromMemory((const char*)vs.buf, (const char*)fs.buf); free_s8(&fs); free_s8(&vs); free_s8(&file); oops: return something; } // Exposed Functions // static Shader shader_slots[MAX_SHADER_SIZE] = {0}; static i32 shader_modtimes[MAX_SHADER_SIZE] = {0}; static s8 shader_paths[MAX_SHADER_SIZE] = {0}; void init_shader_sys(void) { for(i32 i = 0; i < MAX_SHADER_SIZE; ++i){ shader_modtimes[i] = BLANK_DEFAULT; } } i32 load_new_shader(const char* path) { s8 path_str = cstr_to_s8(path); i32 current_idx = BLANK_DEFAULT; for(i32 i = 0; i < MAX_SHADER_SIZE; ++i){ if(equal_s8(path_str, shader_paths[current_idx])){ free_s8(&path_str); return i; } if(shader_slots[i].id <= 0){ current_idx = i; shader_slots[current_idx] = load_joined_shader(path_str); shader_modtimes[current_idx] = GetFileModTime((const char*)path_str.buf); shader_paths[current_idx] = path_str; break; } } //TODO: Handle slots a bit better. assert(current_idx != BLANK_DEFAULT); return current_idx; } void set_active_shader(i32 idx) { assert(idx >= 0 && idx < MAX_SHADER_SIZE); 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((const char*)shader_paths[i].buf); if(current_mod != shader_modtimes[i]){ shader_modtimes[i] = current_mod; UnloadShader(shader_slots[i]); shader_slots[i] = load_joined_shader(shader_paths[i]); } } } } void reset_active_shader(void) { EndShaderMode(); } void unload_shader(i32 idx) { assert(idx >= 0 && idx < MAX_SHADER_SIZE); UnloadShader(shader_slots[idx]); shader_modtimes[idx] = BLANK_DEFAULT; free_s8(&shader_paths[idx]); } void unload_active_shaders(void) { for(i32 i = 0; i < MAX_SHADER_SIZE; ++i){ if(shader_slots[i].id > 0) unload_shader(i); } }