Text
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
module('spritebatch')
|
||||
module('camera')
|
||||
module('color')
|
||||
module('ui')
|
||||
-- module('ui')
|
||||
module('text')
|
||||
module('screen')
|
||||
module('time')
|
||||
|
||||
camera = cameraCreate(CAMERA_PROJECTION_TYPE_PERSPECTIVE)
|
||||
|
||||
uiPush('ui/test.dsf')
|
||||
camera = cameraCreate(CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC)
|
||||
|
||||
function sceneDispose()
|
||||
end
|
||||
@@ -13,16 +14,22 @@ end
|
||||
function sceneUpdate()
|
||||
end
|
||||
|
||||
text = "Hello World"
|
||||
|
||||
function sceneRender()
|
||||
cameraPushMatrix(camera)
|
||||
|
||||
spriteBatchPush(
|
||||
nil,
|
||||
0, 0,
|
||||
1, 2,
|
||||
colorBlue()
|
||||
)
|
||||
spriteBatchFlush()
|
||||
camera.bottom = screenGetHeight()
|
||||
camera.right = screenGetWidth()
|
||||
|
||||
width, height = textMeasure(text)
|
||||
x = (screenGetWidth() - width)
|
||||
x = math.sin(TIME.time * 2) * (x / 2) + (x / 2)
|
||||
|
||||
y = (screenGetHeight() - height) / 2
|
||||
y = math.cos(TIME.time * 3) * (y) + (y)
|
||||
|
||||
textDraw(x, y, text)
|
||||
|
||||
cameraPopMatrix()
|
||||
end
|
||||
@@ -3,5 +3,4 @@
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(TILESET minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
|
||||
add_asset(SCRIPT test.lua)
|
||||
add_asset(TILESET minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
|
||||
@@ -1,9 +0,0 @@
|
||||
module('spritebatch')
|
||||
|
||||
function uiElementRender(x, y, w, h)
|
||||
spriteBatchPush(
|
||||
nil,
|
||||
x, y,
|
||||
w, h
|
||||
)
|
||||
end
|
||||
@@ -11,6 +11,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
screen.c
|
||||
texture.c
|
||||
spritebatch.c
|
||||
text.c
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
|
||||
@@ -34,9 +34,9 @@ void cameraInitOrthographic(camera_t *camera) {
|
||||
|
||||
camera->projType = CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC;
|
||||
camera->orthographic.left = 0.0f;
|
||||
camera->orthographic.right = (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND);
|
||||
camera->orthographic.bottom = 0.0f;
|
||||
camera->orthographic.top = (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND);
|
||||
camera->orthographic.right = SCREEN.width;
|
||||
camera->orthographic.top = 0.0f;
|
||||
camera->orthographic.bottom = SCREEN.height;
|
||||
camera->nearClip = -1.0f;
|
||||
camera->farClip = 1.0f;
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef float_t colorchannelf_t;
|
||||
typedef uint8_t colorchannelb_t;
|
||||
|
||||
typedef struct {
|
||||
colorchannelf_t r;
|
||||
colorchannelf_t g;
|
||||
colorchannelf_t b;
|
||||
} color3f_t;
|
||||
|
||||
typedef struct {
|
||||
colorchannelf_t r;
|
||||
colorchannelf_t g;
|
||||
colorchannelf_t b;
|
||||
colorchannelf_t a;
|
||||
} color4f_t;
|
||||
|
||||
typedef struct {
|
||||
colorchannelb_t r;
|
||||
colorchannelb_t g;
|
||||
colorchannelb_t b;
|
||||
} color3b_t;
|
||||
|
||||
typedef struct {
|
||||
colorchannelb_t r;
|
||||
colorchannelb_t g;
|
||||
colorchannelb_t b;
|
||||
colorchannelb_t a;
|
||||
} color4b_t;
|
||||
|
||||
typedef color4b_t color_t;
|
||||
|
||||
#define color3f(r, g, b) ((color3f_t){r, g, b})
|
||||
#define color4f(r, g, b, a) ((color4f_t){r, g, b, a})
|
||||
#define color3b(r, g, b) ((color3b_t){r, g, b})
|
||||
#define color4b(r, g, b, a) ((color4b_t){r, g, b, a})
|
||||
#define color(r, g, b, a) ((color_t){r, g, b, a})
|
||||
|
||||
#define colorHex(hex) color( \
|
||||
((hex >> 24) & 0xFF), \
|
||||
((hex >> 16) & 0xFF), \
|
||||
((hex >> 8) & 0xFF), \
|
||||
(hex & 0xFF) \
|
||||
)
|
||||
|
||||
#define COLOR_WHITE_3F color3f(1.0f, 1.0f, 1.0f)
|
||||
#define COLOR_WHITE_4F color4f(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
#define COLOR_WHITE_3B color3b(255, 255, 255)
|
||||
#define COLOR_WHITE_4B color4b(255, 255, 255, 255)
|
||||
#define COLOR_WHITE color(255, 255, 255, 255)
|
||||
|
||||
#define COLOR_BLACK_3F color3f(0.0f, 0.0f, 0.0f)
|
||||
#define COLOR_BLACK_4F color4f(0.0f, 0.0f, 0.0f, 1.0f)
|
||||
#define COLOR_BLACK_3B color3b(0, 0, 0)
|
||||
#define COLOR_BLACK_4B color4b(0, 0, 0, 255)
|
||||
#define COLOR_BLACK color(0, 0, 0, 255)
|
||||
|
||||
#define COLOR_RED_3F color3f(1.0f, 0.0f, 0.0f)
|
||||
#define COLOR_RED_4F color4f(1.0f, 0.0f, 0.0f, 1.0f)
|
||||
#define COLOR_RED_3B color3b(255, 0, 0)
|
||||
#define COLOR_RED_4B color4b(255, 0, 0, 255)
|
||||
#define COLOR_RED color(255, 0, 0, 255)
|
||||
|
||||
#define COLOR_GREEN_3F color3f(0.0f, 1.0f, 0.0f)
|
||||
#define COLOR_GREEN_4F color4f(0.0f, 1.0f, 0.0f, 1.0f)
|
||||
#define COLOR_GREEN_3B color3b(0, 255, 0)
|
||||
#define COLOR_GREEN_4B color4b(0, 255, 0, 255)
|
||||
#define COLOR_GREEN color(0, 255, 0, 255)
|
||||
|
||||
#define COLOR_BLUE_3F color3f(0.0f, 0.0f, 1.0f)
|
||||
#define COLOR_BLUE_4F color4f(0.0f, 0.0f, 1.0f, 1.0f)
|
||||
#define COLOR_BLUE_3B color3b(0, 0, 255)
|
||||
#define COLOR_BLUE_4B color4b(0, 0, 255, 255)
|
||||
#define COLOR_BLUE color(0, 0, 255, 255)
|
||||
|
||||
#define COLOR_YELLOW_3F color3f(1.0f, 1.0f, 0.0f)
|
||||
#define COLOR_YELLOW_4F color4f(1.0f, 1.0f, 0.0f, 1.0f)
|
||||
#define COLOR_YELLOW_3B color3b(255, 255, 0)
|
||||
#define COLOR_YELLOW_4B color4b(255, 255, 0, 255)
|
||||
#define COLOR_YELLOW color(255, 255, 0, 255)
|
||||
|
||||
#define COLOR_CYAN_3F color3f(0.0f, 1.0f, 1.0f)
|
||||
#define COLOR_CYAN_4F color4f(0.0f, 1.0f, 1.0f, 1.0f)
|
||||
#define COLOR_CYAN_3B color3b(0, 255, 255)
|
||||
#define COLOR_CYAN_4B color4b(0, 255, 255, 255)
|
||||
#define COLOR_CYAN color(0, 255, 255, 255)
|
||||
|
||||
#define COLOR_MAGENTA_3F color3f(1.0f, 0.0f, 1.0f)
|
||||
#define COLOR_MAGENTA_4F color4f(1.0f, 0.0f, 1.0f, 1.0f)
|
||||
#define COLOR_MAGENTA_3B color3b(255, 0, 255)
|
||||
#define COLOR_MAGENTA_4B color4b(255, 0, 255, 255)
|
||||
#define COLOR_MAGENTA color(255, 0, 255, 255)
|
||||
|
||||
#define COLOR_TRANSPARENT_3F color3f(0.0f, 0.0f, 0.0f)
|
||||
#define COLOR_TRANSPARENT_4F color4f(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
#define COLOR_TRANSPARENT_3B color3b(0, 0, 0)
|
||||
#define COLOR_TRANSPARENT_4B color4b(0, 0, 0, 0)
|
||||
#define COLOR_TRANSPARENT color(0, 0, 0, 0)
|
||||
|
||||
#define COLOR_CORNFLOWER_BLUE_3F color3f(0.39f, 0.58f, 0.93f)
|
||||
#define COLOR_CORNFLOWER_BLUE_4F color4f(0.39f, 0.58f, 0.93f, 1.0f)
|
||||
#define COLOR_CORNFLOWER_BLUE_3B color3b(100, 149, 237)
|
||||
#define COLOR_CORNFLOWER_BLUE_4B color4b(100, 149, 237, 255)
|
||||
#define COLOR_CORNFLOWER_BLUE color(100, 149, 237, 255)
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "display/screen.h"
|
||||
#include "ui/ui.h"
|
||||
#include "debug/debug.h"
|
||||
#include "display/text.h"
|
||||
|
||||
display_t DISPLAY;
|
||||
|
||||
@@ -73,6 +74,7 @@ errorret_t displayInit(void) {
|
||||
quadInit();
|
||||
frameBufferInitBackbuffer();
|
||||
spriteBatchInit();
|
||||
errorChain(textInit());
|
||||
screenInit();
|
||||
|
||||
errorOk();
|
||||
@@ -145,6 +147,7 @@ errorret_t displayUpdate(void) {
|
||||
errorret_t displayDispose(void) {
|
||||
spriteBatchDispose();
|
||||
screenDispose();
|
||||
textDispose();
|
||||
|
||||
#if DISPLAY_SDL2
|
||||
if(DISPLAY.glContext) {
|
||||
|
||||
124
src/display/text.c
Normal file
124
src/display/text.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "text.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/spritebatch.h"
|
||||
#include "asset/asset.h"
|
||||
|
||||
texture_t DEFAULT_FONT_TEXTURE;
|
||||
|
||||
errorret_t textInit(void) {
|
||||
errorChain(assetLoad(DEFAULT_FONT_TILESET.image, &DEFAULT_FONT_TEXTURE));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void textDispose(void) {
|
||||
textureDispose(&DEFAULT_FONT_TEXTURE);
|
||||
}
|
||||
|
||||
void textDrawChar(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t c,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
) {
|
||||
int32_t tileIndex = (int32_t)(c) - TEXT_CHAR_START;
|
||||
if(tileIndex < 0 || tileIndex >= tileset->tileCount) {
|
||||
tileIndex = ((int32_t)'@') - TEXT_CHAR_START;
|
||||
}
|
||||
|
||||
assertTrue(
|
||||
tileIndex >= 0 && tileIndex <= tileset->tileCount,
|
||||
"Character is out of bounds for font tiles"
|
||||
);
|
||||
|
||||
vec4 uv;
|
||||
tilesetTileGetUV(tileset, tileIndex, uv);
|
||||
|
||||
spriteBatchPush(
|
||||
texture,
|
||||
x, y,
|
||||
x + tileset->tileWidth,
|
||||
y + tileset->tileHeight,
|
||||
color,
|
||||
uv[0], uv[1], uv[2], uv[3]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void textDraw(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t *text,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
) {
|
||||
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 += tileset->tileHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c == ' ') {
|
||||
posX += tileset->tileWidth;
|
||||
continue;
|
||||
}
|
||||
|
||||
textDrawChar(posX, posY, c, color, tileset, texture);
|
||||
posX += tileset->tileWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void textMeasure(
|
||||
const char_t *text,
|
||||
const tileset_t *tileset,
|
||||
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 = tileset->tileHeight;
|
||||
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 += tileset->tileHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
lineWidth += tileset->tileWidth;
|
||||
}
|
||||
|
||||
if(lineWidth > width) {
|
||||
width = lineWidth;
|
||||
}
|
||||
|
||||
*outWidth = width;
|
||||
*outHeight = height;
|
||||
}
|
||||
80
src/display/text.h
Normal file
80
src/display/text.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "asset/asset.h"
|
||||
#include "display/texture.h"
|
||||
#include "display/tileset/tileset.h"
|
||||
#include "display/tileset/tileset_minogram.h"
|
||||
|
||||
#define TEXT_CHAR_START '!'
|
||||
|
||||
extern texture_t DEFAULT_FONT_TEXTURE;
|
||||
#define DEFAULT_FONT_TILESET TILESET_MINOGRAM
|
||||
|
||||
/**
|
||||
* Initializes the text system.
|
||||
*/
|
||||
errorret_t textInit(void);
|
||||
|
||||
/**
|
||||
* Disposes of the text system.
|
||||
*/
|
||||
void textDispose(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 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 textDrawChar(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t c,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
);
|
||||
|
||||
/**
|
||||
* 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 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 textDraw(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t *text,
|
||||
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 textMeasure(
|
||||
const char_t *text,
|
||||
const tileset_t *tileset,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight
|
||||
);
|
||||
@@ -11,4 +11,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
modulespritebatch.c
|
||||
moduleglm.c
|
||||
modulecolor.c
|
||||
moduletext.c
|
||||
modulescreen.c
|
||||
)
|
||||
29
src/script/module/display/modulescreen.c
Normal file
29
src/script/module/display/modulescreen.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulescreen.h"
|
||||
#include "assert/assert.h"
|
||||
#include "display/screen.h"
|
||||
|
||||
void moduleScreen(scriptcontext_t *context) {
|
||||
assertNotNull(context, "Context cannot be NULL.");
|
||||
|
||||
lua_register(context->luaState, "screenGetWidth", moduleScreenGetWidth);
|
||||
lua_register(context->luaState, "screenGetHeight", moduleScreenGetHeight);
|
||||
}
|
||||
|
||||
int moduleScreenGetWidth(lua_State *L) {
|
||||
assertNotNull(L, "Lua state is null");
|
||||
lua_pushinteger(L, SCREEN.width);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int moduleScreenGetHeight(lua_State *L) {
|
||||
assertNotNull(L, "Lua state is null");
|
||||
lua_pushinteger(L, SCREEN.height);
|
||||
return 1;
|
||||
}
|
||||
32
src/script/module/display/modulescreen.h
Normal file
32
src/script/module/display/modulescreen.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
|
||||
/**
|
||||
* Registers the Screen module with the given script context.
|
||||
*
|
||||
* @param context The script context to register the module with.
|
||||
*/
|
||||
void moduleScreen(scriptcontext_t *context);
|
||||
|
||||
/**
|
||||
* Gets the current screen width.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Count of return values.
|
||||
*/
|
||||
int moduleScreenGetWidth(lua_State *L);
|
||||
|
||||
/**
|
||||
* Gets the current screen height.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Count of return values.
|
||||
*/
|
||||
int moduleScreenGetHeight(lua_State *L);
|
||||
@@ -55,7 +55,6 @@ int moduleSpriteBatchPush(lua_State *L) {
|
||||
return luaL_error(L, "Sprite color must be a color struct or nil");
|
||||
}
|
||||
|
||||
|
||||
// Optional UV min and maxes, defaults to 0,0 -> 1,1
|
||||
float_t u0 = 0.0f;
|
||||
float_t v0 = 0.0f;
|
||||
|
||||
83
src/script/module/display/moduletext.c
Normal file
83
src/script/module/display/moduletext.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduletext.h"
|
||||
#include "assert/assert.h"
|
||||
#include "display/text.h"
|
||||
#include "display/spritebatch.h"
|
||||
|
||||
void moduleText(scriptcontext_t *context) {
|
||||
assertNotNull(context, "Script context is null");
|
||||
|
||||
lua_register(context->luaState, "textDraw", moduleTextDraw);
|
||||
lua_register(context->luaState, "textMeasure", moduleTextMeasure);
|
||||
}
|
||||
|
||||
int moduleTextDraw(lua_State *L) {
|
||||
assertNotNull(L, "Lua state is null");
|
||||
|
||||
// Position.
|
||||
if(!lua_isnumber(L, 1)) {
|
||||
return luaL_error(L, "X position must be a number");
|
||||
}
|
||||
if(!lua_isnumber(L, 2)) {
|
||||
return luaL_error(L, "Y position must be a number");
|
||||
}
|
||||
|
||||
const float_t x = (float_t)lua_tonumber(L, 1);
|
||||
const float_t y = (float_t)lua_tonumber(L, 2);
|
||||
|
||||
// String
|
||||
if(!lua_isstring(L, 3)) {
|
||||
return luaL_error(L, "Text to draw must be a string");
|
||||
}
|
||||
const char_t *text = (const char_t*)lua_tostring(L, 3);
|
||||
|
||||
// Optional color
|
||||
color_t *color = NULL;
|
||||
if(lua_gettop(L) < 6 || lua_isnil(L, 6)) {
|
||||
// Allow NULL
|
||||
} else if(lua_isuserdata(L, 6)) {
|
||||
color = (color_t*)luaL_checkudata(L, 6, "color_mt");
|
||||
} else {
|
||||
return luaL_error(L, "Sprite color must be a color struct or nil");
|
||||
}
|
||||
|
||||
// For now, use the default font tileset and texture.
|
||||
textDraw(
|
||||
x,
|
||||
y,
|
||||
text,
|
||||
color == NULL ? COLOR_WHITE : *color,
|
||||
&DEFAULT_FONT_TILESET,
|
||||
&DEFAULT_FONT_TEXTURE
|
||||
);
|
||||
spriteBatchFlush();
|
||||
}
|
||||
|
||||
int moduleTextMeasure(lua_State *L) {
|
||||
assertNotNull(L, "Lua state is null");
|
||||
|
||||
// String
|
||||
if(!lua_isstring(L, 1)) {
|
||||
return luaL_error(L, "Text to measure must be a string");
|
||||
}
|
||||
const char_t *text = (const char_t*)lua_tostring(L, 1);
|
||||
|
||||
int32_t width = 0;
|
||||
int32_t height = 0;
|
||||
textMeasure(
|
||||
text,
|
||||
&DEFAULT_FONT_TILESET,
|
||||
&width,
|
||||
&height
|
||||
);
|
||||
|
||||
lua_pushinteger(L, width);
|
||||
lua_pushinteger(L, height);
|
||||
return 2;
|
||||
}
|
||||
32
src/script/module/display/moduletext.h
Normal file
32
src/script/module/display/moduletext.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
|
||||
/**
|
||||
* Register text rendering functions to the given script context.
|
||||
*
|
||||
* @param context The script context to register text functions to.
|
||||
*/
|
||||
void moduleText(scriptcontext_t *context);
|
||||
|
||||
/**
|
||||
* Script binding for drawing text.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleTextDraw(lua_State *L);
|
||||
|
||||
/**
|
||||
* Script binding for measuring text dimensions.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleTextMeasure(lua_State *L);
|
||||
@@ -18,6 +18,11 @@ void moduleTime(scriptcontext_t *ctx) {
|
||||
lua_pushcfunction(ctx->luaState, moduleTimeIndex);
|
||||
lua_settable(ctx->luaState, -3);
|
||||
}
|
||||
|
||||
// Global time struct
|
||||
lua_pushlightuserdata(ctx->luaState, &TIME);
|
||||
luaL_setmetatable(ctx->luaState, "time_mt");
|
||||
lua_setglobal(ctx->luaState, "TIME");
|
||||
}
|
||||
|
||||
int moduleTimeIndex(lua_State *L) {
|
||||
|
||||
@@ -12,25 +12,4 @@
|
||||
void moduleUi(scriptcontext_t *ctx) {
|
||||
assertNotNull(ctx, "Script context cannot be NULL");
|
||||
|
||||
lua_register(ctx->luaState, "uiPush", moduleUiPush);
|
||||
}
|
||||
|
||||
int moduleUiPush(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL");
|
||||
|
||||
// Expect path string. TODO Support non scripted ui elements.
|
||||
if(!lua_isstring(L, 1)) {
|
||||
return luaL_error(L, "uiPush expects a string path as the first argument");
|
||||
}
|
||||
|
||||
const char_t *path = lua_tostring(L, 1);
|
||||
|
||||
printf("Pushing UI from script: %s\n", path);
|
||||
errorret_t err = uiPushScript(path);
|
||||
if(err.code != ERROR_OK) {
|
||||
errorCatch(errorPrint(err));
|
||||
return luaL_error(L, "uiPush failed for path: %s", path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -7,20 +7,11 @@
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
#include "error/error.h"
|
||||
|
||||
/**
|
||||
* Registers the ui module within the given script context.
|
||||
*
|
||||
* @param ctx The script context to register the module in.
|
||||
*/
|
||||
void moduleUi(scriptcontext_t *ctx);
|
||||
|
||||
/**
|
||||
* Lua binding for uiPush function.
|
||||
*
|
||||
* Expects a string path to the UI script as the first argument.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleUiPush(lua_State *L);
|
||||
void moduleUi(scriptcontext_t *ctx);
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "script/module/display/modulecamera.h"
|
||||
#include "script/module/display/moduleglm.h"
|
||||
#include "script/module/ui/moduleui.h"
|
||||
#include "script/module/display/moduletext.h"
|
||||
#include "script/module/display/modulescreen.h"
|
||||
#include "util/string.h"
|
||||
|
||||
const scriptmodule_t SCRIPT_MODULE_LIST[] = {
|
||||
@@ -35,6 +37,8 @@ const scriptmodule_t SCRIPT_MODULE_LIST[] = {
|
||||
{ .name = "camera", .callback = moduleCamera },
|
||||
{ .name = "glm", .callback = moduleGLM },
|
||||
{ .name = "ui", .callback = moduleUi },
|
||||
{ .name = "text", .callback = moduleText },
|
||||
{ .name = "screen", .callback = moduleScreen },
|
||||
};
|
||||
|
||||
#define SCRIPT_MODULE_COUNT ( \
|
||||
|
||||
@@ -7,5 +7,4 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
ui.c
|
||||
uielement.c
|
||||
)
|
||||
30
src/ui/ui.c
30
src/ui/ui.c
@@ -24,11 +24,6 @@ errorret_t uiInit(void) {
|
||||
}
|
||||
|
||||
void uiUpdate(void) {
|
||||
uint_fast8_t i = 0;
|
||||
while(i < UI.stackSize) {
|
||||
errorCatch(errorPrint(uiElementUpdate(&UI.stack[i])));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void uiRender(void) {
|
||||
@@ -38,34 +33,9 @@ void uiRender(void) {
|
||||
cameraPushMatrix(&UI.camera);
|
||||
spriteBatchClear();
|
||||
|
||||
uint_fast8_t i = 0;
|
||||
while(i < UI.stackSize) {
|
||||
errorCatch(errorPrint(uiElementRender(&UI.stack[i])));
|
||||
i++;
|
||||
}
|
||||
|
||||
spriteBatchFlush();
|
||||
cameraPopMatrix();
|
||||
}
|
||||
|
||||
errorret_t uiPushScript(const char_t *path) {
|
||||
assertTrue(UI.stackSize < UI_STACK_SIZE, "UI stack overflow");
|
||||
uielement_t *element = &UI.stack[UI.stackSize];
|
||||
errorChain(uiElementInitScript(element, path));
|
||||
UI.stackSize++;
|
||||
// Ret Id or something?
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiPop(void) {
|
||||
assertTrue(UI.stackSize > 0, "UI stack underflow");
|
||||
UI.stackSize--;
|
||||
uielement_t *element = &UI.stack[UI.stackSize];
|
||||
uiElementDispose(element);
|
||||
}
|
||||
|
||||
void uiDispose(void) {
|
||||
while(UI.stackSize > 0) {
|
||||
uiPop();
|
||||
}
|
||||
}
|
||||
19
src/ui/ui.h
19
src/ui/ui.h
@@ -7,15 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
#include "display/camera/camera.h"
|
||||
#include "ui/uielement.h"
|
||||
|
||||
#define UI_STACK_SIZE 64
|
||||
#include "error/error.h"
|
||||
|
||||
typedef struct {
|
||||
camera_t camera;
|
||||
|
||||
uielement_t stack[UI_STACK_SIZE];
|
||||
uint_fast8_t stackSize;
|
||||
} ui_t;
|
||||
|
||||
extern ui_t UI;
|
||||
@@ -35,18 +30,6 @@ void uiUpdate(void);
|
||||
*/
|
||||
void uiRender(void);
|
||||
|
||||
/**
|
||||
* Pushes a new UI element onto the UI stack from a script file.
|
||||
*
|
||||
* @param path Path to the UI script file.
|
||||
*/
|
||||
errorret_t uiPushScript(const char_t *path);
|
||||
|
||||
/**
|
||||
* Pops the top UI element from the UI stack.
|
||||
*/
|
||||
void uiPop(void);
|
||||
|
||||
/**
|
||||
* Disposes of the UI system.
|
||||
*/
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uielement.h"
|
||||
#include "display/screen.h"
|
||||
#include "debug/debug.h"
|
||||
|
||||
errorret_t uiElementInitScript(
|
||||
uielement_t *element,
|
||||
const char_t *path
|
||||
) {
|
||||
errorChain(scriptContextInit(&element->ctx));
|
||||
errorChain(scriptContextExecFile(&element->ctx, path));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t uiElementUpdate(uielement_t *element) {
|
||||
lua_getglobal(element->ctx.luaState, "uiElementUpdate");
|
||||
if(lua_isfunction(element->ctx.luaState, -1)) {
|
||||
if(lua_pcall(element->ctx.luaState, 0, 0, 0) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(element->ctx.luaState, -1);
|
||||
lua_pop(element->ctx.luaState, 1);
|
||||
errorThrow("Failed to call UI element uiElementUpdate: %s", strErr);
|
||||
}
|
||||
} else {
|
||||
lua_pop(element->ctx.luaState, 1);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t uiElementRender(uielement_t *element) {
|
||||
lua_getglobal(element->ctx.luaState, "uiElementRender");
|
||||
if(lua_isfunction(element->ctx.luaState, -1)) {
|
||||
|
||||
// Push parameters: x, y, w, h
|
||||
lua_pushnumber(element->ctx.luaState, 0);
|
||||
lua_pushnumber(element->ctx.luaState, 0);
|
||||
lua_pushnumber(element->ctx.luaState, SCREEN.width);
|
||||
lua_pushnumber(element->ctx.luaState, SCREEN.height);
|
||||
|
||||
if(lua_pcall(element->ctx.luaState, 4, 0, 0) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(element->ctx.luaState, -1);
|
||||
lua_pop(element->ctx.luaState, 1);
|
||||
errorThrow("Failed to call UI element uiElementRender: %s", strErr);
|
||||
}
|
||||
} else {
|
||||
lua_pop(element->ctx.luaState, 1);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiElementDispose(uielement_t *element) {
|
||||
lua_getglobal(element->ctx.luaState, "uiElementDispose");
|
||||
if(lua_isfunction(element->ctx.luaState, -1)) {
|
||||
if(lua_pcall(element->ctx.luaState, 0, 0, 0) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(element->ctx.luaState, -1);
|
||||
lua_pop(element->ctx.luaState, 1);
|
||||
debugPrint("Failed to call UI element uiElementDispose: %s\n", strErr);
|
||||
}
|
||||
} else {
|
||||
lua_pop(element->ctx.luaState, 1);
|
||||
}
|
||||
scriptContextDispose(&element->ctx);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
|
||||
// TODO: Support both scripted and native UI elements.
|
||||
typedef struct {
|
||||
scriptcontext_t ctx;
|
||||
} uielement_t;
|
||||
|
||||
/**
|
||||
* Initializes a scripted UI Element.
|
||||
*
|
||||
* @param element The UI element to initialize.
|
||||
* @param path Path to the UI script file.
|
||||
*/
|
||||
errorret_t uiElementInitScript(
|
||||
uielement_t *element,
|
||||
const char_t *path
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates/ticks a UI element's logic.
|
||||
*
|
||||
* @param element The UI element to tick.
|
||||
*/
|
||||
errorret_t uiElementUpdate(uielement_t *element);
|
||||
|
||||
/**
|
||||
* Renders a UI element.
|
||||
*
|
||||
* @param element The UI element to render.
|
||||
*/
|
||||
errorret_t uiElementRender(uielement_t *element);
|
||||
|
||||
/**
|
||||
* Disposes of a UI element.
|
||||
*
|
||||
* @param element The UI element to dispose of.
|
||||
*/
|
||||
void uiElementDispose(uielement_t *element);
|
||||
Reference in New Issue
Block a user