package renderer import "core:fmt" MAX_DRAW_COMMANDS_CAPACITY :: 4096 PASS_MAX_INPUT_TEXTURES :: 8 Scene_Pass :: struct { name: string, input_textures: [PASS_MAX_INPUT_TEXTURES]^Texture, // TODO: SS - Make this a map? input_texture_count: u8, output_rt: ^Render_Target, draw_commands: [dynamic]Draw_Command, // Capacity is 'MAX_DRAW_COMMANDS_CAPACITY'. clear_color: Maybe(RGB_Color), blend_mode: Blend_Mode, sort_mode: Sort_Mode, } Post_Processing_Pass :: struct { name: string, input_texture: ^Texture, // TODO: SS - Make this an array of texture-pointers, or maybe a map. input_depth_texture: ^Texture, output_rt: ^Render_Target, shader_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, input_textures: []^Texture, output_rt: ^Render_Target, clear_color: Maybe(RGB_Color), blend_mode: Blend_Mode, sort_mode: Sort_Mode, ) -> Scene_Pass { // if input_depth_texture == nil { // if test_depth || clear_depth || write_depth { // assert(false) // } // } p := Scene_Pass { name = name, output_rt = output_rt, draw_commands = make([dynamic]Draw_Command, 0, MAX_DRAW_COMMANDS_CAPACITY), clear_color = clear_color, blend_mode = blend_mode, sort_mode = sort_mode, } for texture, i in input_textures { if p.input_texture_count >= PASS_MAX_INPUT_TEXTURES { fmt.printfln("Hit max capacity of textures per pass.") break } p.input_textures[p.input_texture_count] = texture p.input_texture_count += 1 } return p } create_post_processing_pass :: proc( name: string, input_texture, input_depth_texture: ^Texture, output_rt: ^Render_Target, shader_program: Shader_Program, ) -> Post_Processing_Pass { return { name = name, input_texture = input_texture, input_depth_texture = input_depth_texture, output_rt = output_rt, shader_program = shader_program, } } delete_pass :: proc { delete_scene_pass, } @(private) delete_scene_pass :: proc(pass: ^Scene_Pass) { delete(pass.draw_commands) } add_command_to_pass :: proc(renderer: ^Renderer, pass: ^Scene_Pass, command: Draw_Command) -> bool { assert(renderer != nil) assert(pass != nil) cmd := command cmd.renderer = renderer n, err := append(&pass.draw_commands, cmd) assert(err == .None) return true }