diff --git a/scripts/actor.js b/scripts/actor.js index f52613c..d0bc804 100644 --- a/scripts/actor.js +++ b/scripts/actor.js @@ -1,13 +1,40 @@ var actor = {}; -actor.spawn = function(script, config, callback){ - if (typeof script !== 'string') return undefined; - var padawan = Object.create(actor); - use(script, padawan); +var actor_urs = {}; + +globalThis.class_use = function(script, config, base, callback) +{ + if (!actor_urs[script]) { + var newur = Object.create(base); + actor_urs[script] = newur; + } + + var padawan = Object.create(actor_urs[script]); + + if (callback) callback(padawan); if (typeof config === 'object') Object.merge(padawan,config); + var file = Resources.find_script(script); + var script = Resources.replstrs(file); + script = `(function() { + var self = this; + var $ = this.__proto__; + ${script}; + })`; + + var fn = os.eval(file,script); + fn.call(padawan); + + return padawan; +} + +actor.spawn = function(script, config){ + if (typeof script !== 'string') return undefined; + + var padawan = class_use(script, config, actor); + padawan.padawans = []; padawan.timers = []; padawan.master = this; diff --git a/scripts/base.js b/scripts/base.js index 02a9dd1..4b72f21 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -551,7 +551,7 @@ Object.defineProperty(Object.prototype, 'obscure', { Object.defineProperty(Object.prototype, 'mixin', { value: function(obj) { if (typeof obj === 'string') - obj = use(obj, this); + obj = use(obj); if (obj) Object.mixin(this, obj); @@ -1418,8 +1418,7 @@ bbox.fromobjs = function(objs) /* VECTORS */ var Vector = {}; -Vector.length = function(v) { return Math.hypot(...v); } - +Vector.length = vector.length; Vector.norm = vector.norm; Vector.project = vector.project; Vector.dot = vector.dot; diff --git a/scripts/engine.js b/scripts/engine.js index 1f3a6e2..09cb7c4 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -1,5 +1,8 @@ "use math"; +prosperon.gc_start = function(){} +prosperon.gc_end = function(){} + Object.defineProperty(String.prototype, 'rm', { value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); } }); @@ -223,37 +226,38 @@ globalThis.global = globalThis; var use_cache = {}; -globalThis.use = function use(file, env = {}, script) { +globalThis.use = function use(file) { file = Resources.find_script(file); profile.cache("USE", file); if (use_cache[file]) { - var ret = use_cache[file].call(env); - return; + var ret = use_cache[file](); + profile.endcache(" [cached]"); + return ret; } - script ??= Resources.replstrs(file); - + + var script = Resources.replstrs(file); script = `(function() { var self = this; ${script}; })`; var fn = os.eval(file, script); use_cache[file] = fn; - var ret = fn.call(env); + var ret = fn(); profile.endcache(); - + return ret; } -function stripped_use (file, env = {}, script) { +function stripped_use (file, script) { file = Resources.find_script(file); if (use_cache[file]) { - var ret = use_cache[file].call(env); - return; + var ret = use_cache[file](); + return ret; } script ??= Resources.replstrs(file); script = `(function() { var self = this; ${script}; })`; var fn = os.eval(file, script); - var ret = fn.call(env); + var ret = fn(); profile.endcache(); return ret; @@ -264,7 +268,7 @@ function bare_use(file) var script = io.slurp(file); if (!script) return; script = `(function() { var self = this; ${script}; })`; - Object.assign(globalThis, os.eval(file, script).call(globalThis)); + Object.assign(globalThis, os.eval(file, script)()); } globalThis.debug = {}; diff --git a/scripts/entity.js b/scripts/entity.js index 0c392bb..b1c08d7 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -146,16 +146,15 @@ var entity = { }, spawn(text, config, callback) { - - var ent = Object.create(entity); - ent.transform = os.make_transform(); - - ent.guid = prosperon.guid(); - - ent.components = {}; - ent.objects = {}; - ent.timers = {}; - + var ent = class_use(text, config, entity, function(ent) { + ent.transform = os.make_transform(); + ent.guid = prosperon.guid(); + ent.components = {}; + ent.objects = {}; + ent.timers = {}; + ent.ur = {}; + }); +/* if (!text) ent.ur = emptyur; else if (text instanceof Object) {// assume it's an ur @@ -168,13 +167,7 @@ var entity = { text = ent.ur.text; config = [ent.ur.data, config]; } - - if (typeof text === 'string') - use(text, ent); - else if (Array.isArray(text)) - for (var path of text) use(path,ent); - profile.cache("ENTITY TIME", ent.ur.name); - var st = profile.now(); + if (typeof config === 'string') Object.merge(ent, json.decode(Resources.replstrs(config))); else if (Array.isArray(config)) @@ -186,7 +179,16 @@ var entity = { else if (path instanceof Object) Object.merge(ent,path); }; - + + if (typeof text === 'string') { + class_use( + use(text, ent); + } + else if (Array.isArray(text)) + for (var path of text) use(path,ent); + profile.cache("ENTITY TIME", ent.ur.name); +*/ + ent.reparent(this); for (var [prop, p] of Object.entries(ent)) { diff --git a/scripts/mum.js b/scripts/mum.js index 0b49265..d02cf26 100644 --- a/scripts/mum.js +++ b/scripts/mum.js @@ -76,7 +76,7 @@ var pre = function(data) if (data.pos) cursor = data.pos.slice(); data.drawpos = cursor.slice().add(data.offset); - if (data.opacity !== 1) { + if (data.opacity && data.opacity !== 1) { data.color = data.color.slice(); data.color[3] = data.opacity; } diff --git a/scripts/profile.js b/scripts/profile.js index 1367ad5..935cf80 100644 --- a/scripts/profile.js +++ b/scripts/profile.js @@ -16,6 +16,7 @@ function calc_cpu(fn, times, diff=0) function empty_fn() {} profile.cpu = function profile_cpu(fn, times = 1, q = "unnamed") { + var retgather = gathering_cpu; profile.gather_stop(); var empty = calc_cpu(empty_fn, 100000); var mean = Math.mean(empty); @@ -26,7 +27,10 @@ profile.cpu = function profile_cpu(fn, times = 1, q = "unnamed") { var totalt = profile.best_t(elapsed); say(`profile [${q}]: ${avgt} ± ${profile.best_t(Math.ci(series))} [${totalt} for ${times} loops]`); - start_prof_gather(); + say(`result of function is ${fn()}`); + + if (retgather) + profile.start_prof_gather(); } profile.ms = function(t) { return t/1000000; } @@ -277,3 +281,25 @@ function printreport(cache, name) { return report; }; + +profile.best_mem = function(bytes) +{ + var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + if (bytes == 0) return '0 Bytes'; + var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return (bytes / Math.pow(1024, i)).toPrecision(3) + ' ' + sizes[i]; +} + +profile.print_mem = function() +{ + var mem = os.mem(); + say('total memory used: ' + profile.best_mem(mem.memory_used_size)); + delete mem.memory_used_size; + delete mem.malloc_size; + for (var i in mem) { + if (i.includes("size")) + say(" " + i + " :: " + profile.best_mem(mem[i])); + } +} + +return {profile}; diff --git a/scripts/render.js b/scripts/render.js index 1de71f3..df96e8f 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -920,10 +920,13 @@ prosperon.render = function() render.end_pass(); profile.endframe(); - - profile.frame("post process"); + profile.endframe(); + profile.endframe(); /* draw the image of the game world first */ render.glue_pass(); + profile.frame("frame"); + profile.frame("render"); + profile.frame("post process"); render.viewport(...prosperon.camera.view()); render.use_shader(render.postshader); render.use_mat({diffuse:prosperon.screencolor}); @@ -1002,6 +1005,4 @@ prosperon.process = function process() { profile.endframe(); } - - return {render}; diff --git a/scripts/std.js b/scripts/std.js index 23af7f2..3f76812 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -15,9 +15,11 @@ if (os.sys() === 'macos') { } //appy.inputs.f12 = function() { mum.debug = !mum.debug; } -appy.inputs.f12 = function() { profile.cpu_frame(); } -appy.inputs.f11 = window.toggle_fullscreen; + +appy.inputs.f9 = function() { profile.print_mem(); } appy.inputs.f10 = function() { profile.toggle_frame_avg(); } +appy.inputs.f11 = window.toggle_fullscreen; +appy.inputs.f12 = function() { profile.cpu_frame(); } appy.inputs['M-f4'] = prosperon.quit; player[0].control(appy); @@ -240,7 +242,7 @@ Cmdline.register_order("play", function(argv) { if (argv[0]) io.chdir(argv[0]); - game.loadurs(); +// game.loadurs(); if (!io.exists(projectfile)) { say("No game to play. Try making one with 'prosperon init'."); @@ -320,7 +322,7 @@ Cmdline.register_order("about", function(argv) { }, "Get information about this game."); Cmdline.register_order("ur", function(argv) { - game.loadurs(); +// game.loadurs(); for (var i of ur._list.sort()) say(i); }, "Get information about the ur types in your game."); diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index f17d22b..91476aa 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -33,6 +33,7 @@ #include "par/par_shapes.h" #include "sokol_glue.h" #include +#include #include "gui.h" #include "timer.h" @@ -1315,6 +1316,21 @@ JSC_CCALL(vector_angledist, return number2js(dist); ) +JSC_CCALL(vector_length, + int len = js_arrlen(argv[0]); + switch(len) { + case 2: return number2js(HMM_LenV2(js2vec2(argv[0]))); + case 3: return number2js(HMM_LenV3(js2vec3(argv[0]))); + case 4: return number2js(HMM_LenV4(js2vec4(argv[0]))); + } + + double sum = 0; + for (int i = 0; i < len; i++) + sum += pow(js2number(js_getpropidx(argv[0], i)), 2); + + return number2js(sqrt(sum)); +) + double r2() { return (double)rand() / (double)RAND_MAX ; @@ -1415,7 +1431,8 @@ static const JSCFunctionListEntry js_vector_funcs[] = { MIST_FUNC_DEF(vector, mean, 1), MIST_FUNC_DEF(vector, sum, 1), MIST_FUNC_DEF(vector, sigma, 1), - MIST_FUNC_DEF(vector, median, 1) + MIST_FUNC_DEF(vector, median, 1), + MIST_FUNC_DEF(vector, length, 1) }; #define JS_HMM_FN(OP, HMM, SIGN) \ @@ -2501,6 +2518,46 @@ JSC_CCALL(os_quit, quit();) JSC_CCALL(os_exit, exit(js2number(argv[0]));) JSC_CCALL(os_reindex_static, cpSpaceReindexStatic(space)); JSC_CCALL(os_gc, script_gc()); +JSC_CCALL(os_mem_limit, script_mem_limit(js2number(argv[0]))) +JSC_CCALL(os_gc_threshold, script_gc_threshold(js2number(argv[0]))) +JSC_CCALL(os_max_stacksize, script_max_stacksize(js2number(argv[0]))) + +#define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \ +js_setpropstr(OBJ, #FIELD, TYPE##2js(STRUCT.FIELD));\ + +#define JSJMEMRET(FIELD) JSOBJ_ADD_FIELD(ret, jsmem, FIELD, number) + +JSC_CCALL(os_mem, + JSMemoryUsage jsmem; + JS_ComputeMemoryUsage(rt, &jsmem); + ret = JS_NewObject(js); + JSJMEMRET(malloc_size) + JSJMEMRET(malloc_limit) + JSJMEMRET(memory_used_size) + JSJMEMRET(memory_used_count) + JSJMEMRET(atom_count) + JSJMEMRET(atom_size) + JSJMEMRET(str_count) + JSJMEMRET(str_size) + JSJMEMRET(obj_count) + JSJMEMRET(obj_size) + JSJMEMRET(prop_count) + JSJMEMRET(prop_size) + JSJMEMRET(shape_count) + JSJMEMRET(shape_size) + JSJMEMRET(js_func_count) + JSJMEMRET(js_func_size) + JSJMEMRET(js_func_code_size) + JSJMEMRET(js_func_pc2line_count) + JSJMEMRET(js_func_pc2line_size) + JSJMEMRET(c_func_count) + JSJMEMRET(array_count) + JSJMEMRET(fast_array_count) + JSJMEMRET(fast_array_elements) + JSJMEMRET(binary_object_count) + JSJMEMRET(binary_object_size) +) + JSC_SSCALL(os_eval, ret = script_eval(str, str2)) JSC_CCALL(os_make_body, @@ -2618,6 +2675,13 @@ JSC_CCALL(os_make_circle2d, return ret; ) +JSC_CCALL(os_make_timer, return timer2js(timer_make())) +JSC_CCALL(os_update_timers, timer_update(js2number(argv[0]))) + +JSC_CCALL(os_obj_size, + +) + JSC_CCALL(poly2d_setverts, cpShape *s = js2cpShape(self); HMM_Vec2 *v = js2cpvec2arr(argv[0]); @@ -2938,6 +3002,12 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, make_hemisphere, 2), MIST_FUNC_DEF(os, make_plane, 2), MIST_FUNC_DEF(os, make_video, 1), + MIST_FUNC_DEF(os, make_timer, 0), + MIST_FUNC_DEF(os, update_timers, 1), + MIST_FUNC_DEF(os, mem, 1), + MIST_FUNC_DEF(os, mem_limit, 1), + MIST_FUNC_DEF(os, gc_threshold, 1), + MIST_FUNC_DEF(os, max_stacksize, 1) }; #include "steam.h" diff --git a/source/engine/jsffi.h b/source/engine/jsffi.h index c36aafa..adf4904 100644 --- a/source/engine/jsffi.h +++ b/source/engine/jsffi.h @@ -110,6 +110,7 @@ JSValue TYPE##2js(TYPE *n) { \ return j; }\ \ static JSValue js_##TYPE##_memid (JSContext *js, JSValue self) { return str2js("%p", js2##TYPE(self)); } \ +static JSValue js_##TYPE##_memsize (JSContext *js, JSValue self) { return number2js(sizeof(TYPE)); } \ #define QJSGLOBALCLASS(NAME) \ JSValue NAME = JS_NewObject(js); \ @@ -126,6 +127,7 @@ QJSCLASSPREP(TYPE); \ JSValue TYPE##_proto = JS_NewObject(js); \ JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \ JS_SetPropertyStr(js, TYPE##_proto, "memid", JS_NewCFunction(js, &js_##TYPE##_memid, "memid", 0)); \ +JS_SetPropertyStr(js, TYPE##_proto, "memsize", JS_NewCFunction(js, &js_##TYPE##_memsize, "memsize", 0)); \ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ #define countof(x) (sizeof(x)/sizeof((x)[0])) diff --git a/source/engine/script.c b/source/engine/script.c index af6c0f0..8e4f1a8 100644 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -16,6 +16,9 @@ JSRuntime *rt = NULL; #define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP #endif +static JSValue start_gc; +static JSValue end_gc; + void script_startup() { rt = JS_NewRuntime(); js = JS_NewContext(rt); @@ -44,6 +47,9 @@ return; } void script_gc() { JS_RunGC(rt); } +void script_mem_limit(size_t limit) { JS_SetMemoryLimit(rt, limit); } +void script_gc_threshold(size_t threshold) { JS_SetGCThreshold(rt, threshold); } +void script_max_stacksize(size_t size) { JS_SetMaxStackSize(rt, size); } void js_stacktrace() { if (!js) return; @@ -52,6 +58,7 @@ void js_stacktrace() { #endif } + void script_evalf(const char *format, ...) { JSValue obj; diff --git a/source/engine/script.h b/source/engine/script.h index ecf77a9..654edff 100644 --- a/source/engine/script.h +++ b/source/engine/script.h @@ -30,6 +30,9 @@ JSValue script_eval(const char *file, const char *script); void script_call_sym(JSValue sym, int argc, JSValue *argv); void script_gc(); +void script_mem_limit(size_t limit); +void script_gc_threshold(size_t threshold); +void script_max_stacksize(size_t size); #ifdef __cplusplus } diff --git a/source/engine/thirdparty/quickjs/quickjs.c b/source/engine/thirdparty/quickjs/quickjs.c index abf9eb5..7e3c834 100644 --- a/source/engine/thirdparty/quickjs/quickjs.c +++ b/source/engine/thirdparty/quickjs/quickjs.c @@ -32,6 +32,7 @@ #include #include #include +#include #if defined(__APPLE__) #include #elif defined(__linux__) || defined(__GLIBC__) @@ -112,6 +113,22 @@ void quickjs_set_dumpout(FILE *f) //#define DUMP_PROMISE //#define DUMP_READ_OBJECT +#ifdef DUMP +//#define DUMP_FREE +//#define DUMP_MEM +//#define DUMP_CLOSURE +#define DUMP_GC +//#define DUMP_GC_FREE +#define DUMP_LEAKS 1 +//#define DUMP_OBJECTS +#define DUMP_CLOSURE +//#define DUMP_OBJECTS +//#define DUMP_ATOMS +//#define DUMP_SHAPES +//#define DUMP_MODULE_RESOLVE +//#define DUMP_PROMISE +#endif + /* test the GC by forcing it before each object allocation */ //#define FORCE_GC_AT_MALLOC diff --git a/source/engine/timer.c b/source/engine/timer.c index 276a2b8..f0df0a5 100644 --- a/source/engine/timer.c +++ b/source/engine/timer.c @@ -1,22 +1,33 @@ #include "timer.h" - +#include #include "stb_ds.h" -timer *timers; +timer **timers; timer *timer_make() { - return NULL; + timer *t = calloc(sizeof(*t),1); + arrput(timers, t); + return t; } void timer_free(timer *t) { - + printf("before free arrlen if timers is now %d\n", arrlen(timers)); + for (int i = 0; i < arrlen(timers); i++) { + if (timers[i] == t) { + arrdelswap(timers,i); + break; + } + } + + free(t); + printf("arrlen if timers is now %d\n", arrlen(timers)); } void timer_update(double dt) { for (int i = 0; i < arrlen(timers); i++) { - timers[i].remain -= dt; + timers[i]->remain -= dt; } -} \ No newline at end of file +} diff --git a/source/engine/timer.h b/source/engine/timer.h index 590ee0f..b425b47 100644 --- a/source/engine/timer.h +++ b/source/engine/timer.h @@ -5,9 +5,8 @@ typedef struct timer { double remain; } timer; - timer *timer_make(); void timer_free(timer *t); void timer_update(double dt); -#endif \ No newline at end of file +#endif