Letterbox, maintain render-resolution's aspect ratio
This commit is contained in:
122
renderer.odin
122
renderer.odin
@@ -12,7 +12,10 @@ RENDER_BACKEND_DIRECTX11 :: #config(RENDER_BACKEND_DIRECTX11, false)
|
||||
RENDER_BACKEND_METAL :: #config(RENDER_BACKEND_METAL, false)
|
||||
|
||||
Renderer :: struct {
|
||||
render_resolution: Resolution,
|
||||
viewport: Viewport,
|
||||
backbuffer: Backbuffer,
|
||||
|
||||
surface_ptr: rawptr,
|
||||
vsync: bool,
|
||||
backend: rawptr,
|
||||
@@ -37,19 +40,44 @@ Polygon_Mode :: enum {
|
||||
Point,
|
||||
}
|
||||
|
||||
Resolution :: struct {
|
||||
width, height: u16,
|
||||
}
|
||||
|
||||
Backbuffer :: struct {
|
||||
resolution: Resolution,
|
||||
}
|
||||
|
||||
Viewport :: struct {
|
||||
x, y, width, height: u16,
|
||||
x, y: u16,
|
||||
res: Resolution,
|
||||
}
|
||||
|
||||
get_aspect_ratio :: proc(renderer: ^Renderer) -> f32 {
|
||||
Aspect_Ratio_Type :: enum { // TODO: SS - Rename?
|
||||
Render,
|
||||
Backbuffer,
|
||||
Viewport,
|
||||
}
|
||||
get_aspect_ratio :: proc(renderer: ^Renderer, type: Aspect_Ratio_Type) -> f32 {
|
||||
assert(renderer != nil)
|
||||
|
||||
res: Resolution
|
||||
switch type {
|
||||
case .Render: res = renderer.render_resolution
|
||||
case .Backbuffer: res = renderer.backbuffer.resolution
|
||||
case .Viewport: res = renderer.viewport.res
|
||||
}
|
||||
|
||||
viewport := &renderer.viewport
|
||||
return f32(viewport.width) / f32(viewport.height)
|
||||
return f32(res.width) / f32(res.height)
|
||||
}
|
||||
|
||||
create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
|
||||
create :: proc(render_resolution: Resolution, surface_ptr: rawptr) -> (^Renderer, bool) {
|
||||
if render_resolution.width == 0 || render_resolution.height == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
renderer := new(Renderer)
|
||||
renderer.render_resolution = render_resolution
|
||||
renderer.surface_ptr = surface_ptr
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
@@ -119,21 +147,37 @@ create :: proc(surface_ptr: rawptr) -> (^Renderer, bool) {
|
||||
return renderer, true
|
||||
}
|
||||
|
||||
set_viewport :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
||||
log.infof("Setting viewport to %v:%v, %vx%v.", x, y, width, height)
|
||||
set_backbuffer_resolution :: proc(renderer: ^Renderer, res: Resolution) {
|
||||
assert(renderer != nil)
|
||||
renderer.backbuffer.resolution = res
|
||||
}
|
||||
|
||||
renderer.viewport = {
|
||||
x = x,
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
}
|
||||
set_viewport :: proc {
|
||||
set_viewport_with_viewport,
|
||||
set_viewport_with_x_y_w_h,
|
||||
}
|
||||
|
||||
set_viewport_with_viewport :: proc(renderer: ^Renderer, viewport: Viewport) {
|
||||
assert(renderer != nil)
|
||||
|
||||
// log.infof("Setting viewport to %v:%v, %vx%v.", viewport.x, viewport.y, viewport.res.width, viewport.res.height)
|
||||
|
||||
renderer.viewport = viewport
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_viewport_changed(renderer)
|
||||
}
|
||||
}
|
||||
|
||||
set_viewport_with_x_y_w_h :: proc(renderer: ^Renderer, x, y, width, height: u16) {
|
||||
assert(renderer != nil)
|
||||
|
||||
set_viewport_with_viewport(renderer, Viewport {
|
||||
x, y,
|
||||
{ width, height }
|
||||
})
|
||||
}
|
||||
|
||||
set_vsync :: proc(renderer: ^Renderer, on: bool) {
|
||||
assert(renderer != nil)
|
||||
|
||||
@@ -158,9 +202,9 @@ set_vsync :: proc(renderer: ^Renderer, on: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
@(private) clear_screen :: proc(renderer: ^Renderer, clear_color: bool, clear_depth: bool) {
|
||||
@(private) clear_screen :: proc(renderer: ^Renderer, clear_color, clear_depth, scissor: bool) {
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_clear_screen(renderer, clear_color, clear_depth)
|
||||
opengl_clear_screen(renderer, clear_color, clear_depth, scissor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,25 +217,51 @@ render_frame :: proc(renderer: ^Renderer, texture_to_present: ^Texture, clear_co
|
||||
camera_view_matrix, _ := get_camera_view_matrix(renderer.active_camera)
|
||||
camera_projection_matrix, _ := get_camera_projection_matrix(renderer, renderer.active_camera)
|
||||
|
||||
set_clear_color(renderer, clear_color)
|
||||
clear_screen(renderer, true, true)
|
||||
|
||||
for i in 0 ..< renderer.pipeline.amount_of_passes {
|
||||
execute_pass(renderer, renderer.pipeline.passes[i], camera_view_matrix, camera_projection_matrix)
|
||||
}
|
||||
|
||||
apply_polygon_mode(renderer, .Fill)
|
||||
|
||||
|
||||
if texture_to_present != nil { // Present.
|
||||
// Bind to the screen.
|
||||
bind_render_target(renderer, nil)
|
||||
|
||||
|
||||
// Disable depth
|
||||
apply_depth(renderer, false, false)
|
||||
|
||||
compute_letterboxed_viewport :: proc(backbuffer: Resolution, render: Resolution) -> Viewport {
|
||||
bb_w, bb_h := expand_values(backbuffer)
|
||||
r_w, r_h := expand_values(render)
|
||||
|
||||
bb_aspect := f32(bb_w) / f32(bb_h)
|
||||
r_aspect := f32(r_w) / f32(r_h)
|
||||
|
||||
if bb_aspect > r_aspect {
|
||||
// Pillarbox.
|
||||
h := bb_h
|
||||
w := u16(f32(h) * r_aspect)
|
||||
x := (bb_w - w) / 2
|
||||
|
||||
return { x, 0, { w, h } }
|
||||
} else {
|
||||
// Letterbox.
|
||||
w := bb_w
|
||||
h := u16(f32(w) / r_aspect)
|
||||
y := (bb_h - h) / 2
|
||||
|
||||
return { 0, y, { w, h } }
|
||||
}
|
||||
}
|
||||
|
||||
// Clear
|
||||
set_viewport(renderer, 0, 0, renderer.backbuffer.resolution.width, renderer.backbuffer.resolution.height)
|
||||
set_clear_color(renderer, RGB_Color{ 0, 0, 0 })
|
||||
clear_screen(renderer, true, false, false)
|
||||
|
||||
set_viewport(renderer, compute_letterboxed_viewport(renderer.backbuffer.resolution, renderer.render_resolution))
|
||||
set_clear_color(renderer, clear_color)
|
||||
clear_screen(renderer, true, true)
|
||||
clear_screen(renderer, true, true, true)
|
||||
|
||||
// Create a temporary Material.
|
||||
mat := Material {
|
||||
@@ -230,8 +300,6 @@ execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing
|
||||
defer bind_render_target(renderer, nil)
|
||||
|
||||
apply_depth(renderer, false, false)
|
||||
set_clear_color(renderer, RGBA_Color { 0, 0, 0, 0 })
|
||||
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)
|
||||
|
||||
@@ -252,13 +320,13 @@ execute_post_processing_node :: proc(renderer: ^Renderer, node: ^Post_Processing
|
||||
}
|
||||
|
||||
destroy :: proc(renderer: ^Renderer) {
|
||||
delete_mesh(renderer, &renderer.default_cube_mesh)
|
||||
delete_mesh(renderer, &renderer.default_quad_mesh)
|
||||
delete_mesh(renderer, &renderer.default_sphere_mesh)
|
||||
|
||||
when RENDER_BACKEND_OPENGL {
|
||||
opengl_destroy(renderer)
|
||||
}
|
||||
|
||||
// TODO: SS - Destroy 'default_cube_mesh'
|
||||
// TODO: SS - Destroy 'default_quad_mesh'
|
||||
// TODO: SS - Destroy 'default_sphere_mesh'
|
||||
|
||||
assert(renderer != nil)
|
||||
free(renderer)
|
||||
|
||||
Reference in New Issue
Block a user