Compare commits
5 Commits
b80c321e84
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c1002d5db2 | |||
| cb19295575 | |||
| 3b32097c56 | |||
| efa2c274f3 | |||
| 4394179a71 |
@@ -121,7 +121,7 @@ get_camera_projection_matrix :: proc(renderer: ^Renderer, camera: ^Camera) -> (l
|
||||
case Camera_Perspective: {
|
||||
projection_matrix *= linalg.matrix4_perspective(
|
||||
linalg.to_radians(f32(t.fov_degrees)),
|
||||
get_aspect_ratio(renderer),
|
||||
get_aspect_ratio(renderer, .Render),
|
||||
camera.near,
|
||||
camera.far,
|
||||
flip_z_axis = true,
|
||||
@@ -129,7 +129,7 @@ get_camera_projection_matrix :: proc(renderer: ^Renderer, camera: ^Camera) -> (l
|
||||
}
|
||||
case Camera_Orthographic: {
|
||||
half_h := t.height / 2
|
||||
half_w := half_h * get_aspect_ratio(renderer)
|
||||
half_w := half_h * get_aspect_ratio(renderer, .Render)
|
||||
|
||||
projection_matrix *= linalg.matrix_ortho3d(
|
||||
-half_w, half_w,
|
||||
|
||||
48
color.odin
Normal file
48
color.odin
Normal file
@@ -0,0 +1,48 @@
|
||||
package renderer
|
||||
|
||||
import "core:math/rand"
|
||||
|
||||
Color :: union #no_nil {
|
||||
RGB_Color,
|
||||
RGBA_Color,
|
||||
}
|
||||
|
||||
RGB_Color :: [3]u8
|
||||
RGBA_Color :: [4]u8
|
||||
|
||||
color_to_f32 :: proc {
|
||||
rgb_color_to_f32_array,
|
||||
rgba_color_to_f32_array,
|
||||
}
|
||||
|
||||
rgb_color_to_f32_array :: proc(color: RGB_Color) -> [3]f32 {
|
||||
return {
|
||||
f32(color.r) / f32(max(u8)),
|
||||
f32(color.g) / f32(max(u8)),
|
||||
f32(color.b) / f32(max(u8)),
|
||||
}
|
||||
}
|
||||
|
||||
rgba_color_to_f32_array :: proc(color: RGBA_Color) -> [4]f32 {
|
||||
return {
|
||||
f32(color.r) / f32(max(u8)),
|
||||
f32(color.g) / f32(max(u8)),
|
||||
f32(color.b) / f32(max(u8)),
|
||||
f32(color.a) / f32(max(u8)),
|
||||
}
|
||||
}
|
||||
|
||||
get_random_color_rgb :: proc() -> RGB_Color {
|
||||
r := u8(rand.uint32() / u32(max(u8)))
|
||||
g := u8(rand.uint32() / u32(max(u8)))
|
||||
b := u8(rand.uint32() / u32(max(u8)))
|
||||
|
||||
return { r, g, b }
|
||||
}
|
||||
|
||||
get_random_color_rgba :: proc() -> RGBA_Color {
|
||||
c := get_random_color_rgb()
|
||||
a := u8(rand.uint32() / u32(max(u8)))
|
||||
|
||||
return { c.r, c.g, c.b, a }
|
||||
}
|
||||
@@ -12,10 +12,13 @@ Material :: struct {
|
||||
textures: [MATERIAL_MAX_TEXTURES]^Texture,
|
||||
texture_count: u8,
|
||||
|
||||
uniforms: []Uniform,
|
||||
|
||||
casts_shadow: bool,
|
||||
uv_scale: [2]f32, // TODO: SS - Move?
|
||||
}
|
||||
|
||||
create_material :: proc(program: ^Shader_Program, textures: []^Texture) -> (Material, bool) {
|
||||
create_material :: proc(program: ^Shader_Program, textures: []^Texture, uniforms: []Uniform, casts_shadow: bool) -> (Material, bool) {
|
||||
m: Material
|
||||
m.shader_program = program
|
||||
|
||||
@@ -39,7 +42,10 @@ create_material :: proc(program: ^Shader_Program, textures: []^Texture) -> (Mate
|
||||
// TODO: SS - Should we return false here?
|
||||
}
|
||||
|
||||
m.uv_scale = { 2.0, 2.0 } // NOTE: SS - Hardcoded.
|
||||
|
||||
m.uniforms = uniforms
|
||||
m.casts_shadow = casts_shadow
|
||||
m.uv_scale = { 1.0, 1.0 } // NOTE: SS - Hardcoded.
|
||||
|
||||
return m, true
|
||||
}
|
||||
228
mesh.odin
228
mesh.odin
@@ -1,5 +1,7 @@
|
||||
package renderer
|
||||
|
||||
import "core:math"
|
||||
import "core:log"
|
||||
Mesh :: struct {
|
||||
amount_of_indices: u32,
|
||||
backend: Mesh_Backend,
|
||||
@@ -14,7 +16,12 @@ Mesh_Layout :: struct {
|
||||
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
|
||||
|
||||
if len(vertices) == 0 {
|
||||
@@ -40,3 +47,222 @@ create_mesh :: proc(renderer: ^Renderer, layout: []Mesh_Layout, vertices: []f32,
|
||||
|
||||
return m, true
|
||||
}
|
||||
|
||||
Primitive_Mesh_Type :: enum {
|
||||
Cube,
|
||||
UI_Quad, World_Quad, // NOTE: SS - Not sure I like two quads but it's probably alright.
|
||||
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 .World_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 .UI_Quad: {
|
||||
m, ok := create_mesh(
|
||||
renderer = renderer,
|
||||
layout = {
|
||||
{ "position", 3, size_of(f32), },
|
||||
{ "texture_coords", 2, size_of(f32), },
|
||||
},
|
||||
vertices = []f32 {
|
||||
// Positions. // UV.
|
||||
0.0, 0.0, 0.0, 0.0, 1.0,
|
||||
1.0, 0.0, 0.0, 1.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0, 0.0,
|
||||
},
|
||||
indices = []u32 {
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
}
|
||||
)
|
||||
return m, ok
|
||||
}
|
||||
case .Sphere: {
|
||||
X_SEGMENTS :: 64
|
||||
Y_SEGMENTS :: 32
|
||||
|
||||
vertices := make([dynamic]f32, 0)
|
||||
indices := make([dynamic]u32, 0)
|
||||
defer delete(vertices)
|
||||
defer delete(indices)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
delete_mesh :: proc(renderer: ^Renderer, mesh: ^Mesh) {
|
||||
assert(renderer != nil)
|
||||
assert(mesh != nil)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_delete_mesh(renderer, mesh)
|
||||
}
|
||||
}
|
||||
182
pass.odin
182
pass.odin
@@ -2,6 +2,7 @@ package renderer
|
||||
|
||||
import "core:math/linalg"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
|
||||
MAX_DRAW_COMMANDS_CAPACITY :: 4096
|
||||
MAX_POST_PROCESS_NODES_PER_PASS :: 8
|
||||
@@ -19,6 +20,7 @@ Pass_Type :: union {
|
||||
Scene_Pass :: struct {
|
||||
blend_mode: Blend_Mode,
|
||||
sort_mode: Sort_Mode,
|
||||
cull_mode: Cull_Mode,
|
||||
|
||||
draw_commands: [dynamic]Draw_Command, // Capacity is 'MAX_DRAW_COMMANDS_CAPACITY'.
|
||||
|
||||
@@ -31,9 +33,22 @@ Post_Processing_Pass :: struct {
|
||||
|
||||
Uniform :: union {
|
||||
Uniform_Texture,
|
||||
|
||||
Uniform_Float,
|
||||
Uniform_Float_Pointer,
|
||||
|
||||
Uniform_Matrix4f32,
|
||||
Uniform_Matrix4f32_Pointer,
|
||||
|
||||
Uniform_Vector2,
|
||||
Uniform_Vector2_Pointer,
|
||||
Uniform_Vector3,
|
||||
Uniform_Vector3_Pointer,
|
||||
Uniform_Vector4,
|
||||
Uniform_Vector4_Pointer,
|
||||
|
||||
Uniform_Color,
|
||||
Uniform_Color_Pointer,
|
||||
}
|
||||
|
||||
Uniform_Texture :: struct {
|
||||
@@ -42,20 +57,59 @@ Uniform_Texture :: struct {
|
||||
}
|
||||
|
||||
Uniform_Float :: struct {
|
||||
name: string,
|
||||
value: f32,
|
||||
}
|
||||
Uniform_Float_Pointer :: struct {
|
||||
name: string,
|
||||
value: ^f32,
|
||||
}
|
||||
|
||||
Uniform_Matrix4f32 :: struct {
|
||||
name: string,
|
||||
value: linalg.Matrix4f32,
|
||||
}
|
||||
Uniform_Matrix4f32_Pointer :: struct {
|
||||
name: string,
|
||||
value: ^linalg.Matrix4f32,
|
||||
}
|
||||
|
||||
Uniform_Vector2 :: struct {
|
||||
name: string,
|
||||
value: [2]f32,
|
||||
}
|
||||
Uniform_Vector2_Pointer :: struct {
|
||||
name: string,
|
||||
value: ^[2]f32,
|
||||
}
|
||||
|
||||
Uniform_Vector3 :: struct {
|
||||
name: string,
|
||||
value: [3]f32,
|
||||
}
|
||||
Uniform_Vector3_Pointer :: struct {
|
||||
name: string,
|
||||
value: ^[3]f32,
|
||||
}
|
||||
|
||||
Uniform_Vector4 :: struct {
|
||||
name: string,
|
||||
value: [4]f32,
|
||||
}
|
||||
Uniform_Vector4_Pointer :: struct {
|
||||
name: string,
|
||||
value: ^[4]f32,
|
||||
}
|
||||
|
||||
Uniform_Color :: struct {
|
||||
name: string,
|
||||
value: Color,
|
||||
}
|
||||
Uniform_Color_Pointer :: struct {
|
||||
name: string,
|
||||
value: ^Color,
|
||||
}
|
||||
|
||||
Post_Processing_Node :: struct {
|
||||
uniforms: []Uniform,
|
||||
output: ^Render_Target,
|
||||
@@ -63,16 +117,46 @@ Post_Processing_Node :: struct {
|
||||
program: ^Shader_Program,
|
||||
}
|
||||
|
||||
// TODO: SS - Create a pool of 'Draw_Command's and reuse them.
|
||||
|
||||
MAX_UNIFORMS_PER_DRAW_COMMAND :: 8
|
||||
|
||||
Draw_Command :: struct {
|
||||
renderer: ^Renderer, // Needed for sorting.
|
||||
|
||||
mesh: Mesh,
|
||||
material: Material,
|
||||
uniforms: [MAX_UNIFORMS_PER_DRAW_COMMAND]Uniform,
|
||||
uniform_count: u8,
|
||||
|
||||
position: [3]f32,
|
||||
rotation: [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 {
|
||||
None,
|
||||
Alpha,
|
||||
@@ -111,10 +195,18 @@ Sort_Mode :: enum {
|
||||
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(
|
||||
name: string,
|
||||
blend_mode: Blend_Mode,
|
||||
sort_mode: Sort_Mode,
|
||||
cull_mode: Cull_Mode,
|
||||
output_rt: ^Render_Target,
|
||||
) -> Pass
|
||||
{
|
||||
@@ -125,6 +217,7 @@ create_scene_pass :: proc(
|
||||
p.type = Scene_Pass {
|
||||
blend_mode = blend_mode,
|
||||
sort_mode = sort_mode,
|
||||
cull_mode = cull_mode,
|
||||
|
||||
draw_commands = make([dynamic]Draw_Command, 0, MAX_DRAW_COMMANDS_CAPACITY),
|
||||
|
||||
@@ -160,10 +253,12 @@ delete_pass :: proc(pass: ^Pass) {
|
||||
}
|
||||
|
||||
@(private) delete_scene_pass :: proc(pass: ^Scene_Pass) {
|
||||
assert(pass.draw_commands != nil)
|
||||
delete(pass.draw_commands)
|
||||
}
|
||||
|
||||
@(private) delete_post_processing_pass :: proc(pass: ^Post_Processing_Pass) {
|
||||
assert(pass.post_processing_nodes != nil)
|
||||
delete(pass.post_processing_nodes)
|
||||
}
|
||||
|
||||
@@ -189,6 +284,91 @@ add_command_to_pass :: proc(renderer: ^Renderer, pass: ^Pass, command: Draw_Comm
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
execute_pass :: proc(renderer: ^Renderer, pass: ^Pass, view_matrix, projection_matrix: linalg.Matrix4x4f32) { // TODO: SS - Move to 'pass.odin'.
|
||||
// log.infof("Executing pass '%v'.", pass.name)
|
||||
|
||||
assert(renderer != nil)
|
||||
assert(pass != nil)
|
||||
|
||||
switch &t in &pass.type {
|
||||
case Scene_Pass: {
|
||||
// temp_draw_count := 0
|
||||
|
||||
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
|
||||
should_scissor :: false
|
||||
set_clear_color(renderer, RGBA_Color { 0, 0, 0, 0 })
|
||||
clear_screen(renderer, should_clear_color, should_clear_depth, should_scissor)
|
||||
|
||||
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)
|
||||
|
||||
// TODO: SS - Frustum-culling.
|
||||
|
||||
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)
|
||||
|
||||
// temp_draw_count += 1
|
||||
}
|
||||
|
||||
// Clear the pass' draw-commands.
|
||||
clear(&t.draw_commands)
|
||||
|
||||
// TODO: SS - "Deactivate" the pass?
|
||||
|
||||
apply_polygon_mode(renderer, .Fill)
|
||||
|
||||
// log.infof(" Done! Drew %v meshes.", temp_draw_count)
|
||||
}
|
||||
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?
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import "core:mem"
|
||||
import "core:log"
|
||||
import "core:fmt"
|
||||
|
||||
PIPELINE_MAX_PASSES :: 8
|
||||
PIPELINE_MAX_PASSES :: 16
|
||||
|
||||
Pipeline :: struct {
|
||||
passes: [PIPELINE_MAX_PASSES]^Pass,
|
||||
@@ -40,10 +40,11 @@ add_pass_to_pipeline :: proc(renderer: ^Renderer, pass: ^Pass) -> bool {
|
||||
|
||||
pipeline := &renderer.pipeline
|
||||
|
||||
if pipeline.amount_of_passes == PIPELINE_MAX_PASSES {
|
||||
log.warnf("Failed to add scene-pass '%v' to renderer's pipeline; hit max capacity (%v).", pass.name, PIPELINE_MAX_PASSES)
|
||||
return false
|
||||
}
|
||||
assert(pipeline.amount_of_passes < PIPELINE_MAX_PASSES)
|
||||
// if pipeline.amount_of_passes == PIPELINE_MAX_PASSES {
|
||||
// log.warnf("Failed to add scene-pass '%v' to renderer's pipeline; hit max capacity (%v).", pass.name, PIPELINE_MAX_PASSES)
|
||||
// return false
|
||||
// }
|
||||
|
||||
pipeline.passes[pipeline.amount_of_passes] = pass
|
||||
pipeline.amount_of_passes += 1
|
||||
|
||||
292
renderer.odin
292
renderer.odin
@@ -12,41 +12,72 @@ RENDER_BACKEND_DIRECTX11 :: #config(RENDER_BACKEND_DIRECTX11, false)
|
||||
RENDER_BACKEND_METAL :: #config(RENDER_BACKEND_METAL, false)
|
||||
|
||||
Renderer :: struct {
|
||||
render_resolution: Resolution,
|
||||
viewport: Viewport,
|
||||
backbuffer: Backbuffer,
|
||||
|
||||
surface_ptr: rawptr,
|
||||
vsync: bool,
|
||||
backend: rawptr,
|
||||
|
||||
polygon_mode: Polygon_Mode,
|
||||
|
||||
pipeline: Pipeline,
|
||||
|
||||
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_world_mesh, default_quad_ui_mesh, default_sphere_mesh: Mesh,
|
||||
|
||||
fullscreen_vertex_shader, fullscreen_fragment_shader: Shader,
|
||||
fullscreen_shader_program: Shader_Program,
|
||||
fullscreen_mesh: Mesh,
|
||||
}
|
||||
|
||||
Viewport :: struct {
|
||||
x, y, width, height: u16,
|
||||
Polygon_Mode :: enum {
|
||||
Fill,
|
||||
Line,
|
||||
Point,
|
||||
}
|
||||
|
||||
get_aspect_ratio :: proc(renderer: ^Renderer) -> f32 {
|
||||
Resolution :: struct {
|
||||
width, height: u16,
|
||||
}
|
||||
|
||||
Backbuffer :: struct {
|
||||
resolution: Resolution,
|
||||
}
|
||||
|
||||
Viewport :: struct {
|
||||
x, y: u16,
|
||||
res: Resolution,
|
||||
}
|
||||
|
||||
Aspect_Ratio_Type :: enum { // TODO: SS - Rename?
|
||||
Render,
|
||||
Backbuffer,
|
||||
Viewport,
|
||||
}
|
||||
get_aspect_ratio :: proc(renderer: ^Renderer, type: Aspect_Ratio_Type) -> f32 {
|
||||
assert(renderer != nil)
|
||||
|
||||
viewport := &renderer.viewport
|
||||
return f32(viewport.width) / f32(viewport.height)
|
||||
res: Resolution
|
||||
switch type {
|
||||
case .Render: res = renderer.render_resolution
|
||||
case .Backbuffer: res = renderer.backbuffer.resolution
|
||||
case .Viewport: res = renderer.viewport.res
|
||||
}
|
||||
|
||||
return f32(res.width) / f32(res.height)
|
||||
}
|
||||
|
||||
Color :: union {
|
||||
RGB_Color,
|
||||
RGBA_Color,
|
||||
}
|
||||
create :: proc(render_resolution: Resolution, surface_ptr: rawptr) -> (^Renderer, bool) {
|
||||
if render_resolution.width == 0 || render_resolution.height == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
RGB_Color :: [3]u8
|
||||
RGBA_Color :: [4]u8
|
||||
|
||||
create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
|
||||
renderer := new(Renderer)
|
||||
renderer.render_resolution = render_resolution
|
||||
renderer.surface_ptr = surface_ptr
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
@@ -65,6 +96,23 @@ create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
|
||||
|
||||
set_vsync(renderer, true)
|
||||
|
||||
{ // Create the default mesh-primitives.
|
||||
// default_cube_mesh, default_quad_world_mesh, default_sphere_mesh: Mesh,
|
||||
|
||||
if m, ok := create_mesh(renderer, .Cube); ok {
|
||||
renderer.default_cube_mesh = m
|
||||
}
|
||||
if m, ok := create_mesh(renderer, .World_Quad); ok {
|
||||
renderer.default_quad_world_mesh = m
|
||||
}
|
||||
if m, ok := create_mesh(renderer, .UI_Quad); ok {
|
||||
renderer.default_quad_ui_mesh = m
|
||||
}
|
||||
if m, ok := create_mesh(renderer, .Sphere); ok {
|
||||
renderer.default_sphere_mesh = m
|
||||
}
|
||||
}
|
||||
|
||||
{ // Create the fullscreen shaders, material and mesh.
|
||||
fs_vertex_shader, fs_vertex_shader_ok := create_shader(renderer, .Vertex, "fs_vertex.glsl")
|
||||
assert(fs_vertex_shader_ok)
|
||||
@@ -102,21 +150,37 @@ create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
|
||||
return renderer, true
|
||||
}
|
||||
|
||||
set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
||||
log.infof("Setting viewport to %v:%v, %vx%v.", x, y, width, height)
|
||||
set_backbuffer_resolution :: proc(renderer: ^Renderer, res: Resolution) {
|
||||
assert(renderer != nil)
|
||||
renderer.backbuffer.resolution = res
|
||||
}
|
||||
|
||||
renderer.viewport = {
|
||||
x = x,
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
}
|
||||
set_viewport :: proc {
|
||||
set_viewport_with_viewport,
|
||||
set_viewport_with_x_y_w_h,
|
||||
}
|
||||
|
||||
set_viewport_with_viewport :: proc(renderer: ^Renderer, viewport: Viewport) {
|
||||
assert(renderer != nil)
|
||||
|
||||
// log.infof("Setting viewport to %v:%v, %vx%v.", viewport.x, viewport.y, viewport.res.width, viewport.res.height)
|
||||
|
||||
renderer.viewport = viewport
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_viewport_changed(renderer)
|
||||
}
|
||||
}
|
||||
|
||||
set_viewport_with_x_y_w_h :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
||||
assert(renderer != nil)
|
||||
|
||||
set_viewport_with_viewport(renderer, Viewport {
|
||||
x, y,
|
||||
{ width, height }
|
||||
})
|
||||
}
|
||||
|
||||
set_vsync :: proc(renderer: ^Renderer, on: bool) {
|
||||
assert(renderer != nil)
|
||||
|
||||
@@ -135,15 +199,15 @@ 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 {
|
||||
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, clear_depth, scissor: bool) {
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_clear_screen(renderer, clear_color, clear_depth)
|
||||
opengl_clear_screen(renderer, clear_color, clear_depth, scissor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,16 +217,15 @@ render_frame :: proc(renderer: ^Renderer, texture_to_present: ^Texture, clear_co
|
||||
return
|
||||
}
|
||||
|
||||
view_matrix, _ := get_camera_view_matrix(renderer.active_camera)
|
||||
projection_matrix, _ := get_camera_projection_matrix(renderer, renderer.active_camera)
|
||||
|
||||
set_clear_color(renderer, clear_color)
|
||||
clear_screen(renderer, true, true)
|
||||
camera_view_matrix, _ := get_camera_view_matrix(renderer.active_camera)
|
||||
camera_projection_matrix, _ := get_camera_projection_matrix(renderer, renderer.active_camera)
|
||||
|
||||
for i in 0 ..< renderer.pipeline.amount_of_passes {
|
||||
execute_pass(renderer, renderer.pipeline.passes[i], view_matrix, projection_matrix)
|
||||
execute_pass(renderer, renderer.pipeline.passes[i], camera_view_matrix, camera_projection_matrix)
|
||||
}
|
||||
|
||||
apply_polygon_mode(renderer, .Fill)
|
||||
|
||||
if texture_to_present != nil { // Present.
|
||||
// Bind to the screen.
|
||||
bind_render_target(renderer, nil)
|
||||
@@ -170,9 +233,38 @@ render_frame :: proc(renderer: ^Renderer, texture_to_present: ^Texture, clear_co
|
||||
// Disable depth
|
||||
apply_depth(renderer, false, false)
|
||||
|
||||
compute_letterboxed_viewport :: proc(backbuffer: Resolution, render: Resolution) -> Viewport {
|
||||
bb_w, bb_h := expand_values(backbuffer)
|
||||
r_w, r_h := expand_values(render)
|
||||
|
||||
bb_aspect := f32(bb_w) / f32(bb_h)
|
||||
r_aspect := f32(r_w) / f32(r_h)
|
||||
|
||||
if bb_aspect > r_aspect {
|
||||
// Pillarbox.
|
||||
h := bb_h
|
||||
w := u16(f32(h) * r_aspect)
|
||||
x := (bb_w - w) / 2
|
||||
|
||||
return { x, 0, { w, h } }
|
||||
} else {
|
||||
// Letterbox.
|
||||
w := bb_w
|
||||
h := u16(f32(w) / r_aspect)
|
||||
y := (bb_h - h) / 2
|
||||
|
||||
return { 0, y, { w, h } }
|
||||
}
|
||||
}
|
||||
|
||||
// Clear
|
||||
set_viewport(renderer, 0, 0, renderer.backbuffer.resolution.width, renderer.backbuffer.resolution.height)
|
||||
set_clear_color(renderer, RGB_Color{ 0, 0, 0 })
|
||||
clear_screen(renderer, true, false, false)
|
||||
|
||||
set_viewport(renderer, compute_letterboxed_viewport(renderer.backbuffer.resolution, renderer.render_resolution))
|
||||
set_clear_color(renderer, clear_color)
|
||||
clear_screen(renderer, true, true)
|
||||
clear_screen(renderer, true, true, true)
|
||||
|
||||
// Create a temporary Material.
|
||||
mat := Material {
|
||||
@@ -200,72 +292,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) {
|
||||
// fmt.printfln("Executing pass '%v'.", pass.name)
|
||||
|
||||
assert(renderer != nil)
|
||||
assert(pass != nil)
|
||||
|
||||
switch &t in &pass.type {
|
||||
case Scene_Pass: {
|
||||
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?
|
||||
|
||||
}
|
||||
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) {
|
||||
assert(renderer != nil)
|
||||
assert(node != nil)
|
||||
@@ -277,48 +303,19 @@ execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing
|
||||
defer bind_render_target(renderer, nil)
|
||||
|
||||
apply_depth(renderer, false, false)
|
||||
set_clear_color(renderer, RGBA_Color { 0, 0, 0, 0 })
|
||||
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)
|
||||
|
||||
set_shader_uniforms(node.program, node.uniforms)
|
||||
|
||||
mat: Material
|
||||
mat.shader_program = node.program
|
||||
|
||||
fs_path := node.program.fragment_shader != nil ? node.program.fragment_shader.path : "nil"
|
||||
vs_path := node.program.vertex_shader != nil ? node.program.vertex_shader.path : "nil"
|
||||
|
||||
for u, i in node.uniforms {
|
||||
switch &t in u {
|
||||
case Uniform_Texture: {
|
||||
if mat.texture_count > MATERIAL_MAX_TEXTURES {
|
||||
continue
|
||||
}
|
||||
|
||||
if set_shader_uniform(node.program, t) {
|
||||
for u in node.uniforms {
|
||||
if t, is_texture := u.(Uniform_Texture); is_texture {
|
||||
mat.textures[mat.texture_count] = t.value
|
||||
mat.texture_count += 1
|
||||
}
|
||||
else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activate_fullscreen_material(renderer, &mat)
|
||||
@@ -326,6 +323,10 @@ execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing
|
||||
}
|
||||
|
||||
destroy :: proc(renderer: ^Renderer) {
|
||||
delete_mesh(renderer, &renderer.default_cube_mesh)
|
||||
delete_mesh(renderer, &renderer.default_quad_world_mesh)
|
||||
delete_mesh(renderer, &renderer.default_sphere_mesh)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_destroy(renderer)
|
||||
}
|
||||
@@ -334,9 +335,20 @@ destroy :: proc(renderer: ^Renderer) {
|
||||
free(renderer)
|
||||
}
|
||||
|
||||
@(private) activate_shader_program :: proc(program: ^Shader_Program) {
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_activate_shader_program(program)
|
||||
}
|
||||
}
|
||||
|
||||
@(private) activate_material :: proc(material: ^Material, model_matrix, view_matrix, projection_matrix: linalg.Matrix4x4f32, uv_scale: [2]f32 = { 1.0, 1.0 }) {
|
||||
assert(material != nil)
|
||||
|
||||
p := material.shader_program
|
||||
|
||||
activate_shader_program(p)
|
||||
set_shader_uniforms(material.shader_program, material.uniforms)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_activate_material(material, model_matrix, view_matrix, projection_matrix)
|
||||
}
|
||||
@@ -364,7 +376,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) {
|
||||
// TODO: SS - Set the pass' 'renderer' variable here instead?
|
||||
switch pass.sort_mode {
|
||||
case .None: {}
|
||||
case .Back_To_Front: {
|
||||
@@ -424,6 +443,11 @@ distance_to_camera :: proc(camera: ^Camera, position: [3]f32) -> f32 {
|
||||
|
||||
@(private) activate_fullscreen_material :: proc(renderer: ^Renderer, material: ^Material) { // TODO: SS - Maybe remove.
|
||||
assert(renderer != nil)
|
||||
assert(material != nil)
|
||||
assert(material.shader_program != nil)
|
||||
|
||||
activate_shader_program(material.shader_program)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_activate_fullscreen_material(material)
|
||||
}
|
||||
@@ -435,3 +459,11 @@ distance_to_camera :: proc(camera: ^Camera, position: [3]f32) -> f32 {
|
||||
opengl_deactivate_fullscreen_material()
|
||||
}
|
||||
}
|
||||
|
||||
@(private) apply_polygon_mode :: proc(renderer: ^Renderer, mode: Polygon_Mode) {
|
||||
assert(renderer != nil)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_apply_polygon_mode(renderer, mode)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#+private
|
||||
package renderer
|
||||
|
||||
import "core:log"
|
||||
import "core:math/linalg"
|
||||
import "core:bytes"
|
||||
import "core:slice"
|
||||
@@ -89,43 +90,50 @@ when RENDER_BACKEND_OPENGL {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
opengl_viewport_changed :: proc(renderer: ^Renderer) {
|
||||
@(private) opengl_apply_renderer_viewport :: proc(renderer: ^Renderer) {
|
||||
gl.Viewport(
|
||||
i32(renderer.viewport.x), i32(renderer.viewport.y),
|
||||
i32(renderer.viewport.width), i32(renderer.viewport.height)
|
||||
i32(renderer.viewport.res.width), i32(renderer.viewport.res.height)
|
||||
)
|
||||
}
|
||||
|
||||
opengl_viewport_changed :: proc(renderer: ^Renderer) {
|
||||
opengl_apply_renderer_viewport(renderer)
|
||||
}
|
||||
|
||||
opengl_set_vsync :: proc(renderer: ^Renderer, on: bool) -> bool {
|
||||
if win.wglSwapIntervalEXT == nil {
|
||||
fmt.printfln("'wglSwapIntervalEXT' is nil.")
|
||||
return false
|
||||
}
|
||||
|
||||
// Kommer inte in hit.
|
||||
win.wglSwapIntervalEXT(on ? 1 : 0)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
opengl_set_clear_color :: proc(renderer: ^Renderer, color: Color) {
|
||||
r, g, b, a: u8 = max(u8), max(u8), max(u8), max(u8)
|
||||
r, g, b, a: f32 = 1.0, 1.0, 1.0, 1.0
|
||||
|
||||
switch &c in color {
|
||||
case RGB_Color: r, g, b = expand_values(c.rgb)
|
||||
case RGBA_Color: r, g, b, a = expand_values(c.rgba)
|
||||
case RGB_Color: r, g, b = expand_values(color_to_f32(c))
|
||||
case RGBA_Color: r, g, b, a = expand_values(color_to_f32(c))
|
||||
}
|
||||
|
||||
gl.ClearColor(
|
||||
f32(r) / f32(max(u8)),
|
||||
f32(g) / f32(max(u8)),
|
||||
f32(b) / f32(max(u8)),
|
||||
f32(a) / f32(max(u8)),
|
||||
gl.ClearColor(r, g, b, a)
|
||||
}
|
||||
|
||||
opengl_clear_screen :: proc(renderer: ^Renderer, clear_color, clear_depth, scissor: bool) {
|
||||
if scissor {
|
||||
gl.Enable(gl.SCISSOR_TEST)
|
||||
gl.Scissor(
|
||||
i32(renderer.viewport.x),
|
||||
i32(renderer.viewport.y),
|
||||
i32(renderer.viewport.res.width),
|
||||
i32(renderer.viewport.res.height)
|
||||
)
|
||||
}
|
||||
|
||||
opengl_clear_screen :: proc(renderer: ^Renderer, clear_color: bool, clear_depth: bool) {
|
||||
flags := u32(0)
|
||||
if clear_color {
|
||||
flags |= gl.COLOR_BUFFER_BIT
|
||||
@@ -134,6 +142,10 @@ when RENDER_BACKEND_OPENGL {
|
||||
flags |= gl.DEPTH_BUFFER_BIT
|
||||
}
|
||||
gl.Clear(flags)
|
||||
|
||||
if scissor {
|
||||
gl.Disable(gl.SCISSOR_TEST)
|
||||
}
|
||||
}
|
||||
|
||||
opengl_swap_buffers :: proc(renderer: ^Renderer) {
|
||||
@@ -212,7 +224,19 @@ when RENDER_BACKEND_OPENGL {
|
||||
return m, true
|
||||
}
|
||||
|
||||
opengl_create_shader :: proc(renderer: ^Renderer, type: Shader_Type, data: []u8) -> (Shader_OpenGL, bool) {
|
||||
opengl_delete_mesh :: proc(renderer: ^Renderer, mesh: ^Mesh) {
|
||||
if mesh == nil { return }
|
||||
|
||||
gl.DeleteBuffers(1, &mesh.backend.vbo)
|
||||
gl.DeleteBuffers(1, &mesh.backend.ebo)
|
||||
gl.DeleteVertexArrays(1, &mesh.backend.vao)
|
||||
|
||||
mesh.backend.vbo = 0
|
||||
mesh.backend.ebo = 0
|
||||
mesh.backend.vao = 0
|
||||
}
|
||||
|
||||
opengl_create_shader :: proc(renderer: ^Renderer, type: Shader_Type, path: string, data: []u8) -> (Shader_OpenGL, bool) {
|
||||
handle: u32
|
||||
|
||||
switch type {
|
||||
@@ -237,7 +261,10 @@ when RENDER_BACKEND_OPENGL {
|
||||
gl.GetShaderiv(handle, gl.COMPILE_STATUS, &success)
|
||||
if success != 1 {
|
||||
gl.GetShaderInfoLog(handle, 512, nil, raw_data(&info_log))
|
||||
fmt.printfln("OPENGL: Failed to compile shader of type %v. Log: '%v'.", type, info_log)
|
||||
str := string(transmute(cstring)(&info_log))
|
||||
b := transmute([]u8)str
|
||||
b = b[:len(b) - 1]
|
||||
log.errorf("OPENGL: Failed to compile shader '%v' of type %v. Log: '%v'.", path, type, string(b))
|
||||
|
||||
return {}, false
|
||||
}
|
||||
@@ -263,7 +290,10 @@ when RENDER_BACKEND_OPENGL {
|
||||
gl.GetProgramiv(handle, gl.LINK_STATUS, &success)
|
||||
if success != 1 {
|
||||
gl.GetProgramInfoLog(handle, 512, nil, raw_data(&info_log))
|
||||
fmt.printfln("OPENGL: Failed to create shader-program. Log: '%v'.", info_log)
|
||||
str := string(transmute(cstring)(&info_log))
|
||||
b := transmute([]u8)str
|
||||
b = b[:len(b) - 1]
|
||||
log.errorf("OPENGL: Failed to create shader-program. Log: '%v'.", string(b))
|
||||
|
||||
return {}, false
|
||||
}
|
||||
@@ -290,11 +320,15 @@ when RENDER_BACKEND_OPENGL {
|
||||
}
|
||||
}
|
||||
|
||||
opengl_activate_material :: proc(material: ^Material, model_matrix, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
||||
gl.UseProgram(material.shader_program.backend.handle)
|
||||
opengl_activate_shader_program :: proc(program: ^Shader_Program) {
|
||||
gl.UseProgram(program.backend.handle)
|
||||
}
|
||||
|
||||
opengl_activate_material :: proc(material: ^Material, model_matrix, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
||||
opengl_activate_bind_textures_in_material(material)
|
||||
|
||||
// TODO: SS - Move uniforms up one step to the renderer-agnostic part of the codebase.
|
||||
|
||||
model_matrix_loc := gl.GetUniformLocation(material.shader_program.backend.handle, "in_model_matrix")
|
||||
if model_matrix_loc >= 0 {
|
||||
model_matrix_as_f32_array := transmute([16]f32)(model_matrix)
|
||||
@@ -321,17 +355,8 @@ when RENDER_BACKEND_OPENGL {
|
||||
|
||||
opengl_activate_fullscreen_material :: proc(material: ^Material) { // TODO: SS - Maybe remove.
|
||||
assert(material != nil)
|
||||
gl.UseProgram(material.shader_program.backend.handle)
|
||||
|
||||
assert(material.texture_count > 0)
|
||||
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, material.textures[0].backend.handle)
|
||||
|
||||
loc := gl.GetUniformLocation(material.shader_program.backend.handle, "texture0")
|
||||
if loc != -1 {
|
||||
gl.Uniform1i(loc, 0)
|
||||
}
|
||||
opengl_activate_bind_textures_in_material(material)
|
||||
|
||||
gl.Disable(gl.DEPTH_TEST)
|
||||
gl.DepthMask(gl.FALSE)
|
||||
@@ -520,16 +545,34 @@ 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) {
|
||||
if rt == nil {
|
||||
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
|
||||
|
||||
gl.Viewport(
|
||||
0,
|
||||
0,
|
||||
i32(renderer.viewport.width),
|
||||
i32(renderer.viewport.height),
|
||||
)
|
||||
opengl_apply_renderer_viewport(renderer)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -538,13 +581,20 @@ when RENDER_BACKEND_OPENGL {
|
||||
status := gl.CheckFramebufferStatus(gl.FRAMEBUFFER)
|
||||
assert(status == gl.FRAMEBUFFER_COMPLETE)
|
||||
|
||||
assert(len(rt.color_textures) > 0)
|
||||
texture: ^Texture = nil
|
||||
if len(rt.color_textures) > 0 {
|
||||
texture = rt.color_textures[0]
|
||||
}
|
||||
else {
|
||||
texture = rt.depth_texture
|
||||
}
|
||||
|
||||
assert(texture != nil)
|
||||
gl.Viewport(
|
||||
0,
|
||||
0,
|
||||
i32(rt.color_textures[0].width),
|
||||
i32(rt.color_textures[0].height),
|
||||
i32(texture.width),
|
||||
i32(texture.height),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -599,7 +649,7 @@ when RENDER_BACKEND_OPENGL {
|
||||
|
||||
|
||||
opengl_set_shader_uniform_texture :: proc(program: ^Shader_Program, uniform: Uniform_Texture) -> bool {
|
||||
gl.UseProgram(program.backend.handle)
|
||||
opengl_activate_shader_program(program)
|
||||
|
||||
i := uniform.index
|
||||
|
||||
@@ -617,7 +667,7 @@ when RENDER_BACKEND_OPENGL {
|
||||
}
|
||||
|
||||
opengl_set_shader_uniform_float :: proc(program: ^Shader_Program, uniform: Uniform_Float) -> bool {
|
||||
gl.UseProgram(program.backend.handle)
|
||||
opengl_activate_shader_program(program)
|
||||
|
||||
loc := gl.GetUniformLocation(program.backend.handle, fmt.ctprintf("%v", uniform.name))
|
||||
if loc < 0 {
|
||||
@@ -625,14 +675,14 @@ when RENDER_BACKEND_OPENGL {
|
||||
return false
|
||||
}
|
||||
|
||||
gl.Uniform1f(loc, uniform.value^)
|
||||
gl.Uniform1f(loc, uniform.value)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: SS - This procedure and _float ^^ are very similar and will do pretty much the same thing but with calls to different gl.Uniform-- procedures. Make it generic instead then switch on the type?
|
||||
opengl_set_shader_uniform_matrix4f32 :: proc(program: ^Shader_Program, uniform: Uniform_Matrix4f32) -> bool {
|
||||
gl.UseProgram(program.backend.handle)
|
||||
opengl_activate_shader_program(program)
|
||||
|
||||
loc := gl.GetUniformLocation(program.backend.handle, fmt.ctprintf("%v", uniform.name))
|
||||
if loc < 0 {
|
||||
@@ -640,14 +690,29 @@ when RENDER_BACKEND_OPENGL {
|
||||
return false
|
||||
}
|
||||
|
||||
data := transmute([16]f32)(uniform.value^)
|
||||
data := transmute([16]f32)(uniform.value)
|
||||
gl.UniformMatrix4fv(loc, 1, gl.FALSE, &data[0])
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
opengl_set_shader_uniform_vector2 :: proc(program: ^Shader_Program, uniform: Uniform_Vector2) -> bool {
|
||||
opengl_activate_shader_program(program)
|
||||
|
||||
loc := gl.GetUniformLocation(program.backend.handle, fmt.ctprintf("%v", uniform.name))
|
||||
if loc < 0 {
|
||||
fmt.printfln("vector2 Loc: %v", loc)
|
||||
return false
|
||||
}
|
||||
|
||||
v := transmute([2]f32)uniform.value
|
||||
gl.Uniform2fv(loc, 1, &v[0])
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
opengl_set_shader_uniform_vector3 :: proc(program: ^Shader_Program, uniform: Uniform_Vector3) -> bool {
|
||||
gl.UseProgram(program.backend.handle)
|
||||
opengl_activate_shader_program(program)
|
||||
|
||||
loc := gl.GetUniformLocation(program.backend.handle, fmt.ctprintf("%v", uniform.name))
|
||||
if loc < 0 {
|
||||
@@ -655,9 +720,37 @@ when RENDER_BACKEND_OPENGL {
|
||||
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
|
||||
}
|
||||
|
||||
opengl_apply_polygon_mode :: proc(renderer: ^Renderer, mode: Polygon_Mode) {
|
||||
assert(renderer != nil)
|
||||
|
||||
m: u32 = gl.FILL
|
||||
switch mode {
|
||||
case .Fill: m = gl.FILL
|
||||
case .Line: m = gl.LINE
|
||||
case .Point: m = gl.POINT
|
||||
}
|
||||
|
||||
gl.PolygonMode(gl.FRONT_AND_BACK, m)
|
||||
}
|
||||
}
|
||||
145
shader.odin
145
shader.odin
@@ -33,7 +33,7 @@ create_shader :: proc(renderer: ^Renderer, type: Shader_Type, path: string) -> (
|
||||
s.path = path
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
shader_opengl, ok := opengl_create_shader(renderer, type, bytes)
|
||||
shader_opengl, ok := opengl_create_shader(renderer, type, path, bytes)
|
||||
if !ok {
|
||||
return {}, false
|
||||
}
|
||||
@@ -123,11 +123,43 @@ reload_shader_program :: proc(renderer: ^Renderer, p: ^Shader_Program) -> bool {
|
||||
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_Vector2: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (vector2) '%v' in program (vs: '%s', fs: '%s').", t.name, vs_path, fs_path) }}
|
||||
case Uniform_Vector2_Pointer: { if !set_shader_uniform(program, t) { fmt.printfln("Failed to set uniform (vector2 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_texture,
|
||||
set_shader_uniform_float,
|
||||
set_shader_uniform_float_pointer,
|
||||
set_shader_uniform_matrix4f32,
|
||||
set_shader_uniform_matrix4f32_pointer,
|
||||
set_shader_uniform_vector2,
|
||||
set_shader_uniform_vector2_pointer,
|
||||
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_pointer,
|
||||
}
|
||||
|
||||
set_shader_uniform_texture :: proc(program: ^Shader_Program, uniform: Uniform_Texture) -> bool {
|
||||
@@ -142,13 +174,15 @@ set_shader_uniform_texture :: proc(program: ^Shader_Program, uniform: Uniform_Te
|
||||
return false
|
||||
}
|
||||
|
||||
set_shader_uniform_float :: proc(program: ^Shader_Program, uniform: Uniform_Float) -> bool {
|
||||
assert(program != nil)
|
||||
assert(len(uniform.name) > 0)
|
||||
|
||||
set_shader_uniform_float_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Float_Pointer) -> bool {
|
||||
if uniform.value == nil {
|
||||
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)?
|
||||
|
||||
@@ -159,13 +193,15 @@ set_shader_uniform_float :: proc(program: ^Shader_Program, uniform: Uniform_Floa
|
||||
return false
|
||||
}
|
||||
|
||||
set_shader_uniform_matrix4f32 :: proc(program: ^Shader_Program, uniform: Uniform_Matrix4f32) -> bool {
|
||||
assert(program != nil)
|
||||
assert(len(uniform.name) > 0)
|
||||
|
||||
set_shader_uniform_matrix4f32_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Matrix4f32_Pointer) -> bool {
|
||||
if uniform.value == nil {
|
||||
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)?
|
||||
|
||||
@@ -176,13 +212,34 @@ set_shader_uniform_matrix4f32 :: proc(program: ^Shader_Program, uniform: Uniform
|
||||
return false
|
||||
}
|
||||
|
||||
set_shader_uniform_vector3 :: proc(program: ^Shader_Program, uniform: Uniform_Vector3) -> bool {
|
||||
assert(program != nil)
|
||||
assert(len(uniform.name) > 0)
|
||||
|
||||
set_shader_uniform_vector2_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Vector2_Pointer) -> bool {
|
||||
if uniform.value == nil {
|
||||
return false
|
||||
}
|
||||
return set_shader_uniform(program, Uniform_Vector2 { uniform.name, uniform.value^ })
|
||||
}
|
||||
set_shader_uniform_vector2 :: proc(program: ^Shader_Program, uniform: Uniform_Vector2) -> 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_vector2(program, uniform)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
set_shader_uniform_vector3_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Vector3_Pointer) -> bool {
|
||||
if uniform.value == nil {
|
||||
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)?
|
||||
|
||||
@@ -190,5 +247,67 @@ set_shader_uniform_vector3 :: proc(program: ^Shader_Program, uniform: Uniform_Ve
|
||||
return opengl_set_shader_uniform_vector3(program, uniform)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
set_shader_uniform_vector4_pointer :: proc(program: ^Shader_Program, uniform: Uniform_Vector4_Pointer) -> bool {
|
||||
if uniform.value == nil {
|
||||
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)?
|
||||
|
||||
switch &c in uniform.value {
|
||||
case RGB_Color: {
|
||||
rgb := color_to_f32(c)
|
||||
|
||||
u := Uniform_Vector3 {
|
||||
name = uniform.name,
|
||||
value = rgb,
|
||||
}
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
return opengl_set_shader_uniform_vector3(program, u)
|
||||
}
|
||||
}
|
||||
case RGBA_Color: {
|
||||
rgba := color_to_f32(c)
|
||||
|
||||
u := Uniform_Vector4 {
|
||||
name = uniform.name,
|
||||
value = rgba,
|
||||
}
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
return opengl_set_shader_uniform_vector4(program, u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user