diff --git a/Makefile b/Makefile index 129a085..0edf872 100755 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ ifdef NQOA endif ifeq ($(DBG),1) - CPPFLAGS += -g + CPPFLAGS += -g -fsanitize=address INFO += _dbg else CPPFLAGS += -DNDEBUG diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c index 7a84fc9..5662aae 100644 --- a/quickjs/quickjs.c +++ b/quickjs/quickjs.c @@ -95,14 +95,14 @@ /* dump the occurence of the automatic GC */ #define DUMP_GC /* dump objects freed by the garbage collector */ -//#define DUMP_GC_FREE +#define DUMP_GC_FREE /* dump objects leaking when freeing the runtime */ #define DUMP_LEAKS 1 /* dump memory usage before running the garbage collector */ -//#define DUMP_MEM -//#define DUMP_OBJECTS /* dump objects in JS_FreeContext */ -//#define DUMP_ATOMS /* dump atoms in JS_FreeContext */ -//#define DUMP_SHAPES /* dump shapes in JS_FreeContext */ +#define DUMP_MEM +#define DUMP_OBJECTS /* dump objects in JS_FreeContext */ +#define DUMP_ATOMS /* dump atoms in JS_FreeContext */ +#define DUMP_SHAPES /* dump shapes in JS_FreeContext */ //#define DUMP_MODULE_RESOLVE //#define DUMP_PROMISE //#define DUMP_READ_OBJECT diff --git a/scripts/base.js b/scripts/base.js index fc4bb6c..6007a56 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -472,8 +472,8 @@ Object.hide = function(obj,...props) for (var prop of props) { var p = Object.getOwnPropertyDescriptor(obj,prop); if (!p) { - Log.warn(`No property of name ${prop}.`); - return; + Log.info(`No property of name ${prop}.`); + continue; } p.enumerable = false; Object.defineProperty(obj, prop, p); diff --git a/scripts/components.js b/scripts/components.js index 51fd8a0..046743b 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -44,7 +44,7 @@ var component = { make(go) { var nc = Object.create(this); - nc.gameobject = go; +// nc.gameobject = go; Object.assign(nc, this._enghook(go.body)); nc.sync(); assign_impl(nc,this.impl); @@ -571,7 +571,8 @@ component.edge2d = Object.copy(collider2d, { var spoints = this.cpoints.slice(); if (this.flipx) { - for (var i = spoints.length-1; i >= 0; i--) { + var endcap = Spline.is_bezier(this.type) ? spoints.length-2 : spoints.length-1; + for (var i = endcap; i >= 0; i--) { var newpoint = spoints[i].slice(); newpoint.x = -newpoint.x; spoints.push(newpoint); @@ -653,6 +654,11 @@ component.edge2d = Object.copy(collider2d, { pick(pos) { var i = Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints); var p = this.cpoints[i]; + if (!p) return undefined; + + if (Spline.is_catmull(this.type)) + return make_point_obj(this,p); + var that = this.gameobject; var me = this; if (p) { @@ -677,8 +683,6 @@ component.edge2d = Object.copy(collider2d, { } return o; } - - return undefined; }, pick_all() { @@ -791,8 +795,6 @@ bucket.inputs['C-lm'] = function() { if (this.cpoints.length >= 2) idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 400); - console.say("new point"); - if (idx === this.cpoints.length) this.cpoints.push(this.gameobject.world2this(screen2world(Mouse.pos))); else diff --git a/scripts/debug.js b/scripts/debug.js index 514d05e..8fe07dc 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -113,6 +113,16 @@ var Debug = { }, }; +Debug.assert = function(b, str) +{ + str ??= ""; + + if (!b) { + console.error(`Assertion failed. ${str}`); + Game.quit(); + } +} + Debug.Options = { }; Debug.Options.Color = { set trigger(x) { cmd(17,x); }, diff --git a/scripts/editor.js b/scripts/editor.js index 0f9f98b..3d47c37 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -319,7 +319,7 @@ var editor = { // this.backshots.push(this.edit_level.save()); var dd = this.snapshots.pop(); Object.dainty_assign(this.edit_level, dd); - this.edit_level._ed.check_dirty(); + this.edit_level.check_dirty(); }, restore_buffer() { @@ -395,7 +395,7 @@ var editor = { Debug.coordinate([0,0]); }, - gui() { + gui() { /* Clean out killed objects */ this.selectlist = this.selectlist.filter(function(x) { return x.alive; }); @@ -429,14 +429,14 @@ var editor = { if (alldirty) lvl._ed.dirty = true; else { - lvl._ed.check_dirty(); + lvl.check_dirty(); if (lvl._ed.dirty) alldirty = true; } } lvlchain.reverse(); lvlchain.forEach(function(x,i) { depth = i; - var lvlstr = x._ed.namestr(); + var lvlstr = x.namestr(); if (i === lvlchain.length-1) lvlstr += "[this]"; GUI.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]); @@ -449,7 +449,7 @@ var editor = { this.selectlist.forEach(function(x) { var sname = x.__proto__.toString(); - x._ed.check_dirty(); + x.check_dirty(); if (x._ed.dirty) sname += "*"; GUI.text(sname, x.screenpos().add([0, 32]), 1, Color.editor.ur); @@ -457,7 +457,7 @@ var editor = { }); Object.entries(thiso.objects).forEach(function(x) { - var p = x[1]._ed.namestr(); + var p = x[1].namestr(); GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]); }); @@ -554,7 +554,6 @@ var editor = { lvl_history: [], load(file) { - Log.warn("LOADING " + file); var ur = prototypes.get_ur(file); if (!ur) return; var obj = editor.edit_level.spawn(ur); @@ -617,7 +616,7 @@ editor.inputs.post = function() { }; editor.inputs.release_post = function() { editor.snapshot(); - editor.edit_level._ed.check_dirty(); + editor.edit_level.check_dirty(); }; editor.inputs['C-a'] = function() { if (!editor.selectlist.empty) { editor.unselect(); return; } @@ -833,7 +832,7 @@ editor.inputs['C-s'] = function() { } else if (editor.selectlist.length === 1) saveobj = editor.selectlist[0]; -// saveobj._ed.check_dirty(); +// saveobj.check_dirty(); // if (!saveobj._ed.dirty) return; var savejs = saveobj.json_obj(); @@ -844,7 +843,7 @@ editor.inputs['C-s'] = function() { IO.slurpwrite(JSON.stringify(saveobj.__proto__,null,1), path); Log.warn(`Wrote to file ${path}`); - Object.values(saveobj.objects).forEach(function(x) { x._ed.check_dirty(); }); + Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); }); Game.all_objects(function(x) { @@ -852,7 +851,7 @@ editor.inputs['C-s'] = function() { if (!('_ed' in x)) return; if (x._ed.dirty) return; x.revert(); - x._ed.check_dirty(); + x.check_dirty(); }); }; editor.inputs['C-s'].doc = "Save selected."; diff --git a/scripts/engine.js b/scripts/engine.js index cab97e6..0b475f2 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -337,6 +337,9 @@ Spline.sample_angle = function(type, points, angle) { return spline_cmd(0, type, points[0].length, points, angle); } +Spline.is_bezier = function(t) { return t === Spline.type.bezier; } +Spline.is_catmull = function(t) { return t === Spline.type.catmull; } + Spline.bezier2catmull = function(b) { var c = []; @@ -455,37 +458,15 @@ var Game = { }, - quit() - { - sys_cmd(0); - }, - - pause() - { - sys_cmd(3); - }, - - stop() - { - Game.pause(); - }, - - step() - { - sys_cmd(4); - }, - + quit() { sys_cmd(0); }, + pause() { sys_cmd(3); }, + stop() { Game.pause(); }, + step() { sys_cmd(4);}, editor_mode(m) { sys_cmd(10, m); }, - playing() { return sys_cmd(5); }, paused() { return sys_cmd(6); }, - stepping() { - return cmd(79); }, - - play() - { - sys_cmd(1); - }, + stepping() { return cmd(79); }, + play() { sys_cmd(1); }, wait_fns: [], @@ -525,15 +506,14 @@ Register.update.register(Game.exec, Game); load("scripts/entity.js"); - function world_start() { globalThis.Primum = Object.create(gameobject); Primum.objects = {}; + Primum.check_dirty = function() {}; + Primum.namestr = function(){}; Primum._ed = { selectable:false, - check_dirty() {}, dirty:false, - namestr(){}, }; Primum.toString = function() { return "Primum"; }; Primum.ur = undefined; diff --git a/scripts/entity.js b/scripts/entity.js index ac05b11..f040993 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -56,6 +56,25 @@ actor.remaster = function(to){ }; var gameobject = { + check_dirty() { + this._ed.urdiff = this.json_obj(); + this._ed.dirty = !this._ed.urdiff.empty; + var lur = ur[this.level.ur]; + if (!lur) return; + var lur = lur.objects[this.toString()]; + var d = ediff(this._ed.urdiff,lur); + if (!d || d.empty) + this._ed.inst = true; + else + this._ed.inst = false; + }, + namestr() { + var s = this.toString(); + if (this._ed.dirty) + if (this._ed.inst) s += "#"; + else s += "*"; + return s; + }, full_path() { return this.path_from(Primum); }, @@ -115,9 +134,10 @@ var gameobject = { cmd(36,this.body,x) }, get scale() { - if (!this.level) return this.gscale(); + Debug.assert(this.level, `No level set on ${this.toString()}`); return this.gscale().map((x,i) => x/this.level.gscale()[i]); }, + set scale(x) { if (typeof x === 'number') x = [x,x]; @@ -134,21 +154,18 @@ var gameobject = { }, set pos(x) { - if (!this.level) - this.set_worldpos(x); - else - this.set_worldpos(this.level.this2world(x)); + Debug.assert(this.level, `Entity ${this.toString()} has no level.`); + this.set_worldpos(this.level.this2world(x)); }, - get pos() { - if (!this.level) return this.worldpos(); + get pos() { + Debug.assert(this.level, `Entity ${this.toString()} has no level.`); return this.level.world2this(this.worldpos()); }, get draw_layer() { return cmd(171, this.body); }, set draw_layer(x) { cmd(172, this.body, x); }, - get elasticity() { return cmd(107,this.body); }, set elasticity(x) { cmd(106,this.body,x); }, @@ -186,7 +203,8 @@ var gameobject = { worldangle() { return Math.rad2deg(q_body(2,this.body))%360; }, sworldangle(x) { set_body(0,this.body,Math.deg2rad(x)); }, get angle() { - if (!this.level) return this.worldangle(); + Debug.assert(this.level, `No level set on ${this.toString()}`); + return this.worldangle() - this.level.worldangle(); }, set angle(x) { @@ -208,9 +226,7 @@ var gameobject = { set_body(0,this.body,x); }, - rotate(x) { - this.sworldangle(this.worldangle()+x); - }, + rotate(x) { this.sworldangle(this.worldangle()+x); }, spawn_from_instance(inst) { return this.spawn(inst.ur, inst); @@ -231,6 +247,7 @@ var gameobject = { /* Reparent 'this' to be 'parent's child */ reparent(parent) { + Debug.assert(parent, `Tried to reparent ${this.toString()} to nothing.`); if (this.level === parent) return; @@ -277,21 +294,21 @@ var gameobject = { set_body(13, this.body, x); }, - pulse(vec) { set_body(4, this.body, vec);}, - shove(vec) { set_body(12,this.body,vec);}, - shove_at(vec, at) { set_body(14,this.body,vec,at); }, - world2this(pos) { return cmd(70, this.body, pos); }, - this2world(pos) { return cmd(71, this.body, pos); }, - this2screen(pos) { return world2screen(this.this2world(pos)); }, + pulse(vec) { set_body(4, this.body, vec);}, + shove(vec) { set_body(12,this.body,vec);}, + shove_at(vec, at) { set_body(14,this.body,vec,at); }, + world2this(pos) { return cmd(70, this.body, pos); }, + this2world(pos) { return cmd(71, this.body, pos); }, + this2screen(pos) { return world2screen(this.this2world(pos)); }, dir_world2this(dir) { return cmd(160, this.body, dir); }, dir_this2world(dir) { return cmd(161, this.body, dir); }, - set layer(x) { cmd(75,this.body,x); }, - get layer() { cmd(77,this.body); }, - alive() { return this.body >= 0; }, - in_air() { return q_body(7, this.body);}, + set layer(x) { cmd(75,this.body,x); }, + get layer() { cmd(77,this.body); }, + alive() { return this.body >= 0; }, + in_air() { return q_body(7, this.body);}, - hide() { this.components.forEach(function(x) { x.hide(); }); this.objects.forEach(function(x) { x.hide(); }); }, + hide() { this.components.forEach(x=>x.hide()); this.objects.forEach(x=>x.hide());}, show() { this.components.forEach(function(x) { x.show(); }); this.objects.forEach(function(x) { x.show(); }); }, get_relangle() { @@ -487,6 +504,7 @@ var gameobject = { kill() { this.timers.forEach(t => t()); + this.timers = undefined; if (this.level) { this.level.remove_obj(this); @@ -496,19 +514,18 @@ var gameobject = { Player.do_uncontrol(this); Register.unregister_obj(this); - if (this.__proto__.instances) - this.__proto__.instances.remove(this); + this.__proto__.instances.remove(this); for (var key in this.components) { Register.unregister_obj(this.components[key]); - Log.info(`Destroying component ${key}`); + (`Destroying component ${key}`); this.components[key].kill(); this.components.gameobject = undefined; + delete this.components[key]; } - delete this.components; - this.clear(); + this.objects = undefined; if (typeof this.stop === 'function') this.stop(); @@ -520,11 +537,9 @@ var gameobject = { left() { return [-1,0].rotate(Math.deg2rad(this.angle));}, make(level, data) { - level ??= Primum; var obj = Object.create(this); obj.make = undefined; - if (this.instances) this.instances.push(obj); @@ -533,55 +548,32 @@ var gameobject = { obj.components = {}; obj.objects = {}; obj.timers = []; + obj._ed = { selectable: true, - check_dirty() { - this.urdiff = obj.json_obj(); - this.dirty = !this.urdiff.empty; - if (!obj.level) return; - var lur = ur[obj.level.ur]; - if (!lur) return; - var lur = lur.objects[obj.toString()]; - var d = ediff(this.urdiff,lur); - if (!d || d.empty) - this.inst = true; - else - this.inst = false; - }, - dirty: false, inst: false, urdiff: {}, - namestr() { - var s = obj.toString(); - if (this.dirty) - if (this.inst) s += "#"; - else s += "*"; - - return s; - }, }; obj.ur = this.toString(); obj.reparent(level); - + cmd(113, obj.body, obj); // set the internal obj reference to this obj - for (var prop in this) { - var p = this[prop]; - if (typeof p !== 'object') continue; + for (var [prop,p] of Object.entries(this)) { if (typeof p.make === 'function') { obj[prop] = p.make(obj); - obj.components[prop] = obj[prop]; + obj.components[prop] = obj[prop]; } }; + Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level', 'timers'); + if (this.objects) obj.make_objs(this.objects); - Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level', 'timers'); - Object.dainty_assign(obj, this); obj.sync(); gameobject.check_registers(obj); @@ -591,7 +583,7 @@ var gameobject = { if (typeof obj.warmup === 'function') obj.warmup(); if (Game.playing() && typeof obj.start === 'function') obj.start(); - + return obj; }, @@ -669,6 +661,7 @@ gameobject.doc = { set_worldpos: `Function to set the position of the object in world coordinates.`, worldangle: `Function to get the angle of the entity in the world.`, rotate: `Function to rotate this object by x degrees.`, + move: 'Move an object by x,y,z. If the first parameter is an array, uses up to the first three array values.', pulse: `Apply an impulse to this body in world coordinates. Impulse is a short force.`, shove: `Apply a force to this body in world coordinates. Should be used over many frames.`, shove_at: 'Apply a force to this body, at a position relative to itself.', diff --git a/scripts/input.js b/scripts/input.js index 87c88e2..e39cd85 100644 --- a/scripts/input.js +++ b/scripts/input.js @@ -5,20 +5,10 @@ var Input = { var Mouse = { get pos() { return cmd(45); }, - screenpos() { return cmd(45); }, - - get worldpos() { - return screen2world(cmd(45)); - }, - - disabled() { - cmd(46, 1); - }, - - normal() { - cmd(46, 0); - }, + get worldpos() { return screen2world(cmd(45)); }, + disabled() { cmd(46, 1); }, + normal() { cmd(46, 0);}, }; Mouse.doc = {}; @@ -28,21 +18,10 @@ Mouse.disabled.doc = "Set the mouse to hidden. This locks it to the game and hid Mouse.normal.doc = "Set the mouse to show again after hiding."; var Keys = { - shift() { - return cmd(50, 340);// || cmd(50, 344); - }, - - ctrl() { - return cmd(50, 341);// || cmd(50, 344); - }, - - alt() { - return cmd(50, 342);// || cmd(50, 346); - }, - - super() { - return cmd(50, 343);// || cmd(50, 347); - }, + shift() { return cmd(50, 340); }, + ctrl() { return cmd(50, 341); }, + alt() { return cmd(50, 342); }, + super() { return cmd(50, 343); }, }; Input.state2str = function(state) { diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 41aea2e..92f3660 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -11,27 +11,14 @@ static gameobject **gameobjects; gameobject *body2go(cpBody *body) { return cpBodyGetUserData(body); } -gameobject *shape2go(cpShape *shape) -{ - return ((struct phys2d_shape *)cpShapeGetUserData(shape))->go; -} +gameobject *shape2go(cpShape *shape) { return ((struct phys2d_shape *)cpShapeGetUserData(shape))->go; } HMM_Vec2 go_pos(gameobject *go) { cpVect p = cpBodyGetPosition(go->body); return (HMM_Vec2){p.x, p.y}; } - -HMM_Vec2 go_worldpos(gameobject *go) -{ - HMM_Vec2 ret; - ret.cp = cpBodyGetPosition(go->body); - return ret; -} - -float go_angle(gameobject *go) { return go_worldangle(go); } -float go_worldangle(gameobject *go) { return cpBodyGetAngle(go->body); } -float go2angle(gameobject *go) { return cpBodyGetAngle(go->body); } +float go_angle(gameobject *go) { return cpBodyGetAngle(go->body); } transform3d go2t3(gameobject *go) { @@ -212,8 +199,6 @@ void gameobject_clean(gameobject *go) { /* Really more of a "mark for deletion" ... */ void gameobject_free(gameobject *go) { if (!go) return; - YughWarn("FREEING A GAMEOBJECT"); - JS_FreeValue(js, go->ref); for (int i = arrlen(gameobjects)-1; i >= 0; i--) if (gameobjects[i] == go) { diff --git a/source/engine/gameobject.h b/source/engine/gameobject.h index 4a40189..6c1b1e0 100644 --- a/source/engine/gameobject.h +++ b/source/engine/gameobject.h @@ -69,11 +69,9 @@ HMM_Mat4 t3d_go2world(gameobject *go); HMM_Mat4 t3d_world2go(gameobject *go); HMM_Vec2 go_pos(gameobject *go); -HMM_Vec2 go_worldpos(gameobject *go); -//float go_angle(gameobject *go); -float go_worldangle(gameobject *go); - -float go2angle(gameobject *go); +void gameobject_setpos(gameobject *go, cpVect vec); +float go_angle(gameobject *go); +void gameobject_setangle(gameobject *go, float angle); gameobject *body2go(cpBody *body); gameobject *shape2go(cpShape *shape); @@ -83,10 +81,6 @@ void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go); /* Tries a few methods to select a gameobject; if none is selected returns -1 */ gameobject *pos2gameobject(HMM_Vec2 pos); -void gameobject_move(gameobject *go, HMM_Vec2 vec); -void gameobject_rotate(gameobject *go, float as); -void gameobject_setangle(gameobject *go, float angle); -void gameobject_setpos(gameobject *go, cpVect vec); void gameobject_draw_debug(gameobject *go); void gameobject_draw_debugs(); #endif diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 835b70d..1c03419 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -403,8 +403,6 @@ JSValue duk_spline_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst samples = bezier_cb_ma_v2(points, param); break; } - - arrfree(points); @@ -638,7 +636,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 30: - sprite_setanim(id2sprite(js2int(argv[1])), js2ptr(argv[2]), js2int(argv[3])); break; case 31: @@ -784,6 +781,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 63: + set_cam_body(NULL); break; case 64: @@ -996,7 +994,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) break; case 113: - js2gameobject(argv[1])->ref = argv[2];//JS_DupValue(js,argv[2]); + js2gameobject(argv[1])->ref = argv[2]; break; case 114: @@ -1511,7 +1509,6 @@ JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *ar } JSValue duk_make_gameobject(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - YughWarn("MAKING GAMOBJECT"); return gameobject2js(MakeGameobject()); } @@ -1648,19 +1645,6 @@ JSValue duk_make_sprite(JSContext *js, JSValueConst this, int argc, JSValueConst return sprite; } -/* Make anim from texture */ -JSValue duk_make_anim2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - const char *path = JS_ToCString(js, argv[0]); - int frames = js2int(argv[1]); - int fps = js2int(argv[2]); - - struct TexAnim *anim = anim2d_from_tex(path, frames, fps); - - JS_FreeCString(js, path); - - return ptr2js(anim); -} - JSValue duk_make_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { gameobject *go = js2gameobject(argv[0]); HMM_Vec2 size = js2vec2(argv[1]); @@ -1888,7 +1872,6 @@ void ffi_load() { DUK_FUNC(sys_cmd, 1) DUK_FUNC(make_sprite, 1) - DUK_FUNC(make_anim2d, 3) DUK_FUNC(spline_cmd, 6) DUK_FUNC(make_box2d, 3) diff --git a/source/engine/render.c b/source/engine/render.c index d106d23..b0d0bfd 100644 --- a/source/engine/render.c +++ b/source/engine/render.c @@ -466,13 +466,8 @@ void render_winsize() } static cpBody *camera = NULL; -void set_cam_body(cpBody *body) { - camera = body; -} - -cpVect cam_pos() { - return camera ? cpBodyGetPosition(camera) : cpvzero; -} +void set_cam_body(cpBody *body) { camera = body; } +cpVect cam_pos() { return camera ? cpBodyGetPosition(camera) : cpvzero; } static float zoom = 1.f; float cam_zoom() { return zoom; } diff --git a/source/engine/sound/dsp.c b/source/engine/sound/dsp.c index 77bc693..b9e21e3 100644 --- a/source/engine/sound/dsp.c +++ b/source/engine/sound/dsp.c @@ -9,6 +9,8 @@ #include "stb_ds.h" #include "smbPitchShift.h" +#include "pthread.h" + #define PI 3.14159265 dsp_node *masterbus = NULL; @@ -22,7 +24,6 @@ void iir_free(struct dsp_iir *iir) free(iir); } - void interleave(soundbyte *a, soundbyte *b, soundbyte *stereo, int frames) { for (int i = 0; i < frames; i++) { @@ -117,10 +118,7 @@ void scale_soundbytes(soundbyte *a, float scale, int samples) for (int i = 0; i < samples; i++) a[i] *= scale; } -void zero_soundbytes(soundbyte *a, int samples) -{ - memset(a, 0, sizeof(soundbyte)*samples); -} +void zero_soundbytes(soundbyte *a, int samples) { memset(a, 0, sizeof(soundbyte)*samples); } void set_soundbytes(soundbyte *a, soundbyte *b, int samples) { @@ -151,13 +149,15 @@ dsp_node *make_node(void *data, void (*proc)(void *data, soundbyte *out, int sam void node_free(dsp_node *node) { - YughWarn("FREEING A NODE"); + if (node == masterbus) return; /* Simple check to not delete the masterbus */ + pthread_mutex_lock(&soundrun); unplug_node(node); if (node->data) if (node->data_free) node->data_free(node->data); else free(node->data); - free(node); + free(node); + pthread_mutex_unlock(&soundrun); } void dsp_node_free(dsp_node *node) { node_free(node); } diff --git a/source/engine/sound/sound.c b/source/engine/sound/sound.c index d859554..0f6f630 100644 --- a/source/engine/sound/sound.c +++ b/source/engine/sound/sound.c @@ -8,6 +8,9 @@ #include "string.h" #include "time.h" #include +#include "pthread.h" + +pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER; #include "samplerate.h" @@ -105,9 +108,10 @@ void change_samplerate(struct wav *w, int rate) { w->samplerate = rate; } -void push_sound(soundbyte *buffer, int frames, int chan) -{ +void push_sound(soundbyte *buffer, int frames, int chan) { + pthread_mutex_lock(&soundrun); set_soundbytes(buffer, dsp_node_out(masterbus), frames*chan); + pthread_mutex_unlock(&soundrun); } void filter_mod(pocketmod_context *mod, soundbyte *buffer, int frames) diff --git a/source/engine/sound/sound.h b/source/engine/sound/sound.h index 676c2e4..0b06446 100644 --- a/source/engine/sound/sound.h +++ b/source/engine/sound/sound.h @@ -3,8 +3,10 @@ #include "script.h" #include "samplerate.h" +#include "pthread.h" typedef float soundbyte; +extern pthread_mutex_t soundrun; struct dsp_node; diff --git a/source/engine/sprite.c b/source/engine/sprite.c index ff3c104..6e94141 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -56,7 +56,7 @@ int make_sprite(gameobject *go) { .t = t2d_unit, .color = color_white, .emissive = {0,0,0,0}, - .tex = texture_loadfromfile(NULL), + .tex = texture_pullfromfile(NULL), .go = go, .layer = 0, .next = -1, @@ -83,27 +83,7 @@ struct sprite *id2sprite(int id) { static int sprite_count = 0; -void sprite_flush() { - sprite_count = 0; -} - -void sprite_io(struct sprite *sprite, FILE *f, int read) { - char path[100]; - if (read) { - // fscanf(f, "%s", &path); - for (int i = 0; i < 100; i++) { - path[i] = fgetc(f); - - if (path[i] == '\0') break; - } - fread(sprite, sizeof(*sprite), 1, f); - sprite_loadtex(sprite, path, ST_UNIT); - } else { - fputs(tex_get_path(sprite->tex), f); - fputc('\0', f); - fwrite(sprite, sizeof(*sprite), 1, f); - } -} +void sprite_flush() { sprite_count = 0; } int sprite_sort(int *a, int *b) { @@ -140,7 +120,7 @@ void sprite_loadtex(struct sprite *sprite, const char *path, struct glrect frame YughWarn("NO SPRITE!"); return; } - sprite->tex = texture_loadfromfile(path); + sprite->tex = texture_pullfromfile(path); sprite_setframe(sprite, &frame); } @@ -244,19 +224,12 @@ void sprite_draw(struct sprite *sprite) { HMM_Mat3 sm = transform2d2mat(sprite->t); tex_draw(sprite->tex, HMM_MulM3(m, sm), sprite->frame, sprite->color, 0, (HMM_Vec2){0,0}, 0, sprite->emissive); - -} - -void sprite_setanim(struct sprite *sprite, struct TexAnim *anim, int frame) { - if (!sprite) return; - sprite->tex = anim->tex; - sprite->frame = anim->st_frames[frame]; } void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) { sg_apply_pipeline(pip_sprite); sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj)); - struct Texture *tex = texture_loadfromfile(img); + struct Texture *tex = texture_pullfromfile(img); tex_draw(tex, transform2d2mat(t), tex_get_rect(tex), color, wrap, wrapoffset, wrapscale, (struct rgba){0,0,0,0}); } @@ -264,7 +237,7 @@ void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba { sg_apply_pipeline(slice9_pipe); sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj)); - struct Texture *tex = texture_loadfromfile(img); + struct Texture *tex = texture_pullfromfile(img); struct glrect r = tex_get_rect(tex); diff --git a/source/engine/sprite.h b/source/engine/sprite.h index 0d26d40..c292e65 100644 --- a/source/engine/sprite.h +++ b/source/engine/sprite.h @@ -28,7 +28,6 @@ void sprite_enabled(int id, int e); void sprite_io(struct sprite *sprite, FILE *f, int read); void sprite_loadtex(struct sprite *sprite, const char *path, struct glrect rect); void sprite_settex(struct sprite *sprite, struct Texture *tex); -void sprite_setanim(struct sprite *sprite, struct TexAnim *anim, int frame); void sprite_setframe(struct sprite *sprite, struct glrect *frame); void sprite_initialize(); void sprite_draw(struct sprite *sprite); diff --git a/source/engine/texture.c b/source/engine/texture.c index 97709c5..fe4cf71 100644 --- a/source/engine/texture.c +++ b/source/engine/texture.c @@ -29,10 +29,7 @@ static struct { } *texhash = NULL; struct Texture *tex_default; - -struct Texture *texture_notex() { - return texture_pullfromfile("icons/no_tex.gif"); -} +struct Texture *texture_notex() { return texture_pullfromfile("icons/no_tex.gif"); } unsigned int next_pow2(unsigned int v) { @@ -201,9 +198,7 @@ struct Texture *texture_pullfromfile(const char *path) { return tex; } -void texture_sync(const char *path) { - YughWarn("Need to implement texture sync."); -} +void texture_sync(const char *path) { YughWarn("Need to implement texture sync."); } char *tex_get_path(struct Texture *tex) { for (int i = 0; i < shlen(texhash); i++) { @@ -289,94 +284,9 @@ struct Texture *texture_fromdata(void *raw, long size) struct Texture *texture_loadfromfile(const char *path) { struct Texture *new = texture_pullfromfile(path); - /* - if (new->id == 0) { - glGenTextures(1, &new->id); - - //tex_gpu_load(new); - - YughInfo("Loaded texture path %s", path); - } - */ - return new; } -void tex_gpu_reload(struct Texture *tex) { - tex_gpu_free(tex); - - // tex_gpu_load(tex); -} - -void anim_calc(struct anim2d *anim) { - anim->size[0] = anim->anim->tex->width * st_s_w(anim->anim->st_frames[anim->frame]); - anim->size[1] = anim->anim->tex->height * st_s_h(anim->anim->st_frames[anim->frame]); -} - -void anim_incr(struct anim2d *anim) { - anim->frame = (anim->frame + 1) % arrlen(anim->anim->st_frames); - - if (!anim->anim->loop && anim->frame == arrlen(anim->anim->st_frames)) - anim_pause(anim); - - anim_calc(anim); -} - -void anim_decr(struct anim2d *anim) { - anim->frame = (anim->frame + arrlen(anim->anim->st_frames) - 1) % arrlen(anim->anim->st_frames); - anim_calc(anim); -} - -struct glrect anim_get_rect(struct anim2d *anim) { - return anim->anim->st_frames[anim->frame]; -} - -void anim_setframe(struct anim2d *anim, int frame) { - anim->frame = frame; - anim_calc(anim); -} - -struct TexAnim *anim2d_from_tex(const char *path, int frames, int fps) { - struct TexAnim *anim = malloc(sizeof(*anim)); - anim->tex = texture_loadfromfile(path); - texanim_fromframes(anim, frames); - anim->ms = (float)1 / fps; - - return anim; -} - -void texanim_fromframes(struct TexAnim *anim, int frames) { - if (anim->st_frames) { - free(anim->st_frames); - } - - arrsetlen(anim->st_frames, frames); - - float width = (float)1 / frames; - - for (int i = 0; i < frames; i++) { - anim->st_frames[i].s0 = width * i; - anim->st_frames[i].s1 = width * (i + 1); - anim->st_frames[i].t0 = 0.f; - anim->st_frames[i].t1 = 1.f; - } -} - -void tex_gpu_free(struct Texture *tex) { - /* - if (tex->id != 0) { - glDeleteTextures(1, &tex->id); - tex->id = 0; - } - */ -} - -int anim_frames(struct TexAnim *a) { - return arrlen(a->st_frames); -} - -struct glrect tex_get_rect(struct Texture *tex) { - return ST_UNIT; -} +struct glrect tex_get_rect(struct Texture *tex) { return ST_UNIT; } HMM_Vec2 tex_get_dimensions(struct Texture *tex) { if (!tex) return (HMM_Vec2){0,0}; @@ -386,69 +296,6 @@ HMM_Vec2 tex_get_dimensions(struct Texture *tex) { return d; } -void tex_bind(struct Texture *tex) { - /* glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex->id); - glBindTexture(GL_TEXTURE_2D_ARRAY, tex->id); - */ -} +float st_s_w(struct glrect st) { return (st.s1 - st.s0); } -/********************** ANIM2D ****************/ - -void anim_load(struct anim2d *anim, const char *path) { - anim->anim = &texture_pullfromfile(path)->anim; - anim->anim->tex->opts.animation = 1; - anim_stop(anim); - anim_play(anim); -} - -void anim_play(struct anim2d *anim) { -// if (anim->playing) -// return; - -// if (anim->frame == anim_frames(anim->anim)) -// anim->frame = 0; - -// anim->playing = 1; - -// if (anim->timer == NULL) -// anim->timer = id2timer(timer_make(1.f / anim->anim->ms, anim_incr, anim, 0, 0)); -// else -// timerr_settime(anim->timer, 1.f / anim->anim->ms); - -// timer_start(anim->timer); -} - -void anim_stop(struct anim2d *anim) { - if (!anim->playing) - return; - - anim->playing = 0; - anim->frame = 0; - anim->pausetime = 0; - timer_stop(anim->timer); -} - -void anim_pause(struct anim2d *anim) { - if (!anim->playing) - return; - - anim->playing = 0; - timer_pause(anim->timer); -} - -void anim_fwd(struct anim2d *anim) { - anim_incr(anim); -} - -void anim_bkwd(struct anim2d *anim) { - anim_decr(anim); -} - -float st_s_w(struct glrect st) { - return (st.s1 - st.s0); -} - -float st_s_h(struct glrect st) { - return (st.t1 - st.t0); -} +float st_s_h(struct glrect st) { return (st.t1 - st.t0); } diff --git a/source/engine/texture.h b/source/engine/texture.h index 136e5b6..1c71c4d 100644 --- a/source/engine/texture.h +++ b/source/engine/texture.h @@ -33,25 +33,6 @@ struct uvrect { int v1; }; -/* Tracks a playing animation */ -/* Objects should keep this, and just change what TexAnim they are pointing to */ -struct anim2d { - int frame; - int playing; - int pausetime; - struct timer *timer; - struct TexAnim *anim; - float size[2]; /* Current size of animation in pixels*/ -}; - -/* Describes an animation on a particular texture */ -struct TexAnim { - struct Texture *tex; - struct glrect *st_frames; /* Dynamic array of frames of animation */ - int ms; - int loop; -}; - struct TextureOptions { int sprite; int mips; @@ -59,7 +40,6 @@ struct TextureOptions { int animation; int wrapx; int wrapy; - }; /* Represents an actual texture on the GPU */ @@ -69,7 +49,6 @@ struct Texture { uint16_t height; unsigned char *data; struct TextureOptions opts; - struct TexAnim anim; int frames; }; @@ -79,30 +58,15 @@ struct Image { }; struct Texture *texture_pullfromfile(const char *path); // Create texture from image -struct Texture *texture_loadfromfile(const char *path); // Create texture & load to gpu struct Texture *texture_fromdata(void *raw, long size); + +/* Hot reloads a texture, if needed */ void texture_sync(const char *path); -struct Texture *str2tex(const char *path); -void tex_gpu_reload(struct Texture *tex); // gpu_free then gpu_load -void tex_gpu_free(struct Texture *tex); // Remove texture data from gpu -void tex_bind(struct Texture *tex); // Bind to gl context char * tex_get_path(struct Texture *tex); // Get image path for texture -struct TexAnim *anim2d_from_tex(const char *path, int frames, int fps); void texanim_fromframes(struct TexAnim *anim, int frames); -void anim_load(struct anim2d *anim, const char *path); /* Load and start new animation */ -void anim_calc(struct anim2d *anim); -void anim_play(struct anim2d *anim); -void anim_setframe(struct anim2d *anim, int frame); -void anim_stop(struct anim2d *anim); -void anim_pause(struct anim2d *anim); -void anim_fwd(struct anim2d *anim); -void anim_bkwd(struct anim2d *anim); -void anim_incr(struct anim2d *anim); -void anim_decr(struct anim2d *anim); - int gif_nframes(const char *path); struct glrect tex_get_rect(struct Texture *tex); diff --git a/source/engine/yugine.c b/source/engine/yugine.c index 5963c36..25d0712 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -304,7 +304,7 @@ dam->update_activity(dam, &da, NULL, NULL); if (argc > i+1) argsize++; } - char cmdstr[argsize]; + char cmdstr[argsize+1]; cmdstr[0] = '\0'; for (int i = 0; i < argc; i++) {