123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- package vendor_gl
- // Helper for loading shaders into a program
- import "core:os"
- import "core:fmt"
- import "core:strings"
- import "base:runtime"
- _ :: fmt
- _ :: runtime
- Shader_Type :: enum i32 {
- NONE = 0x0000,
- FRAGMENT_SHADER = 0x8B30,
- VERTEX_SHADER = 0x8B31,
- GEOMETRY_SHADER = 0x8DD9,
- COMPUTE_SHADER = 0x91B9,
- TESS_EVALUATION_SHADER = 0x8E87,
- TESS_CONTROL_SHADER = 0x8E88,
- SHADER_LINK = -1, // @Note: Not an OpenGL constant, but used for error checking.
- }
- @(private, thread_local)
- last_compile_error_message: []byte
- @(private, thread_local)
- last_link_error_message: []byte
- @(private, thread_local)
- last_compile_error_type: Shader_Type
- @(private, thread_local)
- last_link_error_type: Shader_Type
- get_last_error_messages :: proc() -> (compile_message: string, compile_type: Shader_Type, link_message: string, link_type: Shader_Type) {
- compile_message = string(last_compile_error_message[:max(0, len(last_compile_error_message)-1)])
- compile_type = last_compile_error_type
- link_message = string(last_link_error_message[:max(0, len(last_link_error_message)-1)])
- link_type = last_link_error_type
- return
- }
- get_last_error_message :: proc() -> (compile_message: string, compile_type: Shader_Type) {
- compile_message = string(last_compile_error_message[:max(0, len(last_compile_error_message)-1)])
- compile_type = last_compile_error_type
- return
- }
- // Shader checking and linking checking are identical
- // except for calling differently named GL functions
- // it's a bit ugly looking, but meh
- when GL_DEBUG {
- @private
- check_error :: proc(
- id: u32, type: Shader_Type, status: u32,
- iv_func: proc "c" (u32, u32, [^]i32, runtime.Source_Code_Location),
- log_func: proc "c" (u32, i32, ^i32, [^]u8, runtime.Source_Code_Location),
- loc := #caller_location,
- ) -> (success: bool) {
- result, info_log_length: i32
- iv_func(id, status, &result, loc)
- iv_func(id, INFO_LOG_LENGTH, &info_log_length, loc)
- if result == 0 {
- if log_func == GetShaderInfoLog {
- delete(last_compile_error_message)
- last_compile_error_message = make([]byte, info_log_length)
- last_compile_error_type = type
- log_func(id, i32(info_log_length), nil, raw_data(last_compile_error_message), loc)
- //fmt.printf_err("Error in %v:\n%s", type, string(last_compile_error_message[0:len(last_compile_error_message)-1]));
- } else {
- delete(last_link_error_message)
- last_link_error_message = make([]byte, info_log_length)
- last_compile_error_type = type
- log_func(id, i32(info_log_length), nil, raw_data(last_link_error_message), loc)
- //fmt.printf_err("Error in %v:\n%s", type, string(last_link_error_message[0:len(last_link_error_message)-1]));
- }
- return false
- }
- return true
- }
- } else {
- @private
- check_error :: proc(
- id: u32, type: Shader_Type, status: u32,
- iv_func: proc "c" (u32, u32, [^]i32),
- log_func: proc "c" (u32, i32, ^i32, [^]u8),
- ) -> (success: bool) {
- result, info_log_length: i32
- iv_func(id, status, &result)
- iv_func(id, INFO_LOG_LENGTH, &info_log_length)
- if result == 0 {
- if log_func == GetShaderInfoLog {
- delete(last_compile_error_message)
- last_compile_error_message = make([]u8, info_log_length)
- last_link_error_type = type
- log_func(id, i32(info_log_length), nil, raw_data(last_compile_error_message))
- fmt.eprintf("Error in %v:\n%s", type, string(last_compile_error_message[0:len(last_compile_error_message)-1]))
- } else {
- delete(last_link_error_message)
- last_link_error_message = make([]u8, info_log_length)
- last_link_error_type = type
- log_func(id, i32(info_log_length), nil, raw_data(last_link_error_message))
- fmt.eprintf("Error in %v:\n%s", type, string(last_link_error_message[0:len(last_link_error_message)-1]))
- }
- return false
- }
- return true
- }
- }
- // Compiling shaders are identical for any shader (vertex, geometry, fragment, tesselation, (maybe compute too))
- compile_shader_from_source :: proc(shader_data: string, shader_type: Shader_Type) -> (shader_id: u32, ok: bool) {
- shader_id = CreateShader(cast(u32)shader_type)
- length := i32(len(shader_data))
- shader_data_copy := cstring(raw_data(shader_data))
- ShaderSource(shader_id, 1, &shader_data_copy, &length)
- CompileShader(shader_id)
- check_error(shader_id, shader_type, COMPILE_STATUS, GetShaderiv, GetShaderInfoLog) or_return
- ok = true
- return
- }
- // only used once, but I'd just make a subprocedure(?) for consistency
- create_and_link_program :: proc(shader_ids: []u32, binary_retrievable := false) -> (program_id: u32, ok: bool) {
- program_id = CreateProgram()
- for id in shader_ids {
- AttachShader(program_id, id)
- }
- if binary_retrievable {
- ProgramParameteri(program_id, PROGRAM_BINARY_RETRIEVABLE_HINT, 1/*true*/)
- }
- LinkProgram(program_id)
- check_error(program_id, Shader_Type.SHADER_LINK, LINK_STATUS, GetProgramiv, GetProgramInfoLog) or_return
- ok = true
- return
- }
- load_compute_file :: proc(filename: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
- cs_data := os.read_entire_file(filename) or_return
- defer delete(cs_data)
- // Create the shaders
- compute_shader_id := compile_shader_from_source(string(cs_data), Shader_Type(COMPUTE_SHADER)) or_return
- return create_and_link_program([]u32{compute_shader_id}, binary_retrievable)
- }
- load_compute_source :: proc(cs_data: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
- // Create the shaders
- compute_shader_id := compile_shader_from_source(cs_data, Shader_Type(COMPUTE_SHADER)) or_return
- return create_and_link_program([]u32{compute_shader_id}, binary_retrievable)
- }
- load_shaders_file :: proc(vs_filename, fs_filename: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
- vs_data := os.read_entire_file(vs_filename) or_return
- defer delete(vs_data)
-
- fs_data := os.read_entire_file(fs_filename) or_return
- defer delete(fs_data)
- return load_shaders_source(string(vs_data), string(fs_data), binary_retrievable)
- }
- load_shaders_source :: proc(vs_source, fs_source: string, binary_retrievable := false) -> (program_id: u32, ok: bool) {
- // actual function from here
- vertex_shader_id := compile_shader_from_source(vs_source, Shader_Type.VERTEX_SHADER) or_return
- defer DeleteShader(vertex_shader_id)
- fragment_shader_id := compile_shader_from_source(fs_source, Shader_Type.FRAGMENT_SHADER) or_return
- defer DeleteShader(fragment_shader_id)
- return create_and_link_program([]u32{vertex_shader_id, fragment_shader_id}, binary_retrievable)
- }
- load_shaders :: proc{load_shaders_file}
- when ODIN_OS == .Windows {
- update_shader_if_changed :: proc(
- vertex_name, fragment_name: string,
- program: u32,
- last_vertex_time, last_fragment_time: os.File_Time,
- ) -> (
- old_program: u32,
- current_vertex_time, current_fragment_time: os.File_Time,
- updated: bool,
- ) {
- current_vertex_time, _ = os.last_write_time_by_name(vertex_name)
- current_fragment_time, _ = os.last_write_time_by_name(fragment_name)
- old_program = program
- if current_vertex_time != last_vertex_time || current_fragment_time != last_fragment_time {
- new_program, success := load_shaders(vertex_name, fragment_name)
- if success {
- DeleteProgram(old_program)
- old_program = new_program
- fmt.println("Updated shaders")
- updated = true
- } else {
- fmt.println("Failed to update shaders")
- }
- }
- return old_program, current_vertex_time, current_fragment_time, updated
- }
- update_shader_if_changed_compute :: proc(
- compute_name: string,
- program: u32,
- last_compute_time: os.File_Time,
- ) -> (
- old_program: u32,
- current_compute_time: os.File_Time,
- updated: bool,
- ) {
- current_compute_time, _ = os.last_write_time_by_name(compute_name)
- old_program = program
- if current_compute_time != last_compute_time {
- new_program, success := load_compute_file(compute_name)
- if success {
- DeleteProgram(old_program)
- old_program = new_program
- fmt.println("Updated shaders")
- updated = true
- } else {
- fmt.println("Failed to update shaders")
- }
- }
- return old_program, current_compute_time, updated
- }
- }
- Uniform_Type :: enum i32 {
- FLOAT = 0x1406,
- FLOAT_VEC2 = 0x8B50,
- FLOAT_VEC3 = 0x8B51,
- FLOAT_VEC4 = 0x8B52,
- DOUBLE = 0x140A,
- DOUBLE_VEC2 = 0x8FFC,
- DOUBLE_VEC3 = 0x8FFD,
- DOUBLE_VEC4 = 0x8FFE,
- INT = 0x1404,
- INT_VEC2 = 0x8B53,
- INT_VEC3 = 0x8B54,
- INT_VEC4 = 0x8B55,
- UNSIGNED_INT = 0x1405,
- UNSIGNED_INT_VEC2 = 0x8DC6,
- UNSIGNED_INT_VEC3 = 0x8DC7,
- UNSIGNED_INT_VEC4 = 0x8DC8,
- BOOL = 0x8B56,
- BOOL_VEC2 = 0x8B57,
- BOOL_VEC3 = 0x8B58,
- BOOL_VEC4 = 0x8B59,
- FLOAT_MAT2 = 0x8B5A,
- FLOAT_MAT3 = 0x8B5B,
- FLOAT_MAT4 = 0x8B5C,
- FLOAT_MAT2x3 = 0x8B65,
- FLOAT_MAT2x4 = 0x8B66,
- FLOAT_MAT3x2 = 0x8B67,
- FLOAT_MAT3x4 = 0x8B68,
- FLOAT_MAT4x2 = 0x8B69,
- FLOAT_MAT4x3 = 0x8B6A,
- DOUBLE_MAT2 = 0x8F46,
- DOUBLE_MAT3 = 0x8F47,
- DOUBLE_MAT4 = 0x8F48,
- DOUBLE_MAT2x3 = 0x8F49,
- DOUBLE_MAT2x4 = 0x8F4A,
- DOUBLE_MAT3x2 = 0x8F4B,
- DOUBLE_MAT3x4 = 0x8F4C,
- DOUBLE_MAT4x2 = 0x8F4D,
- DOUBLE_MAT4x3 = 0x8F4E,
- SAMPLER_1D = 0x8B5D,
- SAMPLER_2D = 0x8B5E,
- SAMPLER_3D = 0x8B5F,
- SAMPLER_CUBE = 0x8B60,
- SAMPLER_1D_SHADOW = 0x8B61,
- SAMPLER_2D_SHADOW = 0x8B62,
- SAMPLER_1D_ARRAY = 0x8DC0,
- SAMPLER_2D_ARRAY = 0x8DC1,
- SAMPLER_1D_ARRAY_SHADOW = 0x8DC3,
- SAMPLER_2D_ARRAY_SHADOW = 0x8DC4,
- SAMPLER_2D_MULTISAMPLE = 0x9108,
- SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910B,
- SAMPLER_CUBE_SHADOW = 0x8DC5,
- SAMPLER_BUFFER = 0x8DC2,
- SAMPLER_2D_RECT = 0x8B63,
- SAMPLER_2D_RECT_SHADOW = 0x8B64,
- INT_SAMPLER_1D = 0x8DC9,
- INT_SAMPLER_2D = 0x8DCA,
- INT_SAMPLER_3D = 0x8DCB,
- INT_SAMPLER_CUBE = 0x8DCC,
- INT_SAMPLER_1D_ARRAY = 0x8DCE,
- INT_SAMPLER_2D_ARRAY = 0x8DCF,
- INT_SAMPLER_2D_MULTISAMPLE = 0x9109,
- INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910C,
- INT_SAMPLER_BUFFER = 0x8DD0,
- INT_SAMPLER_2D_RECT = 0x8DCD,
- UNSIGNED_INT_SAMPLER_1D = 0x8DD1,
- UNSIGNED_INT_SAMPLER_2D = 0x8DD2,
- UNSIGNED_INT_SAMPLER_3D = 0x8DD3,
- UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4,
- UNSIGNED_INT_SAMPLER_1D_ARRAY = 0x8DD6,
- UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7,
- UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 0x910A,
- UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910D,
- UNSIGNED_INT_SAMPLER_BUFFER = 0x8DD8,
- UNSIGNED_INT_SAMPLER_2D_RECT = 0x8DD5,
- IMAGE_1D = 0x904C,
- IMAGE_2D = 0x904D,
- IMAGE_3D = 0x904E,
- IMAGE_2D_RECT = 0x904F,
- IMAGE_CUBE = 0x9050,
- IMAGE_BUFFER = 0x9051,
- IMAGE_1D_ARRAY = 0x9052,
- IMAGE_2D_ARRAY = 0x9053,
- IMAGE_CUBE_MAP_ARRAY = 0x9054,
- IMAGE_2D_MULTISAMPLE = 0x9055,
- IMAGE_2D_MULTISAMPLE_ARRAY = 0x9056,
- INT_IMAGE_1D = 0x9057,
- INT_IMAGE_2D = 0x9058,
- INT_IMAGE_3D = 0x9059,
- INT_IMAGE_2D_RECT = 0x905A,
- INT_IMAGE_CUBE = 0x905B,
- INT_IMAGE_BUFFER = 0x905C,
- INT_IMAGE_1D_ARRAY = 0x905D,
- INT_IMAGE_2D_ARRAY = 0x905E,
- INT_IMAGE_CUBE_MAP_ARRAY = 0x905F,
- INT_IMAGE_2D_MULTISAMPLE = 0x9060,
- INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x9061,
- UNSIGNED_INT_IMAGE_1D = 0x9062,
- UNSIGNED_INT_IMAGE_2D = 0x9063,
- UNSIGNED_INT_IMAGE_3D = 0x9064,
- UNSIGNED_INT_IMAGE_2D_RECT = 0x9065,
- UNSIGNED_INT_IMAGE_CUBE = 0x9066,
- UNSIGNED_INT_IMAGE_BUFFER = 0x9067,
- UNSIGNED_INT_IMAGE_1D_ARRAY = 0x9068,
- UNSIGNED_INT_IMAGE_2D_ARRAY = 0x9069,
- UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 0x906A,
- UNSIGNED_INT_IMAGE_2D_MULTISAMPLE = 0x906B,
- UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x906C,
- UNSIGNED_INT_ATOMIC_COUNTER = 0x92DB,
- }
- Uniform_Info :: struct {
- location: i32,
- size: i32,
- kind: Uniform_Type,
- name: string, // NOTE: This will need to be freed
- }
- Uniforms :: map[string]Uniform_Info
- destroy_uniforms :: proc(u: Uniforms) {
- for _, v in u {
- delete(v.name)
- }
- delete(u)
- }
- get_uniforms_from_program :: proc(program: u32) -> (uniforms: Uniforms) {
- uniform_count: i32
- GetProgramiv(program, ACTIVE_UNIFORMS, &uniform_count)
- if uniform_count > 0 {
- reserve(&uniforms, int(uniform_count))
- }
- for i in 0..<uniform_count {
- uniform_info: Uniform_Info
- length: i32
- cname: [256]u8
- GetActiveUniform(program, u32(i), 256, &length, &uniform_info.size, cast(^u32)&uniform_info.kind, &cname[0])
- uniform_info.location = GetUniformLocation(program, cstring(&cname[0]))
- uniform_info.name = strings.clone(string(cname[:length])) // @NOTE: These need to be freed
- uniforms[uniform_info.name] = uniform_info
- }
- return uniforms
- }
|