diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eeeb2c..aa99c7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,9 +29,6 @@ set(DUSK_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET} set(DUSK_ASSETS "" CACHE INTERNAL ${DUSK_CACHE_TARGET}) # Toolchain -if(DUSK_TARGET_SYSTEM STREQUAL "gb") - include(${CMAKE_SOURCE_DIR}/cmake/toolchains/gbdk.cmake) -endif() # Create directories file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 126e6e2..a699daf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,8 +5,6 @@ add_subdirectory(dusk) -if(DUSK_TARGET_SYSTEM STREQUAL "gb") - add_subdirectory(duskgb) -elseif(DUSK_TARGET_SYSTEM STREQUAL "raylib") +if(DUSK_TARGET_SYSTEM STREQUAL "raylib") add_subdirectory(duskraylib) endif() \ No newline at end of file diff --git a/src/dusk/CMakeLists.txt b/src/dusk/CMakeLists.txt index f78afd4..1fadb62 100644 --- a/src/dusk/CMakeLists.txt +++ b/src/dusk/CMakeLists.txt @@ -23,4 +23,5 @@ target_sources(${DUSK_TARGET_NAME} # Subdirs add_subdirectory(assert) add_subdirectory(display) -add_subdirectory(util) \ No newline at end of file +add_subdirectory(util) +add_subdirectory(world) \ No newline at end of file diff --git a/src/dusk/display/CMakeLists.txt b/src/dusk/display/CMakeLists.txt index 46c5dbd..6213aa6 100644 --- a/src/dusk/display/CMakeLists.txt +++ b/src/dusk/display/CMakeLists.txt @@ -6,5 +6,6 @@ # Sources target_sources(${DUSK_TARGET_NAME} PRIVATE - render.c + renderbase.c + scene.c ) \ No newline at end of file diff --git a/src/dusk/display/render.h b/src/dusk/display/render.h deleted file mode 100644 index 46d3b86..0000000 --- a/src/dusk/display/render.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "display/renderimpl.h" - -#define RENDER_WIDTH_PIXELS 160 -#define RENDER_HEIGHT_PIXELS 144 -#define RENDER_WIDTH_TILES 20 -#define RENDER_HEIGHT_TILES 18 - -extern uint8_t RENDER_STATUS; -#define RENDER_SHOULD_EXIT (1 << 0) - -/** - * Initializes the rendering system. - */ -void renderInit(void); - -/** - * Vsyncs the frame. - */ -void renderVsync(void); - -/** - * Disposes of the rendering system. - */ -void renderDispose(void); - -/** - * Turns off the display. - */ -void renderDisplayOff(void); - -/** - * Turns on the display. - */ -void renderDisplayOn(void); \ No newline at end of file diff --git a/src/dusk/display/render.c b/src/dusk/display/renderbase.c similarity index 84% rename from src/dusk/display/render.c rename to src/dusk/display/renderbase.c index 4a61745..9331e01 100644 --- a/src/dusk/display/render.c +++ b/src/dusk/display/renderbase.c @@ -5,4 +5,4 @@ * https://opensource.org/licenses/MIT */ -#include "render.h" \ No newline at end of file +#include "display/render.h" \ No newline at end of file diff --git a/src/dusk/display/renderbase.h b/src/dusk/display/renderbase.h index 3c3e7fa..8c3843e 100644 --- a/src/dusk/display/renderbase.h +++ b/src/dusk/display/renderbase.h @@ -8,12 +8,27 @@ #pragma once #include "dusk.h" -#define RENDER_TILE_COUNT 384 -#define RENDER_TILE_WIDTH 8 -#define RENDER_TILE_BYTES_PER_ROW 2 -#define RENDER_TILE_HEIGHT 8 -#define RENDER_TILE_BYTES_PER_TILE (RENDER_TILE_BYTES_PER_ROW * RENDER_TILE_HEIGHT) -#define RENDER_BACKGROUND_COLUMNS 32 -#define RENDER_BACKGROUND_ROWS 32 -#define RENDER_BACKGROUND_TILE_COUNT (RENDER_BACKGROUND_COLUMNS * RENDER_BACKGROUND_ROWS) -#define RENDER_PALETTE_COLOR_COUNT 4 \ No newline at end of file +#define RENDER_WIDTH 320 +#define RENDER_HEIGHT 240 + +/** + * Initializes the rendering system. + */ +void renderInit(void); + +/** + * Tells the rendering system to actually draw the frame. + */ +void renderDraw(void); + +/** + * Disposes of the rendering system. + */ +void renderDispose(void); + +/** + * Checks if the rendering system should exit. + * + * @return true if the rendering system should exit, false otherwise. + */ +bool_t renderShouldExit(); \ No newline at end of file diff --git a/src/dusk/display/scene.c b/src/dusk/display/scene.c new file mode 100644 index 0000000..e8e5023 --- /dev/null +++ b/src/dusk/display/scene.c @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "scene.h" + +scene_t SCENE_CURRENT = SCENE_INITIAL; \ No newline at end of file diff --git a/src/dusk/display/scene.h b/src/dusk/display/scene.h new file mode 100644 index 0000000..6f4a28e --- /dev/null +++ b/src/dusk/display/scene.h @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once + +typedef enum { + SCENE_INITIAL, + SCENE_OVERWORLD, +} scene_t; + +extern scene_t SCENE_CURRENT; \ No newline at end of file diff --git a/src/duskgb/duskgb.h b/src/dusk/entity/player.h similarity index 81% rename from src/duskgb/duskgb.h rename to src/dusk/entity/player.h index cf8fb96..1e6be71 100644 --- a/src/duskgb/duskgb.h +++ b/src/dusk/entity/player.h @@ -6,5 +6,4 @@ */ #pragma once -#include "dusk.h" -#include \ No newline at end of file +#include "dusk.h" \ No newline at end of file diff --git a/src/dusk/main.c b/src/dusk/main.c index 171a846..498e9e4 100644 --- a/src/dusk/main.c +++ b/src/dusk/main.c @@ -1,126 +1,30 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ #include "display/render.h" #include "util/memory.h" - - -#define backgroundTilesCount 7 -uint8_t backgroundTiles[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFE, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0xFE, 0xFE, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0xFE, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0xFE, 0xFE, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x7F, 0x7F, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, - 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xAA, 0xFF, 0x00, 0x55, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00 -}; - -#define backgroundmapWidth 40 -#define backgroundmapHeight 18 -#define backgroundmapBank 0 - -uint8_t backgroundmap[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, - 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, - 0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, - 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, - 0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, - 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, - 0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, - 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, - 0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x03, - 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, - 0x01,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, - 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, - 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 -}; - -void pdelay(uint8_t numVbls) { - uint8_t i; - for (i = 0; i < numVbls; i++) { - renderVsync(); - } -} +#include "world/chunk.h" +#include "display/scene.h" +#include "world/overworld.h" // Press F5 to compile and run the compiled game.gb in the Emulicous Emulator/Debugger void main(void) { renderInit(); + + overworldInit(); - renderTilesBuffer(0, 7, backgroundTiles); - renderBackgroundTilesBufferRectangle(0, 0, backgroundmapWidth, backgroundmapHeight, backgroundmap); + SCENE_CURRENT = SCENE_OVERWORLD; - renderDisplayOn(); - - while (1) { - RENDER_BACKGROUND_X++; - pdelay(3); - - if((RENDER_STATUS & RENDER_SHOULD_EXIT) != 0) break; + while(!renderShouldExit()) { + renderDraw(); + + OVERWORLD_CAMERA_SUB_X++; + + overworldUpdate(); } renderDispose(); diff --git a/src/duskgb/display/CMakeLists.txt b/src/dusk/world/CMakeLists.txt similarity index 85% rename from src/duskgb/display/CMakeLists.txt rename to src/dusk/world/CMakeLists.txt index 3aa6f61..446cdbf 100644 --- a/src/duskgb/display/CMakeLists.txt +++ b/src/dusk/world/CMakeLists.txt @@ -1,10 +1,11 @@ # 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 - renderimpl.c + chunk.c + overworld.c ) \ No newline at end of file diff --git a/src/dusk/world/chunk.c b/src/dusk/world/chunk.c new file mode 100644 index 0000000..2f691ab --- /dev/null +++ b/src/dusk/world/chunk.c @@ -0,0 +1,190 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "chunk.h" +#include "util/memory.h" +#include "assert/assert.h" + +chunkmap_t CHUNK_MAP; + +void chunkMapInit() { + memoryZero(&CHUNK_MAP, sizeof(chunkmap_t)); + + // Load default chunks, YX order. + uint16_t i = 0; + chunk_t *chunk; + for(uint8_t y = 0; y < CHUNK_MAP_HEIGHT; y++) { + for(uint8_t x = 0; x < CHUNK_MAP_WIDTH; x++) { + assertTrue(i < CHUNK_MAP_COUNT, "Chunk index out of bounds"); + + chunk = CHUNK_MAP.chunks + i; + CHUNK_MAP.chunkOrder[i] = chunk; + + chunkLoad(chunk, x, y); + assertTrue( + chunk->x == x && chunk->y == y, + "Chunk coordinates do not match expected values" + ); + + i++; + } + } +} + +void chunkMapShift(const int16_t x, const int16_t y) { + if(x == 0 && y == 0) assertUnreachable("ChunkMapShift called with no shift"); + + chunk_t *newChunkOrder[CHUNK_MAP_COUNT]; + chunk_t *unloadedChunks[CHUNK_MAP_COUNT]; + chunk_t *chunk; + uint8_t i, j; + uint16_t + /** New Map Coordinates */ + newX, newY, + newChunkX, newChunkY + ; + + // Calculate the new map coordinates + newX = CHUNK_MAP.topLeftX + x; + newY = CHUNK_MAP.topLeftY + y; + + // Zero the new chunk order + memoryZero(newChunkOrder, sizeof(newChunkOrder)); + + // For each chunk... + j = 0; + chunk = CHUNK_MAP.chunks; + do { + // Is this chunk still going to be within the map bounds? + if( + chunk->x < newX || chunk->y < newY || + chunk->x >= newX + CHUNK_MAP_WIDTH || + chunk->y >= newY + CHUNK_MAP_HEIGHT + ) { + // No, it's not, let's unload it and make it available for reuse. + chunkUnload(chunk); + assertTrue( + j < CHUNK_MAP_COUNT, + "Unloaded chunk index out of bounds" + ); + unloadedChunks[j++] = chunk; + chunk++; + continue; + } + + // Yes it is still valid, determine the new index that it will be at + i = (chunk->y - newY) * CHUNK_MAP_WIDTH + (chunk->x - newX); + assertTrue( + i < CHUNK_MAP_COUNT, + "Chunk index out of bounds after shifting" + ); + assertNull( + newChunkOrder[i], + "New chunk order index is already occupied" + ); + + // Set the new chunk order + newChunkOrder[i] = chunk; + chunk++; + } while(chunk < CHUNK_MAP.chunks + CHUNK_MAP_COUNT); + + // Now check the new chunk order list for missing chunks. + i = 0; + do { + assertTrue( + i < CHUNK_MAP_COUNT, + "New chunk order index out of bounds after shifting" + ); + + // Is this chunk loaded still? + chunk = newChunkOrder[i]; + if(chunk != NULL) { + i++; + continue; + } + + // Determine the new chunk coordinates. + newChunkX = i % CHUNK_MAP_WIDTH + newX; + newChunkY = i / CHUNK_MAP_WIDTH + newY; + assertTrue( + newChunkX >= newX && newChunkX < newX + CHUNK_MAP_WIDTH, + "New chunk X coordinate out of bounds after shifting" + ); + assertTrue( + newChunkY >= newY && newChunkY < newY + CHUNK_MAP_HEIGHT, + "New chunk Y coordinate out of bounds after shifting" + ); + + // Pop a chunk from the unloaded chunks list. + assertTrue(j > 0, "No unloaded chunks available to reuse"); + chunk = unloadedChunks[--j]; + assertNotNull(chunk, "Unloaded chunk pointer is null"); + + // Load the chunk at the new coordinates. + chunkLoad(chunk, newChunkX, newChunkY); + assertTrue( + chunk->x == newChunkX && chunk->y == newChunkY, + "Chunk coordinates do not match expected values after shifting" + ); + + // Set it in order. + newChunkOrder[i] = chunk; + i++; + } while(i < CHUNK_MAP_COUNT); + + // Update Absolutes. + CHUNK_MAP.topLeftX = newX; + CHUNK_MAP.topLeftY = newY; + + // Update the chunk order. + memoryCopy( + CHUNK_MAP.chunkOrder, + newChunkOrder, + sizeof(CHUNK_MAP.chunkOrder) + ); +} + + +void chunkMapSetPosition(const uint16_t x, const uint16_t y) { + if(x == CHUNK_MAP.topLeftX && y == CHUNK_MAP.topLeftY) { + return; + } + + int16_t shiftX = x - CHUNK_MAP.topLeftX; + int16_t shiftY = y - CHUNK_MAP.topLeftY; + + // Are we shifting the entire map? + if( + shiftX >= CHUNK_MAP_WIDTH || shiftX < -CHUNK_MAP_WIDTH || + shiftY >= CHUNK_MAP_HEIGHT || shiftY < -CHUNK_MAP_HEIGHT + ) { + printf("Shifting chunk map to new position (%u, %u)\n", x, y); + } + + // Shift the chunk map by the specified offsets. + chunkMapShift(shiftX, shiftY); +} + +void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { + assertNotNull(chunk, "Chunk pointer is null"); + + chunk->x = x; + chunk->y = y; + + if( + ((x % 2 == 0) && (y % 2 == 0)) || + ((x % 2 == 1) && (y % 2 == 1)) + ) { + memorySet(chunk->tiles, 1, sizeof(chunk->tiles)); + } else { + memorySet(chunk->tiles, 0, sizeof(chunk->tiles)); + } +} + +void chunkUnload(chunk_t *chunk) { + assertNotNull(chunk, "Chunk pointer is null"); +} \ No newline at end of file diff --git a/src/dusk/world/chunk.h b/src/dusk/world/chunk.h new file mode 100644 index 0000000..7c9f0a8 --- /dev/null +++ b/src/dusk/world/chunk.h @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "tile.h" + +#define CHUNK_MAP_WIDTH 5 +#define CHUNK_MAP_HEIGHT 5 +#define CHUNK_MAP_COUNT (CHUNK_MAP_WIDTH * CHUNK_MAP_HEIGHT) + +#define CHUNK_WIDTH 4 +#define CHUNK_HEIGHT 4 +#define CHUNK_TILE_COUNT (CHUNK_WIDTH * CHUNK_HEIGHT) + +typedef struct { + uint16_t x, y; + tile_t tiles[CHUNK_TILE_COUNT]; +} chunk_t; + +typedef struct { + chunk_t chunks[CHUNK_MAP_COUNT]; + chunk_t *chunkOrder[CHUNK_MAP_COUNT]; + + uint16_t topLeftX; + uint16_t topLeftY; +} chunkmap_t; + +extern chunkmap_t CHUNK_MAP; + +/** + * Initializes the chunk map. + */ +void chunkMapInit(); + +/** + * Shifts the chunk map by the specified x and y offsets. + * + * @param x The x offset to shift the chunk map. + * @param y The y offset to shift the chunk map. + */ +void chunkMapShift(const int16_t x, const int16_t y); + +/** + * Sets the position of the chunk map to the specified coordinates. + * + * @param x The x coordinate of the top-left chunk. + * @param y The y coordinate of the top-left chunk. + */ +void chunkMapSetPosition(const uint16_t x, const uint16_t y); + +/** + * Loads a chunk at the specified coordinates. + * + * @param chunk The chunk to load. + * @param x The x coordinate of the chunk. + * @param y The y coordinate of the chunk. + */ +void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y); + +/** + * Unloads a chunk (that is currently loaded). + * + * @param chunk The chunk to unload. + */ +void chunkUnload(chunk_t *chunk); \ No newline at end of file diff --git a/src/dusk/world/overworld.c b/src/dusk/world/overworld.c new file mode 100644 index 0000000..b282ffe --- /dev/null +++ b/src/dusk/world/overworld.c @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "overworld.h" +#include "chunk.h" +#include "display/render.h" + +uint16_t OVERWORLD_CAMERA_X = 0; +int8_t OVERWORLD_CAMERA_SUB_X = 0; +uint16_t OVERWORLD_CAMERA_Y = 0; +int8_t OVERWORLD_CAMERA_SUB_Y = 0; + +void overworldInit(void) { + OVERWORLD_CAMERA_X = 0; + OVERWORLD_CAMERA_SUB_X = 0; + OVERWORLD_CAMERA_Y = 0; + OVERWORLD_CAMERA_SUB_Y = 0; + + chunkMapInit(); +} + +void overworldUpdate() { + while(OVERWORLD_CAMERA_SUB_X >= TILE_WIDTH) { + OVERWORLD_CAMERA_SUB_X -= TILE_WIDTH; + OVERWORLD_CAMERA_X++; + } + + while(OVERWORLD_CAMERA_SUB_X < 0) { + OVERWORLD_CAMERA_SUB_X += TILE_WIDTH; + OVERWORLD_CAMERA_X--; + } + + while(OVERWORLD_CAMERA_SUB_Y >= TILE_HEIGHT) { + OVERWORLD_CAMERA_SUB_Y -= TILE_HEIGHT; + OVERWORLD_CAMERA_Y++; + } + + while(OVERWORLD_CAMERA_SUB_Y < 0) { + OVERWORLD_CAMERA_SUB_Y += TILE_HEIGHT; + OVERWORLD_CAMERA_Y--; + } + + chunkMapSetPosition( + (OVERWORLD_CAMERA_X - (RENDER_WIDTH / 2 / TILE_WIDTH)) / CHUNK_WIDTH, + (OVERWORLD_CAMERA_Y - (RENDER_HEIGHT / 2 / TILE_HEIGHT)) / CHUNK_HEIGHT + ); +} \ No newline at end of file diff --git a/src/dusk/world/overworld.h b/src/dusk/world/overworld.h new file mode 100644 index 0000000..276c321 --- /dev/null +++ b/src/dusk/world/overworld.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" + +extern uint16_t OVERWORLD_CAMERA_X; +extern int8_t OVERWORLD_CAMERA_SUB_X; +extern uint16_t OVERWORLD_CAMERA_Y; +extern int8_t OVERWORLD_CAMERA_SUB_Y; + + +/** + * Initializes the overworld. + */ +void overworldInit(void); + +/** + * Updates the overworld. + */ +void overworldUpdate(void); \ No newline at end of file diff --git a/src/dusk/world/tile.h b/src/dusk/world/tile.h new file mode 100644 index 0000000..8aea9f4 --- /dev/null +++ b/src/dusk/world/tile.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +#define TILE_WIDTH 16 +#define TILE_HEIGHT 16 + +typedef uint8_t tile_t; \ No newline at end of file diff --git a/src/duskgb/CMakeLists.txt b/src/duskgb/CMakeLists.txt deleted file mode 100644 index 3121693..0000000 --- a/src/duskgb/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Definitions -target_compile_definitions(${DUSK_TARGET_NAME} - PUBLIC - ASSERTIONS_FAKED=1 -) - -# Libs -target_link_libraries(${DUSK_TARGET_NAME} - PUBLIC -) - -# Includes -target_include_directories(${DUSK_TARGET_NAME} - PUBLIC - ${CMAKE_CURRENT_LIST_DIR} -) - -# Sources -target_sources(${DUSK_TARGET_NAME} - PRIVATE -) - -# Subdirs -add_subdirectory(display) - -add_gb_rom(${DUSK_TARGET_NAME} 0x10 2 4) \ No newline at end of file diff --git a/src/duskgb/display/renderimpl.c b/src/duskgb/display/renderimpl.c deleted file mode 100644 index c92954e..0000000 --- a/src/duskgb/display/renderimpl.c +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "display/render.h" - -uint8_t RENDER_STATUS = 0; - -void renderInit(void) { - SHOW_BKG; - DISPLAY_ON; -} - -void renderVsync(void) { - vsync(); -} - -void renderDispose(void) { - -} \ No newline at end of file diff --git a/src/duskraylib/display/CMakeLists.txt b/src/duskraylib/display/CMakeLists.txt index 3aa6f61..eb0ee09 100644 --- a/src/duskraylib/display/CMakeLists.txt +++ b/src/duskraylib/display/CMakeLists.txt @@ -6,5 +6,8 @@ # Sources target_sources(${DUSK_TARGET_NAME} PRIVATE - renderimpl.c -) \ No newline at end of file + render.c +) + +# Subdirs +add_subdirectory(draw) \ No newline at end of file diff --git a/src/duskraylib/display/draw/CMakeLists.txt b/src/duskraylib/display/draw/CMakeLists.txt new file mode 100644 index 0000000..456174c --- /dev/null +++ b/src/duskraylib/display/draw/CMakeLists.txt @@ -0,0 +1,11 @@ +# 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 + drawscene.c + drawoverworld.c +) \ No newline at end of file diff --git a/src/duskraylib/display/draw/drawoverworld.c b/src/duskraylib/display/draw/drawoverworld.c new file mode 100644 index 0000000..3314764 --- /dev/null +++ b/src/duskraylib/display/draw/drawoverworld.c @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "drawoverworld.h" +#include "world/chunk.h" +#include "world/overworld.h" +#include "display/render.h" + +Camera2D DRAW_OVERWORLD_CAMERA = { 0 }; + +void drawOverworldInit(void) { + DRAW_OVERWORLD_CAMERA = (Camera2D){ + .offset = { 0, 0 }, + .target = { 0, 0 }, + .rotation = 0.0f, + .zoom = 1.0f + }; +} + +void drawOverworldDraw(void) { + BeginMode2D(DRAW_OVERWORLD_CAMERA); + + DRAW_OVERWORLD_CAMERA.target.x = ( + OVERWORLD_CAMERA_X * TILE_WIDTH + OVERWORLD_CAMERA_SUB_X + ) - ( + RENDER_WIDTH / 2 + ); + DRAW_OVERWORLD_CAMERA.target.y = ( + OVERWORLD_CAMERA_Y * TILE_HEIGHT + OVERWORLD_CAMERA_SUB_Y + ) - ( + RENDER_HEIGHT / 2 + ); + + chunk_t *chunk = CHUNK_MAP.chunks; + do { + DrawRectangle( + ((int32_t)chunk->x) * CHUNK_WIDTH * TILE_WIDTH, + ((int32_t)chunk->y) * CHUNK_HEIGHT * TILE_HEIGHT, + CHUNK_WIDTH * TILE_WIDTH, + CHUNK_HEIGHT * TILE_HEIGHT, + (chunk->tiles[0] == 0) ? RED : GREEN + ); + chunk++; + } while(chunk < CHUNK_MAP.chunks + CHUNK_MAP_COUNT); + + EndMode2D(); +} \ No newline at end of file diff --git a/src/duskraylib/display/draw/drawoverworld.h b/src/duskraylib/display/draw/drawoverworld.h new file mode 100644 index 0000000..e84ec71 --- /dev/null +++ b/src/duskraylib/display/draw/drawoverworld.h @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "duskraylib.h" + +/** + * Initializes the overworld drawing system. + */ +void drawOverworldInit(void); + +/** + * Renders the overworld, including map and characters. + */ +void drawOverworldDraw(void); \ No newline at end of file diff --git a/src/duskraylib/display/draw/drawscene.c b/src/duskraylib/display/draw/drawscene.c new file mode 100644 index 0000000..9d5ca79 --- /dev/null +++ b/src/duskraylib/display/draw/drawscene.c @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "drawscene.h" +#include "display/scene.h" +#include "assert/assert.h" +#include "drawoverworld.h" + +void drawScene(void) { + switch(SCENE_CURRENT){ + case SCENE_INITIAL: + break; + + case SCENE_OVERWORLD: + drawOverworldDraw(); + break; + + default: + assertUnreachable("Unknown scene in drawScene"); + } +} \ No newline at end of file diff --git a/src/duskraylib/display/draw/drawscene.h b/src/duskraylib/display/draw/drawscene.h new file mode 100644 index 0000000..2bd08d7 --- /dev/null +++ b/src/duskraylib/display/draw/drawscene.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "duskraylib.h" + +/** + * Draws the current scene to the screen. + */ +void drawScene(void); \ No newline at end of file diff --git a/src/duskraylib/display/render.c b/src/duskraylib/display/render.c new file mode 100644 index 0000000..ba67cbe --- /dev/null +++ b/src/duskraylib/display/render.c @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "render.h" +#include "display/draw/drawscene.h" +#include "display/draw/drawoverworld.h" + + +RenderTexture2D RENDER_SCREEN_TEXTURE; + +void renderInit(void) { + InitWindow( + RENDER_WIDTH * 2, + RENDER_HEIGHT * 2, + "Dusk Raylib Render" + ); + SetTargetFPS(60); + SetWindowState( + FLAG_WINDOW_RESIZABLE | + FLAG_WINDOW_HIGHDPI | + FLAG_VSYNC_HINT + ); + + RENDER_SCREEN_TEXTURE = LoadRenderTexture(RENDER_WIDTH, RENDER_HEIGHT); + + drawOverworldInit(); +} + +void renderDraw(void) { + // Draw the actual game. + BeginTextureMode(RENDER_SCREEN_TEXTURE); + ClearBackground(BLACK); + + drawScene(); + + EndTextureMode(); + + // Draw the render texture to the screen. + BeginDrawing(); + ClearBackground(WHITE); + // Keep aspect and center the render + int32_t renderWidth, renderHeight, renderX, renderY; + const int32_t width = GetScreenWidth(); + const int32_t height = GetScreenHeight(); + if(RENDER_WIDTH * height > RENDER_HEIGHT * width) { + renderWidth = width; + renderHeight = (RENDER_HEIGHT * width) / RENDER_WIDTH; + renderX = 0; + renderY = (height - renderHeight) / 2; + } else { + renderWidth = (RENDER_WIDTH * height) / RENDER_HEIGHT; + renderHeight = height; + renderX = (width - renderWidth) / 2; + renderY = 0; + } + DrawTexturePro( + RENDER_SCREEN_TEXTURE.texture, + (Rectangle) { 0, 0, RENDER_WIDTH, -RENDER_HEIGHT }, + (Rectangle) { renderX, renderY, renderWidth, renderHeight }, + (Vector2) { 0, 0 }, + 0.0f, + WHITE + ); + EndDrawing(); +} + +void renderDispose(void) { + UnloadRenderTexture(RENDER_SCREEN_TEXTURE); + CloseWindow(); +} + +bool_t renderShouldExit() { + return WindowShouldClose(); +} \ No newline at end of file diff --git a/src/duskgb/display/renderimpl.h b/src/duskraylib/display/render.h similarity index 58% rename from src/duskgb/display/renderimpl.h rename to src/duskraylib/display/render.h index faee41d..7847270 100644 --- a/src/duskgb/display/renderimpl.h +++ b/src/duskraylib/display/render.h @@ -6,10 +6,8 @@ */ #pragma once -#include "duskgb.h" +#include "duskraylib.h" #include "display/renderbase.h" -#define RENDER_BACKGROUND_X SCX_REG -#define RENDER_BACKGROUND_Y SCY_REG - -#define renderTilesBuffer set_bkg_data \ No newline at end of file +extern RenderTexture2D RENDER_SCREEN_TEXTURE; +extern Camera2D RENDER_CAMERA; \ No newline at end of file diff --git a/src/duskraylib/display/renderimpl.c b/src/duskraylib/display/renderimpl.c deleted file mode 100644 index d787231..0000000 --- a/src/duskraylib/display/renderimpl.c +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "display/render.h" -#include "assert/assert.h" -#include "util/memory.h" - -uint8_t RENDER_BACKGROUND_X = 0; -uint8_t RENDER_BACKGROUND_Y = 0; -uint8_t RENDER_STATUS = 0; -bool_t RENDER_DISPLAY_ON = false; -uint8_t RENDER_TILES[RENDER_TILE_COUNT] = { 0 }; -uint8_t RENDER_BACKGROUND_TILEMAP[RENDER_BACKGROUND_TILE_COUNT] = { 0 }; -Color RENDER_PALETTE[RENDER_PALETTE_COLOR_COUNT] = { - { 102, 191, 47, 255 }, - { 78, 146, 35, 255 }, - { 48, 89, 22, 255 }, - { 18, 33, 8, 255 } -}; - -RenderTexture2D RENDER_BACKBUFFER; -RenderTexture2D RENDER_TILES_TEXTURE; - -void renderInit(void) { - InitWindow(RENDER_WIDTH_PIXELS * 4, RENDER_HEIGHT_PIXELS * 4, "Dusk"); - SetTargetFPS(60); - SetWindowState( - FLAG_WINDOW_RESIZABLE | - FLAG_WINDOW_HIGHDPI | - FLAG_VSYNC_HINT - ); - - // Create back buffer for rendering. - RENDER_BACKBUFFER = LoadRenderTexture( - RENDER_WIDTH_PIXELS, - RENDER_HEIGHT_PIXELS - ); - - // Create texture to hold the tile data. - RENDER_TILES_TEXTURE = LoadRenderTexture( - RENDER_TILE_COUNT * RENDER_TILE_WIDTH, - RENDER_TILE_HEIGHT - ); -} - -void renderVsync() { - int32_t x, y, i; - BeginDrawing(); - - if(RENDER_DISPLAY_ON) { - // Update the texture with the new tile data - BeginTextureMode(RENDER_TILES_TEXTURE); - i = 0; - for(i = 0; i < RENDER_TILE_COUNT; i++) { - uint8_t *tile = RENDER_TILES + (i * RENDER_TILE_BYTES_PER_TILE); - - // For each pixel in the tile... - for(y = 0; y < RENDER_TILE_HEIGHT; y++) { - uint8_t low = tile[y * RENDER_TILE_BYTES_PER_ROW]; - uint8_t high = tile[y * RENDER_TILE_BYTES_PER_ROW + 1]; - - for(x = 0; x < RENDER_TILE_WIDTH; x++) { - uint8_t loBit = (low >> (7 - x)) & 1; - uint8_t hiBit = (high >> (7 - x)) & 1; - uint8_t paletteIndex = (hiBit << 1) | loBit; - - // Draw the pixel to the texture - DrawPixel( - (i * RENDER_TILE_WIDTH) + x, - y, - RENDER_PALETTE[paletteIndex] - ); - } - } - } - EndTextureMode(); - - // Clear the back buffer - BeginTextureMode(RENDER_BACKBUFFER); - ClearBackground(RENDER_PALETTE[0]); - - // Render background tiles - i = 0; - for(y = 0; y < RENDER_BACKGROUND_ROWS; y++) { - for(x = 0; x < RENDER_BACKGROUND_COLUMNS; x++) { - // Get the tile index from the tilemap - uint8_t tileIndex = RENDER_BACKGROUND_TILEMAP[i++]; - - DrawTexturePro( - RENDER_TILES_TEXTURE.texture, - (Rectangle){ - .x = ((int32_t)tileIndex) * RENDER_TILE_WIDTH, - .y = 0, - .width = RENDER_TILE_WIDTH, - .height = -RENDER_TILE_HEIGHT - }, - (Rectangle){ - ((int32_t)x * RENDER_TILE_WIDTH) - RENDER_BACKGROUND_X, - ((int32_t)y * RENDER_TILE_HEIGHT) - RENDER_BACKGROUND_Y, - RENDER_TILE_WIDTH, - RENDER_TILE_HEIGHT - }, - (Vector2){ 0, 0 }, - 0.0f, - WHITE - ); - } - } - - // Render the back buffer to the screen - EndTextureMode(); - ClearBackground(WHITE); - - // Keep aspect and center the render - int32_t renderWidth, renderHeight, renderX, renderY; - const int32_t width = GetScreenWidth(); - const int32_t height = GetScreenHeight(); - if (RENDER_WIDTH_PIXELS * height > RENDER_HEIGHT_PIXELS * width) { - renderWidth = width; - renderHeight = (RENDER_HEIGHT_PIXELS * width) / RENDER_WIDTH_PIXELS; - renderX = 0; - renderY = (height - renderHeight) / 2; - } else { - renderWidth = (RENDER_WIDTH_PIXELS * height) / RENDER_HEIGHT_PIXELS; - renderHeight = height; - renderX = (width - renderWidth) / 2; - renderY = 0; - } - DrawTexturePro( - RENDER_BACKBUFFER.texture, - (Rectangle) { 0, 0, RENDER_WIDTH_PIXELS, -RENDER_HEIGHT_PIXELS }, - (Rectangle) { renderX, renderY, renderWidth, renderHeight }, - (Vector2) { 0, 0 }, - 0.0f, - WHITE - ); - } - - EndDrawing(); - if(WindowShouldClose()) RENDER_STATUS |= RENDER_SHOULD_EXIT; -} - -void renderDispose() { - UnloadRenderTexture(RENDER_TILES_TEXTURE); - CloseWindow(); -} - -void renderDisplayOn(void) { - RENDER_DISPLAY_ON = true; -} - -void renderDisplayOff(void) { - RENDER_DISPLAY_ON = false; -} - -void renderTilesBuffer( - const uint8_t index, - const uint8_t count, - const uint8_t *tiles -) { - assertTrue(count > 0, "Count must be greater than zero"); - assertNotNull(tiles, "Tiles pointer must not be null"); - - // Copy data to fake vram - memoryCopy( - &RENDER_TILES[index * RENDER_TILE_BYTES_PER_TILE], - tiles, - count * RENDER_TILE_BYTES_PER_TILE - ); -} - -void renderBackgroundTilesBufferRectangle( - const uint8_t xPos, - const uint8_t yPos, - const uint8_t width, - const uint8_t height, - const uint8_t *tiles -) { - uint8_t w = width, h = height, x = xPos, y = yPos; - assertNotNull(tiles, "Tiles pointer must not be null"); - - // Clamp x and y to tilemap bounds - if (x >= RENDER_BACKGROUND_COLUMNS) x = RENDER_BACKGROUND_COLUMNS - 1; - if (y >= RENDER_BACKGROUND_ROWS) y = RENDER_BACKGROUND_ROWS - 1; - - // Clamp width and height so we don't overflow past edges - if (x + w > RENDER_BACKGROUND_COLUMNS) { - w = RENDER_BACKGROUND_COLUMNS - x; - } - if (y + h > RENDER_BACKGROUND_ROWS) { - h = RENDER_BACKGROUND_ROWS - y; - } - - if (w == 0 || h == 0) return; - - for (uint8_t row = 0; row < h; row++) { - memoryCopy( - &RENDER_BACKGROUND_TILEMAP[(y + row) * RENDER_BACKGROUND_COLUMNS + x], - &tiles[row * width], - w - ); - } -} diff --git a/src/duskraylib/display/renderimpl.h b/src/duskraylib/display/renderimpl.h deleted file mode 100644 index 26542a9..0000000 --- a/src/duskraylib/display/renderimpl.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "duskraylib.h" -#include "display/renderbase.h" - -extern uint8_t RENDER_BACKGROUND_X; -extern uint8_t RENDER_BACKGROUND_Y; -extern bool_t RENDER_DISPLAY_ON; -extern uint8_t RENDER_TILES[RENDER_TILE_COUNT]; -extern Color RENDER_PALETTE[RENDER_PALETTE_COLOR_COUNT]; - -/** - * Sets the background tile data. - * - * @param index The starting index of the tile data. - * @param count The number of tiles to set. - * @param tiles Pointer to the tile data array. - */ -void renderTilesBuffer( - const uint8_t index, - const uint8_t count, - const uint8_t *tiles -); - -/** - * Sets the background tiles. - * - * @param x The x-coordinate of the top-left corner of the background. - * @param y The y-coordinate of the top-left corner of the background. - * @param width The width of the background in tiles. - * @param height The height of the background in tiles. - * @param tiles Pointer to the tile map data. - */ -void renderBackgroundTilesBufferRectangle( - const uint8_t x, - const uint8_t y, - const uint8_t width, - const uint8_t height, - const uint8_t *tiles -); \ No newline at end of file