remove unnneded headers; reorganization

This commit is contained in:
2025-11-30 01:20:14 -06:00
parent 5fd83c6928
commit c1534dfe44
42 changed files with 617 additions and 1101 deletions

392
staef.c
View File

@@ -1,25 +1,381 @@
#include "font.h"
#include "qjs_macros.h"
#include "HandmadeMath.h"
#include "render.h"
#include "stb_ds.h"
#include "cell.h"
#include "qjs_sdl.h"
#include "prosperon.h"
#include "HandmadeMath.h"
#include "stb_ds.h"
#include "sdl.h"
#include <SDL3/SDL.h>
#include <string.h>
#include "qjs_geometry.h"
// External functions from jsffi.c
typedef HMM_Vec4 colorf;
extern colorf js2color(JSContext *js, JSValue v);
extern JSValue vec22js(JSContext *js, HMM_Vec2 v);
extern HMM_Vec2 js2vec2(JSContext *js, JSValue v);
extern rect js2rect(JSContext *js, JSValue v);
extern double js2number(JSContext *js, JSValue v);
extern JSValue number2js(JSContext *js, double g);
extern void *js_get_blob_data(JSContext *js, size_t *len, JSValue v);
extern JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t size);
extern int uncaught_exception(JSContext *js, JSValue ret);
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stb_image_write.h"
#include "stb_rect_pack.h"
#define STB_TRUETYPE_IMPLEMENTATION
#define STB_TRUETYPE_NO_STDIO
#include "stb_truetype.h"
#define STB_DS_IMPLEMENTATION
#include "stb_ds.h"
#include "HandmadeMath.h"
typedef enum {
LEFT,
RIGHT,
CENTER,
JUSTIFY
} TEXT_ALIGN;
typedef enum {
WORD,
CHARACTER
} TEXT_BREAK;
struct text_char {
rect pos;
rect uv;
HMM_Vec4 color;
};
struct shader;
struct window;
struct character {
float advance;
rect quad;
rect uv;
float xoff;
float yoff;
float width;
float height;
};
// text data
struct sFont {
uint32_t height; /* in pixels */
float ascent; // pixels
float descent; // pixels
float linegap; //pixels
float line_height; // pixels
struct character Characters[256];
SDL_Surface *surface;
};
typedef struct sFont font;
typedef struct Character glyph;
typedef struct { const char *start, *end; float width; } line_t;
typedef struct { line_t *lines; float max_width; } layout_lines;
struct sFont *use_font;
void font_free(JSRuntime *rt, font *f)
{
if (f->surface) SDL_DestroySurface(f->surface);
free(f);
}
struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) {
if (!ttf_buffer)
return NULL;
int packsize = 1024;
struct sFont *newfont = calloc(1, sizeof(struct sFont));
newfont->height = height;
unsigned char *bitmap = malloc(packsize * packsize);
stbtt_packedchar glyphs[95];
stbtt_pack_context pc;
int pad = 2;
stbtt_PackBegin(&pc, bitmap, packsize, packsize, 0, pad, NULL);
stbtt_PackFontRange(&pc, ttf_buffer, 0, height, 32, 95, glyphs);
stbtt_PackEnd(&pc);
stbtt_fontinfo fontinfo;
if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0))) {
// YughError("Failed to make font %s", fontfile);
}
int ascent, descent, linegap;
stbtt_GetFontVMetrics(&fontinfo, &ascent, &descent, &linegap);
float s = stbtt_ScaleForPixelHeight(&fontinfo, height);
newfont->ascent = ascent * s;
newfont->descent = descent * s; /* descent is negative */
newfont->linegap = linegap * s;
newfont->line_height = (newfont->ascent - newfont->descent) + newfont->linegap;
newfont->surface = SDL_CreateSurface(packsize,packsize, SDL_PIXELFORMAT_RGBA32);
if (!newfont->surface) printf("SDL ERROR: %s\n", SDL_GetError());
for (int i = 0; i < packsize; i++)
for (int j = 0; j < packsize; j++)
if (!SDL_WriteSurfacePixel(newfont->surface, j, i, 255,255,255,bitmap[i*packsize+j]))
printf("SDLERROR: %s\n", SDL_GetError());
for (unsigned char c = 32; c < 127; c++) {
stbtt_packedchar glyph = glyphs[c - 32];
rect uv;
uv.x = (glyph.x0) / (float)packsize;
uv.w = (glyph.x1-glyph.x0) / (float)packsize;
uv.y = (glyph.y1) / (float)packsize;
uv.h = (glyph.y0-glyph.y1) / (float)packsize;
newfont->Characters[c].uv = uv;
rect quad;
quad.x = glyph.xoff;
quad.y = -glyph.yoff2; // Top of glyph relative to baseline
quad.w = glyph.xoff2 - glyph.xoff;
quad.h = glyph.yoff2 - glyph.yoff; // Height from baseline
newfont->Characters[c].quad = quad;
newfont->Characters[c].advance = glyph.xadvance;
}
free(bitmap);
return newfont;
}
layout_lines layout_text_lines(const char *text, font *f,
float letter_spacing,
float wrap,
TEXT_BREAK break_at)
{
layout_lines out = {0};
int break_at_word = (break_at == WORD);
const char *line_start = text;
const char *word_start = text;
float line_width = 0;
float word_width = 0;
float max_width = 0;
for (const char *p = text; *p; p++) {
if (*p == '\n') {
line_t L = { line_start, p, line_width };
arrput(out.lines, L);
if (line_width > max_width) max_width = line_width;
line_start = p + 1;
word_start = p + 1;
line_width = 0;
word_width = 0;
continue;
}
unsigned char ch = (unsigned char)*p;
float char_w = f->Characters[ch].advance + letter_spacing;
if (wrap > 0 && line_width + char_w > wrap) {
const char *break_pt = p;
float break_w = line_width;
if (break_at_word && *p != ' ' && word_width > 0 && word_start > line_start) {
break_pt = word_start;
break_w = line_width - word_width;
}
line_t L = { line_start, break_pt, break_w };
arrput(out.lines, L);
if (break_w > max_width) max_width = break_w;
line_start = break_pt;
if (break_at_word && *line_start == ' ') line_start++;
p = line_start - 1;
word_start = line_start;
line_width = 0;
word_width = 0;
continue;
}
line_width += char_w;
if (break_at_word) {
if (*p == ' ') {
word_width = 0;
word_start = p + 1;
} else {
word_width += char_w;
}
}
}
if (line_start < text + strlen(text)) {
line_t L = { line_start, text + strlen(text), line_width };
arrput(out.lines, L);
if (line_width > max_width) max_width = line_width;
}
out.max_width = max_width;
return out;
}
void sdrawCharacter(struct text_vert **buffer, stbtt_packedchar c, HMM_Vec2 cursor, float scale, struct rgba color) {
struct text_vert vert;
// vert.pos.x = cursor.X + c.leftbearing;
// vert.pos.y = cursor.Y + c.topbearing;
// vert.wh = c.size;
// if (vert.pos.x > frame.l || vert.pos.y > frame.t || (vert.pos.y + vert.wh.y) < frame.b || (vert.pos.x + vert.wh.x) < frame.l) return;
// vert.uv.x = c.rect.x;
// vert.uv.y = c.rect.y;
// vert.st.x = c.rect.w;
// vert.st.y = c.rect.h;
rgba2floats(vert.color.e, color);
arrput(*buffer, vert);
}
void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cursor, colorf color)
{
// packedchar has
// Adds four verts: bottom left, bottom right, top left, top right
text_vert bl;
bl.pos.x = cursor.X + c.quad.x;
bl.pos.y = cursor.Y + c.quad.y;
bl.uv.x = c.uv.x;
bl.uv.y = c.uv.y;
bl.color = color;
arrput(*buffer, bl);
text_vert br = bl;
br.pos.x += c.quad.w;
br.uv.x += c.uv.w;
arrput(*buffer, br);
text_vert ul = bl;
ul.pos.y += c.quad.h;
ul.uv.y += c.uv.h;
arrput(*buffer, ul);
text_vert ur = ul;
ur.pos.x = br.pos.x;
ur.uv.x = br.uv.x;
arrput(*buffer, ur);
}
const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
{
struct rgba d;
if (!color) color = &d;
if (*c != '\033') return c;
c++;
if (*c != '[') return c;
c++;
if (*c == '0') {
*color = defc;
c++;
return c;
}
else if (!strncmp(c, "38;2;", 5)) {
c += 5;
*color = (struct rgba){0,0,0,255};
color->r = atoi(c);
c = strchr(c, ';')+1;
color->g = atoi(c);
c = strchr(c,';')+1;
color->b = atoi(c);
c = strchr(c,';')+1;
return c;
}
return c;
}
// text is a string, font f, wrap is how long a line is before wrapping. -1 to not wrap
HMM_Vec2 measure_text(const char *text, font *f, float letter_spacing, float wrap, TEXT_BREAK break_at, TEXT_ALIGN align)
{
layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at);
float lh = f->line_height;
int line_count = arrlen(lay.lines);
float height = line_count > 0 ? line_count * lh : 0;
float width = lay.max_width;
if (wrap > 0 && align != LEFT && align != JUSTIFY) {
// For RIGHT or CENTER we might shift lines visually, but width is still max(line.width, wrap ? min(wrap, ...) ).
// Usually you'd report max(wrap, width) or just wrap, depending on how you want containers to size.
}
HMM_Vec2 dim = { width, height };
arrfree(lay.lines);
return dim;
}
/* pos given in screen coordinates */
struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, colorf color,
float wrap, TEXT_BREAK break_at, TEXT_ALIGN align,
float letter_spacing)
{
text_vert *buffer = NULL;
float lh = f->line_height;
layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at);
line_t *lines = lay.lines;
HMM_Vec2 cursor = pos;
for (int i = 0; i < arrlen(lines); i++) {
line_t *L = &lines[i];
float start_x = pos.x;
float extra_space = 0;
int space_count = 0;
if (wrap > 0) {
switch (align) {
case RIGHT: start_x = pos.x + wrap - L->width; break;
case CENTER: start_x = pos.x + (wrap - L->width) * 0.5f; break;
case JUSTIFY:
if (i < arrlen(lines) - 1 && *(L->end) != '\n') {
for (const char *p = L->start; p < L->end; p++) if (*p == ' ') space_count++;
if (space_count > 0) extra_space = (wrap - L->width) / space_count;
}
break;
case LEFT: default: break;
}
}
cursor.x = start_x;
const char *p = L->start;
while (p < L->end) {
unsigned char ch = (unsigned char)*p;
struct character g = f->Characters[ch];
if (!isspace(*p)) draw_char_verts(&buffer, g, cursor, color);
cursor.x += g.advance;
/* add letter spacing unless this is last char of the line */
if (p + 1 < L->end) cursor.x += letter_spacing;
if (align == JUSTIFY && *p == ' ') cursor.x += extra_space;
p++;
}
cursor.x = pos.x;
cursor.y -= lh;
}
arrfree(lines);
return buffer;
}
// QuickJS class for font
QJSCLASS(font,)