fonts managed by javascript

This commit is contained in:
John Alanbrook 2024-04-09 16:48:15 -05:00
parent 5051d11005
commit 941106ced5
15 changed files with 226 additions and 166 deletions

View file

@ -357,10 +357,8 @@ var editor = {
this._sel_comp = x; this._sel_comp = x;
if (this._sel_comp) { if (this._sel_comp)
console.info("sel comp is now " + this._sel_comp);
player[0].control(this._sel_comp); player[0].control(this._sel_comp);
}
}, },
time: 0, time: 0,
@ -399,7 +397,7 @@ var editor = {
render.text([0,0], game.camera.world2view([0,0])); render.text([0,0], game.camera.world2view([0,0]));
render.text("WORKING LAYER: " + this.working_layer, [0,520]); render.text("WORKING LAYER: " + this.working_layer, [0,520]);
render.text("MODE: " + this.edit_mode, [0,500]); render.text("MODE: " + this.edit_mode, [0,520-render.font.linegap]);
if (this.comp_info && this.sel_comp) if (this.comp_info && this.sel_comp)
render.text(input.print_pawn_kbm(this.sel_comp,false), [100,700],1); render.text(input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
@ -440,23 +438,23 @@ var editor = {
var lvlstr = x.namestr(); var lvlstr = x.namestr();
if (i === lvlchain.length-1) lvlstr += "[this]"; if (i === lvlchain.length-1) lvlstr += "[this]";
render.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]); render.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]);
ypos += render.font.linegap;
render.text("^^^^^^", [0,ypos+=5],1); render.text("^^^^^^", [0,ypos],1);
ypos += 15; ypos += render.font.linegap;
}); });
depth++; depth++;
render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]); render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
this.selectlist.forEach(function(x) { this.selectlist.forEach(function(x) {
render.text(x.urstr(), x.screenpos().add([0, 32]), 1, Color.editor.ur); render.text(x.urstr(), x.screenpos().add([0, render.font.linegap*2]), 1, Color.editor.ur);
render.text(x.pos.map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white); render.text(x.pos.map(function(x) { return Math.round(x); }), x.screenpos());
render.cross(x.screenpos(), 10, Color.blue); render.cross(x.screenpos(), 10, Color.blue);
}); });
Object.entries(thiso.objects).forEach(function(x) { Object.entries(thiso.objects).forEach(function(x) {
var p = x[1].namestr(); var p = x[1].namestr();
render.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]); render.text(p, x[1].screenpos().add([0,render.font.linegap]),1,editor.color_depths[depth]);
render.point(x[1].screenpos(),5,Color.blue.alpha(0.3)); render.point(x[1].screenpos(),5,Color.blue.alpha(0.3));
render.point(x[1].screenpos(), 1, Color.red); render.point(x[1].screenpos(), 1, Color.red);
}); });
@ -476,7 +474,7 @@ var editor = {
for (var key in this.selectlist[0].components) { for (var key in this.selectlist[0].components) {
var selected = this.sel_comp === this.selectlist[0].components[key]; var selected = this.sel_comp === this.selectlist[0].components[key];
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]"; var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
render.text(str, this.selectlist[0].screenpos().add([0,-16*(i++)])); render.text(str, this.selectlist[0].screenpos().add([0,-render.font.linegap*(i++)]));
} }
if (this.sel_comp) { if (this.sel_comp) {
@ -692,9 +690,9 @@ editor.inputs.n = function() {
if (o === editor.selectlist[0]) return; if (o === editor.selectlist[0]) return;
if (o.master !== editor.selectlist[0].master) return; if (o.master !== editor.selectlist[0].master) return;
var tpos = editor.selectlist[0].pos; var tpos = editor.selectlist[0].get_pos(editor.selectlist[0].master);
tpos.x *= -1; tpos.x *= -1;
o.pos = tpos; o.set_pos(tpos, o.master);
}; };
editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the X axis." editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the X axis."
editor.inputs['M-n'] = function() editor.inputs['M-n'] = function()
@ -743,7 +741,6 @@ editor.inputs['C-d'] = function() {
}; };
editor.inputs['C-d'].doc = "Duplicate all selected objects."; editor.inputs['C-d'].doc = "Duplicate all selected objects.";
editor.inputs['C-m'] = function() { editor.inputs['C-m'] = function() {
if (editor.sel_comp) { if (editor.sel_comp) {
if ('flipy' in editor.sel_comp) if ('flipy' in editor.sel_comp)
@ -969,6 +966,10 @@ editor.inputs['C-y'] = function() {
}; };
editor.inputs['C-y'].doc = "Open script editor for the level."; editor.inputs['C-y'].doc = "Open script editor for the level.";
editor.inputs['C-p'] = function() {
os.system("prosperon");
}
editor.inputs['M-y'] = function() { editor.programmode = !editor.programmode; }; editor.inputs['M-y'] = function() { editor.programmode = !editor.programmode; };
editor.inputs['M-y'].doc = "Toggle program mode."; editor.inputs['M-y'].doc = "Toggle program mode.";

View file

@ -152,7 +152,7 @@ var gameobject = {
get scale() { return this.rscale; }, get scale() { return this.rscale; },
set_pos(x, relative = world) { set_pos(x, relative = world) {
var newpos = x.add(relative.pos); var newpos = relative.this2world(x);
var move = newpos.sub(this.pos); var move = newpos.sub(this.pos);
this.rpos = newpos; this.rpos = newpos;
this.objects.forEach(x => x.move(move)); this.objects.forEach(x => x.move(move));
@ -181,7 +181,8 @@ var gameobject = {
get_pos(relative = world) { get_pos(relative = world) {
if (relative === world) return this.pos; if (relative === world) return this.pos;
return this.pos.sub(relative.pos); return relative.world2this(this.pos);
//return this.pos.sub(relative.pos);
}, },
get_angle(relative = world) { get_angle(relative = world) {
@ -325,15 +326,14 @@ var gameobject = {
parent.objects[name] = this; parent.objects[name] = this;
parent[name] = this; parent[name] = this;
Object.hide(parent, name);
this.toString = function() { return name; }; this.toString = function() { return name; };
}, },
remove_obj(obj) { remove_obj(obj) {
if (this[obj.toString()] === this.objects[obj.toString()])
delete this[obj.toString()];
delete this.objects[obj.toString()]; delete this.objects[obj.toString()];
delete this[obj.toString()]; delete this[obj.toString()];
Object.unhide(this, obj.toString());
}, },
components: {}, components: {},
@ -419,7 +419,6 @@ var gameobject = {
d ??= {}; d ??= {};
var objects = {};
fresh.objects ??= {}; fresh.objects ??= {};
var curobjs = {}; var curobjs = {};
for (var o in this.objects) for (var o in this.objects)
@ -446,15 +445,9 @@ var gameobject = {
transform() { transform() {
var t = {}; var t = {};
t.pos = this.get_pos(this.master); t.pos = this.get_pos(this.master).map(x => Math.places(x, 0));
if (t.pos.every(x => x === 0)) delete t.pos;
t.angle = Math.places(this.get_angle(this.master), 4); t.angle = Math.places(this.get_angle(this.master), 4);
if (t.angle === 0) delete t.angle; t.scale = this.get_scale(this.master).map(x => Math.places(x, 2));;
return t;
t.scale = this.get_scale(this.master);
t.scale = t.scale.map((x, i) => x / this.ur.fresh.scale[i]);
t.scale = t.scale.map(x => Math.places(x, 3));
if (t.scale.every(x => x === 1)) delete t.scale;
return t; return t;
}, },
@ -466,9 +459,16 @@ var gameobject = {
return phys; return phys;
}, },
phys_mat() {
return {
friction: this.friction,
elasticity: this.elasticity
}
},
dup(diff) { dup(diff) {
var n = this.master.spawn(this.ur); var n = this.master.spawn(this.ur);
Object.totalmerge(n, this.instance_obj()); Object.totalmerge(n, this.transform());
return n; return n;
}, },

View file

@ -136,7 +136,7 @@ Mum.text = Mum.extend({
this.height = this.wh.y; this.height = this.wh.y;
var aa = [0,1].sub(params.anchor); var aa = [0,1].sub(params.anchor);
var pos = cursor.add(params.wh.scale(aa)).add(params.offset); var pos = cursor.add(params.wh.scale(aa)).add(params.offset);
gui.font_set(params.font); // gui.font_set(params.font);
render.text(params.str, pos, params.font_size, params.color, this.width, undefined, params.caret); render.text(params.str, pos, params.font_size, params.color, this.width, undefined, params.caret);
}, },

View file

@ -129,6 +129,15 @@ render.image = function(tex, pos, rotation = 0, color = Color.white, dimensions
return bbox.fromcwh([0,0], [tex.width,tex.height]); return bbox.fromcwh([0,0], [tex.width,tex.height]);
} }
render.fontcache = {};
render.set_font = function(path, size) {
var fontstr = `${path}-${size}`;
if (!render.fontcache[fontstr]) render.fontcache[fontstr] = os.make_font(path, size);
gui.font_set(render.fontcache[fontstr]);
render.font = render.fontcache[fontstr];
}
render.doc = "Draw shapes in screen space."; render.doc = "Draw shapes in screen space.";
render.circle.doc = "Draw a circle at pos, with a given radius and color."; render.circle.doc = "Draw a circle at pos, with a given radius and color.";
render.cross.doc = "Draw a cross centered at pos, with arm length size."; render.cross.doc = "Draw a cross centered at pos, with arm length size.";

View file

@ -199,6 +199,8 @@ Cmdline.register_order("edit", function() {
global.mixin("scripts/editor.js"); global.mixin("scripts/editor.js");
use("editorconfig.js"); use("editorconfig.js");
use("config.js"); use("config.js");
render.set_font("fonts/c64.ttf", 8);
console.info(`set font with linegap ${render.font.linegap}`);
editor.enter_editor(); editor.enter_editor();
}); });
}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?"); }, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?");

View file

@ -560,7 +560,7 @@ JSValue arb2js(cpArbiter *arb)
JS_SetPropertyStr(js, obj, "normal", vec22js((HMM_Vec2)cpArbiterGetNormal(arb))); JS_SetPropertyStr(js, obj, "normal", vec22js((HMM_Vec2)cpArbiterGetNormal(arb)));
JS_SetPropertyStr(js, obj, "obj", JS_DupValue(js,go2->ref)); JS_SetPropertyStr(js, obj, "obj", JS_DupValue(js,go2->ref));
JS_SetPropertyStr(js, obj, "shape", JS_DupValue(js, pshape->ref)); JS_SetPropertyStr(js, obj, "shape", JS_DupValue(js, pshape->ref));
JS_SetPropertyStr(js, obj, "point", vec22js((HMM_Vec2)cpArbiterGetPointA(arb, 0))); // JS_SetPropertyStr(js, obj, "point", vec22js((HMM_Vec2)cpArbiterGetPointA(arb, 0)));
HMM_Vec2 srfv; HMM_Vec2 srfv;
srfv.cp = cpArbiterGetSurfaceVelocity(arb); srfv.cp = cpArbiterGetSurfaceVelocity(arb);

View file

@ -167,7 +167,9 @@ sg_buffer texcoord_floats(float *f, int verts, int comp)
return sg_make_buffer(&(sg_buffer_desc){ return sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed, .data.ptr = packed,
.data.size = sizeof(unsigned short) * verts}); .data.size = sizeof(unsigned short) * verts,
.label = "tex coord vert buffer",
});
} }
sg_buffer normal_floats(float *f, int verts, int comp) sg_buffer normal_floats(float *f, int verts, int comp)
@ -178,7 +180,9 @@ sg_buffer normal_floats(float *f, int verts, int comp)
return sg_make_buffer(&(sg_buffer_desc){ return sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed_norms, .data.ptr = packed_norms,
.data.size = sizeof(uint32_t) * verts}); .data.size = sizeof(uint32_t) * verts,
.label = "normal vert buffer",
});
} }
HMM_Vec3 index_to_vert(uint32_t idx, float *f) HMM_Vec3 index_to_vert(uint32_t idx, float *f)
@ -195,9 +199,11 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
memcpy(idxs, cgltf_buffer_view_data(prim->indices->buffer_view), sizeof(uint16_t) * c); memcpy(idxs, cgltf_buffer_view_data(prim->indices->buffer_view), sizeof(uint16_t) * c);
mesh->bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){ mesh->bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs, .data.ptr = idxs,
.data.size = sizeof(uint16_t) * c, .data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER}); .type = SG_BUFFERTYPE_INDEXBUFFER,
.label = "mesh index buffer",
});
mesh->idx_count = c; mesh->idx_count = c;
} else { } else {
@ -232,8 +238,10 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
switch (attribute.type) { switch (attribute.type) {
case cgltf_attribute_type_position: case cgltf_attribute_type_position:
mesh->bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ mesh->bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = vs, .data.ptr = vs,
.data.size = sizeof(float) * n}); .data.size = sizeof(float) * n,
.label = "mesh vert buffer"
});
break; break;
case cgltf_attribute_type_normal: case cgltf_attribute_type_normal:

View file

@ -209,7 +209,8 @@ void debugdraw_init()
point_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ point_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct point_vertex)*v_amt, .size = sizeof(struct point_vertex)*v_amt,
.usage = SG_USAGE_STREAM .usage = SG_USAGE_STREAM,
.label = "point vertex buffer"
}); });
line_shader = sg_make_shader(line_shader_desc(sg_query_backend())); line_shader = sg_make_shader(line_shader_desc(sg_query_backend()));
@ -233,13 +234,15 @@ void debugdraw_init()
line_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ line_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct line_vert)*v_amt, .size = sizeof(struct line_vert)*v_amt,
.usage = SG_USAGE_STREAM .usage = SG_USAGE_STREAM,
.label = "line vertex buffer",
}); });
line_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){ line_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(uint16_t)*v_amt, .size = sizeof(uint16_t)*v_amt,
.usage = SG_USAGE_STREAM, .usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_INDEXBUFFER .type = SG_BUFFERTYPE_INDEXBUFFER,
.label = "line index buffer",
}); });
csg = sg_make_shader(circle_shader_desc(sg_query_backend())); csg = sg_make_shader(circle_shader_desc(sg_query_backend()));
@ -266,6 +269,7 @@ void debugdraw_init()
circle_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ circle_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct circle_vertex)*v_amt, .size = sizeof(struct circle_vertex)*v_amt,
.usage = SG_USAGE_STREAM, .usage = SG_USAGE_STREAM,
.label = "circle vert buffer",
}); });
float circleverts[8] = { float circleverts[8] = {
@ -278,6 +282,7 @@ void debugdraw_init()
circle_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){ circle_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8}, .data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
.usage = SG_USAGE_IMMUTABLE, .usage = SG_USAGE_IMMUTABLE,
.label = "circle quarter buffer",
}); });
grid_shader = sg_make_shader(grid_shader_desc(sg_query_backend())); grid_shader = sg_make_shader(grid_shader_desc(sg_query_backend()));
@ -315,12 +320,14 @@ void debugdraw_init()
.size = sizeof(struct poly_vertex)*v_amt, .size = sizeof(struct poly_vertex)*v_amt,
.usage = SG_USAGE_STREAM, .usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_VERTEXBUFFER, .type = SG_BUFFERTYPE_VERTEXBUFFER,
.label = "poly vert buffer",
}); });
poly_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){ poly_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(uint32_t)*6*v_amt, .size = sizeof(uint32_t)*6*v_amt,
.usage = SG_USAGE_STREAM, .usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_INDEXBUFFER .type = SG_BUFFERTYPE_INDEXBUFFER,
.label = "poly index buffer"
}); });
} }

View file

@ -17,18 +17,12 @@
#include "stb_image_write.h" #include "stb_image_write.h"
#include "stb_rect_pack.h" #include "stb_rect_pack.h"
#include "stb_truetype.h" #include "stb_truetype.h"
#include "stb_ds.h"
#include "HandmadeMath.h" #include "HandmadeMath.h"
struct sFont *font; struct sFont *use_font;
static struct { #define max_chars 100000
char *key;
struct sFont *value;
} *fonthash = NULL;
#define max_chars 10000
static sg_shader fontshader; static sg_shader fontshader;
static sg_bindings bind_text; static sg_bindings bind_text;
@ -74,7 +68,8 @@ void font_init() {
bind_text.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){ bind_text.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(text_verts), .data = SG_RANGE(text_verts),
.usage = SG_USAGE_IMMUTABLE .usage = SG_USAGE_IMMUTABLE,
.label = "text rectangle buffer",
}); });
bind_text.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ bind_text.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
@ -84,31 +79,19 @@ void font_init() {
.label = "text buffer" .label = "text buffer"
}); });
font_set("fonts/c64.ttf");
bind_text.fs.images[0] = font->texID;
bind_text.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){}); bind_text.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
} }
void font_set(const char *path) void font_free(font *f)
{ {
if (shlen(fonthash) == 0) sh_new_arena(fonthash); sg_destroy_image(f->texID);
int index = shgeti(fonthash, path); free(f);
if (index != -1) { }
if (font == fonthash[index].value) return;
font = fonthash[index].value;
bind_text.fs.images[0] = font->texID;
return;
}
struct sFont *newfont = MakeFont(path, 8); void font_set(font *f)
if (!newfont) { {
YughError("Could not make font from %s.", path); use_font = f;
return; bind_text.fs.images[0] = f->texID;
}
font = newfont;
shput(fonthash, path, newfont);
bind_text.fs.images[0] = font->texID;
} }
struct sFont *MakeSDFFont(const char *fontfile, int height) struct sFont *MakeSDFFont(const char *fontfile, int height)
@ -145,6 +128,10 @@ struct sFont *MakeFont(const char *fontfile, int height) {
newfont->height = height; newfont->height = height;
unsigned char *ttf_buffer = slurp_file(fontfile, NULL); unsigned char *ttf_buffer = slurp_file(fontfile, NULL);
if (!ttf_buffer) {
YughWarn("Could not find font at %s.");
return NULL;
}
unsigned char *bitmap = malloc(packsize * packsize); unsigned char *bitmap = malloc(packsize * packsize);
stbtt_packedchar glyphs[95]; stbtt_packedchar glyphs[95];
@ -163,19 +150,21 @@ struct sFont *MakeFont(const char *fontfile, int height) {
} }
stbtt_GetFontVMetrics(&fontinfo, &newfont->ascent, &newfont->descent, &newfont->linegap); stbtt_GetFontVMetrics(&fontinfo, &newfont->ascent, &newfont->descent, &newfont->linegap);
newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16); //newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
newfont->linegap = (newfont->ascent - newfont->descent) * newfont->emscale; newfont->emscale = stbtt_ScaleForPixelHeight(&fontinfo, height);
newfont->linegap = (newfont->ascent - newfont->descent) * newfont->emscale*1.5;
newfont->texID = sg_make_image(&(sg_image_desc){ newfont->texID = sg_make_image(&(sg_image_desc){
.type = SG_IMAGETYPE_2D, .type = SG_IMAGETYPE_2D,
.width = packsize, .width = packsize,
.height = packsize, .height = packsize,
.pixel_format = SG_PIXELFORMAT_R8, .pixel_format = SG_PIXELFORMAT_R8,
.usage = SG_USAGE_IMMUTABLE, .usage = SG_USAGE_IMMUTABLE,
.data.subimage[0][0] = { .data.subimage[0][0] = {
.ptr = bitmap, .ptr = bitmap,
.size = packsize * packsize}}); .size = packsize * packsize
}
});
for (unsigned char c = 32; c < 127; c++) { for (unsigned char c = 32; c < 127; c++) {
stbtt_packedchar glyph = glyphs[c - 32]; stbtt_packedchar glyph = glyphs[c - 32];
@ -208,7 +197,7 @@ static int curchar = 0;
void draw_underline_cursor(HMM_Vec2 pos, float scale, struct rgba color) void draw_underline_cursor(HMM_Vec2 pos, float scale, struct rgba color)
{ {
pos.Y -= 2; pos.Y -= 2;
sdrawCharacter(font->Characters['_'], pos, scale, color); sdrawCharacter(use_font->Characters['_'], pos, scale, color);
} }
void draw_char_box(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) void draw_char_box(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color)
@ -270,10 +259,6 @@ void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgb
curchar++; curchar++;
} }
void text_settype(struct sFont *mfont) {
font = mfont;
}
const char *esc_color(const char *c, struct rgba *color, struct rgba defc) const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
{ {
struct rgba d; struct rgba d;
@ -303,6 +288,7 @@ const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking) struct boundingbox text_bb(const char *text, float scale, float lw, float tracking)
{ {
if (!use_font) return;
struct rgba dummy; struct rgba dummy;
HMM_Vec2 cursor = {0,0}; HMM_Vec2 cursor = {0,0};
const char *line, *wordstart; const char *line, *wordstart;
@ -310,10 +296,10 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
while (*line != '\0') { while (*line != '\0') {
if (isblank(*line)) { if (isblank(*line)) {
cursor.X += font->Characters[*line].Advance * tracking * scale; cursor.X += use_font->Characters[*line].Advance * tracking * scale;
line++; line++;
} else if (isspace(*line)) { } else if (isspace(*line)) {
cursor.Y -= scale * font->linegap; cursor.Y -= scale * use_font->linegap;
cursor.X = 0; cursor.X = 0;
line++; line++;
} else { } else {
@ -324,26 +310,26 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
int wordWidth = 0; int wordWidth = 0;
while (!isspace(*line) && *line != '\0') { while (!isspace(*line) && *line != '\0') {
wordWidth += font->Characters[*line].Advance * tracking * scale; wordWidth += use_font->Characters[*line].Advance * tracking * scale;
line++; line++;
} }
if (lw > 0 && (cursor.X + wordWidth) >= lw) { if (lw > 0 && (cursor.X + wordWidth) >= lw) {
cursor.X = 0; cursor.X = 0;
cursor.Y -= scale * font->linegap; cursor.Y -= scale * use_font->linegap;
} }
while (wordstart < line) { while (wordstart < line) {
if (*wordstart == '\e') if (*wordstart == '\e')
line = esc_color(wordstart, NULL, dummy); line = esc_color(wordstart, NULL, dummy);
cursor.X += font->Characters[*wordstart].Advance * tracking * scale; cursor.X += use_font->Characters[*wordstart].Advance * tracking * scale;
wordstart++; wordstart++;
} }
} }
} }
return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){cursor.X,font->linegap-cursor.Y}); return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){cursor.X,use_font->linegap-cursor.Y});
} }
void check_caret(int caret, int l, HMM_Vec2 pos, float scale, struct rgba color) void check_caret(int caret, int l, HMM_Vec2 pos, float scale, struct rgba color)
@ -354,6 +340,11 @@ void check_caret(int caret, int l, HMM_Vec2 pos, float scale, struct rgba color)
/* pos given in screen coordinates */ /* pos given in screen coordinates */
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) { int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) {
if (!use_font) {
YughError("Cannot render text before a font is set.");
return;
}
int len = strlen(text); int len = strlen(text);
HMM_Vec2 cursor = pos; HMM_Vec2 cursor = pos;
@ -366,13 +357,13 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
while (*line != '\0') { while (*line != '\0') {
if (isblank(*line)) { if (isblank(*line)) {
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor); sdrawCharacter(use_font->Characters[*line], cursor, scale, usecolor);
cursor.X += font->Characters[*line].Advance * tracking * scale; cursor.X += use_font->Characters[*line].Advance * tracking * scale;
line++; line++;
check_caret(caret, line-drawstart, cursor, scale, usecolor); check_caret(caret, line-drawstart, cursor, scale, usecolor);
} else if (isspace(*line)) { } else if (isspace(*line)) {
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor); sdrawCharacter(use_font->Characters[*line], cursor, scale, usecolor);
cursor.Y -= scale * font->linegap; cursor.Y -= scale * use_font->linegap;
cursor.X = pos.X; cursor.X = pos.X;
line++; line++;
check_caret(caret, line-drawstart, cursor, scale, usecolor); check_caret(caret, line-drawstart, cursor, scale, usecolor);
@ -385,23 +376,23 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
while (!isspace(*line) && *line != '\0') { while (!isspace(*line) && *line != '\0') {
wordWidth += font->Characters[*line].Advance * tracking * scale; wordWidth += use_font->Characters[*line].Advance * tracking * scale;
line++; line++;
} }
if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) { if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) {
cursor.X = pos.X; cursor.X = pos.X;
cursor.Y -= scale * font->linegap; cursor.Y -= scale * use_font->linegap;
} }
while (wordstart < line) { while (wordstart < line) {
if (*wordstart == '\e') if (*wordstart == '\e')
wordstart = esc_color(wordstart, &usecolor, color); wordstart = esc_color(wordstart, &usecolor, color);
sdrawCharacter(font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255}); sdrawCharacter(use_font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor); sdrawCharacter(use_font->Characters[*wordstart], cursor, scale, usecolor);
cursor.X += font->Characters[*wordstart].Advance * tracking * scale; cursor.X += use_font->Characters[*wordstart].Advance * tracking * scale;
wordstart++; wordstart++;
check_caret(caret, wordstart-drawstart, cursor, scale, usecolor); check_caret(caret, wordstart-drawstart, cursor, scale, usecolor);
} }

View file

@ -28,9 +28,13 @@ struct sFont {
sg_image texID; sg_image texID;
}; };
typedef struct sFont font;
void font_free(font *f);
void font_init(); void font_init();
struct sFont *MakeFont(const char *fontfile, int height); struct sFont *MakeFont(const char *fontfile, int height);
void font_set(const char *path); void font_set(font *f);
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color); void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color);
void text_settype(struct sFont *font); void text_settype(struct sFont *font);
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking); struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);

View file

@ -65,6 +65,7 @@ QJSCLASS(gameobject)
QJSCLASS(emitter) QJSCLASS(emitter)
QJSCLASS(dsp_node) QJSCLASS(dsp_node)
QJSCLASS(texture) QJSCLASS(texture)
QJSCLASS(font)
QJSCLASS(sprite) QJSCLASS(sprite)
QJSCLASS(warp_gravity) QJSCLASS(warp_gravity)
QJSCLASS(warp_damp) QJSCLASS(warp_damp)
@ -674,7 +675,7 @@ JSC_CCALL(gui_img,
gui_draw_img(js2texture(argv[0]), t, js2boolean(argv[4]), js2vec2(argv[5]), 1.0, js2color(argv[6])); gui_draw_img(js2texture(argv[0]), t, js2boolean(argv[4]), js2vec2(argv[5]), 1.0, js2color(argv[6]));
) )
JSC_SCALL(gui_font_set, font_set(str)) JSC_CCALL(gui_font_set, font_set(js2font(argv[0])))
static const JSCFunctionListEntry js_gui_funcs[] = { static const JSCFunctionListEntry js_gui_funcs[] = {
MIST_FUNC_DEF(gui, flush, 0), MIST_FUNC_DEF(gui, flush, 0),
@ -1134,7 +1135,7 @@ JSValue js_gameobject_set_rscale(JSContext *js, JSValue this, JSValue val) { js2
JSC_GETSET_BODY(velocity, Velocity, cvec2) JSC_GETSET_BODY(velocity, Velocity, cvec2)
JSValue js_gameobject_set_angularvelocity (JSContext *js, JSValue this, JSValue val) { cpBodySetAngularVelocity(js2gameobject(this)->body, HMM_TurnToRad*js2number(val)); } JSValue js_gameobject_set_angularvelocity (JSContext *js, JSValue this, JSValue val) { cpBodySetAngularVelocity(js2gameobject(this)->body, HMM_TurnToRad*js2number(val)); }
JSValue js_gameobject_get_angularvelocity (JSContext *js, JSValue this) { return number2js(HMM_RadToTurn*cpBodyGetAngularVelocity(js2gameobject(this)->body)); } JSValue js_gameobject_get_angularvelocity (JSContext *js, JSValue this) { return number2js(HMM_RadToTurn*cpBodyGetAngularVelocity(js2gameobject(this)->body)); }
JSC_GETSET_BODY(moi, Moment, number) //JSC_GETSET_BODY(moi, Moment, number)
JSC_GETSET_BODY(torque, Torque, number) JSC_GETSET_BODY(torque, Torque, number)
JSC_CCALL(gameobject_impulse, cpBodyApplyImpulseAtWorldPoint(js2gameobject(this)->body, js2vec2(argv[0]).cp, cpBodyGetPosition(js2gameobject(this)->body))) JSC_CCALL(gameobject_impulse, cpBodyApplyImpulseAtWorldPoint(js2gameobject(this)->body, js2vec2(argv[0]).cp, cpBodyGetPosition(js2gameobject(this)->body)))
JSC_CCALL(gameobject_force, cpBodyApplyForceAtWorldPoint(js2gameobject(this)->body, js2vec2(argv[0]).cp, cpBodyGetPosition(js2gameobject(this)->body))) JSC_CCALL(gameobject_force, cpBodyApplyForceAtWorldPoint(js2gameobject(this)->body, js2vec2(argv[0]).cp, cpBodyGetPosition(js2gameobject(this)->body)))
@ -1167,12 +1168,12 @@ static const JSCFunctionListEntry js_gameobject_funcs[] = {
CGETSET_ADD(gameobject,layer), CGETSET_ADD(gameobject,layer),
CGETSET_ADD(gameobject,warp_filter), CGETSET_ADD(gameobject,warp_filter),
CGETSET_ADD(gameobject,drawlayer), CGETSET_ADD(gameobject,drawlayer),
CGETSET_ADD(gameobject, rpos), CGETSET_ADD_HID(gameobject, rpos),
CGETSET_ADD(gameobject, rangle), CGETSET_ADD_HID(gameobject, rangle),
CGETSET_ADD(gameobject, rscale), CGETSET_ADD_HID(gameobject, rscale),
CGETSET_ADD(gameobject, velocity), CGETSET_ADD(gameobject, velocity),
CGETSET_ADD(gameobject, angularvelocity), CGETSET_ADD(gameobject, angularvelocity),
CGETSET_ADD(gameobject, moi), // CGETSET_ADD(gameobject, moi),
CGETSET_ADD(gameobject, phys), CGETSET_ADD(gameobject, phys),
CGETSET_ADD(gameobject, torque), CGETSET_ADD(gameobject, torque),
MIST_FUNC_DEF(gameobject, impulse, 1), MIST_FUNC_DEF(gameobject, impulse, 1),
@ -1303,6 +1304,14 @@ static const JSCFunctionListEntry js_texture_funcs[] = {
MIST_GET(texture, delays), MIST_GET(texture, delays),
}; };
JSC_GETSET(font, linegap, number)
JSC_GET(font, height, number)
static const JSCFunctionListEntry js_font_funcs[] = {
CGETSET_ADD(font, linegap),
MIST_GET(font, height),
};
JSValue js_constraint_set_max_force (JSContext *js, JSValue this, JSValue val) { JSValue js_constraint_set_max_force (JSContext *js, JSValue this, JSValue val) {
cpConstraintSetMaxForce(js2constraint(this)->c, js2number(val)); cpConstraintSetMaxForce(js2constraint(this)->c, js2number(val));
return JS_UNDEFINED; return JS_UNDEFINED;
@ -1487,6 +1496,8 @@ JSC_CCALL(os_make_model,
return ret; return ret;
) )
JSC_CCALL(os_make_font, return font2js(MakeFont(js2str(argv[0]), js2number(argv[1]))))
JSC_SCALL(os_system, system(str); ) JSC_SCALL(os_system, system(str); )
static const JSCFunctionListEntry js_os_funcs[] = { static const JSCFunctionListEntry js_os_funcs[] = {
@ -1507,6 +1518,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, make_edge2d, 2), MIST_FUNC_DEF(os, make_edge2d, 2),
MIST_FUNC_DEF(os, make_model, 2), MIST_FUNC_DEF(os, make_model, 2),
MIST_FUNC_DEF(os, make_texture, 1), MIST_FUNC_DEF(os, make_texture, 1),
MIST_FUNC_DEF(os, make_font, 2),
}; };
#include "steam.h" #include "steam.h"
@ -1525,6 +1537,7 @@ void ffi_load() {
QJSCLASSPREP_FUNCS(warp_damp); QJSCLASSPREP_FUNCS(warp_damp);
QJSCLASSPREP_FUNCS(sprite); QJSCLASSPREP_FUNCS(sprite);
QJSCLASSPREP_FUNCS(texture); QJSCLASSPREP_FUNCS(texture);
QJSCLASSPREP_FUNCS(font);
QJSCLASSPREP_FUNCS(constraint); QJSCLASSPREP_FUNCS(constraint);
QJSCLASSPREP_FUNCS(window); QJSCLASSPREP_FUNCS(window);
QJSCLASSPREP_FUNCS(drawmodel); QJSCLASSPREP_FUNCS(drawmodel);

View file

@ -25,11 +25,13 @@
JS_FreeCString(js,str); \ JS_FreeCString(js,str); \
) \ ) \
#define MIST_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } #define MIST_CGETSET_BASE(name, fgetter, fsetter, props) { name, props, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
#define MIST_CGETSET_DEF(name, fgetter, fsetter) MIST_CGETSET_BASE(name, fgetter, fsetter, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)
#define MIST_CGETET_HID(name, fgetter, fsetter) MIST_CGETSET_BASE(name, fgetter, fsetter, JS_PROP_CONFIGURABLE)
#define MIST_GET(name, fgetter) { #fgetter , JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = js_##name##_get_##fgetter } } } } #define MIST_GET(name, fgetter) { #fgetter , JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = js_##name##_get_##fgetter } } } }
#define CGETSET_ADD(ID, ENTRY) MIST_CGETSET_DEF(#ENTRY, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY) #define CGETSET_ADD(ID, ENTRY) MIST_CGETSET_DEF(#ENTRY, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY)
#define CGETSET_ADD_HID(ID, ENTRY) MIST_CGETSET_BASE(#ENTRY, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY, JS_PROP_CONFIGURABLE)
#define JSC_CCALL(NAME, FN) JSValue js_##NAME (JSContext *js, JSValue this, int argc, JSValue *argv) { \ #define JSC_CCALL(NAME, FN) JSValue js_##NAME (JSContext *js, JSValue this, int argc, JSValue *argv) { \
JSValue ret = JS_UNDEFINED; \ JSValue ret = JS_UNDEFINED; \

View file

@ -80,7 +80,8 @@ void particle_init()
par_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){ par_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8}, .data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
.usage = SG_USAGE_IMMUTABLE .usage = SG_USAGE_IMMUTABLE,
.label = "particle quater buffer"
}); });
par_bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){}); par_bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});

View file

@ -133,70 +133,89 @@ static struct {
sg_shader shader; sg_shader shader;
} sg_shadow; } sg_shadow;
void trace_init_image(sg_image id, const sg_image_desc *d, void *data)
{
YughSpam("Init image %s", d->label);
}
void trace_make_shader(const sg_shader_desc *d, sg_shader id, void *data)
{
YughSpam("Making shader %s", d->label);
if (sg_query_shader_state(id) == SG_RESOURCESTATE_FAILED)
YughError("FAILED MAKING A SHADER: %s\n%s\n%s", d->label);
}
void trace_fail_shader(sg_shader id, void *data)
{
YughError("Shader %u did not compile.", id);
}
void trace_destroy_shader(sg_shader id, void *data)
{
YughSpam("Destroyed shader %u.", id);
}
void trace_fail_image(sg_image id, void *data)
{
sg_image_desc desc = sg_query_image_desc(id);
YughError("Failed to make image %u %s", id, desc.label);
}
void trace_make_pipeline(const sg_pipeline_desc *d, sg_pipeline id, void *data)
{
YughSpam("Making pipeline %u [%s].", id, d->label);
}
void trace_apply_pipeline(sg_pipeline pip, void *data) void trace_apply_pipeline(sg_pipeline pip, void *data)
{ {
// YughSpam("Applying pipeline %u %s.", pip, sg_query_pipeline_desc(pip).label); // YughSpam("Applying pipeline %u %s.", pip, sg_query_pipeline_desc(pip).label);
} }
void trace_fail_pipeline(sg_pipeline pip, void *data)
{
YughError("Failed pipeline %s", sg_query_pipeline_desc(pip).label);
}
void trace_make_attachments(const sg_attachment_desc *d, sg_attachments result, void *data)
{
YughSpam("Making attachments %s", "IMPLEMENT");
}
void trace_begin_pass(sg_pass pass, const sg_pass_action *action, void *data) void trace_begin_pass(sg_pass pass, const sg_pass_action *action, void *data)
{ {
// YughSpam("Begin pass %s", pass.label); // YughSpam("Begin pass %s", pass.label);
} }
#define SG_TRACE_SET(NAME) \
void trace_alloc_##NAME (sg_##NAME id, void *data) \
{ \
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
YughSpam("Alloc " #NAME " %d [%s]", id, desc.label); \
} \
\
void trace_dealloc_##NAME(sg_##NAME id, void *data) \
{ \
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
YughSpam("Dealloc " #NAME " %d [%s]", id, desc.label); \
} \
\
void trace_make_##NAME(sg_##NAME##_desc *desc, void *data) \
{ \
YughSpam("Make " #NAME " [%s]", desc->label); \
} \
\
void trace_destroy_##NAME(sg_##NAME id, void *data) \
{ \
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
YughSpam("Destroy " #NAME " %d [%s]", id, desc.label); \
} \
\
void trace_init_##NAME(sg_##NAME id, sg_##NAME##_desc *desc, void *data) \
{ \
YughSpam("Init " #NAME " %d [%s]", id, desc->label); \
} \
\
void trace_uninit_##NAME(sg_##NAME id, void *data) \
{ \
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
YughSpam("Init " #NAME " %d [%s]", id, desc.label); \
} \
\
void trace_fail_##NAME(sg_##NAME id, void *data) \
{ \
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
YughError("Failed " #NAME " %d: %s", id, desc.label); \
} \
SG_TRACE_SET(buffer)
SG_TRACE_SET(image)
SG_TRACE_SET(sampler)
SG_TRACE_SET(shader)
SG_TRACE_SET(pipeline)
SG_TRACE_SET(attachments)
#define SG_HOOK_SET(NAME) \
.alloc_##NAME = trace_alloc_##NAME, \
.dealloc_##NAME = trace_dealloc_##NAME, \
.init_##NAME = trace_init_##NAME, \
.uninit_##NAME = trace_uninit_##NAME, \
.fail_##NAME = trace_fail_##NAME, \
.destroy_##NAME = trace_destroy_##NAME, \
.make_##NAME = trace_make_##NAME \
void trace_append_buffer(sg_buffer id, sg_range *data, void *user)
{
sg_buffer_desc desc = sg_query_buffer_desc(id);
YughSpam("Appending buffer %d [%s]", id, desc.label);
}
static sg_trace_hooks hooks = { static sg_trace_hooks hooks = {
.fail_shader = trace_fail_shader,
.make_shader = trace_make_shader,
.destroy_shader = trace_destroy_shader,
.fail_image = trace_fail_image,
.init_image = trace_init_image,
.make_pipeline = trace_make_pipeline,
.fail_pipeline = trace_fail_pipeline,
.apply_pipeline = trace_apply_pipeline, .apply_pipeline = trace_apply_pipeline,
.begin_pass = trace_begin_pass, .begin_pass = trace_begin_pass,
.make_attachments = trace_make_attachments, SG_HOOK_SET(buffer),
SG_HOOK_SET(image),
SG_HOOK_SET(shader),
SG_HOOK_SET(sampler),
SG_HOOK_SET(pipeline),
SG_HOOK_SET(attachments),
.append_buffer = trace_append_buffer
}; };
void render_init() { void render_init() {
@ -256,6 +275,7 @@ void render_init() {
sg_gif.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ sg_gif.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(gif_quad), .size = sizeof(gif_quad),
.data = gif_quad, .data = gif_quad,
.label = "gif vert buffer",
}); });
sg_gif.bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){}); sg_gif.bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
@ -274,7 +294,8 @@ void render_init() {
sg_crt.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ sg_crt.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(crt_quad), .size = sizeof(crt_quad),
.type = SG_BUFFERTYPE_VERTEXBUFFER, .type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_IMMUTABLE .usage = SG_USAGE_IMMUTABLE,
.label = "crt vert buffer",
}); });
} }

View file

@ -148,6 +148,7 @@ void sprite_initialize() {
.size = sizeof(struct slice9_vert) * 100, .size = sizeof(struct slice9_vert) * 100,
.type = SG_BUFFERTYPE_VERTEXBUFFER, .type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_STREAM, .usage = SG_USAGE_STREAM,
.label = "slice9 buffer"
}); });
} }