diff --git a/camera.odin b/camera.odin new file mode 100644 index 0000000..a945c91 --- /dev/null +++ b/camera.odin @@ -0,0 +1,62 @@ +package renderer + +import "core:math/linalg" + +Camera :: struct { + position: [3]f32, + forward, up: [3]f32, + + fov: f32, + near, far: f32, + + yaw, pitch: f32, +} + +create_camera :: proc(renderer: ^Renderer, position: [3]f32, forward, up: [3]f32, fov, near, far: f32) -> Camera { + c: Camera + c.position = position + c.forward = forward + c.up = up + c.fov = fov + c.near = near + c.far = far + + assert(c.forward != {}) + assert(c.up != {}) + assert(fov > 0) + assert(near > 0) + assert(far > 0) + + return c +} + +get_camera_view_matrix :: proc(camera: ^Camera) -> (linalg.Matrix4f32, bool) { + if camera == nil { + return {}, false + } + + center := camera.position + camera.forward + view_matrix := linalg.identity(linalg.Matrix4x4f32) + view_matrix *= linalg.matrix4_look_at_f32(camera.position, center, camera.up) + + return view_matrix, true +} + +get_camera_projection_matrix :: proc(renderer: ^Renderer, camera: ^Camera) -> (linalg.Matrix4f32, bool) { + if camera == nil { + return {}, false + } + + projection_matrix := linalg.identity(linalg.Matrix4x4f32) + projection_matrix *= linalg.matrix4_perspective(camera.fov, get_aspect_ratio(renderer), camera.near, camera.far) + + return projection_matrix, true +} + +set_active_camera :: proc(renderer: ^Renderer, camera: ^Camera) { + renderer.active_camera = camera +} + +get_active_camera :: proc(renderer: ^Renderer) -> ^Camera { + return renderer.active_camera +} \ No newline at end of file diff --git a/pass.odin b/pass.odin index fa4f249..8b780a3 100644 --- a/pass.odin +++ b/pass.odin @@ -8,6 +8,9 @@ Pass :: struct { name: string, clear_color: RGB_Color, + should_test_depth: bool, + should_clear_depth: bool, + draw_commands: [MAX_DRAW_COMMANDS_PER_PASS]Draw_Command, draw_command_count: u32, } diff --git a/renderer.odin b/renderer.odin index 1be885d..df1ee68 100644 --- a/renderer.odin +++ b/renderer.odin @@ -15,12 +15,21 @@ Renderer :: struct { backend: rawptr, pipeline: Pipeline, + + active_camera: ^Camera, } Viewport :: struct { x, y, width, height: u16, } +get_aspect_ratio :: proc(renderer: ^Renderer) -> f32 { + assert(renderer != nil) + + viewport := &renderer.viewport + return f32(viewport.width) / f32(viewport.height) +} + RGB_Color :: [3]u8 RGBA_Color :: [4]u8 @@ -46,7 +55,7 @@ create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) { } set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) { - fmt.printfln("Setting viewport to %v:%v, %vx%v.", x, y, width, height) + log.infof("Setting viewport to %v:%v, %vx%v.", x, y, width, height) renderer.viewport = { x = x, @@ -66,39 +75,50 @@ set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) { } } -@(private="file") clear_screen :: proc(renderer: ^Renderer) { // TODO: SS - Add options here to say if you want to clear depth or not, for example. +@(private="file") clear_screen :: proc(renderer: ^Renderer, clear_depth: bool) { when RENDER_BACKEND_OPENGL { - opengl_clear_screen(renderer) + opengl_clear_screen(renderer, clear_depth) } } render_frame :: proc(renderer: ^Renderer) { + if renderer.active_camera == nil { + fmt.printfln("No active camera!") + return + } + + view_matrix, view_matrix_ok := get_camera_view_matrix(renderer.active_camera) + assert(view_matrix_ok) + projection_matrix, projection_matrix_ok := get_camera_projection_matrix(renderer, renderer.active_camera) + assert(projection_matrix_ok) + 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) + clear_screen(renderer, pass.should_clear_depth) + enable_depth_testing(renderer, pass.should_test_depth) for i in 0..