About to refator tools... again

This commit is contained in:
2025-09-01 17:22:33 -05:00
parent 3ce1566a2e
commit 4541d5219b
14 changed files with 468 additions and 43 deletions

View File

@@ -3,5 +3,6 @@
# 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
add_asset(first.palette.png) add_asset(PALETTE first.palette.png test0)
add_asset(entities.tsx) add_asset(TILESET entities.tsx test test3)
add_asset(IMAGE minogram_6x10.png test2)

BIN
assets/minogram_6x10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -17,6 +17,7 @@ add_subdirectory(mesh)
add_subdirectory(texture) add_subdirectory(texture)
add_subdirectory(scene) add_subdirectory(scene)
add_subdirectory(spritebatch) add_subdirectory(spritebatch)
add_subdirectory(ui)
if(DUSK_TARGET_SYSTEM STREQUAL "linux") if(DUSK_TARGET_SYSTEM STREQUAL "linux")
target_compile_definitions(${DUSK_TARGET_NAME} target_compile_definitions(${DUSK_TARGET_NAME}

View File

@@ -10,32 +10,28 @@
#include "assert/assert.h" #include "assert/assert.h"
#include "display/framebuffer/framebuffer.h" #include "display/framebuffer/framebuffer.h"
camera_t CAMERA_DATA[CAMERA_COUNT_MAX] = { 0 };
camera_t *CAMERA_MAIN = NULL;
void cameraInit(camera_t *camera) { void cameraInit(camera_t *camera) {
assertNotNull(camera, "Not a camera component"); assertNotNull(camera, "Not a camera component");
camera->type = CAMERA_TYPE_PERSPECTIVE; camera->projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE;
camera->perspective.fov = glm_rad(45.0f); camera->perspective.fov = glm_rad(45.0f);
camera->nearClip = 0.1f; camera->nearClip = 0.1f;
camera->farClip = 100.0f; camera->farClip = 1000.0f;
glm_lookat( camera->viewType = CAMERA_VIEW_TYPE_LOOKAT;
(vec3){ 5.0f, 5.0f, 5.0f }, glm_vec3_copy((vec3){ 5.0f, 5.0f, 5.0f }, camera->lookat.position);
(vec3){ 0.0f, 0.0f, 0.0f }, glm_vec3_copy((vec3){ 0.0f, 1.0f, 0.0f }, camera->lookat.up);
(vec3){ 0.0f, 1.0f, 0.0f }, glm_vec3_copy((vec3){ 0.0f, 0.0f, 0.0f }, camera->lookat.target);
camera->transform
);
} }
void cameraPushMatrix(camera_t *camera) { void cameraPushMatrix(camera_t *camera) {
assertNotNull(camera, "Not a camera component"); assertNotNull(camera, "Not a camera component");
mat4 projection; mat4 projection;
mat4 view;
switch(camera->type) { switch(camera->projType) {
case CAMERA_TYPE_ORTHOGRAPHIC: case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC:
glm_ortho( glm_ortho(
camera->orthographic.left, camera->orthographic.left,
camera->orthographic.right, camera->orthographic.right,
@@ -47,7 +43,7 @@ void cameraPushMatrix(camera_t *camera) {
); );
break; break;
case CAMERA_TYPE_PERSPECTIVE: case CAMERA_PROJECTION_TYPE_PERSPECTIVE:
const float_t aspect = ( const float_t aspect = (
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) / (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND) (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
@@ -61,6 +57,21 @@ void cameraPushMatrix(camera_t *camera) {
); );
} }
switch(camera->viewType) {
case CAMERA_VIEW_TYPE_MATRIX:
glm_mat4_copy(camera->view, view);
break;
case CAMERA_VIEW_TYPE_LOOKAT:
glm_lookat(
camera->lookat.position,
camera->lookat.target,
camera->lookat.up,
view
);
break;
}
#if DISPLAY_SDL2 #if DISPLAY_SDL2
// mat4 pv; // mat4 pv;
// glm_mat4_mul(projection, camera->transform, pv); // glm_mat4_mul(projection, camera->transform, pv);
@@ -72,7 +83,7 @@ void cameraPushMatrix(camera_t *camera) {
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
glLoadMatrixf((const GLfloat*)camera->transform); glLoadMatrixf((const GLfloat*)view);
#endif #endif
} }

View File

@@ -12,14 +12,27 @@
#define CAMERA_COUNT_MAX 4 #define CAMERA_COUNT_MAX 4
typedef enum { typedef enum {
CAMERA_TYPE_PERSPECTIVE, CAMERA_PROJECTION_TYPE_PERSPECTIVE,
CAMERA_TYPE_ORTHOGRAPHIC CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
} cameraprojectiontype_t; } cameraprojectiontype_t;
typedef struct { typedef enum {
cameraprojectiontype_t type; CAMERA_VIEW_TYPE_MATRIX,
CAMERA_VIEW_TYPE_LOOKAT
} cameraviewtype_t;
mat4 transform; typedef struct {
cameraprojectiontype_t projType;
cameraviewtype_t viewType;
union {
mat4 view;
struct {
float_t position[3];
float_t target[3];
float_t up[3];
} lookat;
};
union { union {
struct { struct {
@@ -38,9 +51,6 @@ typedef struct {
float_t farClip; float_t farClip;
} camera_t; } camera_t;
extern camera_t CAMERA_DATA[CAMERA_COUNT_MAX];
extern camera_t *CAMERA_MAIN;
/** /**
* Initializes a camera to default values. * Initializes a camera to default values.
*/ */

View File

@@ -86,8 +86,12 @@ errorret_t displayUpdate(void) {
glViewport(0, 0, windowWidth, windowHeight); glViewport(0, 0, windowWidth, windowHeight);
#endif #endif
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
spriteBatchClear(); spriteBatchClear();
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
frameBufferClear(
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
COLOR_CORNFLOWER_BLUE
);
sceneManagerUpdate(); sceneManagerUpdate();
sceneManagerRender(); sceneManagerRender();

View File

@@ -16,15 +16,7 @@ camera_t SCENE_OVERWORLD_CAMERA;
void sceneOverworldInit(void) { void sceneOverworldInit(void) {
cameraInit(&SCENE_OVERWORLD_CAMERA); cameraInit(&SCENE_OVERWORLD_CAMERA);
SCENE_OVERWORLD_CAMERA.type = CAMERA_TYPE_ORTHOGRAPHIC; glm_vec3_copy((vec3){32.0f, 32.0f, 32.0f}, SCENE_OVERWORLD_CAMERA.lookat.position);
SCENE_OVERWORLD_CAMERA.orthographic.left = 0.0f;
SCENE_OVERWORLD_CAMERA.orthographic.right = frameBufferGetWidth(FRAMEBUFFER_BOUND);
SCENE_OVERWORLD_CAMERA.orthographic.top = 0.0f;
SCENE_OVERWORLD_CAMERA.orthographic.bottom = frameBufferGetHeight(FRAMEBUFFER_BOUND);
SCENE_OVERWORLD_CAMERA.nearClip = -1.0f;
SCENE_OVERWORLD_CAMERA.farClip = 100.0f;
glm_mat4_identity(SCENE_OVERWORLD_CAMERA.transform);
scene_t *scene = &SCENE_MANAGER_SCENES[SCENE_TYPE_OVERWORLD]; scene_t *scene = &SCENE_MANAGER_SCENES[SCENE_TYPE_OVERWORLD];
scene->flags |= SCENE_FLAG_ACTIVE | SCENE_FLAG_VISIBLE; scene->flags |= SCENE_FLAG_ACTIVE | SCENE_FLAG_VISIBLE;
@@ -34,17 +26,17 @@ void sceneOverworldUpdate(void) {
} }
void sceneOverworldRender(void) { void sceneOverworldRender(void) {
frameBufferClear(
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
COLOR_CORNFLOWER_BLUE
);
cameraPushMatrix(&SCENE_OVERWORLD_CAMERA); cameraPushMatrix(&SCENE_OVERWORLD_CAMERA);
meshDraw(&QUAD_MESH_SIMPLE, -1, -1);
// Draw base layer
// Draw entities
// Draw overlay layer.
spriteBatchPush( spriteBatchPush(
NULL, NULL,
0.0f, 0.0f, 32.0f, 32.0f, 0.0f, 0.0f, 12.0f, 12.0f,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0.0f, 0.0f, 1.0f, 1.0f 0.0f, 0.0f, 1.0f, 1.0f
); );

View File

@@ -0,0 +1,10 @@
# 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
rendertext.c
)

160
src/display/ui/rendertext.c Normal file
View File

@@ -0,0 +1,160 @@
// /**
// * Copyright (c) 2025 Dominic Masters
// *
// * This software is released under the MIT License.
// * https://opensource.org/licenses/MIT
// */
// #include "rendertext.h"
// #include "display/display.h"
// #include "assert/assert.h"
// #include "display/spritebatch/spritebatch.h"
// #include "util/memory.h"
// #include "util/math.h"
// texture_t RENDER_TEXT_TEXTURE;
// static mesh_t RENDER_TEXT_QUAD_MESH;
// void renderTextInit(void) {
// const int32_t cols = FONT_COLUMN_COUNT;
// const int32_t rows = (FONT_TILE_COUNT + cols - 1) / cols;
// const int32_t inputFontWidth = cols * FONT_TILE_WIDTH;
// const int32_t inputFontHeight = rows * FONT_TILE_HEIGHT;
// int32_t outputFontWidth = inputFontWidth;
// int32_t outputFontHeight = inputFontHeight;
// // // Round up to nearest power of 2
// // #if PSP
// // outputFontWidth = mathNextPowTwo(inputFontWidth);
// // outputFontHeight = mathNextPowTwo(inputFontHeight);
// // #endif
// uint8_t *pixels = (uint8_t *)memoryAllocate(
// outputFontWidth * outputFontHeight *
// sizeof(uint8_t)
// );
// // Buffer the pixels.
// for(int tileIndex = 0; tileIndex < FONT_TILE_COUNT; ++tileIndex) {
// const int32_t tileX = (tileIndex % FONT_COLUMN_COUNT) * FONT_TILE_WIDTH;
// const int32_t tileY = (tileIndex / FONT_COLUMN_COUNT) * FONT_TILE_HEIGHT;
// const uint8_t* tile = TILE_PIXEL_DATA[tileIndex];
// for (int y = 0; y < FONT_TILE_HEIGHT; ++y) {
// for (int x = 0; x < FONT_TILE_WIDTH; ++x) {
// const int32_t pixel = (tileY + y) * outputFontWidth + (tileX + x);
// const int32_t pixelOffset = pixel;
// uint8_t value = tile[y * FONT_TILE_WIDTH + x];
// pixels[pixel] = value ? 0xFF : 0x00; // Alpha channel
// }
// }
// }
// textureInit(
// &RENDER_TEXT_TEXTURE,
// outputFontWidth, outputFontHeight,
// TEXTURE_FORMAT_ALPHA, pixels
// );
// memoryFree(pixels);
// }
// void renderTextDrawChar(
// const float_t x,
// const float_t y,
// const char_t c,
// const uint8_t r,
// const uint8_t g,
// const uint8_t b
// ) {
// int32_t tileIndex = (int32_t)(c) - FONT_CHAR_START;
// assertTrue(
// tileIndex >= 0 && tileIndex < FONT_TILE_COUNT,
// "Character is out of bounds for font tiles"
// );
// const float_t w = (float)RENDER_TEXT_TEXTURE.width;
// const float_t h = (float)RENDER_TEXT_TEXTURE.height;
// const int32_t tileX = (tileIndex % FONT_COLUMN_COUNT);
// const int32_t tileY = (tileIndex / FONT_COLUMN_COUNT);
// spriteBatchPush(
// &RENDER_TEXT_TEXTURE,
// x, y,
// x + FONT_TILE_WIDTH, y + FONT_TILE_HEIGHT,
// r, g, b, 0xFF,
// (tileX * FONT_TILE_WIDTH) / w,
// (tileY * FONT_TILE_HEIGHT) / h,
// ((tileX + 1) * FONT_TILE_WIDTH) / w,
// ((tileY + 1) * FONT_TILE_HEIGHT) / h
// );
// }
// void renderTextDraw(
// const float_t x,
// const float_t y,
// const char_t *text,
// const uint8_t r,
// const uint8_t g,
// const uint8_t b
// ) {
// assertNotNull(text, "Text cannot be NULL");
// float_t posX = x;
// float_t posY = y;
// char_t c;
// int32_t i = 0;
// while((c = text[i++]) != '\0') {
// if(c == '\n') {
// posX = x;
// posY += FONT_TILE_HEIGHT;
// continue;
// }
// renderTextDrawChar(posX, posY, c, r, g, b);
// posX += FONT_TILE_WIDTH;
// }
// }
// void renderTextMeasure(
// const char_t *text,
// int32_t *outWidth,
// int32_t *outHeight
// ) {
// assertNotNull(text, "Text cannot be NULL");
// assertNotNull(outWidth, "Output width pointer cannot be NULL");
// assertNotNull(outHeight, "Output height pointer cannot be NULL");
// int32_t width = 0;
// int32_t height = FONT_TILE_HEIGHT;
// int32_t lineWidth = 0;
// char_t c;
// int32_t i = 0;
// while((c = text[i++]) != '\0') {
// if(c == '\n') {
// if(lineWidth > width) {
// width = lineWidth;
// }
// lineWidth = 0;
// height += FONT_TILE_HEIGHT;
// continue;
// }
// lineWidth += FONT_TILE_WIDTH;
// }
// if(lineWidth > width) {
// width = lineWidth;
// }
// *outWidth = width;
// *outHeight = height;
// }
// lineWidth += FONT_TILE_WIDTH;
// void renderTextDispose(void) {
// textureDispose(&RENDER_TEXT_TEXTURE);
// }

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/texture/texture.h"
extern texture_t RENDER_TEXT_TEXTURE;
/**
* Initializes the text rendering system.
*/
void renderTextInit(void);
/**
* Draws a single character at the specified position.
*
* @param x The x-coordinate to draw the character at.
* @param y The y-coordinate to draw the character at.
* @param c The character to draw.
* @param r The red component of the color (0-255).
* @param g The green component of the color (0-255).
* @param b The blue component of the color (0-255).
*/
void renderTextDrawChar(
const float_t x,
const float_t y,
const char_t c,
const uint8_t r,
const uint8_t g,
const uint8_t b
);
/**
* Draws a string of text at the specified position.
*
* @param x The x-coordinate to draw the text at.
* @param y The y-coordinate to draw the text at.
* @param text The null-terminated string of text to draw.
* @param r The red component of the color (0-255).
* @param g The green component of the color (0-255).
* @param b The blue component of the color (0-255).
*/
void renderTextDraw(
const float_t x,
const float_t y,
const char_t *text,
const uint8_t r,
const uint8_t g,
const uint8_t b
);
/**
* Measures the width and height of the given text string when rendered.
*
* @param text The null-terminated string of text to measure.
* @param outWidth Pointer to store the measured width in pixels.
* @param outHeight Pointer to store the measured height in pixels.
*/
void renderTextMeasure(
const char_t *text,
int32_t *outWidth,
int32_t *outHeight
);
/**
* Disposes of the text rendering system, freeing any allocated resources.
*/
void renderTextDispose(void);

View File

@@ -9,4 +9,5 @@ target_sources(${DUSK_TARGET_NAME}
memory.c memory.c
string.c string.c
math.c math.c
reflist.c
) )

83
src/util/reflist.c Normal file
View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "reflist.h"
#include "util/memory.h"
#include "assert/assert.h"
void refListInit(
reflist_t *list,
ref_t *array,
const uint_fast16_t max
) {
assertNotNull(list, "Reference list cannot be NULL");
assertNotNull(array, "Reference array cannot be NULL");
assertTrue(max > 0, "Reference list max must be greater than 0");
assertTrue(max <= UINT16_MAX, "Reference list too large");
memoryZero(list, sizeof(reflist_t));
memoryZero(array, sizeof(ref_t) * max);
list->array = array;
list->max = max;
}
ref_t refListLock(reflist_t *list) {
assertFalse(refListIsFull(list), "Reference list is full");
ref_t ref = list->refNext++;
assertTrue(ref > 0, "Reference ID overflow");
assertTrue(ref < UINT16_MAX, "Reference ID too large.");
bool_t empty = list->onNotEmpty && refListIsEmpty(list);
list->array[list->count++] = ref;
if(empty) list->onNotEmpty(list);
if(list->onAdd) list->onAdd(list, ref);
if(list->onFull && refListIsFull(list)) list->onFull(list);
return ref;
}
void refListUnlock(reflist_t *list, const ref_t ref) {
assertFalse(refListIsEmpty(list), "Reference list is empty");
ref_t *slot = list->array;
ref_t *end = list->array + list->count;
do {
if(*slot == ref) break;
++slot;
} while(slot < end);
assertTrue(slot < end, "Reference not found in list");
memoryMove(slot, slot + 1, (end - slot - 1) * sizeof(ref_t));
list->count--;
if(list->onRemove) list->onRemove(list, ref);
if(list->onEmpty && refListIsEmpty(list)) list->onEmpty(list);
}
bool_t refListIsFull(const reflist_t *list) {
assertNotNull(list, "Reference list cannot be NULL");
assertNotNull(list->array, "Reference list array cannot be NULL");
assertTrue(list->max > 0, "Reference list max must be greater than 0");
assertTrue(list->max <= UINT16_MAX, "Reference list too large");
return (list->count >= list->max);
}
bool_t refListIsEmpty(const reflist_t *list) {
assertNotNull(list, "Reference list cannot be NULL");
assertNotNull(list->array, "Reference list array cannot be NULL");
assertTrue(list->max > 0, "Reference list max must be greater than 0");
assertTrue(list->max <= UINT16_MAX, "Reference list too large");
return (list->count == 0);
}

77
src/util/reflist.h Normal file
View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef uint_fast16_t ref_t;
typedef struct reflist_s reflist_t;
typedef struct reflist_s {
ref_t *array;
uint_fast16_t max;
uint_fast16_t count;
ref_t refNext;
void *user;
void (*onNotEmpty)(reflist_t *list);
void (*onFull)(reflist_t *list);
void (*onAdd)(reflist_t *list, const ref_t ref);
void (*onRemove)(reflist_t *list, const ref_t ref);
void (*onEmpty)(reflist_t *list);
} reflist_t;
/**
* Initialize a reference list. Reference lists just hold a list of references
* that are "holding on to" a given object/resource.
*
* @param list The reference list to initialize.
* @param array The array to use as backing storage for the list.
* @param max The maximum number of references the list can hold.
*/
void refListInit(
reflist_t *list,
ref_t *array,
const uint_fast16_t max
);
/**
* Lock a reference in the list. This will return a new reference ID that can be
* used to access the locked reference.
*
* @param list The reference list to lock a reference in.
* @return The locked reference ID, or 0 if the list is full.
*/
ref_t refListLock(reflist_t *list);
/**
* Unlock a reference in the list. This will free up the reference ID for
* reuse.
*
* @param list The reference list to unlock a reference in.
* @param ref The reference ID to unlock.
*/
void refListUnlock(reflist_t *list, const ref_t ref);
/**
* Checks if the reference list is full.
*
* @param list The reference list to check.
* @return true if the list is full, false otherwise.
*/
bool_t refListIsFull(const reflist_t *list);
/**
* Checks if the reference list is empty.
*
* @param list The reference list to check.
* @return true if the list is empty, false otherwise.
*/
bool_t refListIsEmpty(const reflist_t *list);

View File

@@ -4,7 +4,10 @@
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
# Function that adds an asset to be compiled # Function that adds an asset to be compiled
function(add_asset ASSET_PATH) function(add_asset ASSET_TYPE ASSET_PATH)
message(STATUS "Adding asset: ${ASSET_PATH} (type: ${ASSET_TYPE})")
message(STATUS " Options: ${ARGN}")
set(FULL_ASSET_PATH "${CMAKE_CURRENT_LIST_DIR}/${ASSET_PATH}") set(FULL_ASSET_PATH "${CMAKE_CURRENT_LIST_DIR}/${ASSET_PATH}")
list(APPEND DUSK_ASSETS ${FULL_ASSET_PATH}) list(APPEND DUSK_ASSETS ${FULL_ASSET_PATH})
set(DUSK_ASSETS ${DUSK_ASSETS} CACHE INTERNAL ${DUSK_CACHE_TARGET}) set(DUSK_ASSETS ${DUSK_ASSETS} CACHE INTERNAL ${DUSK_CACHE_TARGET})