diff --git a/Makefile b/Makefile index 0edf872..d45774b 100755 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ ifdef NQOA endif ifeq ($(DBG),1) - CPPFLAGS += -g -fsanitize=address + CPPFLAGS += -g #-fsanitize=address INFO += _dbg else CPPFLAGS += -DNDEBUG diff --git a/scripts/base.js b/scripts/base.js index d775e09..9c0915b 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -787,12 +787,9 @@ Object.defineProperty(String.prototype, 'pct', { }); Object.defineProperty(String.prototype, 'uc', { value: function() { return this.toUpperCase(); } }); - Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }}); - /* ARRAY DEFS */ - Object.defineProperty(Array.prototype, 'copy', { value: function() { var c = []; @@ -1199,6 +1196,10 @@ Math.grab_from_points = function(pos, points, slop) { return idx; }; +Math.nearest = function(n, incr) +{ + return Math.round(n/incr)*incr; +} Number.prec = function(num) { @@ -1425,6 +1426,10 @@ var Vector = { var p = Vector.norm(plane); return vec.sub(p.scale(2*Vector.dot(vec, p))); }, + + reflect_point(vec, point) { + return point.add(vec.sub(point).scale(-1)); + }, }; diff --git a/scripts/components.js b/scripts/components.js index 9470dc0..c29273a 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -97,14 +97,13 @@ component.sprite.impl = { set layer(x) { cmd(60, this.id, x); }, get layer() { return undefined; }, emissive(x) { cmd(170, this.id, x); }, + pick() { return this; }, + move(d) { this.pos = this.pos.add(d); }, boundingbox() { - return cwh2bb([0,0],[0,0]); var dim = this.dimensions(); - dim = dim.scale(this.gameobject.scale); - var realpos = this.pos.copy(); - realpos.x = realpos.x * dim.x + (dim.x/2); - realpos.y = realpos.y * dim.y + (dim.y/2); + dim = dim.scale(this.gameobject.gscale()); + var realpos = dim.scale(0.5).add(this.pos); return cwh2bb(realpos,dim); }, @@ -123,6 +122,7 @@ component.model = Object.copy(component, { component.model.impl = { set path(x) { cmd(149, this.id, x); }, draw() { cmd(150, this.id); }, + kill() { cmd(213, this.id); }, }; var sprite = component.sprite; @@ -134,15 +134,15 @@ sprite.doc = { }; sprite.inputs = {}; -sprite.inputs.kp9 = function() { this.pos = [0,0]; }; -sprite.inputs.kp8 = function() { this.pos = [-0.5, 0]; }; -sprite.inputs.kp7 = function() { this.pos = [-1,0]; }; -sprite.inputs.kp6 = function() { this.pos = [0,-0.5]; }; -sprite.inputs.kp5 = function() { this.pos = [-0.5,-0.5]; }; -sprite.inputs.kp4 = function() { this.pos = [-1,-0.5]; }; -sprite.inputs.kp3 = function() { this.pos = [0, -1]; }; -sprite.inputs.kp2 = function() { this.pos = [-0.5,-1]; }; -sprite.inputs.kp1 = function() { this.pos = [-1,-1]; }; +sprite.inputs.kp9 = function() { this.pos = this.dimensions().scale([0,0]); }; +sprite.inputs.kp8 = function() { this.pos = this.dimensions().scale([-0.5, 0]); }; +sprite.inputs.kp7 = function() { this.pos = this.dimensions().scale([-1,0]); }; +sprite.inputs.kp6 = function() { this.pos = this.dimensions().scale([0,-0.5]); }; +sprite.inputs.kp5 = function() { this.pos = this.dimensions().scale([-0.5,-0.5]); }; +sprite.inputs.kp4 = function() { this.pos = this.dimensions().scale([-1,-0.5]); }; +sprite.inputs.kp3 = function() { this.pos = this.dimensions().scale([0, -1]); }; +sprite.inputs.kp2 = function() { this.pos = this.dimensions().scale([-0.5,-1]); }; +sprite.inputs.kp1 = function() { this.pos = this.dimensions().scale([-1,-1]); }; Object.seal(sprite); var SpriteAnim = { @@ -535,8 +535,6 @@ polygon2d.inputs['C-b'] = function() { }; polygon2d.inputs['C-b'].doc = "Freeze mirroring in place."; -//Object.freeze(polygon2d); - component.edge2d = Object.copy(collider2d, { dimensions:2, thickness:0, @@ -544,7 +542,7 @@ component.edge2d = Object.copy(collider2d, { type: Spline.type.catmull, C: 1, /* when in bezier, continuity required. 0, 1 or 2. */ looped: false, - angle: 3, /* maximum angle between two segments */ + angle: 0.5, /* smaller for smoother bezier */ flipx: false, flipy: false, @@ -559,8 +557,10 @@ component.edge2d = Object.copy(collider2d, { var spoints = this.cpoints.slice(); if (this.flipx) { - var endcap = Spline.is_bezier(this.type) ? spoints.length-2 : spoints.length-1; - for (var i = endcap; i >= 0; i--) { + if (Spline.is_bezier(this.type)) + spoints.push(Vector.reflect_point(spoints.at(-2), spoints.at(-1))); + + for (var i = spoints.length-1; i >= 0; i--) { var newpoint = spoints[i].slice(); newpoint.x = -newpoint.x; spoints.push(newpoint); @@ -568,6 +568,9 @@ component.edge2d = Object.copy(collider2d, { } if (this.flipy) { + if (Spline.is_bezier(this.type)) + spoints.push(Vector.reflect(point(spoints.at(-2),spoints.at(-1)))); + for (var i = spoints.length-1; i >= 0; i--) { var newpoint = spoints[i].slice(); newpoint.y = -newpoint.y; @@ -611,6 +614,9 @@ component.edge2d = Object.copy(collider2d, { return Spline.sample_angle(this.type, spoints,this.angle); } + if (this.looped && Spline.is_bezier(this.type)) + spoints = Spline.bezier_loop(spoints); + return Spline.sample_angle(this.type, spoints, this.angle); }, @@ -875,7 +881,6 @@ component.circle2d = Object.copy(collider2d, { toString() { return "circle2d"; }, boundingbox() { - var diameter = this.radius*2*this.gameobject.scale; return cwh2bb(this.offset.scale(this.gameobject.scale), [this.radius,this.radius]); }, diff --git a/scripts/editor.js b/scripts/editor.js index 8a46ceb..be4ad97 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -389,8 +389,6 @@ var editor = { Debug.boundingbox(bb, Color.Editor.select.alpha(0.1)); Shape.line(bb2points(bb).wrapped(1), Color.white); } - - }, gui() { @@ -459,8 +457,8 @@ var editor = { Object.entries(thiso.objects).forEach(function(x) { var p = x[1].namestr(); GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]); - Shape.circle(x[1].screenpos(),10,Color.blue); - Shape.arrow(x[1].screenpos(), x[1].screenpos().add([0,50]), Color.red, 10); + Shape.circle(x[1].screenpos(),10,Color.blue.alpha(0.3)); + Shape.arrow(x[1].screenpos(), x[1].screenpos().add(x[1].up().scale(15)), Color.red, 10); }); var mg = physics.pos_query(Mouse.worldpos,10); @@ -470,6 +468,9 @@ var editor = { GUI.text(p, Mouse.screenpos(),1,Color.teal); } + if (this.rotlist.length === 1) + GUI.text(Math.trunc(this.rotlist[0].obj.angle), Mouse.screenpos(), 1, Color.teal); + if (this.selectlist.length === 1) { var i = 1; for (var key in this.selectlist[0].components) { @@ -1143,6 +1144,8 @@ editor.inputs.mouse.move = function(pos, dpos) editor.rotlist?.forEach(function(x) { var anglediff = Math.atan2(relpos.y, relpos.x) - x.rotoffset; x.obj.angle = x.angle + Math.rad2deg(anglediff); + if (Keys.shift()) + x.obj.angle = Math.nearest(x.obj.angle, 45); if (x.pos) x.obj.pos = x.pos.sub(x.offset).add(x.offset.rotate(anglediff)); }); @@ -1151,7 +1154,6 @@ editor.inputs.mouse.move = function(pos, dpos) editor.inputs.mouse.scroll = function(scroll) { scroll.y *= -1; -// editor.grabselect?.forEach(x => x.move(Game.camera.dir_view2world(scroll))); editor.camera.move(Game.camera.dir_view2world(scroll.scale(-3))); } diff --git a/scripts/engine.js b/scripts/engine.js index 4182a5a..6a30820 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -234,42 +234,15 @@ register(9, Log.stack, this); Register.gamepad_playermap[0] = Player.players[0]; var Signal = { - signals: [], obj_begin(fn, obj, go) { - this.signals.push([fn, obj]); register_collide(0, fn, obj, go.body); }, obj_separate(fn, obj, go) { - this.signals.push([fn,obj]); register_collide(3,fn,obj,go.body); }, - - clear_obj(obj) { - this.signals.filter(function(x) { return x[1] !== obj; }); - }, - - c:{}, - register(name, fn) { - if (!this.c[name]) - this.c[name] = []; - - this.c[name].push(fn); - }, - - call(name, ...args) { - if (this.c[name]) - this.c[name].forEach(function(fn) { fn.call(this, ...args); }); - }, }; -var game_quit = function() -{ - Primum.kill(); -} - -Signal.register("quit", game_quit); - var Event = { events: {}, @@ -282,6 +255,10 @@ var Event = { this.events[name] = this.events[name].filter(x => x[0] !== obj); }, + rm_obj(obj) { + Object.keys(this.events).forEach(name => Event.unobserve(name,obj)); + }, + notify(name) { if (!this.events[name]) return; this.events[name].forEach(function(x) { @@ -290,6 +267,8 @@ var Event = { }, }; +Event.observe('quit', undefined, function() { Primum.kill(); }); + var Window = { fullscreen(f) { cmd(145, f); }, set width(w) { cmd(125, w); }, @@ -337,6 +316,14 @@ Spline.sample_angle = function(type, points, angle) { return spline_cmd(0, type, points[0].length, points, angle); } +Spline.bezier_loop = function(cp) +{ + cp.push(Vector.reflect_point(cp.at(-2),cp.at(-1))); + cp.push(Vector.reflect_point(cp[1],cp[0])); + cp.push(cp[0].slice()); + return cp; +} + Spline.is_bezier = function(t) { return t === Spline.type.bezier; } Spline.is_catmull = function(t) { return t === Spline.type.catmull; } @@ -448,6 +435,10 @@ var Game = { edit: true, + object_count() { + return cmd(214); + }, + all_objects(fn) { /* Wind down from Primum */ }, @@ -463,7 +454,7 @@ var Game = { }, /* List of all objects spawned that have a specific tag */ - find_tag(tag) { + find_tag(tag){ }, diff --git a/scripts/entity.js b/scripts/entity.js index 857e2ae..8966a32 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -191,7 +191,7 @@ var gameobject = { set_gravity(x) { cmd(167, this.body, x); }, set timescale(x) { cmd(168,this.body,x); }, get timescale() { return cmd(169,this.body); }, - set phys(x) { console.warn(`Setting phys to ${x}`); set_body(1, this.body, x); }, + set phys(x) { set_body(1, this.body, x); }, get phys() { return q_body(0,this.body); }, get velocity() { return q_body(3, this.body); }, set velocity(x) { set_body(9, this.body, x); }, @@ -411,7 +411,12 @@ var gameobject = { /* Bounding box of the object in world dimensions */ boundingbox() { var boxes = []; - boxes.push({t:0, r:0,b:0,l:0}); + boxes.push({ + t:0, + r:0, + b:0, + l:0 + }); for (var key in this.components) { if ('boundingbox' in this.components[key]) @@ -420,23 +425,11 @@ var gameobject = { for (var key in this.objects) boxes.push(this.objects[key].boundingbox()); - if (boxes.empty) return cwh2bb([0,0], [0,0]); + var bb = boxes.shift(); - var bb = boxes[0]; - - boxes.forEach(function(x) { - bb = bb_expand(bb, x); - }); - - var cwh = bb2cwh(bb); - - if (!bb) return; - - if (this.flipx) cwh.c.x *= -1; - if (this.flipy) cwh.c.y *= -1; - - cwh.c = cwh.c.add(this.pos); - bb = cwh2bb(cwh.c, cwh.wh); + boxes.forEach(function(x) { bb = bb_expand(bb, x); }); + + bb = movebb(bb, this.pos); return bb ? bb : cwh2bb([0,0], [0,0]); }, @@ -519,8 +512,6 @@ var gameobject = { this.level = undefined; } - - Player.do_uncontrol(this); Register.unregister_obj(this); @@ -536,6 +527,7 @@ var gameobject = { this.clear(); this.objects = undefined; + Event.rm_obj(this); if (typeof this.stop === 'function') this.stop(); @@ -633,16 +625,12 @@ var gameobject = { }, register_hit(fn, obj) { - if (!obj) - obj = this; - + obj ??= this; Signal.obj_begin(fn, obj, this); }, register_separate(fn, obj) { - if (!obj) - obj = this; - + obj ??= this; Signal.obj_separate(fn,obj,this); }, } diff --git a/scripts/std.js b/scripts/std.js index c2cd9ca..911292a 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -4,18 +4,11 @@ function compile_env(str, env, file) return cmd(123, str, env, file); } -function fcompile_env(file, env) -{ - return compile_env(IO.slurp(file), env, file); -} +function fcompile_env(file, env) { return compile_env(IO.slurp(file), env, file); } -var OS = { - get cwd() { return cmd(144); }, -}; -OS.exec = function(s) -{ - cmd(143, s); -} +var OS = {}; +OS.cwd = function() { return cmd(144); } +OS.exec = function(s) { cmd(143, s); } var Resources = {}; Resources.images = ["png", "jpg", "jpeg", "gif"]; diff --git a/source/engine/3d/model.c b/source/engine/3d/model.c index 7409738..6d9a994 100644 --- a/source/engine/3d/model.c +++ b/source/engine/3d/model.c @@ -20,6 +20,7 @@ #define CGLTF_IMPLEMENTATION #include + #include #include @@ -32,6 +33,8 @@ static struct { struct model *value; } *modelhash = NULL; +struct drawmodel **models = NULL; + static void processnode(); static void processmesh(); static void processtexture(); @@ -116,6 +119,8 @@ unsigned short pack_short_texcoord(float x, float y) return (((unsigned short)yc) << 8) | xc; } +unsigned short pack_short_tex(float c) { return c * USHRT_MAX; } + uint32_t pack_int10_n2(float *norm) { uint32_t ni[3]; @@ -144,7 +149,7 @@ void mesh_add_material(mesh *mesh, cgltf_material *mat) free(imp); } } else - mesh->bind.fs.images[0] = texture_pullfromfile("k")->id; + mesh->bind.fs.images[0] = texture_pullfromfile("k")->id; mesh->bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){}); /* @@ -157,9 +162,10 @@ void mesh_add_material(mesh *mesh, cgltf_material *mat) sg_buffer texcoord_floats(float *f, int verts, int comp) { - unsigned short packed[verts]; - for (int i = 0, v = 0; v < verts; i+=comp, v++) - packed[v] = pack_short_texcoord(f[i], f[i+1]); + int n = verts*comp; + unsigned short packed[n]; + for (int i = 0, v = 0; i < n; i++) + packed[i] = pack_short_tex(f[i]); return sg_make_buffer(&(sg_buffer_desc){ .data.ptr = packed, @@ -390,9 +396,16 @@ struct drawmodel *make_drawmodel(gameobject *go) dm->model = NULL; dm->amodel = HMM_M4D(1.f); dm->go = go; + arrpush(models,dm); return dm; } +void model_draw_all() +{ + for (int i = 0; i < arrlen(models); i++) + draw_drawmodel(models[i]); +} + void draw_drawmodel(struct drawmodel *dm) { if (!dm->model) return; @@ -401,5 +414,15 @@ void draw_drawmodel(struct drawmodel *dm) draw_model(dm->model, rst); } -void free_drawmodel(struct drawmodel *dm) { free(dm); } +void free_drawmodel(struct drawmodel *dm) { + int rm; + for (int i = 0; i < arrlen(models); i++) + if (models[i] == dm) { + rm = i; + break; + } + + arrdelswap(models,rm); + free(dm); +} diff --git a/source/engine/3d/model.h b/source/engine/3d/model.h index b374dfa..c02d0c2 100644 --- a/source/engine/3d/model.h +++ b/source/engine/3d/model.h @@ -53,6 +53,7 @@ void model_init(); struct drawmodel *make_drawmodel(gameobject *go); void draw_drawmodel(struct drawmodel *dm); +void model_draw_all(); void free_drawmodel(struct drawmodel *dm); #endif diff --git a/source/engine/debug/log.c b/source/engine/debug/log.c index 43c628c..2dd3f3e 100644 --- a/source/engine/debug/log.c +++ b/source/engine/debug/log.c @@ -62,7 +62,7 @@ void mYughLog(int category, int priority, int line, const char *file, const char char *buffer = malloc(len); sprintf(buffer, logfmt, file, line, logstr[priority], catstr[category], msg); - fprintf(stderr, buffer); + fprintf(stderr, "%s", buffer); fflush(stderr); free(msg); diff --git a/source/engine/font.c b/source/engine/font.c index c136f0a..07bd8c9 100644 --- a/source/engine/font.c +++ b/source/engine/font.c @@ -303,7 +303,7 @@ struct boundingbox text_bb(const unsigned char *text, float scale, float lw, flo while (!isspace(*line) && *line != '\0') { wordWidth += font->Characters[*line].Advance * tracking * scale; - line++; + line++; } if (lw > 0 && (cursor.X + wordWidth) >= lw) { diff --git a/source/engine/font.h b/source/engine/font.h index 72d0cfa..a56c544 100644 --- a/source/engine/font.h +++ b/source/engine/font.h @@ -25,7 +25,7 @@ struct sFont { int descent; int linegap; float emscale; - struct Character Characters[127]; + struct Character Characters[255]; sg_image texID; }; diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 1c86bde..91d978a 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -10,6 +10,8 @@ static gameobject **gameobjects; +int go_count() { return arrlen(gameobjects); } + gameobject *body2go(cpBody *body) { return cpBodyGetUserData(body); } gameobject *shape2go(cpShape *shape) { return ((struct phys2d_shape *)cpShapeGetUserData(shape))->go; } diff --git a/source/engine/gameobject.h b/source/engine/gameobject.h index a28129c..399f36f 100644 --- a/source/engine/gameobject.h +++ b/source/engine/gameobject.h @@ -53,6 +53,7 @@ struct gameobject { typedef struct gameobject gameobject; gameobject *MakeGameobject(); +int go_count(); void gameobject_apply(gameobject *go); void gameobject_free(gameobject *go); void gameobjects_cleanup(); diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 0c7ce76..48dac28 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -1120,7 +1120,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) case 143: str = JS_ToCString(js, argv[1]); -// system(str); + system(str); break; case 144: @@ -1349,6 +1349,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) case 212: ret = jsdst(); break; + case 213: + free_drawmodel(js2ptr(argv[1])); + break; + case 214: + ret = int2js(go_count()); + break; } if (str) diff --git a/source/engine/render.c b/source/engine/render.c index b0d0bfd..43aec43 100644 --- a/source/engine/render.c +++ b/source/engine/render.c @@ -509,6 +509,7 @@ void full_2d_pass(struct window *window) hudproj = HMM_Orthographic_LH_ZO(0, window->rwidth, 0, window->rheight, -1.f, 1.f); sprite_draw_all(); + model_draw_all(); call_draw(); //// DEBUG diff --git a/source/engine/resources.c b/source/engine/resources.c index 6a68257..397517e 100644 --- a/source/engine/resources.c +++ b/source/engine/resources.c @@ -249,7 +249,7 @@ char *slurp_text(const char *filename, size_t *size) int cp(char *p1, char *p2) { - long len; + size_t len; void *data = slurp_file(p1, &len); FILE *f = fopen_mkdir(p2, "w"); diff --git a/source/engine/script.c b/source/engine/script.c index df8f986..a3f7415 100644 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -72,6 +72,7 @@ void script_startup() { void script_stop() { timers_free(); + script_evalf("Event.notify('quit');"); send_signal("quit",0,NULL); for (int i = 0; i < shlen(jsstrs); i++) diff --git a/source/engine/yugine.c b/source/engine/yugine.c index 4a9286e..0b272f2 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -79,12 +79,9 @@ static int sim_play = SIM_PLAY; int editor_mode = 0; -const char *engine_info() -{ - static char str[100]; - snprintf(str, 100, "Yugine version %s, %s build.\nCopyright 2022-2023 odplot productions LLC.\n", VER, INFO); - return str; -} +#define ENGINEINFO "Yugine version " VER ", " INFO " build.\nCopyright 2022-2024." + +const char *engine_info() { return ENGINEINFO; } static int argc; static char **args; diff --git a/source/shaders/circle.sglsl b/source/shaders/circle.sglsl index 9ec4901..2feab53 100644 --- a/source/shaders/circle.sglsl +++ b/source/shaders/circle.sglsl @@ -39,14 +39,6 @@ in float radius; void main() { - if (segsize<0) - return; - - float f = atan(coords.y, coords.x) + PI; - - if (mod(f, segsize) < segsize/2) - discard; - float px = 1/radius; float R1 = 1.f; float R2 = 1.0 - fill; @@ -57,6 +49,14 @@ void main() float sm2 = smoothstep(R2-px,R2,dist); float a = sm*sm2; color = mix(vec4(0,0,0,0), fcolor, a); + + if (segsize<0) + return; + + float f = atan(coords.y, coords.x) + PI; + + if (mod(f, segsize) < segsize/2) + discard; } @end