diff --git a/scripts/components.js b/scripts/components.js index 5021cd3..594734d 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -90,38 +90,46 @@ Object.mixin(os.sprite(true), { playing: 0, play(str) { var sp = this; + this.del_anim = function() { + sp = undefined; + advance = undefined; + } str ??= 0; var playing = this.anim[str]; - if (!playing) return; //TODO: ERROR + if (!playing) return; var f = 0; function advance() { + if (!sp) this.del_anim(); + if (!sp.gameobject) return; sp.path = playing.path; sp.frame = playing.frames[f].rect; f = (f+1)%playing.frames.length; - if (f === 0) - sp.anim_done?.(); - sp.ddd = sp.gameobject?.delay(advance, playing.frames[f].time); + if (f === 0) sp.anim_done?.(); + sp.gameobject.delay(advance, playing.frames[f].time); } + advance(); }, set path(p) { p = Resources.find_image(p); if (!p) return; if (p === this.path) return; - this.tex = texture.find(p); + this._p = p; + this.tex(game.texture(p)); + var anim = SpriteAnim.make(p); if (!anim) return; this.anim = anim; this.play(); }, get path() { - return this.tex.path(); + return this._p; }, kill() { + this.del_anim?.(); this.anim = undefined; - this.ddd?.(); - delete this.ddd; + this.gameobject = undefined; }, toString() { return "sprite"; }, move(d) { this.pos = this.pos.add(d); }, @@ -197,10 +205,14 @@ var SpriteAnim = { return undefined; }, gif(path) { + console.info(`making an anim from ${path}`); var anim = {}; anim.frames = []; anim.path = path; - var frames = Resources.gif.frames(path); + var tex = game.texture(path); + var frames = tex.frames; + console.info(`frames are ${frames}`); + if (frames === 1) return undefined; var yslice = 1/frames; for (var f = 0; f < frames; f++) { var frame = {}; @@ -213,11 +225,13 @@ var SpriteAnim = { frame.time = 0.05; anim.frames.push(frame); } - var times = render.gif_times(path); + var times = tex.delays; + console.info(`times are ${times}, num ${times.length}`); for (var i = 0; i < frames; i++) anim.frames[i].time = times[i]/1000; anim.loop = true; - var dim = Resources.texture.dimensions(path); + var dim = [tex.width,tex.height]; + console.info(`dimensions are ${dim}`); dim.y /= frames; anim.dim = dim; return {0:anim}; diff --git a/scripts/engine.js b/scripts/engine.js index 16e3875..73eda51 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -176,6 +176,7 @@ game.engine_start = function(s) { gggstart(function() { world_start(); go_init(); + window.set_icon(os.make_texture("icons/moon.gif")) s(); }, process); } @@ -235,12 +236,18 @@ game.all_objects = function(fn) { eachobj(world,fn); }; game.doc = {}; game.doc.object = "Returns the entity belonging to a given id."; game.doc.pause = "Pause game simulation."; -game.doc.stop = "Stop game simulation. This does the same thing as 'pause', and if the game is a debug build, starts its editor."; game.doc.play = "Resume or start game simulation."; -game.doc.editor_mode = "Set to true for the game to only update on input; otherwise the game updates every frame."; game.doc.dt = "Current frame dt."; game.doc.camera = "Current camera."; +game.texture = function(path) +{ + game.texture.cache[path] ??= os.make_texture(path); + return game.texture.cache[path]; +} +game.texture.cache = {}; + + prosperon.semver = {}; prosperon.semver.valid = function(v, range) { @@ -337,9 +344,7 @@ var timer = { }, }; -global.mixin("scripts/tween"); global.mixin("scripts/physics"); -global.mixin("scripts/ai"); global.mixin("scripts/geometry"); /* @@ -359,7 +364,6 @@ var Register = { fn = fn.bind(obj); fns.push(fn); return function() { - console.spam(`removed from ${name}.`); fns.remove(fn); }; } diff --git a/scripts/entity.js b/scripts/entity.js index f67a71a..42b303c 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -178,23 +178,33 @@ var gameobject = { }, delay(fn, seconds) { - var timescale = this.timescale; - var timers = this.timers; - var thisfn = fn.bind(this); - var rm_register; + var that = this; - var ud = function(dt) { - seconds -= dt*timescale; - if (seconds <= 0) { - thisfn(); - rm_register(); - rm_register = undefined; - thisfn = undefined; - } + var stop = function() { + that.timers.remove(stop); + execute = undefined; + stop = undefined; + rm(); + rm = undefined; + update = undefined; } - rm_register = Register.update.register(ud); - return rm_register; + function execute() { + fn.call(that); + stop?.(); + } + + stop.remain = seconds; + stop.seconds = seconds; + + function update(dt) { + stop.remain -= dt; + if (stop.remain <= 0) execute(); + } + + var rm = Register.update.register(update); + this.timers.push(stop); + return stop; }, tween(prop, values, def) { @@ -535,7 +545,10 @@ var gameobject = { this.__kill = true; console.info(`Killing entity of type ${this.ur}`); + console.info(`killing ${this.timers.length} timers.`); this.timers.forEach(t => t()); + console.info(`now there are ${this.timers.length}`); + for (var i of this.timers) console.info(i); this.timers = []; Event.rm_obj(this); Player.do_uncontrol(this); @@ -679,7 +692,7 @@ gameobject.doc = { gear: 'Keeps the angular velocity ratio of this body and to constant. Ratio is the gear ratio.', motor: 'Keeps the relative angular velocity of this body to to at a constant rate. The most simple idea is for one of the bodies to be static, to the other is kept at rate.', layer: 'Bitmask for collision layers.', - draw_layer: 'Layer for drawing. Higher numbers draw above lower ones.', + drawlayer: 'Layer for drawing. Higher numbers draw above lower ones.', warp_layer: 'Bitmask for selecting what warps should affect this entity.', }; diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index dca3241..2d57bda 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -76,6 +76,8 @@ const char *js2str(JSValue v) { #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_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 JSC_CCALL(NAME, FN) JSValue js_##NAME (JSContext *js, JSValue this, int argc, JSValue *argv) { \ @@ -125,8 +127,12 @@ JSValue js_gameobject_get_##ENTRY (JSContext *js, JSValue this) { \ return TYPE##2js (cpBodyGet##CPENTRY (b)); \ } \ +#define JSC_GET(ID, ENTRY, TYPE) \ +JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue this) { \ + return TYPE##2js(js2##ID (this)->ENTRY); } \ + #define QJSCLASS(TYPE)\ -static JSClassID js_ ## TYPE ## _id;\ +static JSClassID js_##TYPE##_id;\ static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\ TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\ YughSpam("Freeing " #TYPE " at %p", n); \ @@ -797,6 +803,11 @@ JSC_CCALL(os_make_edge2d, return edgeval; ) +JSC_SCALL(os_make_texture, + ret = texture2js(texture_from_file(str)); + JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0])); +) + static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os,sprite,1), MIST_FUNC_DEF(os, cwd, 0), @@ -812,6 +823,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, make_poly2d, 1), MIST_FUNC_DEF(os, make_edge2d, 1), MIST_FUNC_DEF(os, make_model, 2), + MIST_FUNC_DEF(os, make_texture, 1), }; JSC_CCALL(render_normal, opengl_rendermode(LIT)) @@ -841,16 +853,12 @@ JSC_CCALL(render_pass, debug_nextpass()) JSC_CCALL(render_end_pass, sg_end_pass()) JSC_CCALL(render_commit, sg_commit(); debug_newframe();) JSC_SCALL(render_text_size, ret = bb2js(text_bb(str, js2number(argv[1]), js2number(argv[2]), 1))) -JSC_SCALL(render_gif_times, ret = ints2js(gif_delays(str))) -JSC_SCALL(render_gif_frames, ret = number2js(gif_nframes(str))) JSC_CCALL(render_world2screen, return vec22js(world2screen(js2vec2(argv[0])))) JSC_CCALL(render_screen2world, return vec22js(screen2world(js2vec2(argv[0])))) static const JSCFunctionListEntry js_render_funcs[] = { MIST_FUNC_DEF(render,world2screen,1), MIST_FUNC_DEF(render,screen2world,1), - MIST_FUNC_DEF(render,gif_frames,1), - MIST_FUNC_DEF(render, gif_times, 1), MIST_FUNC_DEF(render, normal, 0), MIST_FUNC_DEF(render, wireframe, 0), MIST_FUNC_DEF(render, grid, 3), @@ -1271,8 +1279,7 @@ static JSValue js_window_set_title(JSContext *js, JSValue this, JSValue v) return JS_UNDEFINED; } JSC_CCALL(window_get_title, return str2js(js2window(this)->title)) -JSC_SCALL(window_set_icon, set_icon(str)) -JSC_SCALL(window_icon, set_icon(str)) +JSC_CCALL(window_set_icon, window_seticon(&mainwin, js2texture(argv[0]))) static const JSCFunctionListEntry js_window_funcs[] = { CGETSET_ADD(window, size), @@ -1435,12 +1442,13 @@ JSC_GETSET(sprite, scale, vec2) JSC_GETSET(sprite, angle, number) JSC_GETSET(sprite, frame, rect) JSC_GETSET(sprite,go,gameobject) +JSC_CCALL(sprite_tex, js2sprite(this)->tex = js2texture(argv[0])) static const JSCFunctionListEntry js_sprite_funcs[] = { CGETSET_ADD(sprite,pos), CGETSET_ADD(sprite,scale), CGETSET_ADD(sprite,angle), - CGETSET_ADD(sprite,tex), + MIST_FUNC_DEF(sprite, tex, 1), CGETSET_ADD(sprite,color), CGETSET_ADD(sprite,emissive), CGETSET_ADD(sprite,enabled), @@ -1449,17 +1457,16 @@ static const JSCFunctionListEntry js_sprite_funcs[] = { CGETSET_ADD(sprite,go) }; -GETFN(texture,width,number) -GETFN(texture,height,number) -JSC_CCALL(texture_path, return str2js(tex_get_path(js2texture(this)))) -JSC_SCALL(texture_find, ret = texture2js(texture_from_file(str))) +JSC_GET(texture, width, number) +JSC_GET(texture, height, number) +JSC_GET(texture, frames, number) +JSC_GET(texture, delays, ints) static const JSCFunctionListEntry js_texture_funcs[] = { - MIST_FUNC_DEF(texture, width, 0), - MIST_FUNC_DEF(texture, height, 0), - MIST_FUNC_DEF(texture, path, 0), - MIST_FUNC_DEF(texture, find, 1), -// MIST_FUNC_DEF(texture, dimensions, 1), + MIST_GET(texture, width), + MIST_GET(texture, height), + MIST_GET(texture, frames), + MIST_GET(texture, delays), }; JSValue js_constraint_set_max_force (JSContext *js, JSValue this, JSValue val) { diff --git a/source/engine/particle.c b/source/engine/particle.c index 60b91e7..314fe0a 100644 --- a/source/engine/particle.c +++ b/source/engine/particle.c @@ -99,7 +99,7 @@ emitter *make_emitter() { sampler_add(&e->color, 0, (HMM_Vec4){1,1,1,1}); e->scale = 1; e->speed = 20; - e->texture = texture_from_file("glass_chunk2.gif"); + e->texture = NULL; arrpush(emitters,e); return e; } @@ -166,7 +166,7 @@ void parallel_pv(emitter *e, struct scheduler *sched, struct sched_task_partitio s = lerp(p->time/e->grow_for, 0, p->scale); else if (p->time > (p->life - e->shrink_for)) s = lerp((p->time-(p->life-e->shrink_for))/e->shrink_for, p->scale, 0); - pv[i].scale = HMM_ScaleV2(tex_get_dimensions(e->texture), s); + pv[i].scale = HMM_ScaleV2((HMM_Vec2){e->texture->width,e->texture->height}, s); pv[i].color = vec2rgba(p->color); } } diff --git a/source/engine/render.c b/source/engine/render.c index eae4306..d790e9d 100644 --- a/source/engine/render.c +++ b/source/engine/render.c @@ -174,12 +174,6 @@ static struct { sg_shader shader; } sg_shadow; - -void trace_make_image(const sg_image_desc *d, sg_image id, void *data) -{ - YughSpam("Made image %s.", d->label); -} - void trace_init_image(sg_image id, const sg_image_desc *d, void *data) { YughSpam("Init image %s", d->label); @@ -238,7 +232,6 @@ static sg_trace_hooks hooks = { .make_shader = trace_make_shader, .destroy_shader = trace_destroy_shader, .fail_image = trace_fail_image, - .make_image = trace_make_image, .init_image = trace_init_image, .make_pipeline = trace_make_pipeline, .fail_pipeline = trace_fail_pipeline, diff --git a/source/engine/sprite.c b/source/engine/sprite.c index af8e6c1..10d6668 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -51,7 +51,7 @@ sprite *sprite_make() sp->color = color_white; sp->emissive = color_clear; sp->go = NULL; - sp->tex = texture_from_file(NULL); + sp->tex = NULL; sp->frame = ST_UNIT; sp->drawmode = DRAW_SIMPLE; sp->enabled = 1; @@ -64,8 +64,6 @@ sprite *sprite_make() void sprite_free(sprite *sprite) { - YughWarn("Freeing sprite %p.", sprite); - free(sprite); for (int i = arrlen(sprites)-1; i >= 0; i--) if (sprites[i] == sprite) { @@ -215,6 +213,7 @@ void sprite_draw(struct sprite *sprite) { } void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) { + return; sg_apply_pipeline(pip_sprite); sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj)); struct texture *tex = texture_from_file(img); diff --git a/source/engine/texture.c b/source/engine/texture.c index fd73d3f..15da827 100644 --- a/source/engine/texture.c +++ b/source/engine/texture.c @@ -4,7 +4,6 @@ #include "render.h" #include "sokol/sokol_gfx.h" #include -#include #include #include "resources.h" @@ -23,14 +22,6 @@ struct rect ST_UNIT = {0.f, 0.f, 1.f, 1.f}; -static struct { - char *key; - struct texture *value; -} *texhash = NULL; - -struct texture *tex_default; -struct texture *texture_notex() { return texture_from_file("icons/no_tex.gif"); } - unsigned int next_pow2(unsigned int v) { v--; @@ -70,31 +61,14 @@ int mip_wh(int w, int h, int *mw, int *mh, int lvl) return 0; } -int gif_nframes(const char *path) -{ - struct texture *t = texture_from_file(path); - return t->frames; -} - -int *gif_delays(const char *path) -{ - struct texture *t = texture_from_file(path); - return t->delays; -} - /* If an empty string or null is put for path, loads default texture */ struct texture *texture_from_file(const char *path) { - if (!path) return texture_notex(); - if (shlen(texhash) == 0) sh_new_arena(texhash); - - int index = shgeti(texhash, path); - if (index != -1) - return texhash[index].value; + if (!path) return NULL; size_t rawlen; unsigned char *raw = slurp_file(path, &rawlen); - if (!raw) return texture_notex(); + if (!raw) return NULL; unsigned char *data; @@ -115,8 +89,7 @@ struct texture *texture_from_file(const char *path) { int *dd = tex->delays; tex->delays = NULL; arrsetlen(tex->delays, tex->frames); - for (int i = 0; i < tex->frames;i++) - tex->delays[i] = dd[i]; + for (int i = 0; i < tex->frames; i++) tex->delays[i] = dd[i]; free(dd); tex->height *= tex->frames; } else if (!strcmp(ext, ".svg")) { @@ -141,10 +114,8 @@ struct texture *texture_from_file(const char *path) { } free(raw); - if (data == NULL) { - YughError("STBI failed to load file %s with message: %s\nOpening default instead.", path, stbi_failure_reason()); - return texture_notex(); - } + if (data == NULL) + return NULL; unsigned int nw = next_pow2(tex->width); unsigned int nh = next_pow2(tex->height); @@ -181,15 +152,13 @@ struct texture *texture_from_file(const char *path) { } tex->id = sg_make_image(&(sg_image_desc){ - .type = SG_IMAGETYPE_2D, - .width = tex->width, - .height = tex->height, - .usage = SG_USAGE_IMMUTABLE, - .num_mipmaps = mips, - .data = sg_img_data - }); - - shput(texhash, path, tex); + .type = SG_IMAGETYPE_2D, + .width = tex->width, + .height = tex->height, + .usage = SG_USAGE_IMMUTABLE, + .num_mipmaps = mips, + .data = sg_img_data + }); for (int i = 1; i < mips; i++) free(mipdata[i]); @@ -197,22 +166,13 @@ struct texture *texture_from_file(const char *path) { return tex; } -void texture_sync(const char *path) { YughWarn("Need to implement texture sync."); } - void texture_free(texture *tex) { - -} - -char *tex_get_path(struct texture *tex) { - for (int i = 0; i < shlen(texhash); i++) { - if (tex == texhash[i].value) { - YughSpam("Found key %s", texhash[i].key); - return texhash[i].key; - } - } - - return ""; + if (!tex) return; + free(tex->data); + if (tex->delays) arrfree(tex->delays); + sg_destroy_image(tex->id); + free(tex); } struct texture *texture_fromdata(void *raw, long size) @@ -222,10 +182,8 @@ struct texture *texture_fromdata(void *raw, long size) int n; void *data = stbi_load_from_memory(raw, size, &tex->width, &tex->height, &n, 4); - if (data == NULL) { - YughError("Given raw data not valid. Loading default instead."); - return texture_notex(); - } + if (data == NULL) + NULL; unsigned int nw = next_pow2(tex->width); unsigned int nh = next_pow2(tex->height); @@ -276,14 +234,6 @@ struct texture *texture_fromdata(void *raw, long size) return tex; } -HMM_Vec2 tex_get_dimensions(struct texture *tex) { - if (!tex) return (HMM_Vec2){0,0}; - HMM_Vec2 d; - d.x = tex->width; - d.y = tex->height; - return d; -} - static double fade (double t) { return t*t*t*(t*(t*6-15)+10); } double grad (int hash, double x, double y, double z) { diff --git a/source/engine/texture.h b/source/engine/texture.h index 42c5ab9..b3a02ea 100644 --- a/source/engine/texture.h +++ b/source/engine/texture.h @@ -37,21 +37,10 @@ typedef struct img_sampler{ int mip_filter; } img_sampler; -struct texture *texture_from_file(const char *path); // Create texture from image -struct texture *texture_fromdata(void *raw, long size); - +texture *texture_from_file(const char *path); void texture_free(texture *tex); -/* Hot reloads a texture, if needed */ -void texture_sync(const char *path); - -char * tex_get_path(struct texture *tex); // Get image path for texture - -int gif_nframes(const char *path); -int *gif_delays(const char *path); - -struct glrect tex_get_rect(struct texture *tex); -HMM_Vec2 tex_get_dimensions(struct texture *tex); +struct texture *texture_fromdata(void *raw, long size); double perlin(double x, double y, double z); diff --git a/source/engine/thirdparty/quickjs/quickjs.c b/source/engine/thirdparty/quickjs/quickjs.c index dac19ce..0259443 100644 --- a/source/engine/thirdparty/quickjs/quickjs.c +++ b/source/engine/thirdparty/quickjs/quickjs.c @@ -112,6 +112,7 @@ void quickjs_set_dumpout(FILE *f) //#define DUMP_READ_OBJECT #ifdef DUMP +#define DUMP_MEM #define DUMP_CLOSURE #define DUMP_GC #define DUMP_GC_FREE diff --git a/source/engine/yugine.c b/source/engine/yugine.c index 7f43949..12375c9 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -60,7 +60,6 @@ void c_init() { window_resize(sapp_width(), sapp_height()); phys2d_init(); render_init(); - set_icon("icons/moon.gif"); particle_init(); script_call_sym(c_start,0,NULL); }