From 12c31ba9d11cbe6551e81573e538e55b6e6442bc Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Mon, 6 Oct 2025 15:43:27 -0500 Subject: [PATCH] screen --- src/display/CMakeLists.txt | 1 + src/display/screen.c | 246 +++++++++++++++++++++++- src/display/screen.h | 36 +++- src/game/minesweeper/game.c | 7 + src/game/minesweeper/scene/scenesweep.c | 6 +- src/game/minesweeper/ui/ui.c | 10 +- 6 files changed, 285 insertions(+), 21 deletions(-) diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt index fdeb76e..1f982c7 100644 --- a/src/display/CMakeLists.txt +++ b/src/display/CMakeLists.txt @@ -9,6 +9,7 @@ target_sources(${DUSK_TARGET_NAME} display.c camera.c tileset.c + screen.c ) # Subdirectories diff --git a/src/display/screen.c b/src/display/screen.c index 7e1f524..0f024c2 100644 --- a/src/display/screen.c +++ b/src/display/screen.c @@ -8,23 +8,265 @@ #include "screen.h" #include "assert/assert.h" #include "util/memory.h" +#include "display/mesh/quad.h" + +screen_t SCREEN; void screenInit() { memoryZero(&SCREEN, sizeof(screen_t)); + + #if DISPLAY_SIZE_DYNAMIC == 1 + cameraInitOrthographic(&SCREEN.framebufferCamera); + SCREEN.framebufferCamera.viewType = CAMERA_VIEW_TYPE_2D; + SCREEN.framebufferCamera._2d.position[0] = 0; + SCREEN.framebufferCamera._2d.position[1] = 0; + SCREEN.framebufferCamera._2d.zoom = 1.0f; + + quadBuffer( + SCREEN.frameBufferMeshVertices, + 0.0f, 0.0f, + 1.0f, 1.0f, + COLOR_WHITE, + 0.0f, 0.0f, + 1.0f, 1.0f + ); + meshInit( + &SCREEN.frameBufferMesh, + QUAD_PRIMITIVE_TYPE, + QUAD_VERTEX_COUNT, + SCREEN.frameBufferMeshVertices + ); + #endif } void screenBind() { - // Assume framebuffer is already unbound + // Assume backbuffer is currently bound. + switch(SCREEN.mode) { + case SCREEN_MODE_BACKBUFFER: { + // Screen mode backbuffer uses the full display size + SCREEN.width = frameBufferGetWidth(FRAMEBUFFER_BOUND); + SCREEN.height = frameBufferGetHeight(FRAMEBUFFER_BOUND); + + // No needd for a framebuffer. + #if DISPLAY_SIZE_DYNAMIC == 1 + if(SCREEN.framebufferReady) { + frameBufferDispose(&SCREEN.framebuffer); + SCREEN.framebufferReady = false; + } + #endif + break; + } + + #if DISPLAY_SIZE_DYNAMIC == 1 + case SCREEN_MODE_ASPECT_RATIO: { + // Aspect ratio mode, requires a framebuffer. + int32_t fbWidth, fbHeight; + fbWidth = frameBufferGetWidth(FRAMEBUFFER_BOUND); + fbHeight = frameBufferGetHeight(FRAMEBUFFER_BOUND); + + float_t currentAspect = (float_t)fbWidth / (float_t)fbHeight; + if(currentAspect == SCREEN.aspectRatio.ratio) { + // No need to use framebuffer. + SCREEN.width = fbWidth; + SCREEN.height = fbHeight; + + if(SCREEN.framebufferReady) { + frameBufferDispose(&SCREEN.framebuffer); + SCREEN.framebufferReady = false; + } + return; + } + + int32_t newFbWidth, newFbHeight; + if(currentAspect > SCREEN.aspectRatio.ratio) { + // Wider than target aspect, limit by height + newFbWidth = (int32_t)floorf(fbHeight * SCREEN.aspectRatio.ratio); + newFbHeight = (int32_t)fbHeight; + } else { + // Taller than target aspect, limit by width + newFbHeight = (int32_t)floorf(fbWidth / SCREEN.aspectRatio.ratio); + newFbWidth = (int32_t)fbWidth; + } + + if(SCREEN.framebufferReady) { + // Is current framebuffer the correct size? + int32_t curFbWidth, curFbHeight; + curFbWidth = frameBufferGetWidth(&SCREEN.framebuffer); + curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer); + if(curFbWidth == newFbWidth && curFbHeight == newFbHeight) { + // Correct size, nothing to do. + SCREEN.width = newFbWidth; + SCREEN.height = newFbHeight; + frameBufferBind(&SCREEN.framebuffer); + return; + } + + // Need a new framebuffer. + frameBufferDispose(&SCREEN.framebuffer); + SCREEN.framebufferReady = false; + } + + // Create new framebuffer + frameBufferInit(&SCREEN.framebuffer, newFbWidth, newFbHeight); + SCREEN.framebufferReady = true; + SCREEN.width = newFbWidth; + SCREEN.height = newFbHeight; + + // Bind FB + frameBufferBind(&SCREEN.framebuffer); + break; + } + + case SCREEN_MODE_FIXED_HEIGHT: { + float_t fbWidth = (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND); + float_t fbHeight = (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND); + float_t fbAspect = fbWidth / fbHeight; + + int32_t newFbWidth, newFbHeight; + newFbHeight = SCREEN.fixedHeight.height; + newFbWidth = (int32_t)floorf(newFbHeight * fbAspect); + + SCREEN.width = newFbWidth; + SCREEN.height = newFbHeight; + + if(fbWidth == newFbWidth && fbHeight == newFbHeight) { + // No need to use framebuffer. + if(SCREEN.framebufferReady) { + frameBufferDispose(&SCREEN.framebuffer); + SCREEN.framebufferReady = false; + } + return; + } + + if(SCREEN.framebufferReady) { + // Is current framebuffer the correct size? + int32_t curFbWidth, curFbHeight; + curFbWidth = frameBufferGetWidth(&SCREEN.framebuffer); + curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer); + if(curFbWidth == newFbWidth && curFbHeight == newFbHeight) { + frameBufferBind(&SCREEN.framebuffer); + return; + } + + // Need a new framebuffer. + frameBufferDispose(&SCREEN.framebuffer); + SCREEN.framebufferReady = false; + } + + // Create a new framebuffer. + frameBufferInit(&SCREEN.framebuffer, newFbWidth, newFbHeight); + SCREEN.framebufferReady = true; + frameBufferBind(&SCREEN.framebuffer); + break; + } + #endif + + default: { + assertUnreachable("Invalid screen mode."); + break; + } + } } void screenUnbind() { + switch(SCREEN.mode) { + case SCREEN_MODE_BACKBUFFER: { + // Nothing to do here. + break; + } + + #if DISPLAY_SIZE_DYNAMIC == 1 + case SCREEN_MODE_ASPECT_RATIO: + case SCREEN_MODE_FIXED_HEIGHT: + if(SCREEN.framebufferReady) frameBufferBind(NULL); + break; + #endif + default: { + assertUnreachable("Invalid screen mode."); + break; + } + } } void screenRender() { + if(SCREEN.mode == SCREEN_MODE_BACKBUFFER) { + return; + } + #if DISPLAY_SIZE_DYNAMIC == 1 + if( + SCREEN.mode == SCREEN_MODE_ASPECT_RATIO || + SCREEN.mode == SCREEN_MODE_FIXED_HEIGHT + ) { + if(!SCREEN.framebufferReady) { + // Nothing to do here. + return; + } + + float_t bbWidth, bbHeight; + bbWidth = (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND); + bbHeight = (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND); + + float_t backBufferAspect = bbWidth / bbHeight; + + // Determine framebuffer centering + float_t fbWidth, fbHeight, fbAspect; + float_t fbX, fbY; + + fbWidth = frameBufferGetWidth(&SCREEN.framebuffer); + fbHeight = frameBufferGetHeight(&SCREEN.framebuffer); + fbAspect = fbWidth / fbHeight; + + if(backBufferAspect > fbAspect) { + fbHeight = bbHeight; + fbWidth = fbHeight * fbAspect; + fbX = (bbWidth - fbWidth) * 0.5f; + fbY = 0.0f; + } else { + fbWidth = bbWidth; + fbHeight = fbWidth / fbAspect; + fbX = 0.0f; + fbY = (bbHeight - fbHeight) * 0.5f; + } + + float_t centerX = bbWidth * 0.5f; + float_t centerY = bbHeight * 0.5f; + + SCREEN.framebufferCamera.orthographic.left = 0.0f; + SCREEN.framebufferCamera.orthographic.right = bbWidth; + SCREEN.framebufferCamera.orthographic.top = 0.0f; + SCREEN.framebufferCamera.orthographic.bottom = bbHeight; + quadBuffer( + SCREEN.frameBufferMeshVertices, + centerX - fbWidth * 0.5f, centerY + fbHeight * 0.5f, // top-left + centerX + fbWidth * 0.5f, centerY - fbHeight * 0.5f, // bottom-right + COLOR_WHITE, + 0.0f, 0.0f, + 1.0f, 1.0f + ); + + frameBufferClear( + FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, + COLOR_BLACK + ); + cameraPushMatrix(&SCREEN.framebufferCamera); + textureBind(&SCREEN.framebuffer.texture); + meshDraw(&SCREEN.frameBufferMesh, 0, -1); + cameraPopMatrix(); + + return; + }; + #endif + + assertUnreachable("Invalid screen mode."); } void screenDispose() { - + #if DISPLAY_SIZE_DYNAMIC == 1 + if(SCREEN.framebufferReady) { + frameBufferDispose(&SCREEN.framebuffer); + SCREEN.framebufferReady = false; + } + #endif } \ No newline at end of file diff --git a/src/display/screen.h b/src/display/screen.h index d97c1d9..7cb514b 100644 --- a/src/display/screen.h +++ b/src/display/screen.h @@ -7,31 +7,49 @@ #pragma once #include "dusk.h" +#include "display/framebuffer/framebuffer.h" +#include "display/camera.h" +#include "display/mesh/quad.h" typedef enum { SCREEN_MODE_BACKBUFFER, #if DISPLAY_SIZE_DYNAMIC == 1 + SCREEN_MODE_ASPECT_RATIO,// Maintains aspect at all cost + SCREEN_MODE_FIXED_HEIGHT, // Fixed height, width expands/contracts as needed #endif - // SCREEN_MODE_FIXED_ASPECT, - // SCREEN_MODE_FIXED_ASPECT_INTEGER, - // SCREEN_MODE_FIXED_HEIGHT, - // SCREEN_MODE_FIXED_HEIGHT_INTEGER, - // SCREEN_MODE_FIXED_WIDTH, - // SCREEN_MODE_FIXED_WIDTH_INTEGER, - // SCREEN_MODE_SUPER_RESOLUTION_HEIGHT, - // SCREEN_MODE_SUPER_RESOLUTION_WIDTH } screenmode_t; +typedef enum { + SCREEN_SCALE_MODE_FILL, + SCREEN_SCALE_MODE_INTEGER, + SCREEN_SCALE_MODE_INEGER_OVERFLOW +} screenscalemode_t; + typedef struct { screenmode_t mode; + screenscalemode_t scaleMode; // Calculated dimensions of the viewport, to be used by the camera int32_t width; int32_t height; + + #if DISPLAY_SIZE_DYNAMIC == 1 + framebuffer_t framebuffer; + bool_t framebufferReady; + camera_t framebufferCamera; + mesh_t frameBufferMesh; + meshvertex_t frameBufferMeshVertices[QUAD_VERTEX_COUNT]; + #endif union { - + struct { + float_t ratio; + } aspectRatio; + + struct { + int32_t height; + } fixedHeight; }; } screen_t; diff --git a/src/game/minesweeper/game.c b/src/game/minesweeper/game.c index 605aa39..8b3d7d5 100644 --- a/src/game/minesweeper/game.c +++ b/src/game/minesweeper/game.c @@ -10,8 +10,15 @@ #include "game/minesweeper/scene/scenesweep.h" #include "scene/scenemanager.h" #include "console/console.h" +#include "display/screen.h" errorret_t gameInit(void) { + // Setup screen + // SCREEN.mode = SCREEN_MODE_FIXED_HEIGHT; + // SCREEN.fixedHeight.height = 270; + SCREEN.mode = SCREEN_MODE_ASPECT_RATIO; + SCREEN.aspectRatio.ratio = 16.0f / 9.0f; + errorChain(uiInit()); sceneManagerRegisterScene(&SCENE_SWEEP); diff --git a/src/game/minesweeper/scene/scenesweep.c b/src/game/minesweeper/scene/scenesweep.c index d35dbed..435778f 100644 --- a/src/game/minesweeper/scene/scenesweep.c +++ b/src/game/minesweeper/scene/scenesweep.c @@ -10,6 +10,7 @@ #include "ui/uiframe.h" #include "display/spritebatch/spritebatch.h" #include "game/minesweeper/display/sweepboard.h" +#include "display/screen.h" scene_t SCENE_SWEEP = { .name = "sweep", @@ -34,9 +35,8 @@ void sceneSweepUpdate(void) { } void sceneSweepRender(void) { - float_t w, h; - w = 320; - h = 240; + int32_t w = SCREEN.width; + int32_t h = SCREEN.height; SCENE_SWEEP_DATA.camera.orthographic.left = 0; SCENE_SWEEP_DATA.camera.orthographic.right = w; diff --git a/src/game/minesweeper/ui/ui.c b/src/game/minesweeper/ui/ui.c index cdf0210..8dedac6 100644 --- a/src/game/minesweeper/ui/ui.c +++ b/src/game/minesweeper/ui/ui.c @@ -9,13 +9,12 @@ #include "ui/uifps.h" #include "ui/uiconsole.h" #include "ui/uiframe.h" -#include "display/framebuffer/framebuffer.h" +#include "display/screen.h" #include "display/spritebatch/spritebatch.h" #include "display/tileset/tileset_minogram.h" #include "display/tileset/tileset_ui.h" #include "display/tileset/tileset_ui_frame.h" -#include "display/tileset/tileset_frame_large.h" #include "display/tileset/tileset_background.h" ui_t UI; @@ -55,12 +54,9 @@ errorret_t uiInit(void) { } void uiRender(void) { - int32_t w = frameBufferGetWidth(FRAMEBUFFER_BOUND); - int32_t h = frameBufferGetHeight(FRAMEBUFFER_BOUND); - UI.camera.orthographic.left = 0; - UI.camera.orthographic.right = w; - UI.camera.orthographic.bottom = h; + UI.camera.orthographic.right = SCREEN.width; + UI.camera.orthographic.bottom = SCREEN.height; UI.camera.orthographic.top = 0; cameraPushMatrix(&UI.camera);