Add strided memory pushing and improved spritebatching
This commit is contained in:
@@ -7,29 +7,30 @@ function MoveCubeCutscene(params) {
|
||||
|
||||
var startX = this.cube.position.position.x;
|
||||
|
||||
this.animLeft = new Animation([
|
||||
{ time: 0.0, value: startX, easing: Easing.outQuad },
|
||||
{ time: DURATION, value: startX - SPEED * DURATION }
|
||||
]);
|
||||
// this.animLeft = new Animation([
|
||||
// { time: 0.0, value: startX, easing: Easing.outQuad },
|
||||
// { time: DURATION, value: startX - SPEED * DURATION }
|
||||
// ]);
|
||||
|
||||
this.animRight = new Animation([
|
||||
{ time: 0.0, value: startX - SPEED * DURATION, easing: Easing.inOutQuad },
|
||||
{ time: DURATION, value: startX }
|
||||
]);
|
||||
// this.animRight = new Animation([
|
||||
// { time: 0.0, value: startX - SPEED * DURATION, easing: Easing.inOutQuad },
|
||||
// { time: DURATION, value: startX }
|
||||
// ]);
|
||||
}
|
||||
|
||||
MoveCubeCutscene.prototype = Object.create(Cutscene.prototype);
|
||||
MoveCubeCutscene.prototype.constructor = MoveCubeCutscene;
|
||||
|
||||
MoveCubeCutscene.prototype.update = function() {
|
||||
if(!this.animLeft.complete) {
|
||||
this.cube.position.position.x = this.animLeft.update(TIME.delta);
|
||||
} else {
|
||||
this.cube.position.position.x = this.animRight.update(TIME.delta);
|
||||
if(this.animRight.complete) {
|
||||
Cutscene.finish();
|
||||
}
|
||||
}
|
||||
Cutscene.finish();
|
||||
// if(!this.animLeft.complete) {
|
||||
// this.cube.position.position.x = this.animLeft.update(TIME.delta);
|
||||
// } else {
|
||||
// this.cube.position.position.x = this.animRight.update(TIME.delta);
|
||||
// if(this.animRight.complete) {
|
||||
// Cutscene.finish();
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
module = MoveCubeCutscene;
|
||||
|
||||
@@ -129,11 +129,10 @@ errorret_t consoleDraw(void) {
|
||||
|
||||
for(uint32_t i = 0; i < CONSOLE_HISTORY_MAX; i++) {
|
||||
errorChain(textDraw(
|
||||
0, FONT_TILESET_DEFAULT.tileHeight * i,
|
||||
0, FONT_DEFAULT.tileset.tileHeight * i,
|
||||
CONSOLE.line[i],
|
||||
COLOR_WHITE,
|
||||
&FONT_TILESET_DEFAULT,
|
||||
&FONT_TEXTURE_DEFAULT
|
||||
&FONT_DEFAULT
|
||||
));
|
||||
}
|
||||
return spriteBatchFlush();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "spritebatch.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/math.h"
|
||||
|
||||
meshvertex_t SPRITEBATCH_VERTICES[SPRITEBATCH_VERTEX_COUNT];
|
||||
spritebatch_t SPRITEBATCH;
|
||||
@@ -24,6 +25,97 @@ errorret_t spriteBatchInit() {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t spriteBatchPushv(
|
||||
const float_t *minX,
|
||||
const float_t *minY,
|
||||
const float_t *maxX,
|
||||
const float_t *maxY,
|
||||
const float_t *z,
|
||||
#if MESH_ENABLE_COLOR
|
||||
const color_t *color,
|
||||
#endif
|
||||
const float_t *u0,
|
||||
const float_t *v0,
|
||||
const float_t *u1,
|
||||
const float_t *v1,
|
||||
const size_t count
|
||||
) {
|
||||
size_t offset = 0;
|
||||
while(offset < count) {
|
||||
if(SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX_PER_FLUSH) {
|
||||
errorChain(spriteBatchFlush());
|
||||
}
|
||||
|
||||
size_t available = (size_t)(
|
||||
SPRITEBATCH_SPRITES_MAX_PER_FLUSH - SPRITEBATCH.spriteCount
|
||||
);
|
||||
size_t toPush = mathMin(count - offset, available);
|
||||
|
||||
meshvertex_t *start = &SPRITEBATCH_VERTICES[
|
||||
(SPRITEBATCH.spriteCount + (SPRITEBATCH.spriteFlush *
|
||||
SPRITEBATCH_SPRITES_MAX_PER_FLUSH)) * QUAD_VERTEX_COUNT
|
||||
];
|
||||
|
||||
// Fill all toPush sprites field-by-field, one memoryCopyInterleaved per
|
||||
// vertex-slot per field. Vertex layout matches quadBuffer3D:
|
||||
// v0=(minX,minY,z,u0,v0) v1=(maxX,minY,z,u1,v0) v2=(maxX,maxY,z,u1,v1)
|
||||
// v3=(minX,minY,z,u0,v0) v4=(maxX,maxY,z,u1,v1) v5=(minX,maxY,z,u0,v1)
|
||||
const size_t dstStride = sizeof(meshvertex_t) * QUAD_VERTEX_COUNT;
|
||||
const size_t fSz = sizeof(float_t);
|
||||
const float_t *sMinX = minX + offset;
|
||||
const float_t *sMaxX = maxX + offset;
|
||||
const float_t *sMinY = minY + offset;
|
||||
const float_t *sMaxY = maxY + offset;
|
||||
const float_t *sZ = z + offset;
|
||||
const float_t *sU0 = u0 + offset;
|
||||
const float_t *sU1 = u1 + offset;
|
||||
const float_t *sV0 = v0 + offset;
|
||||
const float_t *sV1 = v1 + offset;
|
||||
|
||||
#define COPY_FIELD(vi, field, srcArr) \
|
||||
memoryCopyInterleaved(&start[vi].field, dstStride, srcArr, fSz, fSz, toPush)
|
||||
|
||||
COPY_FIELD(0, pos[0], sMinX); COPY_FIELD(0, pos[1], sMinY);
|
||||
COPY_FIELD(0, pos[2], sZ); COPY_FIELD(0, uv[0], sU0);
|
||||
COPY_FIELD(0, uv[1], sV0);
|
||||
|
||||
COPY_FIELD(1, pos[0], sMaxX); COPY_FIELD(1, pos[1], sMinY);
|
||||
COPY_FIELD(1, pos[2], sZ); COPY_FIELD(1, uv[0], sU1);
|
||||
COPY_FIELD(1, uv[1], sV0);
|
||||
|
||||
COPY_FIELD(2, pos[0], sMaxX); COPY_FIELD(2, pos[1], sMaxY);
|
||||
COPY_FIELD(2, pos[2], sZ); COPY_FIELD(2, uv[0], sU1);
|
||||
COPY_FIELD(2, uv[1], sV1);
|
||||
|
||||
COPY_FIELD(3, pos[0], sMinX); COPY_FIELD(3, pos[1], sMinY);
|
||||
COPY_FIELD(3, pos[2], sZ); COPY_FIELD(3, uv[0], sU0);
|
||||
COPY_FIELD(3, uv[1], sV0);
|
||||
|
||||
COPY_FIELD(4, pos[0], sMaxX); COPY_FIELD(4, pos[1], sMaxY);
|
||||
COPY_FIELD(4, pos[2], sZ); COPY_FIELD(4, uv[0], sU1);
|
||||
COPY_FIELD(4, uv[1], sV1);
|
||||
|
||||
COPY_FIELD(5, pos[0], sMinX); COPY_FIELD(5, pos[1], sMaxY);
|
||||
COPY_FIELD(5, pos[2], sZ); COPY_FIELD(5, uv[0], sU0);
|
||||
COPY_FIELD(5, uv[1], sV1);
|
||||
|
||||
#undef COPY_FIELD
|
||||
|
||||
#if MESH_ENABLE_COLOR
|
||||
for(uint8_t vi = 0; vi < QUAD_VERTEX_COUNT; vi++) {
|
||||
memoryCopyInterleaved(
|
||||
&start[vi].color, dstStride,
|
||||
color + offset, sizeof(color_t), sizeof(color_t), toPush
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
SPRITEBATCH.spriteCount += (int32_t)toPush;
|
||||
offset += toPush;
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t spriteBatchPush(
|
||||
const float_t minX,
|
||||
const float_t minY,
|
||||
@@ -37,14 +129,13 @@ errorret_t spriteBatchPush(
|
||||
const float_t u1,
|
||||
const float_t v1
|
||||
) {
|
||||
return spriteBatchPush3D(
|
||||
(vec3){ minX, minY, 0 },
|
||||
(vec3){ maxX, maxY, 0 },
|
||||
return spriteBatchPushv(
|
||||
&minX, &minY, &maxX, &maxY, &(float_t){0},
|
||||
#if MESH_ENABLE_COLOR
|
||||
color,
|
||||
&color,
|
||||
#endif
|
||||
(vec2){ u0, v0 },
|
||||
(vec2){ u1, v1 }
|
||||
&u0, &v0, &u1, &v1,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,25 +148,17 @@ errorret_t spriteBatchPush3D(
|
||||
const vec2 uv0,
|
||||
const vec2 uv1
|
||||
) {
|
||||
// Need to flush?
|
||||
if(SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX_PER_FLUSH) {
|
||||
errorChain(spriteBatchFlush());
|
||||
}
|
||||
|
||||
size_t vertexOffset = (
|
||||
SPRITEBATCH.spriteCount +
|
||||
(SPRITEBATCH.spriteFlush * SPRITEBATCH_SPRITES_MAX_PER_FLUSH)
|
||||
) * QUAD_VERTEX_COUNT;
|
||||
quadBuffer3D(
|
||||
&SPRITEBATCH_VERTICES[vertexOffset],
|
||||
min, max,
|
||||
uv0, uv1
|
||||
return spriteBatchPushv(
|
||||
&min[0], &min[1],
|
||||
&max[0], &max[1],
|
||||
&min[2],
|
||||
#if MESH_ENABLE_COLOR
|
||||
, color
|
||||
&color,
|
||||
#endif
|
||||
&uv0[0], &uv0[1],
|
||||
&uv1[0], &uv1[1],
|
||||
1
|
||||
);
|
||||
SPRITEBATCH.spriteCount++;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void spriteBatchClear() {
|
||||
|
||||
@@ -33,6 +33,38 @@ extern spritebatch_t SPRITEBATCH;
|
||||
*/
|
||||
errorret_t spriteBatchInit();
|
||||
|
||||
/**
|
||||
* Pushes multiple sprites to the batch using arrays of values.
|
||||
*
|
||||
* @param minX Array of minimum x coordinates.
|
||||
* @param minY Array of minimum y coordinates.
|
||||
* @param maxX Array of maximum x coordinates.
|
||||
* @param maxY Array of maximum y coordinates.
|
||||
* @param z Array of z coordinates.
|
||||
* @param color Array of colors (if enabled).
|
||||
* @param u0 Array of u0 texture coordinates.
|
||||
* @param v0 Array of v0 texture coordinates.
|
||||
* @param u1 Array of u1 texture coordinates.
|
||||
* @param v1 Array of v1 texture coordinates.
|
||||
* @param count Number of sprites to push.
|
||||
* @return An error code indicating success or failure.
|
||||
*/
|
||||
errorret_t spriteBatchPushv(
|
||||
const float_t *minX,
|
||||
const float_t *minY,
|
||||
const float_t *maxX,
|
||||
const float_t *maxY,
|
||||
const float_t *z,
|
||||
#if MESH_ENABLE_COLOR
|
||||
const color_t *color,
|
||||
#endif
|
||||
const float_t *u0,
|
||||
const float_t *v0,
|
||||
const float_t *u1,
|
||||
const float_t *v1,
|
||||
const size_t count
|
||||
);
|
||||
|
||||
/**
|
||||
* Pushes a sprite to the batch. This basically "queues" it to render (well
|
||||
* technically it is buffering the vertices to the mesh at the moment, but
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "display/texture/texture.h"
|
||||
#include "display/texture/tileset.h"
|
||||
|
||||
typedef struct {
|
||||
texture_t texture;
|
||||
tileset_t tileset;
|
||||
} font_t;
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
@@ -13,19 +13,18 @@
|
||||
#include "asset/loader/display/assettilesetloader.h"
|
||||
#include "display/shader/shaderunlit.h"
|
||||
|
||||
texture_t FONT_TEXTURE_DEFAULT;
|
||||
tileset_t FONT_TILESET_DEFAULT;
|
||||
font_t FONT_DEFAULT;
|
||||
|
||||
errorret_t textInit(void) {
|
||||
errorChain(assetTextureLoad(
|
||||
"ui/minogram.png", &FONT_TEXTURE_DEFAULT, TEXTURE_FORMAT_RGBA
|
||||
"ui/minogram.png", &FONT_DEFAULT.texture, TEXTURE_FORMAT_RGBA
|
||||
));
|
||||
errorChain(assetTilesetLoad("ui/minogram.dtf", &FONT_TILESET_DEFAULT));
|
||||
errorChain(assetTilesetLoad("ui/minogram.dtf", &FONT_DEFAULT.tileset));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t textDispose(void) {
|
||||
errorChain(textureDispose(&FONT_TEXTURE_DEFAULT));
|
||||
errorChain(textureDispose(&FONT_DEFAULT.texture));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -36,27 +35,24 @@ errorret_t textDrawChar(
|
||||
#if MESH_ENABLE_COLOR
|
||||
const color_t color,
|
||||
#endif
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
font_t *font
|
||||
) {
|
||||
int32_t tileIndex = (int32_t)(c) - TEXT_CHAR_START;
|
||||
if(tileIndex < 0 || tileIndex >= tileset->tileCount) {
|
||||
if(tileIndex < 0 || tileIndex >= font->tileset.tileCount) {
|
||||
tileIndex = ((int32_t)'@') - TEXT_CHAR_START;
|
||||
}
|
||||
assertTrue(
|
||||
tileIndex >= 0 && tileIndex <= tileset->tileCount,
|
||||
tileIndex >= 0 && tileIndex <= font->tileset.tileCount,
|
||||
"Character is out of bounds for font tiles"
|
||||
);
|
||||
|
||||
vec4 uv;
|
||||
tilesetTileGetUV(tileset, tileIndex, uv);
|
||||
|
||||
tilesetTileGetUV(&font->tileset, tileIndex, uv);
|
||||
|
||||
errorChain(spriteBatchPush(
|
||||
// texture,
|
||||
x, y,
|
||||
x + tileset->tileWidth,
|
||||
y + tileset->tileHeight,
|
||||
x + font->tileset.tileWidth,
|
||||
y + font->tileset.tileHeight,
|
||||
#if MESH_ENABLE_COLOR
|
||||
color,
|
||||
#endif
|
||||
@@ -65,47 +61,36 @@ errorret_t textDrawChar(
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
errorret_t textDraw(
|
||||
const float_t x,
|
||||
const float_t y,
|
||||
const char_t *text,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
font_t *font
|
||||
) {
|
||||
assertNotNull(text, "Text cannot be NULL");
|
||||
|
||||
float_t posX = x;
|
||||
float_t posY = y;
|
||||
|
||||
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, texture));
|
||||
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &font->texture));
|
||||
|
||||
#if MESH_ENABLE_COLOR
|
||||
#else
|
||||
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, color));
|
||||
#endif
|
||||
|
||||
// errorChain(spriteBatchPush(
|
||||
// // texture,
|
||||
// posX, posY,
|
||||
// posX + texture->width * 1, posY + texture->height * 1,
|
||||
// color,
|
||||
// 0.0f, 0.0f, 1.0f, 1.0f
|
||||
// ));
|
||||
// errorOk();
|
||||
|
||||
char_t c;
|
||||
int32_t i = 0;
|
||||
while((c = text[i++]) != '\0') {
|
||||
if(c == '\n') {
|
||||
posX = x;
|
||||
posY += tileset->tileHeight;
|
||||
posY += font->tileset.tileHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c == ' ') {
|
||||
posX += tileset->tileWidth;
|
||||
posX += font->tileset.tileWidth;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -114,16 +99,16 @@ errorret_t textDraw(
|
||||
#if MESH_ENABLE_COLOR
|
||||
color,
|
||||
#endif
|
||||
tileset, texture
|
||||
font
|
||||
));
|
||||
posX += tileset->tileWidth;
|
||||
posX += font->tileset.tileWidth;
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void textMeasure(
|
||||
const char_t *text,
|
||||
const tileset_t *tileset,
|
||||
const font_t *font,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight
|
||||
) {
|
||||
@@ -132,28 +117,24 @@ void textMeasure(
|
||||
assertNotNull(outHeight, "Output height pointer cannot be NULL");
|
||||
|
||||
int32_t width = 0;
|
||||
int32_t height = tileset->tileHeight;
|
||||
int32_t height = font->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;
|
||||
}
|
||||
if(lineWidth > width) width = lineWidth;
|
||||
lineWidth = 0;
|
||||
height += tileset->tileHeight;
|
||||
height += font->tileset.tileHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
lineWidth += tileset->tileWidth;
|
||||
lineWidth += font->tileset.tileWidth;
|
||||
}
|
||||
|
||||
if(lineWidth > width) {
|
||||
width = lineWidth;
|
||||
}
|
||||
if(lineWidth > width) width = lineWidth;
|
||||
|
||||
*outWidth = width;
|
||||
*outHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
/**
|
||||
* 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/texture.h"
|
||||
#include "display/texture/tileset.h"
|
||||
#include "display/text/font.h"
|
||||
|
||||
#define TEXT_CHAR_START '!'
|
||||
|
||||
extern texture_t FONT_TEXTURE_DEFAULT;
|
||||
extern tileset_t FONT_TILESET_DEFAULT;
|
||||
extern font_t FONT_DEFAULT;
|
||||
|
||||
/**
|
||||
* Initializes the text system.
|
||||
*
|
||||
*
|
||||
* @return Either an error or success result.
|
||||
*/
|
||||
errorret_t textInit(void);
|
||||
|
||||
/**
|
||||
* Disposes of the text system.
|
||||
*
|
||||
*
|
||||
* @return Either an error or success result.
|
||||
*/
|
||||
errorret_t 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.
|
||||
* @param font Font to use for rendering.
|
||||
* @return Either an error or success result.
|
||||
*/
|
||||
errorret_t textDrawChar(
|
||||
@@ -47,19 +44,17 @@ errorret_t textDrawChar(
|
||||
#if MESH_ENABLE_COLOR
|
||||
const color_t color,
|
||||
#endif
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
font_t *font
|
||||
);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param font Font to use for rendering.
|
||||
* @return Either an error or success result.
|
||||
*/
|
||||
errorret_t textDraw(
|
||||
@@ -67,21 +62,20 @@ errorret_t textDraw(
|
||||
const float_t y,
|
||||
const char_t *text,
|
||||
const color_t color,
|
||||
const tileset_t *tileset,
|
||||
texture_t *texture
|
||||
font_t *font
|
||||
);
|
||||
|
||||
/**
|
||||
* 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 font Font 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,
|
||||
const font_t *font,
|
||||
int32_t *outWidth,
|
||||
int32_t *outHeight
|
||||
);
|
||||
);
|
||||
|
||||
@@ -34,7 +34,7 @@ moduleBaseFunction(moduleTextDraw) {
|
||||
}
|
||||
|
||||
errorret_t err = textDraw(
|
||||
x, y, text, col, &FONT_TILESET_DEFAULT, &FONT_TEXTURE_DEFAULT
|
||||
x, y, text, col, &FONT_DEFAULT
|
||||
);
|
||||
if(err.code != ERROR_OK) {
|
||||
errorCatch(errorPrint(err));
|
||||
@@ -54,7 +54,7 @@ moduleBaseFunction(moduleTextMeasure) {
|
||||
moduleBaseToString(args[0], text, sizeof(text));
|
||||
|
||||
int32_t w, h;
|
||||
textMeasure(text, &FONT_TILESET_DEFAULT, &w, &h);
|
||||
textMeasure(text, &FONT_DEFAULT, &w, &h);
|
||||
|
||||
jerry_value_t obj = jerry_object();
|
||||
jerry_value_t wKey = jerry_string_sz("width");
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ errorret_t uiFPSDraw() {
|
||||
errorChain(textDraw(
|
||||
0, 0,
|
||||
fpsText, textColor,
|
||||
&FONT_TILESET_DEFAULT, &FONT_TEXTURE_DEFAULT
|
||||
&FONT_DEFAULT
|
||||
));
|
||||
|
||||
return spriteBatchFlush();
|
||||
|
||||
+13
-14
@@ -21,8 +21,10 @@ errorret_t uiTextboxInit(void) {
|
||||
UI_TEXTBOX.textColor = COLOR_WHITE;
|
||||
UI_TEXTBOX.advanceAction = INPUT_ACTION_ACCEPT;
|
||||
|
||||
float_t fontW = (float_t)FONT_TILESET_DEFAULT.tileWidth;
|
||||
float_t fontH = (float_t)FONT_TILESET_DEFAULT.tileHeight;
|
||||
UI_TEXTBOX.font = &FONT_DEFAULT;
|
||||
|
||||
float_t fontW = (float_t)FONT_DEFAULT.tileset.tileWidth;
|
||||
float_t fontH = (float_t)FONT_DEFAULT.tileset.tileHeight;
|
||||
float_t tbHeight = (
|
||||
(float_t)UI_TEXTBOX_LINES_PER_PAGE_MAX * fontH +
|
||||
(float_t)(UI_TEXTBOX_LINES_PER_PAGE_MAX - 1) * UI_TEXTBOX_LINE_SPACING +
|
||||
@@ -36,13 +38,11 @@ errorret_t uiTextboxInit(void) {
|
||||
UI_TEXTBOX.frame.tileset.columns = 3;
|
||||
UI_TEXTBOX.frame.tileset.rows = 3;
|
||||
UI_TEXTBOX.frame.tileset.tileCount = 9;
|
||||
UI_TEXTBOX.frame.tileset.tileWidth = FONT_TILESET_DEFAULT.tileWidth;
|
||||
UI_TEXTBOX.frame.tileset.tileHeight = FONT_TILESET_DEFAULT.tileHeight;
|
||||
UI_TEXTBOX.frame.tileset.tileWidth = FONT_DEFAULT.tileset.tileWidth;
|
||||
UI_TEXTBOX.frame.tileset.tileHeight = FONT_DEFAULT.tileset.tileHeight;
|
||||
UI_TEXTBOX.frame.tileset.uv[0] = 1.0f / 3.0f;
|
||||
UI_TEXTBOX.frame.tileset.uv[1] = 1.0f / 3.0f;
|
||||
UI_TEXTBOX.frame.texture = &TEXTURE_WHITE;
|
||||
UI_TEXTBOX.textTileset = FONT_TILESET_DEFAULT;
|
||||
UI_TEXTBOX.textTexture = &FONT_TEXTURE_DEFAULT;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -53,8 +53,8 @@ void uiTextboxBuildLayout(void) {
|
||||
|
||||
float_t frameTileW = (float_t)UI_TEXTBOX.frame.tileset.tileWidth;
|
||||
float_t frameTileH = (float_t)UI_TEXTBOX.frame.tileset.tileHeight;
|
||||
float_t fontW = (float_t)UI_TEXTBOX.textTileset.tileWidth;
|
||||
float_t fontH = (float_t)UI_TEXTBOX.textTileset.tileHeight;
|
||||
float_t fontW = (float_t)UI_TEXTBOX.font->tileset.tileWidth;
|
||||
float_t fontH = (float_t)UI_TEXTBOX.font->tileset.tileHeight;
|
||||
|
||||
if(fontW <= 0.0f || fontH <= 0.0f) return;
|
||||
|
||||
@@ -204,7 +204,7 @@ errorret_t uiTextboxDraw(void) {
|
||||
if(UI_TEXTBOX.lineCount == 0 || UI_TEXTBOX.text[0] == '\0') errorOk();
|
||||
|
||||
errorChain(shaderSetTexture(
|
||||
&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, UI_TEXTBOX.textTexture
|
||||
&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &UI_TEXTBOX.font->texture
|
||||
));
|
||||
#if MESH_ENABLE_COLOR
|
||||
#else
|
||||
@@ -215,8 +215,8 @@ errorret_t uiTextboxDraw(void) {
|
||||
|
||||
float_t frameTileW = (float_t)UI_TEXTBOX.frame.tileset.tileWidth;
|
||||
float_t frameTileH = (float_t)UI_TEXTBOX.frame.tileset.tileHeight;
|
||||
float_t fontW = (float_t)UI_TEXTBOX.textTileset.tileWidth;
|
||||
float_t fontH = (float_t)UI_TEXTBOX.textTileset.tileHeight;
|
||||
float_t fontW = (float_t)UI_TEXTBOX.font->tileset.tileWidth;
|
||||
float_t fontH = (float_t)UI_TEXTBOX.font->tileset.tileHeight;
|
||||
float_t contentX = UI_TEXTBOX.x + frameTileW;
|
||||
float_t contentY = UI_TEXTBOX.y + frameTileH;
|
||||
|
||||
@@ -242,8 +242,7 @@ errorret_t uiTextboxDraw(void) {
|
||||
#if MESH_ENABLE_COLOR
|
||||
UI_TEXTBOX.textColor,
|
||||
#endif
|
||||
&UI_TEXTBOX.textTileset,
|
||||
UI_TEXTBOX.textTexture
|
||||
UI_TEXTBOX.font
|
||||
));
|
||||
}
|
||||
|
||||
@@ -256,5 +255,5 @@ errorret_t uiTextboxDraw(void) {
|
||||
|
||||
void uiTextboxDispose(void) {
|
||||
uiFrameDispose(&UI_TEXTBOX.frame);
|
||||
UI_TEXTBOX.textTexture = NULL;
|
||||
UI_TEXTBOX.font = NULL;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
uiframe_t frame;
|
||||
|
||||
tileset_t textTileset;
|
||||
texture_t *textTexture;
|
||||
font_t *font;
|
||||
color_t textColor;
|
||||
|
||||
float_t x, y, width, height;
|
||||
|
||||
@@ -107,6 +107,29 @@ void memoryReallocate(void **ptr, const size_t size) {
|
||||
*ptr = newPointer;
|
||||
}
|
||||
|
||||
void memoryCopyInterleaved(
|
||||
void *dest,
|
||||
const size_t destStride,
|
||||
const void *src,
|
||||
const size_t srcStride,
|
||||
const size_t elementSize,
|
||||
const size_t count
|
||||
) {
|
||||
assertNotNull(dest, "Cannot copy to NULL memory.");
|
||||
assertNotNull(src, "Cannot copy from NULL memory.");
|
||||
assertTrue(elementSize > 0, "Element size must be > 0.");
|
||||
assertTrue(destStride >= elementSize, "Dest stride must be >= element size.");
|
||||
assertTrue(srcStride >= elementSize, "Src stride must be >= element size.");
|
||||
|
||||
uint8_t *d = (uint8_t *)dest;
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
memcpy(d, s, elementSize);
|
||||
d += destStride;
|
||||
s += srcStride;
|
||||
}
|
||||
}
|
||||
|
||||
void memoryResize(void **ptr, const size_t oldSize, const size_t newSize) {
|
||||
assertNotNull(ptr, "Cannot resize NULL pointer.");
|
||||
assertTrue(newSize > 0, "Cannot resize to 0 bytes of memory.");
|
||||
|
||||
+23
-2
@@ -117,9 +117,30 @@ void memoryReallocate(void **ptr, const size_t size);
|
||||
|
||||
/**
|
||||
* Reallocates memory, but copies existing data to the new memory.
|
||||
*
|
||||
*
|
||||
* @param ptr The pointer to the memory to resize.
|
||||
* @param oldSize The old size of the memory.
|
||||
* @param newSize The new size of the memory.
|
||||
*/
|
||||
void memoryResize(void **ptr, const size_t oldSize, const size_t newSize);
|
||||
void memoryResize(void **ptr, const size_t oldSize, const size_t newSize);
|
||||
|
||||
/**
|
||||
* Scatter-copies elements from a contiguous source array into a strided
|
||||
* destination. For each of count elements, copies elementSize bytes from
|
||||
* src[i * srcStride] into dest[i * destStride].
|
||||
*
|
||||
* @param dest Base destination pointer.
|
||||
* @param destStride Byte stride between destination slots.
|
||||
* @param src Base source pointer.
|
||||
* @param srcStride Byte stride between source elements.
|
||||
* @param elementSize Bytes to copy per element.
|
||||
* @param count Number of elements to copy.
|
||||
*/
|
||||
void memoryCopyInterleaved(
|
||||
void *dest,
|
||||
const size_t destStride,
|
||||
const void *src,
|
||||
const size_t srcStride,
|
||||
const size_t elementSize,
|
||||
const size_t count
|
||||
);
|
||||
@@ -423,6 +423,87 @@ static void test_memoryResize(void **state) {
|
||||
assert_int_equal(memoryGetAllocatedCount(), 0);
|
||||
}
|
||||
|
||||
static void test_memoryCopyInterleaved(void **state) {
|
||||
(void)state;
|
||||
|
||||
// Basic: copy 4 uint32_t values from contiguous source into every-other dest
|
||||
// slot (stride = 2*sizeof(uint32_t)).
|
||||
uint32_t src[4] = { 0x11111111, 0x22222222, 0x33333333, 0x44444444 };
|
||||
uint32_t dest[8];
|
||||
memoryZero(dest, sizeof(dest));
|
||||
|
||||
memoryCopyInterleaved(
|
||||
dest, sizeof(uint32_t) * 2,
|
||||
src, sizeof(uint32_t),
|
||||
sizeof(uint32_t), 4
|
||||
);
|
||||
|
||||
assert_int_equal(dest[0], 0x11111111);
|
||||
assert_int_equal(dest[2], 0x22222222);
|
||||
assert_int_equal(dest[4], 0x33333333);
|
||||
assert_int_equal(dest[6], 0x44444444);
|
||||
// Skipped slots should be untouched.
|
||||
assert_int_equal(dest[1], 0);
|
||||
assert_int_equal(dest[3], 0);
|
||||
assert_int_equal(dest[5], 0);
|
||||
assert_int_equal(dest[7], 0);
|
||||
|
||||
// Strided source: pick every second element into a contiguous destination.
|
||||
uint32_t src2[8] = { 0xA, 0xFF, 0xB, 0xFF, 0xC, 0xFF, 0xD, 0xFF };
|
||||
uint32_t dest2[4];
|
||||
memoryZero(dest2, sizeof(dest2));
|
||||
|
||||
memoryCopyInterleaved(
|
||||
dest2, sizeof(uint32_t),
|
||||
src2, sizeof(uint32_t) * 2,
|
||||
sizeof(uint32_t), 4
|
||||
);
|
||||
|
||||
assert_int_equal(dest2[0], 0xA);
|
||||
assert_int_equal(dest2[1], 0xB);
|
||||
assert_int_equal(dest2[2], 0xC);
|
||||
assert_int_equal(dest2[3], 0xD);
|
||||
|
||||
// Multi-byte element: copy structs field-by-field pattern.
|
||||
typedef struct { uint32_t x; uint32_t y; } pair_t;
|
||||
uint32_t yVals[3] = { 10, 20, 30 };
|
||||
pair_t pairs[3];
|
||||
memoryZero(pairs, sizeof(pairs));
|
||||
|
||||
memoryCopyInterleaved(
|
||||
&pairs[0].y, sizeof(pair_t),
|
||||
yVals, sizeof(uint32_t),
|
||||
sizeof(uint32_t), 3
|
||||
);
|
||||
|
||||
assert_int_equal(pairs[0].y, 10);
|
||||
assert_int_equal(pairs[1].y, 20);
|
||||
assert_int_equal(pairs[2].y, 30);
|
||||
assert_int_equal(pairs[0].x, 0);
|
||||
assert_int_equal(pairs[1].x, 0);
|
||||
assert_int_equal(pairs[2].x, 0);
|
||||
|
||||
// Count of 0 is a no-op.
|
||||
uint32_t untouched[2] = { 0xDEAD, 0xBEEF };
|
||||
memoryCopyInterleaved(untouched, 4, src, 4, 4, 0);
|
||||
assert_int_equal(untouched[0], 0xDEAD);
|
||||
|
||||
// NULL dest
|
||||
expect_assert_failure(memoryCopyInterleaved(NULL, 8, src, 4, 4, 2));
|
||||
|
||||
// NULL src
|
||||
expect_assert_failure(memoryCopyInterleaved(dest, 8, NULL, 4, 4, 2));
|
||||
|
||||
// elementSize 0
|
||||
expect_assert_failure(memoryCopyInterleaved(dest, 8, src, 4, 0, 2));
|
||||
|
||||
// destStride smaller than elementSize
|
||||
expect_assert_failure(memoryCopyInterleaved(dest, 2, src, 4, 4, 2));
|
||||
|
||||
// srcStride smaller than elementSize
|
||||
expect_assert_failure(memoryCopyInterleaved(dest, 8, src, 2, 4, 2));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(test_memoryAllocate),
|
||||
@@ -435,6 +516,7 @@ int main(int argc, char **argv) {
|
||||
cmocka_unit_test(test_memoryCompare),
|
||||
cmocka_unit_test(test_memoryReallocate),
|
||||
cmocka_unit_test(test_memoryResize),
|
||||
cmocka_unit_test(test_memoryCopyInterleaved),
|
||||
};
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user