194 lines
5.1 KiB
Odin
194 lines
5.1 KiB
Odin
package renderer
|
|
|
|
import "core:fmt"
|
|
import os "core:os/os2"
|
|
|
|
Shader :: struct {
|
|
path: string,
|
|
type: Shader_Type,
|
|
backend: Shader_Backend,
|
|
}
|
|
|
|
Shader_Program :: struct {
|
|
vertex_shader, fragment_shader: ^Shader,
|
|
backend: Shader_Program_Backend,
|
|
}
|
|
|
|
Shader_Type :: enum {
|
|
Vertex,
|
|
Fragment,
|
|
// ..
|
|
}
|
|
|
|
create_shader :: proc(renderer: ^Renderer, type: Shader_Type, path: string) -> (Shader, bool) {
|
|
fmt.printfln("Creating shader")
|
|
bytes, error := os.read_entire_file_from_path(path, context.allocator)
|
|
if error != nil {
|
|
return {}, false
|
|
}
|
|
defer delete(bytes)
|
|
|
|
s: Shader
|
|
s.type = type
|
|
s.path = path
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
shader_opengl, ok := opengl_create_shader(renderer, type, bytes)
|
|
if !ok {
|
|
return {}, false
|
|
}
|
|
s.backend = shader_opengl
|
|
fmt.printfln("Backend id: %v", s.backend)
|
|
}
|
|
else {
|
|
#assert(false)
|
|
}
|
|
|
|
return s, true
|
|
}
|
|
|
|
delete_shader :: proc(renderer: ^Renderer, shader: ^Shader) {
|
|
assert(shader != nil)
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_delete_shader(renderer, shader)
|
|
}
|
|
}
|
|
|
|
create_shader_program :: proc(renderer: ^Renderer, vertex_shader, fragment_shader: ^Shader) -> (Shader_Program, bool) {
|
|
assert(vertex_shader != nil)
|
|
assert(fragment_shader != nil)
|
|
|
|
p: Shader_Program
|
|
p.vertex_shader = vertex_shader
|
|
p.fragment_shader = fragment_shader
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
program_opengl, ok := opengl_create_shader_program(renderer, vertex_shader, fragment_shader)
|
|
if !ok {
|
|
return {}, false
|
|
}
|
|
p.backend = program_opengl
|
|
}
|
|
else {
|
|
#assert(false)
|
|
}
|
|
|
|
return p, true
|
|
}
|
|
|
|
delete_shader_program :: proc(renderer: ^Renderer, shader_program: ^Shader_Program) {
|
|
assert(shader_program != nil)
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_delete_shader_program(renderer, shader_program)
|
|
}
|
|
}
|
|
|
|
reload_shader_program :: proc(renderer: ^Renderer, p: ^Shader_Program) -> bool {
|
|
assert(renderer != nil)
|
|
assert(p != nil)
|
|
assert(p.vertex_shader != nil)
|
|
assert(p.fragment_shader != nil)
|
|
|
|
new_vs, vs_ok := create_shader(renderer, p.vertex_shader.type, p.vertex_shader.path)
|
|
if !vs_ok {
|
|
fmt.printfln("Failed to reload vertex shader")
|
|
return false
|
|
}
|
|
|
|
new_fs, fs_ok := create_shader(renderer, p.fragment_shader.type, p.fragment_shader.path)
|
|
if !fs_ok {
|
|
fmt.printfln("Failed to reload fragment shader")
|
|
delete_shader(renderer, &new_vs)
|
|
return false
|
|
}
|
|
|
|
new_program, program_ok := create_shader_program(renderer, &new_vs, &new_fs)
|
|
if !program_ok {
|
|
fmt.printfln("Failed to relink shader program")
|
|
delete_shader(renderer, &new_vs)
|
|
delete_shader(renderer, &new_fs)
|
|
return false
|
|
}
|
|
|
|
delete_shader_program(renderer, p)
|
|
delete_shader(renderer, p.vertex_shader)
|
|
delete_shader(renderer, p.fragment_shader)
|
|
|
|
p.backend = new_program.backend
|
|
p.vertex_shader^ = new_vs
|
|
p.fragment_shader^ = new_fs
|
|
|
|
return true
|
|
}
|
|
|
|
set_shader_uniform :: proc { // TODO: SS - Improve setting shader uniforms. A bit bug-prone and annoying to explicitly add code-paths for every 'Uniform' type needed.
|
|
set_shader_uniform_texture,
|
|
set_shader_uniform_float,
|
|
set_shader_uniform_matrix4f32,
|
|
set_shader_uniform_vector3,
|
|
}
|
|
|
|
set_shader_uniform_texture :: proc(program: ^Shader_Program, uniform: Uniform_Texture) -> bool {
|
|
assert(program != nil)
|
|
assert(uniform.index < MATERIAL_MAX_TEXTURES)
|
|
assert(uniform.value != nil)
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
return opengl_set_shader_uniform_texture(program, uniform)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
set_shader_uniform_float :: proc(program: ^Shader_Program, uniform: Uniform_Float) -> bool {
|
|
assert(program != nil)
|
|
assert(len(uniform.name) > 0)
|
|
|
|
if uniform.value == nil {
|
|
return false
|
|
}
|
|
|
|
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
return opengl_set_shader_uniform_float(program, uniform)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
set_shader_uniform_matrix4f32 :: proc(program: ^Shader_Program, uniform: Uniform_Matrix4f32) -> bool {
|
|
assert(program != nil)
|
|
assert(len(uniform.name) > 0)
|
|
|
|
if uniform.value == nil {
|
|
return false
|
|
}
|
|
|
|
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
return opengl_set_shader_uniform_matrix4f32(program, uniform)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
set_shader_uniform_vector3 :: proc(program: ^Shader_Program, uniform: Uniform_Vector3) -> bool {
|
|
assert(program != nil)
|
|
assert(len(uniform.name) > 0)
|
|
|
|
if uniform.value == nil {
|
|
return false
|
|
}
|
|
|
|
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
return opengl_set_shader_uniform_vector3(program, uniform)
|
|
}
|
|
|
|
return false
|
|
} |