140 lines
3.5 KiB
Odin
140 lines
3.5 KiB
Odin
package renderer
|
|
|
|
import "core:math/linalg"
|
|
import "core:fmt"
|
|
import "core:log"
|
|
|
|
RENDER_BACKEND_OPENGL :: #config(RENDER_BACKEND_OPENGL, false)
|
|
RENDER_BACKEND_VULKAN :: #config(RENDER_BACKEND_VULKAN, false)
|
|
RENDER_BACKEND_DIRECTX11 :: #config(RENDER_BACKEND_DIRECTX11, false)
|
|
RENDER_BACKEND_METAL :: #config(RENDER_BACKEND_METAL, false)
|
|
|
|
Renderer :: struct {
|
|
viewport: Viewport,
|
|
surface_ptr: rawptr,
|
|
backend: rawptr,
|
|
|
|
pipeline: Pipeline,
|
|
}
|
|
|
|
Viewport :: struct {
|
|
x, y, width, height: u16,
|
|
}
|
|
|
|
RGB_Color :: [3]u8
|
|
RGBA_Color :: [4]u8
|
|
|
|
create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
|
|
renderer := new(Renderer)
|
|
renderer.surface_ptr = surface_ptr
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
if !opengl_init(renderer) {
|
|
fmt.printfln("Failed to initialize OpenGL.")
|
|
destroy(renderer)
|
|
return nil, false
|
|
}
|
|
}
|
|
else {
|
|
destroy(renderer)
|
|
|
|
fmt.printfln("Unhandled backend or no backend selected.")
|
|
return nil, false
|
|
}
|
|
|
|
return renderer, true
|
|
}
|
|
|
|
set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
|
fmt.printfln("Setting viewport to %v:%v, %vx%v.", x, y, width, height)
|
|
|
|
renderer.viewport = {
|
|
x = x,
|
|
y = y,
|
|
width = width,
|
|
height = height,
|
|
}
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_viewport_changed(renderer)
|
|
}
|
|
}
|
|
|
|
@(private="file") set_clear_color :: proc(renderer: ^Renderer, color: RGB_Color) {
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_set_clear_color(renderer, color)
|
|
}
|
|
}
|
|
|
|
@(private="file") clear_screen :: proc(renderer: ^Renderer) { // TODO: SS - Add options here to say if you want to clear depth or not, for example.
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_clear_screen(renderer)
|
|
}
|
|
}
|
|
|
|
render_frame :: proc(renderer: ^Renderer) {
|
|
pipeline := &renderer.pipeline
|
|
for i in 0 ..< pipeline.amount_of_passes {
|
|
pass := pipeline.passes[i]
|
|
|
|
set_clear_color(renderer, pass.clear_color)
|
|
clear_screen(renderer)
|
|
|
|
for i in 0..<pass.draw_command_count {
|
|
command := &pass.draw_commands[i]
|
|
|
|
transform := linalg.identity(linalg.Matrix4x4f32)
|
|
|
|
scale := linalg.matrix4_scale(command.scale)
|
|
rotation := linalg.matrix4_rotate(0, [3]f32 { 0, 0, 1 })
|
|
translation := linalg.matrix4_translate(command.position)
|
|
|
|
// Scale.
|
|
transform *= scale
|
|
|
|
// Rotate.
|
|
transform *= rotation
|
|
|
|
// Translate.
|
|
transform *= translation
|
|
|
|
activate_material(&command.material, transform)
|
|
|
|
draw_mesh(&command.mesh)
|
|
}
|
|
|
|
// TODO: SS - "Deactivate" the pass.
|
|
|
|
// Clear the pass' draw-commands.
|
|
pass.draw_command_count = 0
|
|
}
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_swap_buffers(renderer)
|
|
}
|
|
}
|
|
|
|
destroy :: proc(renderer: ^Renderer) {
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_destroy(renderer)
|
|
}
|
|
|
|
assert(renderer != nil)
|
|
free(renderer)
|
|
}
|
|
|
|
@(private) activate_material :: proc(material: ^Material, transform: linalg.Matrix4x4f32) {
|
|
assert(material != nil)
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_activate_material(material, transform)
|
|
}
|
|
}
|
|
|
|
@(private) draw_mesh :: proc(mesh: ^Mesh) {
|
|
assert(mesh != nil)
|
|
|
|
when RENDER_BACKEND_OPENGL {
|
|
opengl_draw_mesh(mesh)
|
|
}
|
|
} |