diff --git a/assets/minesweeper/ui/CMakeLists.txt b/assets/minesweeper/ui/CMakeLists.txt index a2ded2e..2877a88 100644 --- a/assets/minesweeper/ui/CMakeLists.txt +++ b/assets/minesweeper/ui/CMakeLists.txt @@ -5,4 +5,5 @@ add_asset(TILESET minogram.png type=ALPHA tileWidth=6 tileHeight=10 columns=16 rows=6) add_asset(TILESET ui.png type=PALETTIZED tileWidth=16 tileHeight=16) -add_asset(TILESET ui_frame.png type=PALETTIZED tileWidth=16 tileHeight=16) \ No newline at end of file +add_asset(TILESET ui_frame.png type=PALETTIZED tileWidth=16 tileHeight=16) +add_asset(TILESET background.png type=PALETTIZED tileWidth=16 tileHeight=16) diff --git a/assets/minesweeper/ui/background.png b/assets/minesweeper/ui/background.png new file mode 100644 index 0000000..077cca2 Binary files /dev/null and b/assets/minesweeper/ui/background.png differ diff --git a/assets/minesweeper/ui/background.pxo b/assets/minesweeper/ui/background.pxo new file mode 100644 index 0000000..49a75fd Binary files /dev/null and b/assets/minesweeper/ui/background.pxo differ diff --git a/assets/minesweeper/ui/frame_large.png b/assets/minesweeper/ui/frame_large.png new file mode 100644 index 0000000..3d3d3ad Binary files /dev/null and b/assets/minesweeper/ui/frame_large.png differ diff --git a/assets/minesweeper/ui/frame_large.pxo b/assets/minesweeper/ui/frame_large.pxo new file mode 100644 index 0000000..51c8460 Binary files /dev/null and b/assets/minesweeper/ui/frame_large.pxo differ diff --git a/src/display/color.h b/src/display/color.h index 91fd15b..4f9daeb 100644 --- a/src/display/color.h +++ b/src/display/color.h @@ -45,6 +45,13 @@ typedef color4b_t color_t; #define color4b(r, g, b, a) ((color4b_t){r, g, b, a}) #define color(r, g, b, a) ((color_t){r, g, b, a}) +#define color_hex(hex) color( \ + ((hex >> 24) & 0xFF), \ + ((hex >> 16) & 0xFF), \ + ((hex >> 8) & 0xFF), \ + (hex & 0xFF) \ +) + #define COLOR_WHITE_3F color3f(1.0f, 1.0f, 1.0f) #define COLOR_WHITE_4F color4f(1.0f, 1.0f, 1.0f, 1.0f) #define COLOR_WHITE_3B color3b(255, 255, 255) diff --git a/src/display/display.c b/src/display/display.c index 4f41279..5dcb480 100644 --- a/src/display/display.c +++ b/src/display/display.c @@ -109,11 +109,6 @@ errorret_t displayUpdate(void) { spriteBatchClear(); frameBufferBind(NULL); - frameBufferClear( - FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, - COLOR_CORNFLOWER_BLUE - ); - sceneManagerRender(); spriteBatchFlush(); diff --git a/src/game/minesweeper/CMakeLists.txt b/src/game/minesweeper/CMakeLists.txt index 459d03e..fb9665a 100644 --- a/src/game/minesweeper/CMakeLists.txt +++ b/src/game/minesweeper/CMakeLists.txt @@ -10,5 +10,6 @@ target_sources(${DUSK_TARGET_NAME} ) # Subdirs +add_subdirectory(display) add_subdirectory(scene) add_subdirectory(ui) \ No newline at end of file diff --git a/src/game/minesweeper/display/CMakeLists.txt b/src/game/minesweeper/display/CMakeLists.txt new file mode 100644 index 0000000..ba4feac --- /dev/null +++ b/src/game/minesweeper/display/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(${DUSK_TARGET_NAME} + PRIVATE + sweepboard.c +) + +# Subdirs \ No newline at end of file diff --git a/src/game/minesweeper/display/sweepboard.c b/src/game/minesweeper/display/sweepboard.c new file mode 100644 index 0000000..2fb13b2 --- /dev/null +++ b/src/game/minesweeper/display/sweepboard.c @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "sweepboard.h" + +sweepboard_t SWEEPBOARD; + +void sweepBoardInit() { + // Initialize the sweep board +} + +void sweepBoardRender(const float_t x, const float_t y) { + // Frame + // uiFrameDrawTiled( + // 32, 32, + // w - 64, h - 64, + // UI.frameTileset, + // 0, 0, + // true, + // &UI.frameAsset->paletteImage.texture + // ); +} + +void sweepBoardDispose() { + // Dispose of the sweep board resources +} \ No newline at end of file diff --git a/src/game/minesweeper/display/sweepboard.h b/src/game/minesweeper/display/sweepboard.h new file mode 100644 index 0000000..69144da --- /dev/null +++ b/src/game/minesweeper/display/sweepboard.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef struct { + int32_t nothing; +} sweepboard_t; + +extern sweepboard_t SWEEPBOARD; + +/** + * Initializes the sweep board. + */ +void sweepBoardInit(); + +/** + * Disposes of the sweep board resources. + */ +void sweepBoardDispose(); \ No newline at end of file diff --git a/src/game/minesweeper/scene/scenesweep.c b/src/game/minesweeper/scene/scenesweep.c index ad877c6..d35dbed 100644 --- a/src/game/minesweeper/scene/scenesweep.c +++ b/src/game/minesweeper/scene/scenesweep.c @@ -7,6 +7,9 @@ #include "scenesweep.h" #include "game/minesweeper/ui/ui.h" +#include "ui/uiframe.h" +#include "display/spritebatch/spritebatch.h" +#include "game/minesweeper/display/sweepboard.h" scene_t SCENE_SWEEP = { .name = "sweep", @@ -14,11 +17,14 @@ scene_t SCENE_SWEEP = { .update = sceneSweepUpdate, .render = sceneSweepRender, .dispose = sceneSweepDispose, + .background = color_hex(0x48413cff) }; scenesweep_t SCENE_SWEEP_DATA; errorret_t sceneSweepInit(void) { + cameraInitOrthographic(&SCENE_SWEEP_DATA.camera); + // Initialize scene data here errorOk(); } @@ -28,7 +34,39 @@ void sceneSweepUpdate(void) { } void sceneSweepRender(void) { - // Render scene here + float_t w, h; + w = 320; + h = 240; + + SCENE_SWEEP_DATA.camera.orthographic.left = 0; + SCENE_SWEEP_DATA.camera.orthographic.right = w; + SCENE_SWEEP_DATA.camera.orthographic.bottom = h; + SCENE_SWEEP_DATA.camera.orthographic.top = 0; + cameraPushMatrix(&SCENE_SWEEP_DATA.camera); + + // Background + uiFrameDrawTiled( + 8, 8, + w - 16, h - 16, + UI.backgroundTileset, + 0, 0, + true, + &UI.backgroundAsset->paletteImage.texture + ); + + // Frame + uiFrameDrawTiled( + 32, 32, + w - 64, h - 64, + UI.frameTileset, + 0, 0, + true, + &UI.frameAsset->paletteImage.texture + ); + + spriteBatchFlush(); + cameraPopMatrix(); + uiRender(); } diff --git a/src/game/minesweeper/scene/scenesweep.h b/src/game/minesweeper/scene/scenesweep.h index 6a4fbf8..4da8de8 100644 --- a/src/game/minesweeper/scene/scenesweep.h +++ b/src/game/minesweeper/scene/scenesweep.h @@ -7,9 +7,10 @@ #pragma once #include "scene/scene.h" +#include "display/camera.h" typedef struct { - int32_t x; + camera_t camera; } scenesweep_t; extern scene_t SCENE_SWEEP; diff --git a/src/game/minesweeper/sweeper.c b/src/game/minesweeper/sweeper.c new file mode 100644 index 0000000..6472ab6 --- /dev/null +++ b/src/game/minesweeper/sweeper.c @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "sweeper.h" +#include "assert/assert.h" +#include "util/memory.h" + +extern sweeper_t SWEEPER; + +void sweeperInit(void) { + memoryZero(&SWEEPER, sizeof(sweeper_t)); +} + +void sweeperReveal(const uint16_t x, const uint16_t y) { + assertTrue(x < SWEEPER_GRID_WIDTH, "X coordinate out of bounds"); + assertTrue(y < SWEEPER_GRID_HEIGHT, "Y coordinate out of bounds"); + + sweepercell_t *cell = &SWEEPER.grid[y * SWEEPER_GRID_WIDTH + x]; + + // Dont reveal twice. + if(*cell != SWEEPER_CELL_HIDDEN) { + return; + } + + // Can't reveal flag. + if(*cell == SWEEPER_CELL_FLAGGED) { + return; + } + + // Game over + if(cell == SWEEPER_CELL_HIDDEN_MINE) { + *cell = SWEEPER_CELL_MINE; + SWEEPER.gameOver = true; + return; + } + + // Adjacent mines + uint8_t surrounding = 0; + for(int16_t dy = -1; dy <= 1; ++dy) { + for(int16_t dx = -1; dx <= 1; ++dx) { + if(dx == 0 && dy == 0) continue; + + int16_t nx = x + dx; + int16_t ny = y + dy; + if( + nx < 0 || nx >= SWEEPER_GRID_WIDTH || + ny < 0 || ny >= SWEEPER_GRID_HEIGHT + ) continue; + + sweepercell_t neighbor = SWEEPER.grid[ny * SWEEPER_GRID_WIDTH + nx]; + if(neighbor == SWEEPER_CELL_HIDDEN_MINE) surrounding++; + } + } + + if(surrounding > 0) { + *cell = SWEEPER_CELL_0 + surrounding; + return; + } + + // Cascade reveal + printf("Cascading reveal at %d, %d\n", x, y); + *cell = SWEEPER_CELL_0; +} + +void sweeperFlag(const uint16_t x, const uint16_t y) { + assertTrue(x < SWEEPER_GRID_WIDTH, "X coordinate out of bounds"); + assertTrue(y < SWEEPER_GRID_HEIGHT, "Y coordinate out of bounds"); + + sweepercell_t *cell = &SWEEPER.grid[y * SWEEPER_GRID_WIDTH + x]; + + if(*cell == SWEEPER_CELL_HIDDEN) { + *cell = SWEEPER_CELL_FLAGGED; + } else if(*cell == SWEEPER_CELL_FLAGGED) { + *cell = SWEEPER_CELL_HIDDEN; + } +} \ No newline at end of file diff --git a/src/game/minesweeper/sweeper.h b/src/game/minesweeper/sweeper.h new file mode 100644 index 0000000..993d9fd --- /dev/null +++ b/src/game/minesweeper/sweeper.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef enum { + SWEEPER_CELL_HIDDEN = 0x00, + SWEEPER_CELL_HIDDEN_MINE = 0x01, + SWEEPER_CELL_0 = 0x02, + SWEEPER_CELL_1 = 0x03, + SWEEPER_CELL_2 = 0x04, + SWEEPER_CELL_3 = 0x05, + SWEEPER_CELL_4 = 0x06, + SWEEPER_CELL_5 = 0x07, + SWEEPER_CELL_6 = 0x08, + SWEEPER_CELL_7 = 0x09, + SWEEPER_CELL_8 = 0x0A, + SWEEPER_CELL_9 = 0x0B, + SWEEPER_CELL_FLAGGED = 0x0C, + SWEEPER_CELL_MINE = 0x0D, +} sweepercell_t; + +#define SWEEPER_GRID_WIDTH 16 +#define SWEEPER_GRID_HEIGHT 16 + +typedef struct { + sweepercell_t grid[SWEEPER_GRID_WIDTH * SWEEPER_GRID_HEIGHT]; + bool_t gameOver; +} sweeper_t; + +extern sweeper_t SWEEPER; + +/** + * Initializes the Minesweeper game state. + */ +void sweeperInit(void); + +/** + * Reveals the cell at the specified coordinates. + * + * @param x The x-coordinate of the cell to reveal. + * @param y The y-coordinate of the cell to reveal. + */ +void sweeperReveal(const uint16_t x, const uint16_t y); + +/** + * Flags or unflags the cell at the specified coordinates. + * + * @param x The x-coordinate of the cell to flag or unflag. + * @param y The y-coordinate of the cell to flag or unflag. + */ +void sweeperFlag(const uint16_t x, const uint16_t y); \ No newline at end of file diff --git a/src/game/minesweeper/ui/ui.c b/src/game/minesweeper/ui/ui.c index 4b62020..cdf0210 100644 --- a/src/game/minesweeper/ui/ui.c +++ b/src/game/minesweeper/ui/ui.c @@ -15,6 +15,8 @@ #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; @@ -42,6 +44,13 @@ errorret_t uiInit(void) { &UI.frameRef )); + UI.backgroundTileset = (tileset_t*)&TILESET_BACKGROUND; + errorChain(assetManagerLoadAsset( + UI.backgroundTileset->image, + &UI.backgroundAsset, + &UI.backgroundRef + )); + errorOk(); } @@ -57,17 +66,6 @@ void uiRender(void) { cameraPushMatrix(&UI.camera); uiFPSRender(UI.minogramTileset, &UI.minogramAsset->alphaImage.texture); - - float_t x, y; - x = 32, y = 32; - uiFrameDrawTiled( - x, y, - 256, 256, - UI.frameTileset, - 0, 0, - &UI.frameAsset->paletteImage.texture - ); - uiConsoleRender( 0, 0, UI.minogramTileset, &UI.minogramAsset->alphaImage.texture diff --git a/src/game/minesweeper/ui/ui.h b/src/game/minesweeper/ui/ui.h index 8f7b321..3155032 100644 --- a/src/game/minesweeper/ui/ui.h +++ b/src/game/minesweeper/ui/ui.h @@ -25,6 +25,10 @@ typedef struct { tileset_t *frameTileset; asset_t *frameAsset; ref_t frameRef; + + tileset_t *backgroundTileset; + asset_t *backgroundAsset; + ref_t backgroundRef; } ui_t; extern ui_t UI; diff --git a/src/scene/scene.h b/src/scene/scene.h index d45a239..fdb589d 100644 --- a/src/scene/scene.h +++ b/src/scene/scene.h @@ -8,6 +8,7 @@ #pragma once #include "dusk.h" #include "error/error.h" +#include "display/color.h" #define SCENE_FLAG_ACTIVE (1 << 0) #define SCENE_FLAG_INITIALIZED (1 << 1) @@ -24,4 +25,5 @@ typedef struct { void (*sleep)(void); uint8_t flags; + color_t background; } scene_t; \ No newline at end of file diff --git a/src/scene/scenemanager.c b/src/scene/scenemanager.c index ae44643..e0c0e7d 100644 --- a/src/scene/scenemanager.c +++ b/src/scene/scenemanager.c @@ -9,6 +9,7 @@ #include "util/memory.h" #include "assert/assert.h" #include "console/console.h" +#include "display/framebuffer/framebuffer.h" #include "util/string.h" scenemanager_t SCENE_MANAGER; @@ -94,6 +95,11 @@ void sceneManagerRender(void) { SCENE_MANAGER.current->flags & SCENE_FLAG_INITIALIZED, "Current scene not initialized" ); + + frameBufferClear( + FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, + SCENE_MANAGER.current->background + ); if(SCENE_MANAGER.current->render) SCENE_MANAGER.current->render(); } diff --git a/src/ui/uiframe.c b/src/ui/uiframe.c index 648d735..80b15dc 100644 --- a/src/ui/uiframe.c +++ b/src/ui/uiframe.c @@ -18,6 +18,7 @@ void uiFrameDraw( const tileset_t *tileset, const uint16_t column, const uint16_t row, + const bool_t drawInner, texture_t *texture ) { assertNotNull(tileset, "Tileset cannot be NULL"); @@ -89,19 +90,21 @@ void uiFrameDraw( ); // Middle-Center - tilesetPositionGetUV( - tileset, - column + 1, - row + 1, - uv - ); - spriteBatchPush( - texture, - x + tileset->tileWidth, y + tileset->tileHeight, - x + width - tileset->tileWidth, y + height - tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); + if(drawInner) { + tilesetPositionGetUV( + tileset, + column + 1, + row + 1, + uv + ); + spriteBatchPush( + texture, + x + tileset->tileWidth, y + tileset->tileHeight, + x + width - tileset->tileWidth, y + height - tileset->tileHeight, + COLOR_WHITE, + uv[0], uv[1], uv[2], uv[3] + ); + } // Middle-Right tilesetPositionGetUV( @@ -172,6 +175,7 @@ void uiFrameDrawTiled( const tileset_t *tileset, const uint16_t column, const uint16_t row, + const bool_t drawInner, texture_t *texture ) { assertNotNull(tileset, "Tileset cannot be NULL"); @@ -337,6 +341,8 @@ void uiFrameDrawTiled( } // Center (Tiled) + if(!drawInner) return; + tilesetPositionGetUV(tileset, column + 1, row + 1, uv); // Center tile float_t centerY = y + tileset->tileHeight; for(uint32_t j = 0; j < segmentsY; ++j, centerY += tileset->tileHeight) { diff --git a/src/ui/uiframe.h b/src/ui/uiframe.h index b5d844a..1a4b82d 100644 --- a/src/ui/uiframe.h +++ b/src/ui/uiframe.h @@ -19,6 +19,7 @@ * @param tileset The tileset to use for rendering the frame. * @param column The column in the tileset to use for the frame. * @param row The row in the tileset to use for the frame. + * @param drawInner Whether to draw the inner area. * @param texture The texture associated with the tileset. */ void uiFrameDraw( @@ -29,6 +30,7 @@ void uiFrameDraw( const tileset_t *tileset, const uint16_t column, const uint16_t row, + const bool_t drawInner, texture_t *texture ); @@ -43,6 +45,7 @@ void uiFrameDraw( * @param tileset The tileset to use for rendering the frame. * @param column The column in the tileset to use for the frame. * @param row The row in the tileset to use for the frame. + * @param drawInner Whether to draw the inner tiled area. * @param texture The texture associated with the tileset. */ void uiFrameDrawTiled( @@ -53,5 +56,6 @@ void uiFrameDrawTiled( const tileset_t *tileset, const uint16_t column, const uint16_t row, + const bool_t drawInner, texture_t *texture ); \ No newline at end of file