Restructured passes
This commit is contained in:
@@ -1,16 +1,41 @@
|
|||||||
package renderer
|
package renderer
|
||||||
|
|
||||||
|
import "core:log"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
MATERIAL_MAX_TEXTURES :: 32
|
||||||
|
|
||||||
Material :: struct {
|
Material :: struct {
|
||||||
// 'Name'?
|
// TODO: SS - 'Name'?
|
||||||
shader_program: ^Shader_Program,
|
shader_program: ^Shader_Program,
|
||||||
texture: ^Texture, // Diffuse, normal etc later.
|
|
||||||
// uniforms, textures, etc.
|
textures: [MATERIAL_MAX_TEXTURES]^Texture,
|
||||||
|
texture_count: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
create_material :: proc(program: ^Shader_Program, texture0: ^Texture) -> (Material, bool) {
|
create_material :: proc(program: ^Shader_Program, textures: []^Texture) -> (Material, bool) {
|
||||||
m: Material
|
m: Material
|
||||||
m.shader_program = program
|
m.shader_program = program
|
||||||
m.texture = texture0
|
|
||||||
|
for t, i in textures {
|
||||||
|
if t == nil {
|
||||||
|
log.warnf("Found nil texture at index %v in when creating material.", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.texture_count >= MATERIAL_MAX_TEXTURES {
|
||||||
|
log.warnf("Too many textures passed when creating material. Max is %v.", MATERIAL_MAX_TEXTURES)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
m.textures[m.texture_count] = t
|
||||||
|
m.texture_count += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.texture_count == 0 {
|
||||||
|
log.warn("No textures passed when creating material.")
|
||||||
|
// TODO: SS - Should we return false here?
|
||||||
|
}
|
||||||
|
|
||||||
return m, true
|
return m, true
|
||||||
}
|
}
|
||||||
128
pass.odin
128
pass.odin
@@ -3,32 +3,36 @@ package renderer
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
MAX_DRAW_COMMANDS_CAPACITY :: 4096
|
MAX_DRAW_COMMANDS_CAPACITY :: 4096
|
||||||
|
MAX_POST_PROCESS_NODES_PER_PASS :: 8
|
||||||
|
|
||||||
PASS_MAX_INPUT_TEXTURES :: 8
|
Pass :: struct {
|
||||||
|
name: string,
|
||||||
|
type: Pass_Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
Pass_Type :: union {
|
||||||
|
Scene_Pass,
|
||||||
|
Post_Processing_Pass,
|
||||||
|
}
|
||||||
|
|
||||||
Scene_Pass :: struct {
|
Scene_Pass :: struct {
|
||||||
name: string,
|
blend_mode: Blend_Mode,
|
||||||
|
sort_mode: Sort_Mode,
|
||||||
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'.
|
draw_commands: [dynamic]Draw_Command, // Capacity is 'MAX_DRAW_COMMANDS_CAPACITY'.
|
||||||
|
|
||||||
clear_color: Maybe(RGB_Color),
|
output_rt: ^Render_Target, // Commands draw to this render-target.
|
||||||
blend_mode: Blend_Mode,
|
|
||||||
sort_mode: Sort_Mode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Post_Processing_Pass :: struct {
|
Post_Processing_Pass :: struct {
|
||||||
name: string,
|
post_processing_nodes: [dynamic]Post_Processing_Node, // These nodes are executed after all commands have been drawn onto the render-target.
|
||||||
|
}
|
||||||
|
|
||||||
input_texture: ^Texture, // TODO: SS - Make this an array of texture-pointers, or maybe a map.
|
Post_Processing_Node :: struct {
|
||||||
input_depth_texture: ^Texture,
|
input: []^Texture,
|
||||||
output_rt: ^Render_Target,
|
output: ^Render_Target,
|
||||||
|
|
||||||
shader_program: Shader_Program,
|
program: ^Shader_Program,
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw_Command :: struct {
|
Draw_Command :: struct {
|
||||||
@@ -81,76 +85,82 @@ Sort_Mode :: enum {
|
|||||||
|
|
||||||
create_scene_pass :: proc(
|
create_scene_pass :: proc(
|
||||||
name: string,
|
name: string,
|
||||||
input_textures: []^Texture,
|
|
||||||
output_rt: ^Render_Target,
|
|
||||||
clear_color: Maybe(RGB_Color),
|
|
||||||
blend_mode: Blend_Mode,
|
blend_mode: Blend_Mode,
|
||||||
sort_mode: Sort_Mode,
|
sort_mode: Sort_Mode,
|
||||||
) -> Scene_Pass
|
output_rt: ^Render_Target,
|
||||||
|
) -> Pass
|
||||||
{
|
{
|
||||||
// if input_depth_texture == nil {
|
assert(len(name) > 0)
|
||||||
// if test_depth || clear_depth || write_depth {
|
|
||||||
// assert(false)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
p := Scene_Pass {
|
p: Pass
|
||||||
name = name,
|
p.name = name
|
||||||
|
p.type = Scene_Pass {
|
||||||
output_rt = output_rt,
|
blend_mode = blend_mode,
|
||||||
|
sort_mode = sort_mode,
|
||||||
|
|
||||||
draw_commands = make([dynamic]Draw_Command, 0, MAX_DRAW_COMMANDS_CAPACITY),
|
draw_commands = make([dynamic]Draw_Command, 0, MAX_DRAW_COMMANDS_CAPACITY),
|
||||||
|
|
||||||
clear_color = clear_color,
|
output_rt = output_rt,
|
||||||
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
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
create_post_processing_pass :: proc(
|
create_post_processing_pass :: proc(name: string, post_processing_nodes: []Post_Processing_Node) -> Pass {
|
||||||
name: string,
|
assert(len(name) > 0)
|
||||||
input_texture, input_depth_texture: ^Texture,
|
|
||||||
output_rt: ^Render_Target,
|
p: Pass
|
||||||
shader_program: Shader_Program,
|
p.name = name
|
||||||
) -> Post_Processing_Pass
|
|
||||||
{
|
ppp := Post_Processing_Pass {
|
||||||
return {
|
post_processing_nodes = make([dynamic]Post_Processing_Node, 0, MAX_POST_PROCESS_NODES_PER_PASS)
|
||||||
name = name,
|
|
||||||
input_texture = input_texture,
|
|
||||||
input_depth_texture = input_depth_texture,
|
|
||||||
output_rt = output_rt,
|
|
||||||
shader_program = shader_program,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_pass :: proc {
|
append(&ppp.post_processing_nodes, ..post_processing_nodes)
|
||||||
delete_scene_pass,
|
|
||||||
|
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) {
|
@(private) delete_scene_pass :: proc(pass: ^Scene_Pass) {
|
||||||
delete(pass.draw_commands)
|
delete(pass.draw_commands)
|
||||||
}
|
}
|
||||||
|
|
||||||
add_command_to_pass :: proc(renderer: ^Renderer, pass: ^Scene_Pass, command: Draw_Command) -> bool {
|
@(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(renderer != nil)
|
||||||
assert(pass != 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 := command
|
||||||
cmd.renderer = renderer
|
cmd.renderer = renderer
|
||||||
n, err := append(&pass.draw_commands, cmd)
|
n, err := append(&t.draw_commands, cmd)
|
||||||
assert(err == .None)
|
assert(err == .None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -2,93 +2,51 @@ package renderer
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
PIPELINE_MAX_SCENE_PASSES :: 8
|
PIPELINE_MAX_PASSES :: 8
|
||||||
PIPELINE_MAX_POST_PROCESSING_PASSES :: 8
|
|
||||||
|
|
||||||
Pipeline :: struct {
|
Pipeline :: struct {
|
||||||
scene_passes: [PIPELINE_MAX_SCENE_PASSES]^Scene_Pass,
|
passes: [PIPELINE_MAX_PASSES]^Pass,
|
||||||
amount_of_scene_passes: u8,
|
amount_of_passes: u8,
|
||||||
|
|
||||||
post_processing_passes: [PIPELINE_MAX_POST_PROCESSING_PASSES]^Post_Processing_Pass,
|
|
||||||
amount_of_post_processing_passes: u8,
|
|
||||||
|
|
||||||
fullscreen_material: ^Material,
|
|
||||||
fullscreen_mesh: ^Mesh,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_pipeline :: proc(renderer: ^Renderer) {
|
clear_pipeline :: proc(renderer: ^Renderer) {
|
||||||
assert(renderer != nil)
|
assert(renderer != nil)
|
||||||
p := &renderer.pipeline
|
p := &renderer.pipeline
|
||||||
|
|
||||||
p.amount_of_scene_passes = 0;
|
p.amount_of_passes = 0;
|
||||||
mem.set(&p.scene_passes[0], 0, PIPELINE_MAX_SCENE_PASSES * size_of(^Scene_Pass))
|
mem.set(&p.passes[0], 0, PIPELINE_MAX_PASSES * size_of(^Scene_Pass))
|
||||||
|
|
||||||
p.amount_of_post_processing_passes = 0;
|
|
||||||
mem.set(&p.post_processing_passes[0], 0, PIPELINE_MAX_POST_PROCESSING_PASSES * size_of(^Post_Processing_Pass))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_pipeline :: proc(
|
set_pipeline :: proc(
|
||||||
renderer: ^Renderer,
|
renderer: ^Renderer,
|
||||||
fullscreen_material: ^Material, fullscreen_mesh: ^Mesh,
|
passes: []^Pass,
|
||||||
scene_passes: []^Scene_Pass,
|
|
||||||
post_processing_passes: []^Post_Processing_Pass,
|
|
||||||
){
|
){
|
||||||
assert(renderer != nil)
|
assert(renderer != nil)
|
||||||
|
|
||||||
clear_pipeline(renderer)
|
clear_pipeline(renderer)
|
||||||
|
|
||||||
renderer.pipeline.fullscreen_material = fullscreen_material
|
for p in passes {
|
||||||
renderer.pipeline.fullscreen_mesh = fullscreen_mesh
|
|
||||||
|
|
||||||
for p in scene_passes {
|
|
||||||
if !add_pass_to_pipeline(renderer, p) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for p in post_processing_passes {
|
|
||||||
if !add_pass_to_pipeline(renderer, p) {
|
if !add_pass_to_pipeline(renderer, p) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_pass_to_pipeline :: proc {
|
add_pass_to_pipeline :: proc(renderer: ^Renderer, pass: ^Pass) -> bool {
|
||||||
add_scene_pass_to_pipeline,
|
|
||||||
add_post_processing_pass_to_pipeline,
|
|
||||||
}
|
|
||||||
|
|
||||||
@(private="file") add_scene_pass_to_pipeline :: proc(renderer: ^Renderer, scene_pass: ^Scene_Pass) -> bool {
|
|
||||||
assert(renderer != nil)
|
assert(renderer != nil)
|
||||||
assert(scene_pass != nil)
|
assert(pass != nil)
|
||||||
|
|
||||||
pipeline := &renderer.pipeline
|
pipeline := &renderer.pipeline
|
||||||
|
|
||||||
if pipeline.amount_of_scene_passes == PIPELINE_MAX_SCENE_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).", scene_pass.name, PIPELINE_MAX_SCENE_PASSES)
|
log.warnf("Failed to add scene-pass '%v' to renderer's pipeline; hit max capacity (%v).", pass.name, PIPELINE_MAX_PASSES)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline.scene_passes[pipeline.amount_of_scene_passes] = scene_pass
|
pipeline.passes[pipeline.amount_of_passes] = pass
|
||||||
pipeline.amount_of_scene_passes += 1
|
pipeline.amount_of_passes += 1
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
@(private="file") add_post_processing_pass_to_pipeline :: proc(renderer: ^Renderer, post_processing_pass: ^Post_Processing_Pass) -> bool {
|
|
||||||
assert(renderer != nil)
|
|
||||||
assert(post_processing_pass != nil)
|
|
||||||
|
|
||||||
pipeline := &renderer.pipeline
|
|
||||||
|
|
||||||
if pipeline.amount_of_post_processing_passes == PIPELINE_MAX_POST_PROCESSING_PASSES {
|
|
||||||
log.warnf("Failed to add post-processing pass '%v' to renderer's pipeline; hit max capacity (%v).", post_processing_pass.name, PIPELINE_MAX_POST_PROCESSING_PASSES)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline.post_processing_passes[pipeline.amount_of_post_processing_passes] = post_processing_pass
|
|
||||||
pipeline.amount_of_post_processing_passes += 1
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
240
renderer.odin
240
renderer.odin
@@ -18,7 +18,11 @@ Renderer :: struct {
|
|||||||
|
|
||||||
pipeline: Pipeline,
|
pipeline: Pipeline,
|
||||||
|
|
||||||
active_camera: ^Camera,
|
active_camera: ^Camera, // NOTE: SS - Hardcoded to 1 active camera. Split-screen is likely not possible due to this. Fix(?).
|
||||||
|
|
||||||
|
fullscreen_vertex_shader, fullscreen_fragment_shader: Shader,
|
||||||
|
fullscreen_shader_program: Shader_Program,
|
||||||
|
fullscreen_mesh: Mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
Viewport :: struct {
|
Viewport :: struct {
|
||||||
@@ -32,6 +36,11 @@ get_aspect_ratio :: proc(renderer: ^Renderer) -> f32 {
|
|||||||
return f32(viewport.width) / f32(viewport.height)
|
return f32(viewport.width) / f32(viewport.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color :: union {
|
||||||
|
RGB_Color,
|
||||||
|
RGBA_Color,
|
||||||
|
}
|
||||||
|
|
||||||
RGB_Color :: [3]u8
|
RGB_Color :: [3]u8
|
||||||
RGBA_Color :: [4]u8
|
RGBA_Color :: [4]u8
|
||||||
|
|
||||||
@@ -53,6 +62,40 @@ create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // 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)
|
||||||
|
|
||||||
|
fs_frag_shader, fs_frag_shader_ok := create_shader(renderer, .Fragment, "fs_frag.glsl")
|
||||||
|
assert(fs_frag_shader_ok)
|
||||||
|
|
||||||
|
fs_program, fs_program_ok := create_shader_program(renderer, &fs_vertex_shader, &fs_frag_shader)
|
||||||
|
assert(fs_program_ok)
|
||||||
|
|
||||||
|
fs_quad_mesh, fs_quad_mesh_created := create_mesh(
|
||||||
|
renderer = renderer,
|
||||||
|
layout = {
|
||||||
|
{ "position", 2, size_of(f32), },
|
||||||
|
},
|
||||||
|
vertices = []f32 {
|
||||||
|
-1, -1,
|
||||||
|
1, -1,
|
||||||
|
1, 1,
|
||||||
|
-1, 1,
|
||||||
|
},
|
||||||
|
indices = []u32 {
|
||||||
|
0, 1, 2,
|
||||||
|
0, 2, 3,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assert(fs_quad_mesh_created)
|
||||||
|
|
||||||
|
renderer.fullscreen_vertex_shader = fs_vertex_shader
|
||||||
|
renderer.fullscreen_fragment_shader = fs_frag_shader
|
||||||
|
renderer.fullscreen_shader_program = fs_program
|
||||||
|
renderer.fullscreen_mesh = fs_quad_mesh
|
||||||
|
}
|
||||||
|
|
||||||
return renderer, true
|
return renderer, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +114,7 @@ set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private="file") set_clear_color :: proc(renderer: ^Renderer, color: RGB_Color) {
|
@(private="file") 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)
|
||||||
}
|
}
|
||||||
@@ -83,7 +126,7 @@ set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_frame :: proc(renderer: ^Renderer) {
|
render_frame :: proc(renderer: ^Renderer, texture_to_present: ^Texture, clear_color: Color) {
|
||||||
if renderer.active_camera == nil {
|
if renderer.active_camera == nil {
|
||||||
fmt.printfln("No active camera!")
|
fmt.printfln("No active camera!")
|
||||||
return
|
return
|
||||||
@@ -92,37 +135,36 @@ render_frame :: proc(renderer: ^Renderer) {
|
|||||||
view_matrix, _ := get_camera_view_matrix(renderer.active_camera)
|
view_matrix, _ := get_camera_view_matrix(renderer.active_camera)
|
||||||
projection_matrix, _ := get_camera_projection_matrix(renderer, renderer.active_camera)
|
projection_matrix, _ := get_camera_projection_matrix(renderer, renderer.active_camera)
|
||||||
|
|
||||||
pipeline := &renderer.pipeline
|
for i in 0 ..< renderer.pipeline.amount_of_passes {
|
||||||
|
execute_pass(renderer, renderer.pipeline.passes[i], view_matrix, projection_matrix)
|
||||||
for i in 0 ..< pipeline.amount_of_scene_passes {
|
|
||||||
execute_scene_pass(renderer, pipeline.scene_passes[i], view_matrix, projection_matrix)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0 ..< pipeline.amount_of_post_processing_passes {
|
if texture_to_present != nil { // Present.
|
||||||
execute_post_processing_pass(renderer, pipeline.post_processing_passes[i], view_matrix, projection_matrix)
|
// Bind to the screen.
|
||||||
|
bind_render_target(renderer, nil)
|
||||||
|
|
||||||
|
// Disable depth
|
||||||
|
apply_depth(renderer, false, false)
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
set_clear_color(renderer, clear_color)
|
||||||
|
clear_screen(renderer, true, true)
|
||||||
|
|
||||||
|
// Create a temporary Material.
|
||||||
|
mat := Material {
|
||||||
|
shader_program = &renderer.fullscreen_shader_program,
|
||||||
|
textures = {
|
||||||
|
0 = texture_to_present,
|
||||||
|
},
|
||||||
|
texture_count = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
bind_render_target(renderer, nil) // Det görs ju här..
|
// Activate.
|
||||||
|
activate_fullscreen_material(renderer, &mat)
|
||||||
|
defer deactivate_fullscreen_material(renderer)
|
||||||
|
|
||||||
if pipeline.fullscreen_material != nil {
|
// Draw.
|
||||||
if pipeline.fullscreen_material.texture != nil {
|
draw_mesh(&renderer.fullscreen_mesh)
|
||||||
activate_fullscreen_material(renderer)
|
|
||||||
|
|
||||||
if pipeline.fullscreen_mesh != nil {
|
|
||||||
draw_mesh(pipeline.fullscreen_mesh)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn("Renderer is missing a fullscreen-mesh.")
|
|
||||||
}
|
|
||||||
|
|
||||||
deactivate_fullscreen_material(renderer)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn("Fullscreen-material does not have a texture.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn("Renderer is missing a fullscreen-material.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
when RENDER_BACKEND_OPENGL {
|
when RENDER_BACKEND_OPENGL {
|
||||||
@@ -130,33 +172,32 @@ render_frame :: proc(renderer: ^Renderer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
execute_scene_pass :: proc(renderer: ^Renderer, pass: ^Scene_Pass, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
execute_pass :: proc(renderer: ^Renderer, pass: ^Pass, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
||||||
// fmt.printfln("Rendering pass '%v' to output_rt %v.", pass.name, pass.output_rt)
|
// fmt.printfln("Executing pass '%v'.", pass.name)
|
||||||
|
|
||||||
// TODO: SS - Use 'pass.input_textures'
|
assert(renderer != nil)
|
||||||
|
assert(pass != nil)
|
||||||
|
|
||||||
assert(pass.output_rt != nil)
|
switch &t in &pass.type {
|
||||||
bind_render_target(renderer, pass.output_rt)
|
case Scene_Pass: {
|
||||||
|
assert(t.output_rt != nil)
|
||||||
|
bind_render_target(renderer, t.output_rt)
|
||||||
|
|
||||||
should_write_depth := pass.output_rt.depth_texture != nil
|
should_write_depth := t.output_rt.depth_texture != nil
|
||||||
should_test_depth := should_write_depth
|
should_test_depth := should_write_depth
|
||||||
should_clear_depth := should_write_depth
|
should_clear_depth := should_write_depth
|
||||||
|
|
||||||
cc, has_clear_color := pass.clear_color.?
|
should_clear_color := true
|
||||||
if has_clear_color {
|
set_clear_color(renderer, RGBA_Color { 0, 0, 0, 0 })
|
||||||
set_clear_color(renderer, cc)
|
|
||||||
}
|
|
||||||
|
|
||||||
should_clear_color := has_clear_color && pass.output_rt.color_texture != nil
|
|
||||||
|
|
||||||
clear_screen(renderer, should_clear_color, should_clear_depth)
|
clear_screen(renderer, should_clear_color, should_clear_depth)
|
||||||
apply_depth(renderer, should_test_depth, should_write_depth)
|
apply_depth(renderer, should_test_depth, should_write_depth)
|
||||||
|
|
||||||
apply_blend_mode(renderer, pass.blend_mode)
|
apply_blend_mode(renderer, t.blend_mode)
|
||||||
|
|
||||||
sort_draw_commands(renderer, pass)
|
sort_draw_commands(renderer, &t)
|
||||||
|
|
||||||
for &dc in &pass.draw_commands { // TODO: SS - Don't think we need the address of the draw-commands.
|
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)
|
model_matrix := linalg.identity(linalg.Matrix4x4f32)
|
||||||
|
|
||||||
// Translate.
|
// Translate.
|
||||||
@@ -178,14 +219,69 @@ execute_scene_pass :: proc(renderer: ^Renderer, pass: ^Scene_Pass, view_matrix,
|
|||||||
draw_mesh(&dc.mesh)
|
draw_mesh(&dc.mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SS - "Deactivate" the pass.
|
|
||||||
|
|
||||||
// Clear the pass' draw-commands.
|
// Clear the pass' draw-commands.
|
||||||
clear(&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)
|
||||||
}
|
}
|
||||||
|
|
||||||
execute_post_processing_pass :: proc(renderer: ^Renderer, pass: ^Post_Processing_Pass, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
// TODO: SS - "Deactivate" the pass?
|
||||||
fmt.printfln("TODO: SS - Execute post-processing pass '%v'.", pass.name)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing_Node, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
||||||
|
assert(renderer != nil)
|
||||||
|
assert(node != nil)
|
||||||
|
assert(node.program != nil)
|
||||||
|
assert(node.output != nil)
|
||||||
|
|
||||||
|
assert(node.output != nil)
|
||||||
|
bind_render_target(renderer, node.output)
|
||||||
|
|
||||||
|
apply_depth(renderer, false, 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)
|
||||||
|
|
||||||
|
t: [MATERIAL_MAX_TEXTURES]^Texture
|
||||||
|
t_count := u8(0)
|
||||||
|
for input_texture, i in node.input {
|
||||||
|
if i > MATERIAL_MAX_TEXTURES {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
set_shader_value(node.program, input_texture, u8(i))
|
||||||
|
t[i] = input_texture
|
||||||
|
t_count += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mat := Material {
|
||||||
|
shader_program = node.program,
|
||||||
|
textures = t,
|
||||||
|
texture_count = t_count,
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_fullscreen_material(renderer, &mat)
|
||||||
|
draw_mesh(&renderer.fullscreen_mesh)
|
||||||
|
}
|
||||||
|
|
||||||
|
set_shader_value :: proc {
|
||||||
|
set_shader_value_texture,
|
||||||
|
}
|
||||||
|
|
||||||
|
set_shader_value_texture :: proc(program: ^Shader_Program, value: ^Texture, index: u8) {
|
||||||
|
assert(program != nil)
|
||||||
|
assert(value != nil)
|
||||||
|
|
||||||
|
when RENDER_BACKEND_OPENGL {
|
||||||
|
opengl_set_shader_value_texture(program, value, index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy :: proc(renderer: ^Renderer) {
|
destroy :: proc(renderer: ^Renderer) {
|
||||||
@@ -205,21 +301,6 @@ destroy :: proc(renderer: ^Renderer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private) activate_fullscreen_material :: proc(renderer: ^Renderer) {
|
|
||||||
assert(renderer != nil)
|
|
||||||
mat := renderer.pipeline.fullscreen_material
|
|
||||||
when RENDER_BACKEND_OPENGL {
|
|
||||||
opengl_activate_fullscreen_material(mat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@(private) deactivate_fullscreen_material :: proc(renderer: ^Renderer) {
|
|
||||||
assert(renderer != nil)
|
|
||||||
when RENDER_BACKEND_OPENGL {
|
|
||||||
opengl_deactivate_fullscreen_material()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@(private) draw_mesh :: proc(mesh: ^Mesh) {
|
@(private) draw_mesh :: proc(mesh: ^Mesh) {
|
||||||
assert(mesh != nil)
|
assert(mesh != nil)
|
||||||
|
|
||||||
@@ -293,24 +374,23 @@ distance_to_camera :: proc(camera: ^Camera, position: [3]f32) -> f32 {
|
|||||||
return linalg.distance(camera.position, position)
|
return linalg.distance(camera.position, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private) bind_framebuffer :: proc(renderer: ^Renderer, rt: ^Render_Target) -> bool {
|
|
||||||
// when RENDER_BACKEND_OPENGL {
|
|
||||||
// return opengl_bind_framebuffer(renderer, rt)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@(private) bind_depth_texture :: proc(renderer: ^Renderer, rt: ^Render_Target) -> bool {
|
|
||||||
// when RENDER_BACKEND_OPENGL {
|
|
||||||
// return opengl_bind_depth_texture(renderer, rt)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@(private) bind_render_target :: proc(renderer: ^Renderer, rt: ^Render_Target) {
|
@(private) bind_render_target :: proc(renderer: ^Renderer, rt: ^Render_Target) {
|
||||||
when RENDER_BACKEND_OPENGL {
|
when RENDER_BACKEND_OPENGL {
|
||||||
opengl_bind_render_target(renderer, rt)
|
opengl_bind_render_target(renderer, rt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(private) activate_fullscreen_material :: proc(renderer: ^Renderer, material: ^Material) { // TODO: SS - Maybe remove.
|
||||||
|
assert(renderer != nil)
|
||||||
|
when RENDER_BACKEND_OPENGL {
|
||||||
|
opengl_activate_fullscreen_material(material)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private) deactivate_fullscreen_material :: proc(renderer: ^Renderer) { // TODO: SS - Maybe remove.
|
||||||
|
assert(renderer != nil)
|
||||||
|
when RENDER_BACKEND_OPENGL {
|
||||||
|
opengl_deactivate_fullscreen_material()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,19 +85,24 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
|
|
||||||
opengl_viewport_changed :: proc(renderer: ^Renderer) {
|
opengl_viewport_changed :: proc(renderer: ^Renderer) {
|
||||||
gl.Viewport(
|
gl.Viewport(
|
||||||
i32(renderer.viewport.x),
|
i32(renderer.viewport.x), i32(renderer.viewport.y),
|
||||||
i32(renderer.viewport.y),
|
i32(renderer.viewport.width), i32(renderer.viewport.height)
|
||||||
i32(renderer.viewport.width),
|
|
||||||
i32(renderer.viewport.height)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
opengl_set_clear_color :: proc(renderer: ^Renderer, color: RGB_Color) {
|
opengl_set_clear_color :: proc(renderer: ^Renderer, color: Color) {
|
||||||
|
r, g, b, a: u8 = max(u8), max(u8), max(u8), max(u8)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
gl.ClearColor(
|
gl.ClearColor(
|
||||||
f32(color.r) / f32(max(u8)),
|
f32(r) / f32(max(u8)),
|
||||||
f32(color.g) / f32(max(u8)),
|
f32(g) / f32(max(u8)),
|
||||||
f32(color.b) / f32(max(u8)),
|
f32(b) / f32(max(u8)),
|
||||||
1.0
|
f32(a) / f32(max(u8)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,33 +258,50 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
gl.DeleteProgram(shader_program.backend.handle)
|
gl.DeleteProgram(shader_program.backend.handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opengl_activate_bind_textures_in_material :: proc(material: ^Material) {
|
||||||
|
assert(material != nil)
|
||||||
|
|
||||||
|
for t, i in material.textures[:material.texture_count] {
|
||||||
|
assert(t != nil)
|
||||||
|
gl.ActiveTexture(gl.TEXTURE0 + u32(i))
|
||||||
|
gl.BindTexture(gl.TEXTURE_2D, t.backend.handle)
|
||||||
|
|
||||||
|
loc := gl.GetUniformLocation(material.shader_program.backend.handle, fmt.ctprintf("texture%d", i))
|
||||||
|
gl.Uniform1i(loc, i32(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
opengl_activate_material :: proc(material: ^Material, model_matrix, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
opengl_activate_material :: proc(material: ^Material, model_matrix, view_matrix, projection_matrix: linalg.Matrix4x4f32) {
|
||||||
gl.UseProgram(material.shader_program.backend.handle)
|
gl.UseProgram(material.shader_program.backend.handle)
|
||||||
|
|
||||||
gl.ActiveTexture(gl.TEXTURE0)
|
opengl_activate_bind_textures_in_material(material)
|
||||||
gl.BindTexture(gl.TEXTURE_2D, material.texture.backend.handle)
|
|
||||||
|
|
||||||
model_matrix_loc := gl.GetUniformLocation(material.shader_program.backend.handle, "in_model_matrix")
|
model_matrix_loc := gl.GetUniformLocation(material.shader_program.backend.handle, "in_model_matrix")
|
||||||
|
assert(model_matrix_loc >= 0)
|
||||||
model_matrix_as_f32_array := transmute([16]f32)(model_matrix)
|
model_matrix_as_f32_array := transmute([16]f32)(model_matrix)
|
||||||
gl.UniformMatrix4fv(model_matrix_loc, 1, false, &model_matrix_as_f32_array[0])
|
gl.UniformMatrix4fv(model_matrix_loc, 1, false, &model_matrix_as_f32_array[0])
|
||||||
|
|
||||||
view_matrix_loc := gl.GetUniformLocation(material.shader_program.backend.handle, "in_view_matrix")
|
view_matrix_loc := gl.GetUniformLocation(material.shader_program.backend.handle, "in_view_matrix")
|
||||||
|
assert(view_matrix_loc >= 0)
|
||||||
view_matrix_as_f32_array := transmute([16]f32)(view_matrix)
|
view_matrix_as_f32_array := transmute([16]f32)(view_matrix)
|
||||||
gl.UniformMatrix4fv(view_matrix_loc, 1, false, &view_matrix_as_f32_array[0])
|
gl.UniformMatrix4fv(view_matrix_loc, 1, false, &view_matrix_as_f32_array[0])
|
||||||
|
|
||||||
projection_matrix_loc := gl.GetUniformLocation(material.shader_program.backend.handle, "in_projection_matrix")
|
projection_matrix_loc := gl.GetUniformLocation(material.shader_program.backend.handle, "in_projection_matrix")
|
||||||
|
assert(projection_matrix_loc >= 0)
|
||||||
projection_matrix_as_f32_array := transmute([16]f32)(projection_matrix)
|
projection_matrix_as_f32_array := transmute([16]f32)(projection_matrix)
|
||||||
gl.UniformMatrix4fv(projection_matrix_loc, 1, false, &projection_matrix_as_f32_array[0])
|
gl.UniformMatrix4fv(projection_matrix_loc, 1, false, &projection_matrix_as_f32_array[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
opengl_activate_fullscreen_material :: proc(material: ^Material) {
|
opengl_activate_fullscreen_material :: proc(material: ^Material) { // TODO: SS - Maybe remove.
|
||||||
assert(material != nil)
|
assert(material != nil)
|
||||||
gl.UseProgram(material.shader_program.backend.handle)
|
gl.UseProgram(material.shader_program.backend.handle)
|
||||||
|
|
||||||
gl.ActiveTexture(gl.TEXTURE0)
|
assert(material.texture_count > 0)
|
||||||
gl.BindTexture(gl.TEXTURE_2D, material.texture.backend.handle)
|
|
||||||
|
|
||||||
loc := gl.GetUniformLocation(material.shader_program.backend.handle, "texture0") // eller "uTex"
|
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 {
|
if loc != -1 {
|
||||||
gl.Uniform1i(loc, 0)
|
gl.Uniform1i(loc, 0)
|
||||||
}
|
}
|
||||||
@@ -288,7 +310,7 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
gl.DepthMask(gl.FALSE)
|
gl.DepthMask(gl.FALSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
opengl_deactivate_fullscreen_material :: proc() {
|
opengl_deactivate_fullscreen_material :: proc() { // TODO: SS - Maybe remove.
|
||||||
gl.DepthMask(gl.TRUE)
|
gl.DepthMask(gl.TRUE)
|
||||||
gl.Enable(gl.DEPTH_TEST)
|
gl.Enable(gl.DEPTH_TEST)
|
||||||
}
|
}
|
||||||
@@ -486,6 +508,8 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gl.BindFramebuffer(gl.FRAMEBUFFER, rt.backend.handle)
|
gl.BindFramebuffer(gl.FRAMEBUFFER, rt.backend.handle)
|
||||||
|
status := gl.CheckFramebufferStatus(gl.FRAMEBUFFER)
|
||||||
|
assert(status == gl.FRAMEBUFFER_COMPLETE)
|
||||||
|
|
||||||
gl.Viewport(
|
gl.Viewport(
|
||||||
0,
|
0,
|
||||||
@@ -529,4 +553,13 @@ when RENDER_BACKEND_OPENGL {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opengl_set_shader_value_texture :: proc(program: ^Shader_Program, value: ^Texture, index: u8) {
|
||||||
|
gl.UseProgram(program.backend.handle)
|
||||||
|
|
||||||
|
gl.ActiveTexture(gl.TEXTURE0 + u32(index))
|
||||||
|
gl.BindTexture(gl.TEXTURE_2D, value.backend.handle)
|
||||||
|
loc := gl.GetUniformLocation(program.backend.handle, fmt.ctprintf("texture%v", index))
|
||||||
|
gl.Uniform1i(loc, i32(index))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package renderer
|
|||||||
import os "core:os/os2"
|
import os "core:os/os2"
|
||||||
|
|
||||||
Shader :: struct {
|
Shader :: struct {
|
||||||
|
path: string,
|
||||||
type: Shader_Type,
|
type: Shader_Type,
|
||||||
backend: Shader_Backend,
|
backend: Shader_Backend,
|
||||||
}
|
}
|
||||||
@@ -27,6 +28,7 @@ create_shader :: proc(renderer: ^Renderer, type: Shader_Type, path: string) -> (
|
|||||||
|
|
||||||
s: Shader
|
s: Shader
|
||||||
s.type = type
|
s.type = type
|
||||||
|
s.path = path
|
||||||
|
|
||||||
when RENDER_BACKEND_OPENGL {
|
when RENDER_BACKEND_OPENGL {
|
||||||
shader_opengl, ok := opengl_create_shader(renderer, type, bytes)
|
shader_opengl, ok := opengl_create_shader(renderer, type, bytes)
|
||||||
|
|||||||
Reference in New Issue
Block a user