This commit is contained in:
2025-10-01 13:20:34 -05:00
parent 28174b8dc8
commit 22e2f703db
229 changed files with 272 additions and 8941 deletions

View File

@@ -33,10 +33,11 @@ add_subdirectory(console)
add_subdirectory(display)
add_subdirectory(engine)
add_subdirectory(error)
add_subdirectory(game)
add_subdirectory(input)
# add_subdirectory(locale)
add_subdirectory(physics)
add_subdirectory(rpg)
# add_subdirectory(rpg)
add_subdirectory(thread)
add_subdirectory(time)
add_subdirectory(util)

View File

@@ -21,9 +21,6 @@ assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT] = {
[ASSET_TYPE_CONFIG] = {
"DCF", assetConfigLoad, assetConfigDispose
},
[ASSET_TYPE_RPG_MAP] = {
"DRM", assetRPGMapLoad, assetRPGMapDispose
},
};
errorret_t assetInit(asset_t *asset, const char_t *filename) {

View File

@@ -13,7 +13,6 @@
#include "asset/type/assetpaletteimage.h"
#include "asset/type/assetalphaimage.h"
#include "asset/type/assetconfig.h"
#include "asset/type/assetrpgmap.h"
#define ASSET_HEADER_SIZE 3
#define ASSET_REFERENCE_COUNT_MAX 8
@@ -34,7 +33,6 @@ typedef enum {
ASSET_TYPE_PALETTE_IMAGE,
ASSET_TYPE_ALPHA_IMAGE,
ASSET_TYPE_CONFIG,
ASSET_TYPE_RPG_MAP,
ASSET_TYPE_COUNT
} assettype_t;
@@ -51,7 +49,6 @@ typedef struct asset_s {
assetpaletteimage_t paletteImage;
assetalphaimage_t alphaImage;
assetconfig_t config;
assetrpgmap_t rpgMap;
};
} asset_t;

View File

@@ -9,5 +9,4 @@ target_sources(${DUSK_TARGET_NAME}
assetalphaimage.c
assetconfig.c
assetpaletteimage.c
assetrpgmap.c
)

View File

@@ -1,98 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetrpgmap.h"
#include "asset/asset.h"
#include "assert/assert.h"
#include "display/tileset/tilesetlist.h"
errorret_t assetRPGMapLoad(asset_t *asset) {
assertNotNull(asset, "Asset cannot be NULL.");
assertTrue(
asset->type == ASSET_TYPE_RPG_MAP,
"Asset is not of type ASSET_TYPE_RPG_MAP."
);
assetrpgmapraw_t raw;
// Read map header info
zip_int64_t bytesRead = zip_fread(
asset->file, &raw.header, sizeof(assetrpgmapheader_t)
);
if(bytesRead != sizeof(raw.header)) {
errorThrow("Failed to read RPG map header.");
}
if(raw.header.mapWidth == 0 || raw.header.mapWidth > MAP_WIDTH_MAX) {
errorThrow("Invalid RPG map width.");
}
if(raw.header.mapHeight == 0 || raw.header.mapHeight > MAP_HEIGHT_MAX) {
errorThrow("Invalid RPG map height.");
}
if(raw.header.tilesetCount == 0) {
errorThrow("Invalid RPG map tileset count.");
}
if(raw.header.tilesetCount > ASSET_RPG_MAP_TILESET_COUNT_MAX) {
errorThrow("Invalid RPG map tileset count.");
}
if(raw.header.tileLayerCount == 0) {
errorThrow("Invalid RPG map layer count.");
}
if(raw.header.tileLayerCount > MAP_LAYER_COUNT_MAX) {
errorThrow("Invalid RPG map layer count.");
}
// Read layers
for(uint32_t layer = 0; layer < raw.header.tileLayerCount; layer++) {
// Read width * height tiles
bytesRead = zip_fread(
asset->file,
&raw.layers[layer].tiles,
sizeof(assetrpgmaptile_t) * raw.header.mapWidth * raw.header.mapHeight
);
if(bytesRead != (
sizeof(assetrpgmaptile_t) * raw.header.mapWidth * raw.header.mapHeight
)) errorThrow("Failed to read RPG map layer %u.", layer);
}
// For each tileset
for(uint32_t tileset = 0; tileset < raw.header.tilesetCount; tileset++) {
// Read tileset
bytesRead = zip_fread(
asset->file,
&raw.tilesets[tileset],
sizeof(assetrpgmaptileset_t)
);
if(bytesRead != sizeof(assetrpgmaptileset_t)) {
errorThrow("Failed to read RPG map tileset %u.", tileset);
}
}
// Map data is loaded, we can load it into the map structure.
mapInit(&asset->rpgMap.map);
entity_t *ent;
ent = mapEntityAdd(&asset->rpgMap.map);
entityInit(ent, ENTITY_TYPE_PLAYER, &asset->rpgMap.map);
errorOk();
}
errorret_t assetRPGMapDispose(asset_t *asset) {
assertNotNull(asset, "Asset cannot be NULL.");
assertTrue(
asset->type == ASSET_TYPE_RPG_MAP,
"Asset is not of type ASSET_TYPE_RPG_MAP."
);
errorOk();
}

View File

@@ -1,64 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
#include "rpg/world/map.h"
typedef struct asset_s asset_t;
#define ASSET_RPG_MAP_TILESET_COUNT_MAX 16
#pragma pack(push, 1)
typedef struct {
uint32_t mapWidth;
uint32_t mapHeight;
uint32_t tilesetCount;
uint32_t tileLayerCount;
} assetrpgmapheader_t;
typedef struct {
uint32_t firstGid;
uint32_t tilesetIndex;
} assetrpgmaptileset_t;
typedef struct {
uint32_t tilesetIndex;
} assetrpgmaptile_t;
typedef struct {
assetrpgmaptile_t tiles[MAP_TILE_COUNT_MAX];
} assetrpgmaplayer_t;
typedef struct {
assetrpgmapheader_t header;
assetrpgmaplayer_t layers[MAP_LAYER_COUNT_MAX];
assetrpgmaptileset_t tilesets[ASSET_RPG_MAP_TILESET_COUNT_MAX];
} assetrpgmapraw_t;
#pragma pack(pop)
typedef struct {
map_t map;
} assetrpgmap_t;
/**
* Loads an RPG map asset from the given asset structure. The asset must be of
* type ASSET_TYPE_RPG_MAP and must be loaded.
*
* @param asset The asset to load the RPG map from.
* @return An error code.
*/
errorret_t assetRPGMapLoad(asset_t *asset);
/**
* Disposes of an RPG map asset, freeing any allocated resources.
*
* @param asset The asset to dispose of.
* @return An error code.
*/
errorret_t assetRPGMapDispose(asset_t *asset);

View File

@@ -28,10 +28,10 @@ void frameBufferInitBackbuffer() {
) {
#if DISPLAY_SDL2 == 1
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
assertTrue(width > 0 && height > 0, "Width & height must be greater than 0");
assertTrue(width > 0 && height > 0, "W/H must be greater than 0");
memoryZero(framebuffer, sizeof(framebuffer_t));
textureInit(&framebuffer->texture, width, height, GL_RGBA, (texturedata_t){
textureInit(&framebuffer->texture, width, height, GL_RGBA,(texturedata_t){
.rgba = { .colors = NULL }
});

View File

@@ -9,6 +9,4 @@ target_sources(${DUSK_TARGET_NAME}
scenemanager.c
)
# Subdirs
add_subdirectory(overworld)
add_subdirectory(test)
# Subdirs

View File

@@ -21,14 +21,4 @@ typedef struct {
void (*sleep)(void);
uint8_t flags;
} scene_t;
typedef enum {
SCENE_TYPE_LOGO,
SCENE_TYPE_TEST,
SCENE_TYPE_OVERWORLD,
SCENE_TYPE_COUNT
} scenetype_t;
#define SCENE_TYPE_INITIAL SCENE_TYPE_OVERWORLD
} scene_t;

View File

@@ -7,55 +7,52 @@
#include "scenemanager.h"
#include "display/scene/overworld/sceneoverworld.h"
#include "display/scene/test/scenetest.h"
scenemanager_t SCENE_MANAGER;
scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT] = {
[SCENE_TYPE_LOGO] = { 0 },
// scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT] = {
// [SCENE_TYPE_LOGO] = { 0 },
[SCENE_TYPE_TEST] = {
.init = sceneTestInit,
.update = sceneTestUpdate,
.render = sceneTestRender,
.dispose = sceneTestDispose
},
// [SCENE_TYPE_TEST] = {
// .init = sceneTestInit,
// .update = sceneTestUpdate,
// .render = sceneTestRender,
// .dispose = sceneTestDispose
// },
[SCENE_TYPE_OVERWORLD] = {
.init = sceneOverworldInit,
.update = sceneOverworldUpdate,
.render = sceneOverworldRender,
.dispose = sceneOverworldDispose
}
};
// [SCENE_TYPE_OVERWORLD] = {
// .init = sceneOverworldInit,
// .update = sceneOverworldUpdate,
// .render = sceneOverworldRender,
// .dispose = sceneOverworldDispose
// }
// };
errorret_t sceneManagerInit(void) {
scene_t *initial = &SCENE_MANAGER_SCENES[SCENE_TYPE_INITIAL];
if(initial->init != NULL) errorChain(initial->init());
// scene_t *initial = &SCENE_MANAGER_SCENES[SCENE_TYPE_INITIAL];
// if(initial->init != NULL) errorChain(initial->init());
errorOk();
}
void sceneManagerUpdate(void) {
// For each scene.
for(uint8_t i = 0; i < SCENE_TYPE_COUNT; i++) {
scene_t *scene = &SCENE_MANAGER_SCENES[i];
if((scene->flags & SCENE_FLAG_ACTIVE) == 0) continue;
if(scene->update != NULL) scene->update();
}
// for(uint8_t i = 0; i < SCENE_TYPE_COUNT; i++) {
// scene_t *scene = &SCENE_MANAGER_SCENES[i];
// if((scene->flags & SCENE_FLAG_ACTIVE) == 0) continue;
// if(scene->update != NULL) scene->update();
// }
}
void sceneManagerRender(void) {
for(uint8_t i = 0; i < SCENE_TYPE_COUNT; i++) {
scene_t *scene = &SCENE_MANAGER_SCENES[i];
if((scene->flags & SCENE_FLAG_VISIBLE) == 0) continue;
if(scene->render != NULL) scene->render();
}
// for(uint8_t i = 0; i < SCENE_TYPE_COUNT; i++) {
// scene_t *scene = &SCENE_MANAGER_SCENES[i];
// if((scene->flags & SCENE_FLAG_VISIBLE) == 0) continue;
// if(scene->render != NULL) scene->render();
// }
}
void sceneManagerDispose(void) {
for(uint8_t i = 0; i < SCENE_TYPE_COUNT; i++) {
scene_t *scene = &SCENE_MANAGER_SCENES[i];
if(scene->dispose != NULL) scene->dispose();
}
// for(uint8_t i = 0; i < SCENE_TYPE_COUNT; i++) {
// scene_t *scene = &SCENE_MANAGER_SCENES[i];
// if(scene->dispose != NULL) scene->dispose();
// }
}

View File

@@ -13,7 +13,7 @@ typedef struct {
} scenemanager_t;
extern scenemanager_t SCENE_MANAGER;
extern scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT];
// extern scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT];
/**
* Initializes the scene manager and the initial scene.

View File

@@ -13,12 +13,22 @@
#include "uifps.h"
#include "util/memory.h"
#include "display/tileset/tileset_minogram.h"
ui_t UI;
errorret_t uiInit(void) {
memoryZero(&UI, sizeof(ui_t));
errorChain(uiTextInit());
// Load debug font.
UI.debugFontTileset = &TILESET_MINOGRAM;
errorChain(assetManagerLoadAsset(
UI.debugFontTileset->image,
&UI.debugFontAsset,
&UI.debugFontRef
));
// Setup UI Camera.
cameraInit(&UI.camera);
UI.camera.projType = CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC;
@@ -28,12 +38,12 @@ errorret_t uiInit(void) {
UI.camera.orthographic.bottom = frameBufferGetHeight(&FRAMEBUFFER_BACKBUFFER);
UI.camera.nearClip = -1.0f;
UI.camera.farClip = 1.0f;
UI.camera.viewType = CAMERA_VIEW_TYPE_MATRIX;
glm_mat4_identity(UI.camera.view);
UI.scale = 1.0f;
// Setup FPS element.
uiFPSInit();
errorOk();
@@ -61,5 +71,5 @@ void uiRender(void) {
}
void uiDispose(void) {
uiTextDispose();
}

View File

@@ -8,10 +8,17 @@
#pragma once
#include "error/error.h"
#include "display/camera.h"
#include "display/texture/texture.h"
#include "display/tileset.h"
#include "asset/asset.h"
typedef struct {
camera_t camera;
float_t scale;
const tileset_t *debugFontTileset;
asset_t *debugFontAsset;
ref_t debugFontRef;
} ui_t;
extern ui_t UI;

View File

@@ -8,6 +8,7 @@
#include "uiconsole.h"
#include "uitext.h"
#include "console/console.h"
#include "ui.h"
void uiConsoleRender(void) {
if(!CONSOLE.visible) return;
@@ -21,7 +22,11 @@ void uiConsoleRender(void) {
i--;
continue;
}
uiTextDraw(0, i * TILESET_MINOGRAM.tileHeight, line, COLOR_WHITE);
uiTextDraw(
0, i * TILESET_MINOGRAM.tileHeight,
line, COLOR_WHITE,
UI.debugFontTileset, &UI.debugFontAsset->alphaImage.texture
);
i--;
} while(i > 0);
}

View File

@@ -10,6 +10,7 @@
#include "time/time.h"
#include "console/console.h"
#include "util/string.h"
#include "ui.h"
void uiFPSInit(void) {
consoleRegVar("fps", "0", NULL);
@@ -36,5 +37,9 @@ void uiFPSRender(void) {
COLOR_RED
);
uiTextDraw(0, 0, buffer, color);
uiTextDraw(
0, 0,
buffer, color,
UI.debugFontTileset, &UI.debugFontAsset->alphaImage.texture
);
}

View File

@@ -11,47 +11,32 @@
#include "util/memory.h"
#include "display/spritebatch/spritebatch.h"
uitext_t UI_TEXT;
errorret_t uiTextInit(void) {
memoryZero(&UI_TEXT, sizeof(uitext_t));
errorChain(assetManagerLoadAsset(
TILESET_MINOGRAM.image, &UI_TEXT.asset, &UI_TEXT.assetRef
));
errorOk();
}
void uiTextDispose(void) {
if(UI_TEXT.asset) {
assetUnlock(UI_TEXT.asset, UI_TEXT.assetRef);
}
}
void uiTextDrawChar(
const float_t x,
const float_t y,
const char_t c,
const color_t color
const color_t color,
const tileset_t *tileset,
texture_t *texture
) {
int32_t tileIndex = (int32_t)(c) - UI_TEXT_CHAR_START;
if(tileIndex < 0 || tileIndex >= TILESET_MINOGRAM.tileCount) {
if(tileIndex < 0 || tileIndex >= tileset->tileCount) {
tileIndex = ((int32_t)'@') - UI_TEXT_CHAR_START;
}
assertTrue(
tileIndex >= 0 && tileIndex <= TILESET_MINOGRAM.tileCount,
tileIndex >= 0 && tileIndex <= tileset->tileCount,
"Character is out of bounds for font tiles"
);
vec4 uv;
tilesetTileGetUV(&TILESET_MINOGRAM, tileIndex, uv);
tilesetTileGetUV(tileset, tileIndex, uv);
spriteBatchPush(
&UI_TEXT.asset->alphaImage.texture,
texture,
x, y,
x + TILESET_MINOGRAM.tileWidth,
y + TILESET_MINOGRAM.tileHeight,
x + tileset->tileWidth,
y + tileset->tileHeight,
color,
uv[0], uv[1], uv[2], uv[3]
);
@@ -61,7 +46,9 @@ void uiTextDraw(
const float_t x,
const float_t y,
const char_t *text,
const color_t color
const color_t color,
const tileset_t *tileset,
texture_t *texture
) {
assertNotNull(text, "Text cannot be NULL");
@@ -73,22 +60,23 @@ void uiTextDraw(
while((c = text[i++]) != '\0') {
if(c == '\n') {
posX = x;
posY += TILESET_MINOGRAM.tileHeight;
posY += tileset->tileHeight;
continue;
}
if(c == ' ') {
posX += TILESET_MINOGRAM.tileWidth;
posX += tileset->tileWidth;
continue;
}
uiTextDrawChar(posX, posY, c, color);
posX += TILESET_MINOGRAM.tileWidth;
uiTextDrawChar(posX, posY, c, color, tileset, texture);
posX += tileset->tileWidth;
}
}
void uiTextMeasure(
const char_t *text,
const tileset_t *tileset,
int32_t *outWidth,
int32_t *outHeight
) {
@@ -97,7 +85,7 @@ void uiTextMeasure(
assertNotNull(outHeight, "Output height pointer cannot be NULL");
int32_t width = 0;
int32_t height = TILESET_MINOGRAM.tileHeight;
int32_t height = tileset->tileHeight;
int32_t lineWidth = 0;
char_t c;
@@ -108,11 +96,11 @@ void uiTextMeasure(
width = lineWidth;
}
lineWidth = 0;
height += TILESET_MINOGRAM.tileHeight;
height += tileset->tileHeight;
continue;
}
lineWidth += TILESET_MINOGRAM.tileWidth;
lineWidth += tileset->tileWidth;
}
if(lineWidth > width) {

View File

@@ -11,18 +11,6 @@
#define UI_TEXT_CHAR_START '!'
typedef struct {
ref_t assetRef;
asset_t *asset;
} uitext_t;
extern uitext_t UI_TEXT;
/**
* Initializes the text rendering system.
*/
errorret_t uiTextInit(void);
/**
* Draws a single character at the specified position.
*
@@ -30,12 +18,16 @@ errorret_t uiTextInit(void);
* @param y The y-coordinate to draw the character at.
* @param c The character to draw.
* @param color The color to draw the character in.
* @param tileset Font tileset to use for rendering.
* @param texture Texture containing the font tileset image.
*/
void uiTextDrawChar(
const float_t x,
const float_t y,
const char_t c,
const color_t color
const color_t color,
const tileset_t *tileset,
texture_t *texture
);
/**
@@ -45,28 +37,29 @@ void uiTextDrawChar(
* @param y The y-coordinate to draw the text at.
* @param text The null-terminated string of text to draw.
* @param color The color to draw the text in.
* @param tileset Font tileset to use for rendering.
* @param texture Texture containing the font tileset image.
*/
void uiTextDraw(
const float_t x,
const float_t y,
const char_t *text,
const color_t color
const color_t color,
const tileset_t *tileset,
texture_t *texture
);
/**
* Measures the width and height of the given text string when rendered.
*
* @param text The null-terminated string of text to measure.
* @param tileset Font tileset to use for measurement.
* @param outWidth Pointer to store the measured width in pixels.
* @param outHeight Pointer to store the measured height in pixels.
*/
void uiTextMeasure(
const char_t *text,
const tileset_t *tileset,
int32_t *outWidth,
int32_t *outHeight
);
/**
* Disposes of the text rendering system, freeing any allocated resources.
*/
void uiTextDispose(void);
);

View File

@@ -12,7 +12,7 @@
#include "console/console.h"
#include "display/display.h"
#include "asset/assetmanager.h"
#include "rpg/rpg.h"
#include "game/game.h"
engine_t ENGINE;
@@ -29,7 +29,7 @@ errorret_t engineInit(void) {
inputInit();
errorChain(assetManagerInit());
errorChain(displayInit());
rpgInit();
errorChain(gameInit());
// Init scripts
#if PSP
@@ -46,14 +46,15 @@ errorret_t engineUpdate(void) {
inputUpdate();
consoleUpdate();
assetManagerUpdate();
rpgUpdate();
gameUpdate();
errorChain(displayUpdate());
errorOk();
}
errorret_t engineDispose(void) {
gameDispose();
errorChain(displayDispose());
assetManagerDispose();
consoleDispose();

18
src/game/CMakeLists.txt Normal file
View File

@@ -0,0 +1,18 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
if(NOT DEFINED DUSK_TARGET_GAME)
message(FATAL_ERROR "DUSK_TARGET_GAME is not defined.")
endif()
string(TOUPPER "${DUSK_TARGET_GAME}" DUSK_TARGET_GAME_UPPER)
target_compile_definitions(${DUSK_TARGET_NAME}
PRIVATE
DUSK_TARGET_GAME=${DUSK_TARGET_GAME}
DUSK_GAME_${DUSK_TARGET_GAME_UPPER}=1
)
add_subdirectory(${DUSK_TARGET_GAME})

16
src/game/game.h Normal file
View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#if DUSK_GAME_RPG == 1
#include "rpg/game.h"
#elif DUSK_GAME_MINESWEEPER == 1
#include "minesweeper/game.h"
#else
#error "Unknown game specified"
#endif

16
src/game/gamescene.h Normal file
View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#if DUSK_GAME_RPG == 1
#include "rpg/scene.h"
#elif DUSK_GAME_MINESWEEPER == 1
#include "minesweeper/scene.h"
#else
#error "Unknown game specified"
#endif

View File

@@ -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
game.c
)
# Subdirs

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "game.h"
errorret_t gameInit(void) {
errorOk();
}
void gameUpdate(void) {
}
void gameDispose(void) {
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
/**
* Initializes the game.
*/
errorret_t gameInit(void);
/**
* Updates the game.
*/
void gameUpdate(void);
/**
* Disposes of the game.
*/
void gameDispose(void);

View File

@@ -0,0 +1,11 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#error TEST