Comitting before AI destroys it.

This commit is contained in:
2025-06-12 21:52:19 -05:00
parent ffaef7aa8d
commit e508d6575d
29 changed files with 632 additions and 492 deletions

View File

@ -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}) set(DUSK_ASSETS "" CACHE INTERNAL ${DUSK_CACHE_TARGET})
# Toolchain # Toolchain
if(DUSK_TARGET_SYSTEM STREQUAL "gb")
include(${CMAKE_SOURCE_DIR}/cmake/toolchains/gbdk.cmake)
endif()
# Create directories # Create directories
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR}) file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})

View File

@ -5,8 +5,6 @@
add_subdirectory(dusk) add_subdirectory(dusk)
if(DUSK_TARGET_SYSTEM STREQUAL "gb") if(DUSK_TARGET_SYSTEM STREQUAL "raylib")
add_subdirectory(duskgb)
elseif(DUSK_TARGET_SYSTEM STREQUAL "raylib")
add_subdirectory(duskraylib) add_subdirectory(duskraylib)
endif() endif()

View File

@ -23,4 +23,5 @@ target_sources(${DUSK_TARGET_NAME}
# Subdirs # Subdirs
add_subdirectory(assert) add_subdirectory(assert)
add_subdirectory(display) add_subdirectory(display)
add_subdirectory(util) add_subdirectory(util)
add_subdirectory(world)

View File

@ -6,5 +6,6 @@
# Sources # Sources
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
render.c renderbase.c
scene.c
) )

View File

@ -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);

View File

@ -5,4 +5,4 @@
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "render.h" #include "display/render.h"

View File

@ -8,12 +8,27 @@
#pragma once #pragma once
#include "dusk.h" #include "dusk.h"
#define RENDER_TILE_COUNT 384 #define RENDER_WIDTH 320
#define RENDER_TILE_WIDTH 8 #define RENDER_HEIGHT 240
#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) * Initializes the rendering system.
#define RENDER_BACKGROUND_COLUMNS 32 */
#define RENDER_BACKGROUND_ROWS 32 void renderInit(void);
#define RENDER_BACKGROUND_TILE_COUNT (RENDER_BACKGROUND_COLUMNS * RENDER_BACKGROUND_ROWS)
#define RENDER_PALETTE_COLOR_COUNT 4 /**
* 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();

10
src/dusk/display/scene.c Normal file
View File

@ -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;

15
src/dusk/display/scene.h Normal file
View File

@ -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;

View File

@ -6,5 +6,4 @@
*/ */
#pragma once #pragma once
#include "dusk.h" #include "dusk.h"
#include <gb/gb.h>

View File

@ -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 "display/render.h"
#include "util/memory.h" #include "util/memory.h"
#include "world/chunk.h"
#include "display/scene.h"
#define backgroundTilesCount 7 #include "world/overworld.h"
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();
}
}
// Press F5 to compile and run the compiled game.gb in the Emulicous Emulator/Debugger // Press F5 to compile and run the compiled game.gb in the Emulicous Emulator/Debugger
void main(void) { void main(void) {
renderInit(); renderInit();
overworldInit();
renderTilesBuffer(0, 7, backgroundTiles); SCENE_CURRENT = SCENE_OVERWORLD;
renderBackgroundTilesBufferRectangle(0, 0, backgroundmapWidth, backgroundmapHeight, backgroundmap);
renderDisplayOn(); while(!renderShouldExit()) {
renderDraw();
while (1) {
RENDER_BACKGROUND_X++; OVERWORLD_CAMERA_SUB_X++;
pdelay(3);
overworldUpdate();
if((RENDER_STATUS & RENDER_SHOULD_EXIT) != 0) break;
} }
renderDispose(); renderDispose();

View File

@ -1,10 +1,11 @@
# Copyright (c) 2025 Dominic Masters # Copyright (c) 2025 Dominic Masters
# #
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
# Sources # Sources
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
renderimpl.c chunk.c
overworld.c
) )

190
src/dusk/world/chunk.c Normal file
View File

@ -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");
}

69
src/dusk/world/chunk.h Normal file
View File

@ -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);

View File

@ -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
);
}

View File

@ -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);

14
src/dusk/world/tile.h Normal file
View File

@ -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;

View File

@ -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)

View File

@ -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) {
}

View File

@ -6,5 +6,8 @@
# Sources # Sources
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
renderimpl.c render.c
) )
# Subdirs
add_subdirectory(draw)

View File

@ -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
)

View File

@ -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();
}

View File

@ -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);

View File

@ -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");
}
}

View File

@ -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);

View File

@ -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();
}

View File

@ -6,10 +6,8 @@
*/ */
#pragma once #pragma once
#include "duskgb.h" #include "duskraylib.h"
#include "display/renderbase.h" #include "display/renderbase.h"
#define RENDER_BACKGROUND_X SCX_REG extern RenderTexture2D RENDER_SCREEN_TEXTURE;
#define RENDER_BACKGROUND_Y SCY_REG extern Camera2D RENDER_CAMERA;
#define renderTilesBuffer set_bkg_data

View File

@ -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
);
}
}

View File

@ -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
);