Spheres/primitive built-in meshes, cull-modes, vec4 uniforms

This commit is contained in:
2026-02-05 00:17:33 +01:00
parent efa2c274f3
commit 3b32097c56
6 changed files with 510 additions and 172 deletions

View File

@@ -1,7 +1,8 @@
package renderer package renderer
import "core:math/rand" import "core:math/rand"
Color :: union {
Color :: union #no_nil {
RGB_Color, RGB_Color,
RGBA_Color, RGBA_Color,
} }

196
mesh.odin
View File

@@ -1,5 +1,7 @@
package renderer package renderer
import "core:math"
import "core:log"
Mesh :: struct { Mesh :: struct {
amount_of_indices: u32, amount_of_indices: u32,
backend: Mesh_Backend, backend: Mesh_Backend,
@@ -14,7 +16,12 @@ Mesh_Layout :: struct {
type_size: u32, type_size: u32,
} }
create_mesh :: proc(renderer: ^Renderer, layout: []Mesh_Layout, vertices: []f32, indices: []u32) -> (Mesh, bool) { // TODO: SS - Should probably return a Mesh_Handle. create_mesh :: proc {
create_mesh_layout_vertices_indices,
create_mesh_from_primitive,
}
create_mesh_layout_vertices_indices :: proc(renderer: ^Renderer, layout: []Mesh_Layout, vertices: []f32, indices: []u32) -> (Mesh, bool) { // TODO: SS - Should probably return a Mesh_Handle.
mesh: Mesh mesh: Mesh
if len(vertices) == 0 { if len(vertices) == 0 {
@@ -39,4 +46,191 @@ create_mesh :: proc(renderer: ^Renderer, layout: []Mesh_Layout, vertices: []f32,
} }
return m, true return m, true
}
Primitive_Mesh_Type :: enum {
Cube,
Quad,
Sphere,
}
create_mesh_from_primitive :: proc(renderer: ^Renderer, primitive_mesh_type: Primitive_Mesh_Type) -> (Mesh, bool) {
switch primitive_mesh_type {
case .Cube: {
m, ok := create_mesh(
renderer = renderer,
layout = {
{ "position", 3, size_of(f32), },
{ "normal", 3, size_of(f32), },
{ "texture_coords", 2, size_of(f32), },
{ "tangent", 3, size_of(f32), },
},
vertices = []f32{
// Positions // Normals // UV // Tangent
// Back face
-0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0,
// Front face
-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,
0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0,
// Left face
-0.5, 0.5, 0.5, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0,
-0.5, 0.5, -0.5, -1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
-0.5, -0.5, -0.5, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,
-0.5, -0.5, 0.5, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
// Right face
0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0,
0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0,
0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0,
0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, -1.0,
// Bottom face
-0.5, -0.5, -0.5, 0.0,-1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0,
0.5, -0.5, -0.5, 0.0,-1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.5, 0.0,-1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0,
-0.5, -0.5, 0.5, 0.0,-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
// Top face
-0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0,
-0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
},
indices = []u32 {
// Back face
0, 3, 1,
1, 3, 2,
// Front face
4, 5, 7,
5, 6, 7,
// Left face
8, 9, 11,
9, 10, 11,
// Right face
12, 13, 15,
13, 14, 15,
// Bottom face
16, 17, 18,
16, 18, 19,
// Top face
20, 22, 21,
20, 23, 22
}
)
return m, ok
}
case .Quad: {
m, ok := create_mesh(
renderer = renderer,
layout = {
{ "position", 3, size_of(f32), },
{ "normal", 3, size_of(f32), },
{ "texture_coords", 2, size_of(f32), },
{ "tangent", 3, size_of(f32), },
},
vertices = []f32 {
// Positions. // Normals // Texture Coordinates. // Tangent.
0.5, 0.5, 0.0, 0, 0, 0, 1.0, 1.0, 1, 0, 0, // Top right.
0.5, -0.5, 0.0, 0, 0, 0, 1.0, 0.0, 1, 0, 0, // Bottom right.
-0.5, -0.5, 0.0, 0, 0, 0, 0.0, 0.0, 1, 0, 0, // Bottom left.
-0.5, 0.5, 0.0, 0, 0, 0, 0.0, 1.0, 1, 0, 0, // Top left.
},
indices = []u32 {
0, 1, 3,
1, 2, 3,
}
)
return m, ok
}
case .Sphere: {
X_SEGMENTS :: 64
Y_SEGMENTS :: 32
vertices := make([dynamic]f32, 0)
indices := make([dynamic]u32, 0)
for y in 0..=Y_SEGMENTS {
y_segment := f32(y) / f32(Y_SEGMENTS)
phi := y_segment * math.PI
for x in 0..=X_SEGMENTS {
x_segment := f32(x) / f32(X_SEGMENTS)
theta := x_segment * math.TAU
px := math.cos(theta) * math.sin(phi)
py := math.cos(phi)
pz := math.sin(theta) * math.sin(phi)
// Position.
append(&vertices, px * 0.5)
append(&vertices, py * 0.5)
append(&vertices, pz * 0.5)
// Normal.
append(&vertices, px)
append(&vertices, py)
append(&vertices, pz)
// UV.
append(&vertices, x_segment)
append(&vertices, 1.0 - y_segment)
// Tangent.
tx := -math.sin(theta)
ty := f32(0.0)
tz := math.cos(theta)
append(&vertices, tx)
append(&vertices, ty)
append(&vertices, tz)
}
}
for y in 0..<Y_SEGMENTS {
for x in 0..<X_SEGMENTS {
i0 := u32(y * (X_SEGMENTS + 1) + x)
i1 := u32((y + 1) * (X_SEGMENTS + 1) + x)
i2 := u32((y + 1) * (X_SEGMENTS + 1) + x + 1)
i3 := u32(y * (X_SEGMENTS + 1) + x + 1)
append(&indices, i0)
append(&indices, i3)
append(&indices, i1)
append(&indices, i1)
append(&indices, i3)
append(&indices, i2)
}
}
m, ok := create_mesh(
renderer = renderer,
layout = {
{ "position", 3, size_of(f32), },
{ "normal", 3, size_of(f32), },
{ "texture_coords", 2, size_of(f32), },
{ "tangent", 3, size_of(f32), },
},
vertices = vertices[:],
indices = indices[:],
)
return m, ok
}
}
return {}, false
} }

155
pass.odin
View File

@@ -2,6 +2,7 @@ package renderer
import "core:math/linalg" import "core:math/linalg"
import "core:fmt" import "core:fmt"
import "core:log"
MAX_DRAW_COMMANDS_CAPACITY :: 4096 MAX_DRAW_COMMANDS_CAPACITY :: 4096
MAX_POST_PROCESS_NODES_PER_PASS :: 8 MAX_POST_PROCESS_NODES_PER_PASS :: 8
@@ -19,6 +20,7 @@ Pass_Type :: union {
Scene_Pass :: struct { Scene_Pass :: struct {
blend_mode: Blend_Mode, blend_mode: Blend_Mode,
sort_mode: Sort_Mode, sort_mode: Sort_Mode,
cull_mode: Cull_Mode,
draw_commands: [dynamic]Draw_Command, // Capacity is 'MAX_DRAW_COMMANDS_CAPACITY'. draw_commands: [dynamic]Draw_Command, // Capacity is 'MAX_DRAW_COMMANDS_CAPACITY'.
@@ -31,10 +33,21 @@ Post_Processing_Pass :: struct {
Uniform :: union { Uniform :: union {
Uniform_Texture, Uniform_Texture,
Uniform_Float, Uniform_Float,
Uniform_Float_Pointer,
Uniform_Matrix4f32, Uniform_Matrix4f32,
Uniform_Matrix4f32_Pointer,
Uniform_Vector3, Uniform_Vector3,
Uniform_Vector3_Pointer,
Uniform_Vector4,
Uniform_Vector4_Pointer,
Uniform_Color, Uniform_Color,
Uniform_Color_Pointer,
} }
Uniform_Texture :: struct { Uniform_Texture :: struct {
@@ -43,21 +56,46 @@ Uniform_Texture :: struct {
} }
Uniform_Float :: struct { Uniform_Float :: struct {
name: string,
value: f32,
}
Uniform_Float_Pointer :: struct {
name: string, name: string,
value: ^f32, value: ^f32,
} }
Uniform_Matrix4f32 :: struct { Uniform_Matrix4f32 :: struct {
name: string,
value: linalg.Matrix4f32,
}
Uniform_Matrix4f32_Pointer :: struct {
name: string, name: string,
value: ^linalg.Matrix4f32, value: ^linalg.Matrix4f32,
} }
Uniform_Vector3 :: struct { Uniform_Vector3 :: struct {
name: string,
value: [3]f32,
}
Uniform_Vector3_Pointer :: struct {
name: string, name: string,
value: ^[3]f32, value: ^[3]f32,
} }
Uniform_Vector4 :: struct {
name: string,
value: [4]f32,
}
Uniform_Vector4_Pointer :: struct {
name: string,
value: ^[4]f32,
}
Uniform_Color :: struct { Uniform_Color :: struct {
name: string,
value: Color,
}
Uniform_Color_Pointer :: struct {
name: string, name: string,
value: ^Color, value: ^Color,
} }
@@ -69,16 +107,46 @@ Post_Processing_Node :: struct {
program: ^Shader_Program, program: ^Shader_Program,
} }
// TODO: SS - Create a pool of 'Draw_Command's and reuse them.
MAX_UNIFORMS_PER_DRAW_COMMAND :: 8
Draw_Command :: struct { Draw_Command :: struct {
renderer: ^Renderer, // Needed for sorting. renderer: ^Renderer, // Needed for sorting.
mesh: Mesh, mesh: Mesh,
material: Material, material: Material,
uniforms: [MAX_UNIFORMS_PER_DRAW_COMMAND]Uniform,
uniform_count: u8,
position: [3]f32, position: [3]f32,
rotation: [3]f32, rotation: [3]f32,
scale: [3]f32, scale: [3]f32,
} }
create_draw_command :: proc(renderer: ^Renderer, mesh: Mesh, material: Material, uniforms: []Uniform, position, rotation, scale: [3]f32, loc := #caller_location) -> Draw_Command {
dc: Draw_Command
dc.renderer = renderer
dc.mesh = mesh
dc.material = material
dc.position = position
dc.rotation = rotation
dc.scale = scale
for u in uniforms {
if dc.uniform_count >= MAX_UNIFORMS_PER_DRAW_COMMAND {
log.warnf("Hit max capacity (%v) of uniforms per draw command! %v", MAX_UNIFORMS_PER_DRAW_COMMAND, loc)
break
}
dc.uniforms[dc.uniform_count] = u
dc.uniform_count += 1
}
return dc
}
Blend_Mode :: enum { Blend_Mode :: enum {
None, None,
Alpha, Alpha,
@@ -117,10 +185,18 @@ Sort_Mode :: enum {
Front_To_Back, // Sorts the commands in the 'draw_commmands' array (from front to back) before drawing them. Front_To_Back, // Sorts the commands in the 'draw_commmands' array (from front to back) before drawing them.
} }
Cull_Mode :: enum {
None,
Back,
Front,
Front_Back,
}
create_scene_pass :: proc( create_scene_pass :: proc(
name: string, name: string,
blend_mode: Blend_Mode, blend_mode: Blend_Mode,
sort_mode: Sort_Mode, sort_mode: Sort_Mode,
cull_mode: Cull_Mode,
output_rt: ^Render_Target, output_rt: ^Render_Target,
) -> Pass ) -> Pass
{ {
@@ -131,6 +207,7 @@ create_scene_pass :: proc(
p.type = Scene_Pass { p.type = Scene_Pass {
blend_mode = blend_mode, blend_mode = blend_mode,
sort_mode = sort_mode, sort_mode = sort_mode,
cull_mode = cull_mode,
draw_commands = make([dynamic]Draw_Command, 0, MAX_DRAW_COMMANDS_CAPACITY), draw_commands = make([dynamic]Draw_Command, 0, MAX_DRAW_COMMANDS_CAPACITY),
@@ -194,7 +271,83 @@ add_command_to_pass :: proc(renderer: ^Renderer, pass: ^Pass, command: Draw_Comm
assert(err == .None) assert(err == .None)
} }
} }
return true return true
}
execute_pass :: proc(renderer: ^Renderer, pass: ^Pass, view_matrix, projection_matrix: linalg.Matrix4x4f32) { // TODO: SS - Move to 'pass.odin'.
// fmt.printfln("Executing pass '%v'.", pass.name)
assert(renderer != nil)
assert(pass != nil)
switch &t in &pass.type {
case Scene_Pass: {
apply_polygon_mode(renderer, renderer.polygon_mode)
assert(t.output_rt != nil)
bind_render_target(renderer, t.output_rt)
defer bind_render_target(renderer, nil)
should_write_depth := t.output_rt.depth_texture != nil
should_test_depth := should_write_depth
should_clear_depth := should_write_depth
should_clear_color := true
set_clear_color(renderer, RGBA_Color { 0, 0, 0, 0 })
clear_screen(renderer, should_clear_color, should_clear_depth)
apply_depth(renderer, should_test_depth, should_write_depth)
apply_blend_mode(renderer, t.blend_mode)
defer apply_blend_mode(renderer, .None)
apply_cull_mode(renderer, t.cull_mode)
defer apply_cull_mode(renderer, .None)
sort_draw_commands(renderer, &t)
for &dc in &t.draw_commands { // TODO: SS - Don't think we need the address of the draw-commands.
model_matrix := linalg.identity(linalg.Matrix4x4f32)
// Translate.
translation := linalg.matrix4_translate(dc.position)
// Rotate.
rot_x := linalg.matrix4_rotate(linalg.to_radians(dc.rotation.x), [3]f32 { 1, 0, 0 })
rot_y := linalg.matrix4_rotate(linalg.to_radians(dc.rotation.y), [3]f32 { 0, 1, 0 })
rot_z := linalg.matrix4_rotate(linalg.to_radians(dc.rotation.z), [3]f32 { 0, 0, 1 })
rotation := rot_z * rot_y * rot_x
// Scale.
scale := linalg.matrix4_scale(dc.scale)
model_matrix *= translation * rotation * scale
// Apply uniforms.
activate_material(&dc.material, model_matrix, view_matrix, projection_matrix)
if dc.uniform_count > 0 {
set_shader_uniforms(dc.material.shader_program, dc.uniforms[:dc.uniform_count])
}
// Draw the mesh.
draw_mesh(&dc.mesh)
}
// Clear the pass' draw-commands.
clear(&t.draw_commands)
// TODO: SS - "Deactivate" the pass?
apply_polygon_mode(renderer, .Fill)
}
case Post_Processing_Pass: {
// Execute the post-processing nodes.
for &pp in &t.post_processing_nodes {
execute_post_processing_node(renderer, &pp, view_matrix, projection_matrix)
}
// TODO: SS - "Deactivate" the pass?
}
}
} }

View File

@@ -23,6 +23,9 @@ Renderer :: struct {
active_camera: ^Camera, // NOTE: SS - Hardcoded to 1 active camera. Split-screen is likely not possible due to this. Fix(?). active_camera: ^Camera, // NOTE: SS - Hardcoded to 1 active camera. Split-screen is likely not possible due to this. Fix(?).
// Primitive meshes.
default_cube_mesh, default_quad_mesh, default_sphere_mesh: Mesh,
fullscreen_vertex_shader, fullscreen_fragment_shader: Shader, fullscreen_vertex_shader, fullscreen_fragment_shader: Shader,
fullscreen_shader_program: Shader_Program, fullscreen_shader_program: Shader_Program,
fullscreen_mesh: Mesh, fullscreen_mesh: Mesh,
@@ -65,6 +68,20 @@ create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
set_vsync(renderer, true) set_vsync(renderer, true)
{ // Create the default mesh-primitives.
// default_cube_mesh, default_quad_mesh, default_sphere_mesh: Mesh,
if m, ok := create_mesh(renderer, .Cube); ok {
renderer.default_cube_mesh = m
}
if m, ok := create_mesh(renderer, .Quad); ok {
renderer.default_quad_mesh = m
}
if m, ok := create_mesh(renderer, .Sphere); ok {
renderer.default_sphere_mesh = m
}
}
{ // Create the fullscreen shaders, material and mesh. { // Create the fullscreen shaders, material and mesh.
fs_vertex_shader, fs_vertex_shader_ok := create_shader(renderer, .Vertex, "fs_vertex.glsl") fs_vertex_shader, fs_vertex_shader_ok := create_shader(renderer, .Vertex, "fs_vertex.glsl")
assert(fs_vertex_shader_ok) assert(fs_vertex_shader_ok)
@@ -135,13 +152,13 @@ set_vsync :: proc(renderer: ^Renderer, on: bool) {
} }
} }
@(private="file") set_clear_color :: proc(renderer: ^Renderer, color: Color) { @(private) set_clear_color :: proc(renderer: ^Renderer, color: Color) {
when RENDER_BACKEND_OPENGL { when RENDER_BACKEND_OPENGL {
opengl_set_clear_color(renderer, color) opengl_set_clear_color(renderer, color)
} }
} }
@(private="file") clear_screen :: proc(renderer: ^Renderer, clear_color: bool, clear_depth: bool) { @(private) clear_screen :: proc(renderer: ^Renderer, clear_color: bool, clear_depth: bool) {
when RENDER_BACKEND_OPENGL { when RENDER_BACKEND_OPENGL {
opengl_clear_screen(renderer, clear_color, clear_depth) opengl_clear_screen(renderer, clear_color, clear_depth)
} }
@@ -202,75 +219,6 @@ render_frame :: proc(renderer: ^Renderer, texture_to_present: ^Texture, clear_co
} }
} }
execute_pass :: proc(renderer: ^Renderer, pass: ^Pass, view_matrix, projection_matrix: linalg.Matrix4x4f32) { // TODO: SS - Move to 'pass.odin'.
// fmt.printfln("Executing pass '%v'.", pass.name)
assert(renderer != nil)
assert(pass != nil)
switch &t in &pass.type {
case Scene_Pass: {
apply_polygon_mode(renderer, renderer.polygon_mode)
assert(t.output_rt != nil)
bind_render_target(renderer, t.output_rt)
defer bind_render_target(renderer, nil)
should_write_depth := t.output_rt.depth_texture != nil
should_test_depth := should_write_depth
should_clear_depth := should_write_depth
should_clear_color := true
set_clear_color(renderer, RGBA_Color { 0, 0, 0, 0 })
clear_screen(renderer, should_clear_color, should_clear_depth)
apply_depth(renderer, should_test_depth, should_write_depth)
apply_blend_mode(renderer, t.blend_mode)
defer apply_blend_mode(renderer, .None)
sort_draw_commands(renderer, &t)
for &dc in &t.draw_commands { // TODO: SS - Don't think we need the address of the draw-commands.
model_matrix := linalg.identity(linalg.Matrix4x4f32)
// Translate.
translation := linalg.matrix4_translate(dc.position)
// Rotate.
rot_x := linalg.matrix4_rotate(linalg.to_radians(dc.rotation.x), [3]f32 { 1, 0, 0 })
rot_y := linalg.matrix4_rotate(linalg.to_radians(dc.rotation.y), [3]f32 { 0, 1, 0 })
rot_z := linalg.matrix4_rotate(linalg.to_radians(dc.rotation.z), [3]f32 { 0, 0, 1 })
rotation := rot_z * rot_y * rot_x
// Scale.
scale := linalg.matrix4_scale(dc.scale)
model_matrix *= translation * rotation * scale
activate_material(&dc.material, model_matrix, view_matrix, projection_matrix)
draw_mesh(&dc.mesh)
}
// Clear the pass' draw-commands.
clear(&t.draw_commands)
// TODO: SS - "Deactivate" the pass?
apply_polygon_mode(renderer, .Fill)
}
case Post_Processing_Pass: {
// Execute the post-processing nodes.
for &pp in &t.post_processing_nodes {
execute_post_processing_node(renderer, &pp, view_matrix, projection_matrix)
}
// TODO: SS - "Deactivate" the pass?
}
}
}
execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing_Node, view_matrix, projection_matrix: linalg.Matrix4x4f32) { execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing_Node, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
assert(renderer != nil) assert(renderer != nil)
assert(node != nil) assert(node != nil)
@@ -286,46 +234,16 @@ execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing
clear_screen(renderer, true, false) clear_screen(renderer, true, false)
// fmt.printfln("TODO: SS - Execute post-processing node '%v' (VS: '%v', FS: '%v').", "NAME", node.program.vertex_shader.path, node.program.fragment_shader.path) // fmt.printfln("TODO: SS - Execute post-processing node '%v' (VS: '%v', FS: '%v').", "NAME", node.program.vertex_shader.path, node.program.fragment_shader.path)
set_shader_uniforms(node.program, node.uniforms)
mat: Material mat: Material
mat.shader_program = node.program mat.shader_program = node.program
fs_path := node.program.fragment_shader != nil ? node.program.fragment_shader.path : "nil" for u in node.uniforms {
vs_path := node.program.vertex_shader != nil ? node.program.vertex_shader.path : "nil" if t, is_texture := u.(Uniform_Texture); is_texture {
mat.textures[mat.texture_count] = t.value
for u, i in node.uniforms { mat.texture_count += 1
switch &t in u {
case Uniform_Texture: {
if mat.texture_count > MATERIAL_MAX_TEXTURES {
continue
}
mat.textures[mat.texture_count] = t.value
mat.texture_count += 1
if !set_shader_uniform(node.program, t) {
fmt.printfln("Failed to set uniform-texture %v in program (vs: '%s', fs: '%s').", t.index, vs_path, fs_path)
}
}
case Uniform_Float: {
if !set_shader_uniform(node.program, t) {
fmt.printfln("Failed to set uniform-float '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
case Uniform_Matrix4f32: {
if !set_shader_uniform(node.program, t) {
fmt.printfln("Failed to set uniform-matrix4f32 '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
case Uniform_Vector3: {
if !set_shader_uniform(node.program, t) {
fmt.printfln("Failed to set uniform-vector3 '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
case Uniform_Color: {
if !set_shader_uniform(node.program, t) {
fmt.printfln("Failed to set uniform-color '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
} }
} }
@@ -337,6 +255,10 @@ destroy :: proc(renderer: ^Renderer) {
when RENDER_BACKEND_OPENGL { when RENDER_BACKEND_OPENGL {
opengl_destroy(renderer) opengl_destroy(renderer)
} }
// TODO: SS - Destroy 'default_cube_mesh'
// TODO: SS - Destroy 'default_quad_mesh'
// TODO: SS - Destroy 'default_sphere_mesh'
assert(renderer != nil) assert(renderer != nil)
free(renderer) free(renderer)
@@ -354,40 +276,8 @@ destroy :: proc(renderer: ^Renderer) {
p := material.shader_program p := material.shader_program
activate_shader_program(p) activate_shader_program(p)
set_shader_uniforms(material.shader_program, material.uniforms)
fs_path := p.fragment_shader != nil ? p.fragment_shader.path : "nil"
vs_path := p.vertex_shader != nil ? p.vertex_shader.path : "nil"
for u in material.uniforms {
switch &t in u {
case Uniform_Texture: {
if !set_shader_uniform(p, t) {
fmt.printfln("Failed to set uniform-texture %v in program (vs: '%s', fs: '%s').", t.index, vs_path, fs_path)
}
}
case Uniform_Float: {
if !set_shader_uniform(p, t) {
fmt.printfln("Failed to set uniform-float '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
case Uniform_Matrix4f32: {
if !set_shader_uniform(p, t) {
fmt.printfln("Failed to set uniform-matrix4f32 '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
case Uniform_Vector3: {
if !set_shader_uniform(p, t) {
fmt.printfln("Failed to set uniform-vector3 '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
case Uniform_Color: {
if !set_shader_uniform(p, t) {
fmt.printfln("Failed to set uniform-color '%s' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path)
}
}
}
}
when RENDER_BACKEND_OPENGL { when RENDER_BACKEND_OPENGL {
opengl_activate_material(material, model_matrix, view_matrix, projection_matrix) opengl_activate_material(material, model_matrix, view_matrix, projection_matrix)
} }
@@ -415,7 +305,14 @@ destroy :: proc(renderer: ^Renderer) {
} }
} }
@(private) apply_cull_mode :: proc(renderer: ^Renderer, cull_mode: Cull_Mode) {
when RENDER_BACKEND_OPENGL {
opengl_set_cull_mode(renderer, cull_mode)
}
}
@(private) sort_draw_commands :: proc(renderer: ^Renderer, pass: ^Scene_Pass) { @(private) sort_draw_commands :: proc(renderer: ^Renderer, pass: ^Scene_Pass) {
// TODO: SS - Set the pass' 'renderer' variable here instead?
switch pass.sort_mode { switch pass.sort_mode {
case .None: {} case .None: {}
case .Back_To_Front: { case .Back_To_Front: {

View File

@@ -517,6 +517,29 @@ when RENDER_BACKEND_OPENGL {
) )
} }
opengl_set_cull_mode :: proc(renderer: ^Renderer, cull_mode: Cull_Mode) {
switch cull_mode {
case .None: {
gl.Disable(gl.CULL_FACE)
}
case .Back: {
gl.Enable(gl.CULL_FACE)
gl.CullFace(gl.BACK)
gl.FrontFace(gl.CCW)
}
case .Front: {
gl.Enable(gl.CULL_FACE)
gl.CullFace(gl.FRONT)
gl.FrontFace(gl.CCW)
}
case .Front_Back: {
gl.Enable(gl.CULL_FACE)
gl.CullFace(gl.FRONT_AND_BACK)
gl.FrontFace(gl.CCW)
}
}
}
opengl_bind_render_target :: proc(renderer: ^Renderer, rt: ^Render_Target) { opengl_bind_render_target :: proc(renderer: ^Renderer, rt: ^Render_Target) {
if rt == nil { if rt == nil {
gl.BindFramebuffer(gl.FRAMEBUFFER, 0) gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
@@ -629,7 +652,7 @@ when RENDER_BACKEND_OPENGL {
return false return false
} }
gl.Uniform1f(loc, uniform.value^) gl.Uniform1f(loc, uniform.value)
return true return true
} }
@@ -644,7 +667,7 @@ when RENDER_BACKEND_OPENGL {
return false return false
} }
data := transmute([16]f32)(uniform.value^) data := transmute([16]f32)(uniform.value)
gl.UniformMatrix4fv(loc, 1, gl.FALSE, &data[0]) gl.UniformMatrix4fv(loc, 1, gl.FALSE, &data[0])
return true return true
@@ -659,7 +682,23 @@ when RENDER_BACKEND_OPENGL {
return false return false
} }
gl.Uniform3fv(loc, 1, &uniform.value[0]) v := transmute([3]f32)uniform.value
gl.Uniform3fv(loc, 1, &v[0])
return true
}
opengl_set_shader_uniform_vector4 :: proc(program: ^Shader_Program, uniform: Uniform_Vector4) -> bool {
opengl_activate_shader_program(program)
loc := gl.GetUniformLocation(program.backend.handle, fmt.ctprintf("%v", uniform.name))
if loc < 0 {
fmt.printfln("vector4 Loc: %v", loc)
return false
}
v := transmute([4]f32)uniform.value
gl.Uniform4fv(loc, 1, &v[0])
return true return true
} }

View File

@@ -123,12 +123,39 @@ reload_shader_program :: proc(renderer: ^Renderer, p: ^Shader_Program) -> bool {
return true return true
} }
set_shader_uniforms :: proc(program: ^Shader_Program, uniforms: []Uniform) {
fs_path := program.fragment_shader != nil ? program.fragment_shader.path : "nil"
vs_path := program.vertex_shader != nil ? program.vertex_shader.path : "nil"
for u in uniforms {
switch &t in u {
case Uniform_Texture: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (texture) %v in program (vs: '%s', fs: '%s').", t.index, vs_path, fs_path) }}
case Uniform_Float: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (float) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Float_Pointer: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (float pointer) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Matrix4f32: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (matrix4f32) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Matrix4f32_Pointer: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (matrix4f32 pointer) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Vector3: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (vector3) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Vector3_Pointer: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (vector3 pointer) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Vector4: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (vector4) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Vector4_Pointer: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (vector4 pointer) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Color: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (color) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
case Uniform_Color_Pointer: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (color pointer) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
}
}
}
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 :: 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_texture,
set_shader_uniform_float, set_shader_uniform_float,
set_shader_uniform_float_pointer,
set_shader_uniform_matrix4f32, set_shader_uniform_matrix4f32,
set_shader_uniform_matrix4f32_pointer,
set_shader_uniform_vector3, set_shader_uniform_vector3,
set_shader_uniform_vector3_pointer,
set_shader_uniform_vector4,
set_shader_uniform_vector4_pointer,
set_shader_uniform_color, set_shader_uniform_color,
set_shader_uniform_color_pointer,
} }
set_shader_uniform_texture :: proc(program: ^Shader_Program, uniform: Uniform_Texture) -> bool { set_shader_uniform_texture :: proc(program: ^Shader_Program, uniform: Uniform_Texture) -> bool {
@@ -143,13 +170,15 @@ set_shader_uniform_texture :: proc(program: ^Shader_Program, uniform: Uniform_Te
return false return false
} }
set_shader_uniform_float :: proc(program: ^Shader_Program, uniform: Uniform_Float) -> bool { set_shader_uniform_float_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Float_Pointer) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
if uniform.value == nil { if uniform.value == nil {
return false return false
} }
return set_shader_uniform(program, Uniform_Float { uniform.name, uniform.value^ })
}
set_shader_uniform_float :: proc(program: ^Shader_Program, uniform: Uniform_Float) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)? // TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
@@ -160,13 +189,15 @@ set_shader_uniform_float :: proc(program: ^Shader_Program, uniform: Uniform_Floa
return false return false
} }
set_shader_uniform_matrix4f32 :: proc(program: ^Shader_Program, uniform: Uniform_Matrix4f32) -> bool { set_shader_uniform_matrix4f32_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Matrix4f32_Pointer) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
if uniform.value == nil { if uniform.value == nil {
return false return false
} }
return set_shader_uniform(program, Uniform_Matrix4f32 { uniform.name, uniform.value^ })
}
set_shader_uniform_matrix4f32 :: proc(program: ^Shader_Program, uniform: Uniform_Matrix4f32) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)? // TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
@@ -177,13 +208,16 @@ set_shader_uniform_matrix4f32 :: proc(program: ^Shader_Program, uniform: Uniform
return false return false
} }
set_shader_uniform_vector3 :: proc(program: ^Shader_Program, uniform: Uniform_Vector3) -> bool { set_shader_uniform_vector3_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Vector3_Pointer) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
if uniform.value == nil { if uniform.value == nil {
return false return false
} }
return set_shader_uniform(program, Uniform_Vector3 { uniform.name, uniform.value^ })
}
set_shader_uniform_vector3 :: proc(program: ^Shader_Program, uniform: Uniform_Vector3) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)? // TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
@@ -194,13 +228,35 @@ set_shader_uniform_vector3 :: proc(program: ^Shader_Program, uniform: Uniform_Ve
return false return false
} }
set_shader_uniform_color :: proc(program: ^Shader_Program, uniform: Uniform_Color) -> bool { set_shader_uniform_vector4_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Vector4_Pointer) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
if uniform.value == nil { if uniform.value == nil {
return false return false
} }
return set_shader_uniform(program, Uniform_Vector4 { uniform.name, uniform.value^ })
}
set_shader_uniform_vector4 :: proc(program: ^Shader_Program, uniform: Uniform_Vector4) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
when RENDER_BACKEND_OPENGL {
return opengl_set_shader_uniform_vector4(program, uniform)
}
return false
}
set_shader_uniform_color_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Color_Pointer) -> bool {
if uniform.value == nil {
return false
}
return set_shader_uniform(program, Uniform_Color { uniform.name, uniform.value^ })
}
set_shader_uniform_color :: proc(program: ^Shader_Program, uniform: Uniform_Color) -> bool {
assert(program != nil)
assert(len(uniform.name) > 0)
// TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)? // TODO: SS - Somehow verify that 'uniform.name' exists in the shader(s)?
@@ -210,7 +266,7 @@ set_shader_uniform_color :: proc(program: ^Shader_Program, uniform: Uniform_Colo
u := Uniform_Vector3 { u := Uniform_Vector3 {
name = uniform.name, name = uniform.name,
value = &rgb, value = rgb,
} }
when RENDER_BACKEND_OPENGL { when RENDER_BACKEND_OPENGL {
@@ -220,16 +276,14 @@ set_shader_uniform_color :: proc(program: ^Shader_Program, uniform: Uniform_Colo
case RGBA_Color: { case RGBA_Color: {
rgba := color_to_f32(c) rgba := color_to_f32(c)
// u := Uniform_Vector4 { u := Uniform_Vector4 {
// name = uniform.name, name = uniform.name,
// value = &rgba, value = rgba,
// } }
// TODO: SS - Set vector4. when RENDER_BACKEND_OPENGL {
// when RENDER_BACKEND_OPENGL { return opengl_set_shader_uniform_vector4(program, u)
// return opengl_set_shader_uniform_vector4(program, uniform) }
// }
assert(false, "TODO: SS - Allow setting rgba in uniform.")
} }
} }