/** * Copyright (c) 2025 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "screen.h" #include "assert/assert.h" #include "display/spritebatch.h" screen_t SCREEN; void screenInit(void) { // Virtual backbuffer for dynamic resolution scaling #if DISPLAY_SIZE_DYNAMIC == 1 frameBufferInit(&SCREEN.frameBuffer, DISPLAY_WIDTH, DISPLAY_HEIGHT); cameraInit(&SCREEN.frameBufferCamera); SCREEN.frameBufferCamera.projType = CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC; SCREEN.frameBufferCamera.viewType = CAMERA_VIEW_TYPE_MATRIX; glm_lookat( (vec3){0.0f, 0.0f, 1.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){0.0f, 1.0f, 0.0f}, SCREEN.frameBufferCamera.view ); SCREEN.frameBufferCamera.nearClip = -1.0f; SCREEN.frameBufferCamera.farClip = 1.0f; #endif } void screenBind(void) { #if DISPLAY_SIZE_DYNAMIC == 1 frameBufferBind(&SCREEN.frameBuffer); #else frameBufferBind(NULL); #endif frameBufferClear( FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, COLOR_CORNFLOWER_BLUE ); } void screenUnbindAndRender(void) { assertTrue(SPRITEBATCH.spriteCount == 0, "Sprite batch not flushed"); // Render to real backbuffer #if DISPLAY_SIZE_DYNAMIC == 1 frameBufferBind(NULL); frameBufferClear( FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, COLOR_BLACK ); SCREEN.frameBufferCamera.orthographic.left = 0; SCREEN.frameBufferCamera.orthographic.right = frameBufferGetWidth( FRAMEBUFFER_BOUND ); SCREEN.frameBufferCamera.orthographic.bottom = frameBufferGetHeight( FRAMEBUFFER_BOUND ); SCREEN.frameBufferCamera.orthographic.top = 0; cameraPushMatrix(&SCREEN.frameBufferCamera); vec2 backbuffer = { (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND), (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND) }; vec2 virtual = { (float_t)frameBufferGetWidth(&SCREEN.frameBuffer), (float_t)frameBufferGetHeight(&SCREEN.frameBuffer) }; // Compare aspect ratios. vec4 viewport; float_t backbufferAspect = backbuffer[0] / backbuffer[1]; float_t virtualAspect = virtual[0] / virtual[1]; if (backbufferAspect > virtualAspect) { // Backbuffer is wider: pillarbox float_t scale = backbuffer[1] / virtual[1]; float_t width = virtual[0] * scale; viewport[0] = (backbuffer[0] - width) * 0.5f; viewport[1] = 0; viewport[2] = width; viewport[3] = backbuffer[1]; } else { // Backbuffer is taller: letterbox float_t scale = backbuffer[0] / virtual[0]; float_t height = virtual[1] * scale; viewport[0] = 0; viewport[1] = (backbuffer[1] - height) * 0.5f; viewport[2] = backbuffer[0]; viewport[3] = height; } spriteBatchPush( &SCREEN.frameBuffer.texture, viewport[0], viewport[1], viewport[0] + viewport[2], viewport[1] + viewport[3], COLOR_WHITE, 0.0f, 1.0f, 1.0f, 0.0f ); spriteBatchFlush(); cameraPopMatrix(); #endif } void screenDispose(void) { frameBufferDispose(&SCREEN.frameBuffer); }