Files
renderer/pass.odin
2026-01-31 02:31:19 +01:00

166 lines
4.0 KiB
Odin

package renderer
import "core:fmt"
MAX_DRAW_COMMANDS_CAPACITY :: 4096
MAX_POST_PROCESS_NODES_PER_PASS :: 8
Pass :: struct {
name: string,
type: Pass_Type,
}
Pass_Type :: union {
Scene_Pass,
Post_Processing_Pass,
}
Scene_Pass :: struct {
blend_mode: Blend_Mode,
sort_mode: Sort_Mode,
draw_commands: [dynamic]Draw_Command, // Capacity is 'MAX_DRAW_COMMANDS_CAPACITY'.
output_rt: ^Render_Target, // Commands draw to this render-target.
}
Post_Processing_Pass :: struct {
post_processing_nodes: [dynamic]Post_Processing_Node, // These nodes are executed after all commands have been drawn onto the render-target.
}
Post_Processing_Node :: struct {
input: []^Texture,
output: ^Render_Target,
program: ^Shader_Program,
}
Draw_Command :: struct {
renderer: ^Renderer, // Needed for sorting.
mesh: Mesh,
material: Material,
position: [3]f32,
rotation: [3]f32,
scale: [3]f32,
}
Blend_Mode :: enum {
None,
Alpha,
Additive,
Multiply,
}
Blend_Factor :: enum {
Zero,
One,
Src_Color,
One_Minus_Src_Color,
Dst_Color,
One_Minus_Dst_Color,
Src_Alpha,
One_Minus_Src_Alpha,
Dst_Alpha,
One_Minus_Dst_Alpha,
// ..
}
Blend_Factors :: struct {
source, destination: Blend_Factor
}
@(private) BLEND_FACTOR_TABLE :: [Blend_Mode]Blend_Factors {
.None = { .One, .Zero },
.Alpha = { .Src_Alpha, .One_Minus_Src_Alpha },
.Additive = { .Src_Alpha, .One },
.Multiply = { .Dst_Color, .Zero },
}
Sort_Mode :: enum {
None, // Draws the commands in the order they're placed in the 'draw_commmands' array.
Back_To_Front, // Sorts the commands in the 'draw_commmands' array (from back to front) before drawing them.
Front_To_Back, // Sorts the commands in the 'draw_commmands' array (from front to back) before drawing them.
}
create_scene_pass :: proc(
name: string,
blend_mode: Blend_Mode,
sort_mode: Sort_Mode,
output_rt: ^Render_Target,
) -> Pass
{
assert(len(name) > 0)
p: Pass
p.name = name
p.type = Scene_Pass {
blend_mode = blend_mode,
sort_mode = sort_mode,
draw_commands = make([dynamic]Draw_Command, 0, MAX_DRAW_COMMANDS_CAPACITY),
output_rt = output_rt,
}
return p
}
create_post_processing_pass :: proc(name: string, post_processing_nodes: []Post_Processing_Node) -> Pass {
assert(len(name) > 0)
p: Pass
p.name = name
ppp := Post_Processing_Pass {
post_processing_nodes = make([dynamic]Post_Processing_Node, 0, MAX_POST_PROCESS_NODES_PER_PASS)
}
append(&ppp.post_processing_nodes, ..post_processing_nodes)
p.type = ppp
return p
}
delete_pass :: proc(pass: ^Pass) {
assert(pass != nil)
switch &t in &pass.type {
case Scene_Pass: delete_scene_pass(&t)
case Post_Processing_Pass: delete_post_processing_pass(&t)
}
}
@(private) delete_scene_pass :: proc(pass: ^Scene_Pass) {
delete(pass.draw_commands)
}
@(private) delete_post_processing_pass :: proc(pass: ^Post_Processing_Pass) {
delete(pass.post_processing_nodes)
}
add_command_to_pass :: proc(renderer: ^Renderer, pass: ^Pass, command: Draw_Command) -> bool {
assert(renderer != nil)
assert(pass != nil)
switch &t in &pass.type {
case Post_Processing_Pass: {
fmt.printfln("Can't add commands to a post-processing pass.")
return false
}
case Scene_Pass: {
if t.output_rt == nil {
fmt.printfln("Pass '%v' does not have a output render-target so you're not allowed to add commands to it.", pass.name)
return false
}
cmd := command
cmd.renderer = renderer
n, err := append(&t.draw_commands, cmd)
assert(err == .None)
}
}
return true
}