text drawing

This commit is contained in:
2025-07-15 16:22:11 -05:00
parent 09b78781e6
commit 4b817b8d1b
7 changed files with 293 additions and 41 deletions

183
.prosperon/imgui.ini Normal file
View File

@@ -0,0 +1,183 @@
[Window][Debug##Default]
Pos=60,60
Size=400,400
[Window][TEST WINDOW]
Pos=156,6
Size=366,275
[Window][editor]
Pos=558,248
Size=274,177
[Window][Editor]
Pos=-113,317
Size=184,174
[Window][Map Editor]
Pos=96,74
Size=312,398
[Window][Edit Tile]
Pos=120,99
Size=356,275
[Window][Level Editor]
Pos=60,45
Size=283,332
Collapsed=1
[Window][Brush Selector]
Pos=189,35
Size=203,474
Collapsed=1
[Window][Tool Selector]
Pos=300,25
Size=247,474
Collapsed=1
[Window][FPS: 12]
Pos=60,60
Size=32,35
[Window][FPS: 87]
Pos=60,60
Size=32,35
[Window][FPS: 59]
Pos=60,60
Size=32,35
[Window][FPS: 107]
Pos=60,60
Size=32,35
[Window][FPS: 135]
Pos=60,60
Size=32,35
[Window][FPS: 136]
Pos=60,60
Size=51,48
[Window][FPS: 140]
Pos=60,60
Size=51,48
[Window][FPS: 137]
Pos=60,60
Size=51,48
[Window][FPS: 138]
Pos=60,60
Size=51,48
[Window][FPS: 141]
Pos=60,60
Size=51,48
[Window][FPS: 143]
Pos=60,60
Size=51,48
[Window][FPS: 142]
Pos=60,60
Size=51,48
[Window][FPS: 144]
Pos=60,60
Size=32,35
[Window][FPS: 139]
Pos=60,60
Size=51,48
[Window][FPS: 133]
Pos=60,60
Size=32,35
[Window][FPS: 134]
Pos=60,60
Size=51,48
[Window][FPS: 131]
Pos=60,60
Size=51,48
[Window][FPS: 130]
Pos=60,60
Size=51,48
[Window][FPS: 128]
Pos=60,60
Size=51,48
[Window][FPS: 126]
Pos=60,60
Size=51,48
[Window][FPS: 123]
Pos=60,60
Size=32,35
[Window][FPS: 124]
Pos=60,60
Size=32,35
[Window][FPS: 121]
Pos=60,60
Size=32,35
[Window][FPS: 122]
Pos=60,60
Size=32,35
[Window][FPS: 119]
Pos=60,60
Size=51,48
[Window][FPS: 117]
Pos=60,60
Size=32,35
[Window][FPS: 118]
Pos=60,60
Size=32,35
[Window][FPS: 116]
Pos=60,60
Size=32,35
[Window][FPS: 108]
Pos=60,60
Size=32,35
[Window][FPS: 109]
Pos=60,60
Size=51,48
[Window][FPS: 115]
Pos=60,60
Size=51,48
[Window][FPS: 114]
Pos=60,60
Size=51,48
[Window][FPS: 113]
Pos=60,60
Size=51,48
[Window][FPS: 110]
Pos=60,60
Size=51,48
[Window][FPS: 112]
Pos=60,60
Size=51,48
[Window][FPS: 111]
Pos=60,60
Size=51,48

View File

@@ -137,7 +137,7 @@ draw.slice9 = function slice9(image, rect = [0,0], slice = 0, info = slice9_info
}) })
} }
draw.image = function image(image, rect, rotation, anchor, shear, info = {mode:"nearest"}, material) { draw.image = function image(image, rect, rotation, anchor, shear, info = {mode:"nearest"}, material = {color:{r:1,g:1,b:1,a:1}}) {
if (!rect) throw Error('Need rectangle to render image.') if (!rect) throw Error('Need rectangle to render image.')
if (!image) throw Error('Need an image to render.') if (!image) throw Error('Need an image to render.')

View File

@@ -212,14 +212,45 @@ function translate_draw_commands(commands) {
case "draw_text": case "draw_text":
if (!cmd.text) break if (!cmd.text) break
if (!cmd.pos) break if (!cmd.pos) break
var rect = worldToScreenRect({x:cmd.pos.x, y:cmd.pos.y, width:8, height:8}, camera)
var pos = {x: rect.x, y: rect.y} // Get font from the font string (e.g., "smalle.16")
var font = graphics.get_font(cmd.font, cmd.size)
if (!font || !font.texture || !font.texture.id) break
// Create text geometry buffer
var text_mesh = graphics.make_text_buffer(
cmd.text,
{x: cmd.pos.x, y: cmd.pos.y, width: 200, height: 50},
cmd.size,
[cmd.material.color.r, cmd.material.color.g, cmd.material.color.b, cmd.material.color.a],
cmd.wrap || 0,
font
)
if (!text_mesh) break
// Transform XY coordinates using camera matrix
var camera_params = [camera.a, camera.c, camera.e, camera.f]
var transformed_xy = geometry.transform_xy_blob(text_mesh.xy, camera_params)
// Create transformed geometry object
var transformed_geom = {
xy: transformed_xy,
xy_stride: text_mesh.xy_stride,
uv: text_mesh.uv,
uv_stride: text_mesh.uv_stride,
color: text_mesh.color,
color_stride: text_mesh.color_stride,
indices: text_mesh.indices,
num_vertices: text_mesh.num_vertices,
num_indices: text_mesh.num_indices,
size_indices: text_mesh.size_indices,
texture_id: font.texture.id
}
renderer_commands.push({ renderer_commands.push({
op: "debugText", op: "geometry_raw",
data: { data: transformed_geom
pos,
text: cmd.text
}
}) })
break break

View File

@@ -98,6 +98,6 @@ function pump()
$_.delay(pump, 1/240) $_.delay(pump, 1/240)
} }
pump() //pump()
return audio; return audio;

View File

@@ -12,6 +12,7 @@ var io = use('io')
var time = use('time') var time = use('time')
var res = use('resources') var res = use('resources')
var json = use('json') var json = use('json')
var os = use('os')
var GPU = Symbol() var GPU = Symbol()
var CPU = Symbol() var CPU = Symbol()
@@ -412,7 +413,12 @@ graphics.get_font = function get_font(path, size) {
if (fontcache[fontstr]) return fontcache[fontstr] if (fontcache[fontstr]) return fontcache[fontstr]
var data = io.slurpbytes(fullpath) var data = io.slurpbytes(fullpath)
var font = graphics.make_font(data,size) // Ensure size is a proper number
var numericSize = Number(size)
if (isNaN(numericSize) || numericSize <= 0) {
numericSize = 16 // default size
}
var font = graphics.make_font(data, numericSize)
// Load font texture via renderer actor (async) // Load font texture via renderer actor (async)
if (renderer_actor) { if (renderer_actor) {

View File

@@ -78,7 +78,6 @@ struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) {
quad.h = glyph.yoff2-glyph.yoff; quad.h = glyph.yoff2-glyph.yoff;
newfont->Characters[c].quad = quad; newfont->Characters[c].quad = quad;
newfont->Characters[c].advance = glyph.xadvance; newfont->Characters[c].advance = glyph.xadvance;
// printf("glyph for %c is x0,y0,x1,y1: %d,%d,%d,%d\n xoff %g, yoff %g, xadvance %g, xoff2 %g, yoff2 %g\n", c, glyph.x0, glyph.y1, glyph.x1, glyph.y1, glyph.xoff, glyph.yoff, glyph.xadvance, glyph.xoff2, glyph.yoff2);
} }
free(bitmap); free(bitmap);
@@ -109,8 +108,8 @@ void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cur
// packedchar has // packedchar has
// Adds four verts: bottom left, bottom right, top left, top right // Adds four verts: bottom left, bottom right, top left, top right
text_vert bl; text_vert bl;
bl.pos.x = cursor.X + c.quad.x; bl.pos.x = cursor.X + c.quad.x * scale;
bl.pos.y = cursor.Y + c.quad.y; bl.pos.y = cursor.Y + c.quad.y * scale;
bl.uv.x = c.uv.x; bl.uv.x = c.uv.x;
bl.uv.y = c.uv.y; bl.uv.y = c.uv.y;
bl.color = color; bl.color = color;
@@ -118,12 +117,12 @@ void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cur
text_vert br = bl; text_vert br = bl;
br.pos.x += c.quad.w; br.pos.x += c.quad.w * scale;
br.uv.x += c.uv.w; br.uv.x += c.uv.w;
arrput(*buffer, br); arrput(*buffer, br);
text_vert ul = bl; text_vert ul = bl;
ul.pos.y += c.quad.h; ul.pos.y += c.quad.h * scale;
ul.uv.y += c.uv.h; ul.uv.y += c.uv.h;
arrput(*buffer, ul); arrput(*buffer, ul);
@@ -238,30 +237,32 @@ struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scal
text_vert *buffer = NULL; text_vert *buffer = NULL;
HMM_Vec2 cursor = pos; HMM_Vec2 cursor = pos;
float lineHeight = f->ascent - f->descent; float lineHeight = (f->ascent - f->descent) * scale;
float lineWidth = 0; float lineWidth = 0;
float scaledLinegap = f->linegap * scale;
for (const char *c = text; *c != 0; c++) { for (const char *c = text; *c != 0; c++) {
if (*c == '\n') { if (*c == '\n') {
cursor.x = pos.x; cursor.x = pos.x;
cursor.y -= lineHeight + f->linegap; cursor.y -= lineHeight + scaledLinegap;
lineWidth = 0; lineWidth = 0;
continue; continue;
} }
struct character chara = f->Characters[(unsigned char)*c]; struct character chara = f->Characters[(unsigned char)*c];
float scaledAdvance = chara.advance * scale;
if (wrap > 0 && lineWidth + chara.advance > wrap) { if (wrap > 0 && lineWidth + scaledAdvance > wrap) {
cursor.x = pos.x; cursor.x = pos.x;
cursor.y -= lineHeight + f->linegap; cursor.y -= lineHeight + scaledLinegap;
lineWidth = 0; lineWidth = 0;
} }
if (!isspace(*c)) if (!isspace(*c))
draw_char_verts(&buffer, chara, cursor, scale, color); draw_char_verts(&buffer, chara, cursor, scale, color);
lineWidth += chara.advance; lineWidth += scaledAdvance;
cursor.x += chara.advance; cursor.x += scaledAdvance;
} }
return buffer; return buffer;

View File

@@ -296,31 +296,61 @@ JSValue quads_to_mesh(JSContext *js, text_vert *buffer)
{ {
size_t verts = arrlen(buffer); size_t verts = arrlen(buffer);
HMM_Vec2 *pos = malloc(arrlen(buffer)*sizeof(HMM_Vec2)); // Allocate flat arrays for xy, uv, and color data
HMM_Vec2 *uv = malloc(arrlen(buffer)*sizeof(HMM_Vec2)); size_t xy_size = verts * 2 * sizeof(float);
HMM_Vec4 *color = malloc(arrlen(buffer)*sizeof(HMM_Vec4)); size_t uv_size = verts * 2 * sizeof(float);
size_t color_size = verts * sizeof(SDL_FColor);
float *xy_data = malloc(xy_size);
float *uv_data = malloc(uv_size);
SDL_FColor *color_data = malloc(color_size);
for (int i = 0; i < arrlen(buffer); i++) { // Convert vertex data to flat arrays
pos[i] = buffer[i].pos; for (int i = 0; i < verts; i++) {
uv[i] = buffer[i].uv; xy_data[i*2] = buffer[i].pos.x;
color[i] = buffer[i].color; xy_data[i*2+1] = buffer[i].pos.y;
uv_data[i*2] = buffer[i].uv.x;
uv_data[i*2+1] = buffer[i].uv.y;
color_data[i].r = buffer[i].color.x;
color_data[i].g = buffer[i].color.y;
color_data[i].b = buffer[i].color.z;
color_data[i].a = buffer[i].color.w;
} }
JSValue jspos = make_gpu_buffer(js, pos, sizeof(HMM_Vec2)*arrlen(buffer), 0, 2,0,0);
JSValue jsuv = make_gpu_buffer(js, uv, sizeof(HMM_Vec2)*arrlen(buffer), 0, 2,0,0);
JSValue jscolor = make_gpu_buffer(js, color, sizeof(HMM_Vec4)*arrlen(buffer), 0, 4,0,0);
size_t quads = verts/4; size_t quads = verts/4;
size_t count = verts/2*3; size_t count = quads*6;
JSValue jsidx = make_quad_indices_buffer(js, quads);
// Create indices
uint16_t *indices = malloc(sizeof(uint16_t)*count);
for (int i = 0, v = 0; i < count; i += 6, v += 4) {
indices[i] = v;
indices[i+1] = v+2;
indices[i+2] = v+1;
indices[i+3] = v+2;
indices[i+4] = v+3;
indices[i+5] = v+1;
}
JSValue ret = JS_NewObject(js); JSValue ret = JS_NewObject(js);
JS_SetPropertyStr(js, ret, "pos", jspos);
JS_SetPropertyStr(js, ret, "uv", jsuv); // Create blobs for geometry data
JS_SetPropertyStr(js, ret, "color", jscolor); JS_SetPropertyStr(js, ret, "xy", js_new_blob_stoned_copy(js, xy_data, xy_size));
JS_SetPropertyStr(js, ret, "indices", jsidx); JS_SetPropertyStr(js, ret, "xy_stride", JS_NewInt32(js, 2 * sizeof(float)));
JS_SetPropertyStr(js, ret, "vertices", number2js(js, verts)); JS_SetPropertyStr(js, ret, "uv", js_new_blob_stoned_copy(js, uv_data, uv_size));
JS_SetPropertyStr(js,ret,"num_indices", number2js(js,count)); JS_SetPropertyStr(js, ret, "uv_stride", JS_NewInt32(js, 2 * sizeof(float)));
JS_SetPropertyStr(js, ret, "color", js_new_blob_stoned_copy(js, color_data, color_size));
JS_SetPropertyStr(js, ret, "color_stride", JS_NewInt32(js, sizeof(SDL_FColor)));
JS_SetPropertyStr(js, ret, "indices", js_new_blob_stoned_copy(js, indices, sizeof(uint16_t)*count));
JS_SetPropertyStr(js, ret, "num_vertices", JS_NewInt32(js, verts));
JS_SetPropertyStr(js, ret, "num_indices", JS_NewInt32(js, count));
JS_SetPropertyStr(js, ret, "size_indices", JS_NewInt32(js, 2)); // uint16_t size
free(xy_data);
free(uv_data);
free(color_data);
free(indices);
return ret; return ret;
} }
@@ -718,7 +748,8 @@ JSC_CCALL(os_make_text_buffer,
colorf c = js2color(js,argv[3]); colorf c = js2color(js,argv[3]);
int wrap = js2number(js,argv[4]); int wrap = js2number(js,argv[4]);
HMM_Vec2 startpos = {.x = rectpos.x, .y = rectpos.y }; HMM_Vec2 startpos = {.x = rectpos.x, .y = rectpos.y };
text_vert *buffer = renderText(s, startpos, f, size, c, wrap); float scale = size / f->height;
text_vert *buffer = renderText(s, startpos, f, scale, c, wrap);
ret = quads_to_mesh(js,buffer); ret = quads_to_mesh(js,buffer);
JS_FreeCString(js, s); JS_FreeCString(js, s);
arrfree(buffer); arrfree(buffer);