From 9982dadd58bd0f86bae735bbab9cf3b12162745c Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 28 Jan 2025 16:42:31 -0600 Subject: [PATCH] remove half assed code --- docs/index.md | 3 +- scripts/convert.js | 53 -- scripts/debug.js | 258 ------- scripts/diff.js | 98 --- scripts/editor.js | 1712 ----------------------------------------- scripts/engine.js | 1 - scripts/gizmos.js | 26 - scripts/layout.js | 10 +- scripts/log.js | 38 - scripts/parseq.js | 590 -------------- scripts/path.js | 22 - scripts/physics.js | 62 -- scripts/profile.js | 392 ---------- scripts/render.js | 97 +-- scripts/sim.js | 29 - scripts/sound.js | 1 - scripts/spline.js | 122 --- scripts/stats.js | 38 - scripts/std.js | 1 - scripts/stdprofile.js | 69 -- scripts/stdtest.js | 6 - scripts/test.js | 46 -- scripts/textedit.js | 343 --------- scripts/tween.js | 5 +- scripts/util.js | 16 + scripts/yaml.js | 51 -- source/jsffi.c | 11 +- 27 files changed, 40 insertions(+), 4060 deletions(-) delete mode 100644 scripts/convert.js delete mode 100644 scripts/debug.js delete mode 100644 scripts/diff.js delete mode 100644 scripts/editor.js delete mode 100644 scripts/gizmos.js delete mode 100644 scripts/log.js delete mode 100644 scripts/parseq.js delete mode 100644 scripts/path.js delete mode 100644 scripts/physics.js delete mode 100644 scripts/profile.js delete mode 100644 scripts/sim.js delete mode 100644 scripts/spline.js delete mode 100644 scripts/stats.js delete mode 100644 scripts/stdprofile.js delete mode 100644 scripts/stdtest.js delete mode 100644 scripts/test.js delete mode 100644 scripts/textedit.js delete mode 100644 scripts/yaml.js diff --git a/docs/index.md b/docs/index.md index 55d3c2d5..6a2fb2ab 100644 --- a/docs/index.md +++ b/docs/index.md @@ -63,4 +63,5 @@ editor yaml spline profile -sim \ No newline at end of file +sim +dmon \ No newline at end of file diff --git a/scripts/convert.js b/scripts/convert.js deleted file mode 100644 index ddf99e58..00000000 --- a/scripts/convert.js +++ /dev/null @@ -1,53 +0,0 @@ -var convert = {}; -convert.romanize = function (num) { - if (!+num) return false; - var digits = String(+num).split(""); - var key = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; - var roman = "", - i = 3; - while (i--) roman = (key[+digits.pop() + i * 10] || "") + roman; - return Array(+digits.join("") + 1).join("M") + roman; -}; - -convert.deromanize = function (str) { - var str = str.toUpperCase(); - var validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/; - var token = /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g; - var key = { - M: 1000, - CM: 900, - D: 500, - CD: 400, - C: 100, - XC: 90, - L: 50, - XL: 40, - X: 10, - IX: 9, - V: 5, - IV: 4, - I: 1, - }; - var num = 0, - m; - if (!(str && validator.test(str))) return false; - while ((m = token.exec(str))) num += key[m[0]]; - return num; -}; - -convert.roman = { - M: 1000, - D: 500, - C: 100, - L: 50, - X: 10, - V: 5, - I: 1, -} - -convert.buf2hex = function (buffer) { - // buffer is an ArrayBuffer - return [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, "0")).join(" "); -}; - -return convert diff --git a/scripts/debug.js b/scripts/debug.js deleted file mode 100644 index dcd97aaa..00000000 --- a/scripts/debug.js +++ /dev/null @@ -1,258 +0,0 @@ -var render = use('render') -var debug = this -var util = use('util') - -debug.build = function (fn) { - if (!debug.show) return; - fn(); -}; -debug.show = true; -debug.urnames = false; -debug.termout = true; -debug.console = false; -debug.cheat = false; -debug.meta = false; -debug.showprofiler = false; - -debug.fn_break = function (fn, obj = globalThis) { - if (typeof fn !== "function") return; - - var newfn = function () { - console.log("broke"); - fn(); - }; - obj[fn.name] = newfn; -}; - -var sim = use('sim') - -debug.draw_phys = false; -debug.draw_bb = false; -debug.draw_gizmos = false; -debug.draw_names = false; -debug.sprite_nums = false; -debug.draw = function () { - if (this.draw_phys) - game.all_objects(function (x) { - debug.draw_gameobject(x); - }); - - if (this.draw_bb) - game.all_objects(function (x) { - debug.boundingbox(x.boundingbox(), Color.debug.boundingbox.alpha(0.05)); - }); - - if (this.draw_gizmos) - game.all_objects(function (x) { - if (!x.icon) return; - gui.image(x.icon, game.camera.world2view(x.pos)); - }); - - if (this.draw_names) - game.all_objects(function (x) { - render.text(x, game.camera.view2screen(x.pos).add([0, 32]), 1, Color.debug.names); - }); - - if (debug.gif.rec) { - render.text("REC", [0, 40], 1); - render.text(time.timecode(time.timenow() - debug.gif.start_time, debug.gif.fps), [0, 30], 1); - } - - return; - - if (sim.paused()) render.text("PAUSED", [0, 0], 1); - - render.text(sim.playing() ? "PLAYING" : sim.stepping() ? "STEP" : sim.paused() ? "PAUSED; EDITING" : "EDIT", [0, 0], 1); -}; - -/* These controls are available during editing, and during play of debug builds */ -debug.inputs = {}; -debug.inputs.f1 = function () { - debug.draw_phys = !debug.draw_phys; -}; -debug.inputs.f1.doc = "Draw physics debugging aids."; -debug.inputs.f3 = function () { - debug.draw_bb = !debug.draw_bb; -}; -debug.inputs.f3.doc = "Toggle drawing bounding boxes."; -debug.inputs.f4 = function () { - debug.draw_names = !debug.draw_names; - debug.draw_gizmos = !debug.draw_gizmos; -}; -debug.inputs.f4.doc = "Toggle drawing gizmos and names of objects."; - -var gif = { - w: 640 /* Max width */, - h: 480 /* Max height */, - stretch: false /* True if you want to stretch */, - cpf: 4, - depth: 16, - file: "out.gif", - rec: false, - secs: 6, - start_time: 0, - fps: 0, - start() { - var w = this.w; - var h = this.h; - if (!this.stretch) { - var win = window.height / window.width; - var gif = h / w; - if (gif > win) h = w * win; - else w = h / win; - } - - // cmd(131, w, h, this.cpf, this.depth); - this.rec = true; - this.fps = (1 / this.cpf) * 100; - this.start_time = time.now(); - - timer.oneshot(this.stop.bind(this), this.secs, this, true); - }, - - stop() { - if (!this.rec) return; - // cmd(132, this.file); - this.rec = false; - }, -}; - -debug.inputs.f8 = function () { - var now = new Date(); - debug.gif.file = now.toISOString() + ".gif"; - debug.gif.start(); -}; -debug.inputs.f9 = function () { - debug.gif.stop(); -}; - -debug.inputs.f10 = function () { - time.timescale = 0.1; -}; -debug.inputs.f10.doc = "Toggle timescale to 1/10."; -debug.inputs.f10.released = function () { - time.timescale = 1.0; -}; -debug.inputs.f12 = function () { - gui.defaults.debug = !gui.defaults.debug; - console.warn("gui toggle debug"); -}; -debug.inputs.f12.doc = "Toggle drawing gui debugging aids."; - -debug.inputs["M-1"] = render.normal; -debug.inputs["M-2"] = render.wireframe; -debug.inputs["C-M-f"] = function () {}; -debug.inputs["C-M-f"].doc = "Enter camera fly mode."; - -debug.api = {}; -debug.api.doc_entry = function (obj, key) { - if (typeof key !== "string") { - console.warn("Cannot print a key that isn't a string."); - return undefined; - } - - var title = key; - - var o = obj[key]; - if (typeof o === "undefined" && obj.impl && typeof obj.impl[key] !== "undefined") o = obj.impl[key]; - - var t = typeof o; - if (Array.isArray(o)) t = "array"; - else if (t === "function") { - title = o.toString().tofirst(")") + ")"; - title = title.fromfirst("("); - title = key + "(" + title; - if (o.doc) doc = o.doc; - t = ""; - } else if (t === "undefined") t = ""; - - if (t) t = "**" + t + "**\n"; - - var doc = ""; - if (o.doc) doc = o.doc; - else if (obj.doc && obj.doc[key]) doc = obj.doc[key]; - else if (Array.isArray(o)) doc = json.encode(o); - - return `#### ${title} -${t} -${doc} -`; -}; - -debug.api.print_doc = function (name) { - var obj = name; - if (typeof name === "string") { - obj = eval(name); - if (!obj) { - console.warn(`Cannot print the API of '${name}', as it was not found.`); - return undefined; - } - - obj = globalThis[name]; - } - - obj = eval(name); - - if (!util.isObject(obj)) { - console.warn("Cannot print the API of something that isn't an object."); - return undefined; - } - - if (!obj) { - console.warn(`Object '${name}' does not exist.`); - return; - } - - var mdoc = "# " + name + "\n"; - if (obj.doc?.doc) mdoc += obj.doc.doc + "\n"; - else if (typeof obj.doc === "string") mdoc += obj.doc + "\n"; - - var keys = Object.keys(obj); - for (var key of keys) { - if (key === "doc") continue; - if (key === "toString") continue; - - mdoc += debug.api.doc_entry(obj, key) + "\n"; - } - - return mdoc; -}; - -debug.onchange_var = function(obj, vars, on_change) -{ - vars.forEach(prop => { - var internal_val = obj[prop]; - Object.defineProperty(obj, prop, { - get() { return internal_val; }, - set(newval) { - if (internal_val !== newval) { - on_change(prop, internal_val, newval); - internal_val = newval; - } - }, - configurable:true, - enumerable:true - }); - }); -} - -debug.log_var = function(obj, vars) -{ - debug.onchange_var(obj,vars, (prop,oldval,newval) => { - console.log(`property ${prop} changed from ${oldval} to ${newval}`); - console.stack(); - }); -} - -debug.break_var = function(obj,vars) -{ - debug.onchange_var(obj,vars,_ => { - console.stack(); - os.exit(1); - }); -} - -debug.doc = Symbol() - -return debug - diff --git a/scripts/diff.js b/scripts/diff.js deleted file mode 100644 index 815c4a56..00000000 --- a/scripts/diff.js +++ /dev/null @@ -1,98 +0,0 @@ -var util = use('util') -var diff = {} - -function deep_copy(from) { - return json.decode(json.encode(from)); -} - -diff.valdiff = function valdiff(from, to) { - if (typeof from !== typeof to) return from; - if (typeof from === "function") return undefined; - if (typeof from === "undefined") return undefined; - - if (typeof from === "number") { - return to; - - return undefined; - } - - if (typeof from === "object") return ediff(from, to); - - if (from !== to) return to; - - return undefined; -} - -diff.ediff = function ediff(from, to) { - var ret = {}; - - if (!to) - // return ediff(from, {}); - return deep_copy(from); - - Object.entries(from).forEach(function ([key, v]) { - if (typeof v === "function") return; - if (typeof v === "undefined") return; - - if (Array.isArray(v)) { - if (!Array.isArray(to[key]) || v.length !== to[key].length) { - var r = ediff(v, []); - if (r) ret[key] = Object.values(r); - return; - } - - var diff = ediff(from[key], to[key]); - if (diff && !util.isEmpty(diff)) ret[key] = Object.values(ediff(v, [])); - - return; - } - - if (typeof v === "object" && v !== null) { - var diff = ediff(v, to[key]); - if (diff && !util.isEmpty(diff)) ret[key] = diff; - return; - } - - if (typeof v === "number" || v === null) { - if (!isFinite(v)) v = null; // Squash infinity to null - if (v !== to[key]) ret[key] = v; - return; - } - - if (!to || v !== to[key]) ret[key] = v; - }); - if (util.isEmpty(ret)) return undefined; - - return ret; -} - -ediff.doc = "Given a from and to object, returns an object that, if applied to from, will make it the same as to. Does not include deletion; it is only additive. If one element in an array is different, the entire array is copied. Squashes infinite numbers to null for use in JSON."; - -diff.samediff = function samediff(from, to) { - var same = []; - if (!to) return same; - if (typeof to !== "object") { - console.warn("'To' must be an object. Got " + to); - return same; - } - Object.keys(from).forEach(function (k) { - if (util.isObject(from[k])) { - samediff(from[k], to[k]); - return; - } - - // if (Array.isArray(from[k])) { - // var d = valdiff(from[k], to[k]); - // if (!d) - // } - - var d = valdiff(from[k], to[k]); - if (!d) delete from[k]; - }); - - return same; -} - -samediff.doc = "Given a from and to object, returns an array of keys that are the same on from as on to."; - -return diff diff --git a/scripts/editor.js b/scripts/editor.js deleted file mode 100644 index 33aebd89..00000000 --- a/scripts/editor.js +++ /dev/null @@ -1,1712 +0,0 @@ -/* - Editor-only variables on objects - selectable -*/ - -game.loadurs(); - -player[0].control(debug); - -var show_frame = true; - -var editor = { - toString() { - return "editor"; - }, - grid_size: 100, - ruler_mark_px: 100, - grid_color: Color.green.alpha(0.3), - machine: undefined, - device_test: undefined, - selectlist: [], - scalelist: [], - rotlist: [], - camera: undefined, - edit_level: undefined /* The current level that is being edited */, - desktop: undefined /* The editor desktop, where all editing objects live */, - working_layer: 0, - get cursor() { - if (this.selectlist.length === 0) return input.mouse.worldpos(); - return physics.com(this.selectlist.map(x => x.pos)); - }, - edit_mode: "basic", - - get_this() { - return this.edit_level; - }, - - try_select() { - /* nullify true if it should set selected to null if it doesn't find an object */ - var go = physics.pos_query(input.mouse.worldpos()); - return this.do_select(go); - }, - - do_select(obj) { - /* select an object, if it is selectable given the current editor state */ - if (!obj) return; - if (!obj._ed.selectable) return undefined; - - if (obj.master !== this.edit_level) { - var testlevel = obj.master; - while (testlevel && testlevel.master !== world && testlevel.master !== this.edit_level && testlevel !== testlevel.master) testlevel = testlevel.master; - return testlevel; - } - - return obj; - - if (this.working_layer > -1 && obj.draw_layer !== this.working_layer) return undefined; - - return obj; - }, - - curpanel: undefined, - - check_level_nested() { - if (this.edit_level.master) { - this.openpanel(gen_notify("Can't close a nested level. Save up to the root before continuing.")); - return true; - } - - return false; - }, - - programmode: false, - - dup_objects(x) { - var objs = x.slice(); - var duped = []; - - objs.forEach(x => duped.push(x.dup())); - return duped; - }, - - sel_start: [], - - mover(amt, snap) { - return function (go) { - go.pos = go.pos.add(amt); - }; - }, - - step_amt() { - return input.keyboard.down("shift") ? 10 : 1; - }, - - on_grid(pos) { - return pos.every(function (x) { - return x % editor.grid_size === 0; - }); - }, - - snapper(dir, grid) { - return function (go) { - go.pos = go.pos.add(dir.scale(grid / 2)); - go.pos = go.pos.map(function (x) { - return Math.snap(x, grid); - }, this); - }; - }, - - key_move(dir) { - if (!editor.grabselect) return; - if (input.keyboard.down("ctrl")) this.selectlist.forEach(this.snapper(dir.scale(1.01), editor.grid_size)); - else this.selectlist.forEach(this.mover(dir.scale(this.step_amt()))); - }, - - /* Snapmode - 0 No snap - 1 Pixel snap - 2 Grid snap - */ - snapmode: 0, - - snapped_pos(pos) { - switch (this.snapmode) { - case 0: - return pos; - - case 1: - return pos.map(function (x) { - return Math.round(x); - }); - - case 2: - return pos.map; - } - }, - - unselect() { - editor.selectlist = []; - this.grabselect = []; - this.scalelist = []; - this.rotlist = []; - this.sel_comp = undefined; - }, - - sel_comp: undefined, - comp_info: false, - brush_obj: undefined, - - camera_recalls: {}, - camera_recall_stack: [], - - camera_recall_store() { - this.camera_recall_stack.push({ - pos: this.camera.pos, - zoom: this.camera.zoom, - }); - }, - - camera_recall_pop() { - Object.assign(this.camera, this.camera_recalls.pop()); - }, - - camera_recall_clear() { - this.camera_recall_stack = []; - }, - - input_num_pressed(num) { - if (input.keyboard.down("ctrl")) { - this.camera_recalls[num] = { - pos: this.camera.pos, - zoom: this.camera.zoom, - }; - return; - } - - if (num in this.camera_recalls) Object.assign(this.camera, this.camera_recalls[num]); - }, - - zoom_to_bb(bb) { - var cwh = bbox.tocwh(bb); - - var xscale = cwh.wh.x / window.width; - var yscale = cwh.wh.y / window.height; - - var zoom = yscale > xscale ? yscale : xscale; - - this.camera.pos = cwh.c; - this.camera.zoom = zoom * 1.3; - }, - - z_start: undefined, - grabselect: undefined, - mousejoy: undefined, - joystart: undefined, - - stash: undefined, - - start_play_ed() { - this.stash = this.desktop.instance_obj(); - world.clear(); - global.mixin("config.js"); - sim.play(); - player[0].uncontrol(this); - player[0].control(limited_editor); - editor.cbs.forEach(cb => cb()); - editor.cbs = []; - global.mixin("predbg.js"); - console.warn(`starting game with ${this.dbg_ur}`); - editor.dbg_play = world.spawn(this.dbg_ur); - editor.dbg_play.pos = [0, 0]; - global.mixin("debug.js"); - }, - - start_play() { - world.clear(); - global.mixin("config.js"); - sim.play(); - player[0].uncontrol(this); - player[0].control(limited_editor); - editor.cbs.forEach(cb => cb()); - editor.cbs = []; - actor.spawn("game.js"); - }, - - cbs: [], - - enter_editor() { - sim.pause(); - player[0].control(this); - player[0].uncontrol(limited_editor); - - editor.cbs.push(Register.gui.register(editor.gui.bind(editor))); - editor.cbs.push(Register.draw.register(editor.draw.bind(editor))); - editor.cbs.push(Register.debug.register(editor.ed_debug.bind(editor))); - editor.cbs.push(Register.update.register(gui.controls.update, gui.controls)); - - this.desktop = world.spawn(); - world.rename_obj(this.desktop.toString(), "desktop"); - this.edit_level = this.desktop; - editor.edit_level._ed.selectable = false; - if (this.stash) { - this.desktop.make_objs(this.stash.objects); - Object.dainty_assign(this.desktop, this.stash); - } - this.selectlist = []; - editor.camera = world.spawn("camera2d"); - editor.camera._ed.selectable = false; - game.camera = editor.camera; - }, - - openpanel(panel) { - if (this.curpanel) { - this.curpanel.close(); - player[0].uncontrol(this.curpanel); - } - - this.curpanel = panel; - player[0].control(this.curpanel); - this.curpanel.open(); - }, - - curpanels: [], - addpanel(panel) { - this.curpanels.push(panel); - panel.open(); - }, - - cleanpanels(panel) { - this.curpanels = this.curpanels.filter(function (x) { - return x.on; - }); - }, - - snapshots: [], - curlvl: {} /* What the level currently looks like on file */, - - reset_undos() { - this.snapshots = []; - this.backshots = []; - }, - - snapshot() { - return; // TODO: Implement - var dif = this.edit_level.json_obj(); - if (!dif) return; - - if (this.snapshots.length !== 0) { - var ddif = ediff(dif, this.snapshots.last()); - if (!ddif) return; - dif = ddif; - } - - this.snapshots.push(dif); - this.backshots = []; - return; - - this.snapshots.push(dif); - - this.backshots = []; - this.backshots.push(diff(this.curlvl, cur)); - this.curlvl = cur; - this.edit_level.check_dirty(); - }, - - backshots: [] /* Redo snapshots */, - - restore_lvl(lvl) { - this.unselect(); - this.edit_level.clear(); - this.edit_level.load(lvl); - this.edit_level.check_dirty(); - }, - - redo() { - if (Object.empty(this.backshots)) { - console.info("Nothing to redo."); - return; - } - - this.snapshots.push(this.edit_level.save()); - var dd = this.backshots.pop(); - this.edit_level.clear(); - this.edit_level.load(dd); - this.edit_level.check_dirty(); - this.curlvl = dd; - }, - - undo() { - if (Object.empty(this.snapshots)) { - console.info("Nothing to undo."); - return; - } - this.unselect(); - // this.backshots.push(this.edit_level.save()); - var dd = this.snapshots.pop(); - Object.dainty_assign(this.edit_level, dd); - this.edit_level.check_dirty(); - }, - - restore_buffer() { - this.restore_level(this.filesnap); - }, - - save_current() { - if (!this.edit_level.file) { - this.openpanel(saveaspanel); - return; - } - }, - - draw_objects_names(obj, root, depth = 0) { - if (!obj) return; - if (!obj.objects) return; - root = root ? root + "." : root; - Object.entries(obj.objects).forEach(function (x) { - var p = root + x[0]; - render.text(p, x[1].this2screen(), 1, editor.color_depths[depth]); - editor.draw_objects_names(x[1], p, depth + 1); - }); - }, - - _sel_comp: undefined, - get sel_comp() { - return this._sel_comp; - }, - set sel_comp(x) { - if (this._sel_comp) player[0].uncontrol(this._sel_comp); - - this._sel_comp = x; - - if (this._sel_comp) player[0].control(this._sel_comp); - }, - - time: 0, - - color_depths: [], - draw() { - this.selectlist.forEach(x => { - if ("gizmo" in x && typeof x["gizmo"] === "function") x.gizmo(); - }); - - render.line(bbox.topoints(bbox.fromcwh([0, 0], [game.width, game.height])).wrapped(1), Color.green); - - /* Draw selection box */ - if (this.sel_start) { - var endpos = input.mouse.worldpos(); - var c = []; - c[0] = (endpos[0] - this.sel_start[0]) / 2; - c[0] += this.sel_start[0]; - c[1] = (endpos[1] - this.sel_start[1]) / 2; - c[1] += this.sel_start[1]; - var wh = []; - wh[0] = Math.abs(endpos[0] - this.sel_start[0]); - wh[1] = Math.abs(endpos[1] - this.sel_start[1]); - var bb = bbox.fromcwh(c, wh); - render.boundingbox(bb, Color.Editor.select.alpha(0.1)); - render.line(bbox.topoints(bb).wrapped(1), Color.white); - } - }, - - gui() { - /* Clean out killed objects */ - // if (show_frame) - /// render.line(shape.box(window.rendersize.x, window.rendersize.y).wrapped(1).map(p => game.camera.world2view(p)), Color.yellow); - - render.text([0, 0], game.camera.world2view([0, 0])); - - render.text("WORKING LAYER: " + this.working_layer, [0, 520]); - render.text("MODE: " + this.edit_mode, [0, 520 - render.font.linegap]); - - if (this.comp_info && this.sel_comp) render.text(input.print_pawn_kbm(this.sel_comp, false), [100, 700], 1); - - render.cross(editor.edit_level.this2screen(), 3, Color.blue); - - var thiso = editor.get_this(); - var clvl = thiso; - - var lvlchain = []; - while (clvl !== world) { - lvlchain.push(clvl); - clvl = clvl.master; - } - lvlchain.push(clvl); - - var colormap = ColorMap.Inferno; - editor.color_depths = []; - for (var i = 1; i > 0; i -= 0.1) editor.color_depths.push(colormap.sample(i)); - - var ypos = 200; - var depth = 0; - var alldirty = false; - for (var lvl of lvlchain) { - if (!lvl._ed?.selectable) continue; - if (alldirty) lvl._ed.dirty = true; - else { - if (!lvl._ed) continue; - lvl.check_dirty(); - if (lvl._ed.dirty) alldirty = true; - } - } - lvlchain.reverse(); - lvlchain.forEach(function (x, i) { - depth = i; - var lvlstr = x.namestr(); - if (i === lvlchain.length - 1) lvlstr += "[this]"; - render.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]); - ypos += render.font.linegap; - render.text("^^^^^^", [0, ypos], 1); - ypos += render.font.linegap; - }); - - depth++; - render.text("$$$$$$", [0, ypos], 1, editor.color_depths[depth]); - - this.selectlist.forEach(function (x) { - render.text(x.urstr(), x.this2screen().add([0, render.font.linegap * 2]), 1, Color.editor.ur); - render.text( - x.pos.map(function (x) { - return Math.round(x); - }), - x.this2screen(), - ); - render.cross(x.this2screen(), 10, Color.blue); - }); - - Object.entries(thiso.objects).forEach(function (x) { - var p = x[1].namestr(); - render.text(p, x[1].this2screen().add([0, render.font.linegap]), 1, editor.color_depths[depth]); - render.point(x[1].this2screen(), 5, Color.blue.alpha(0.3)); - render.point(x[1].this2screen(), 1, Color.red); - }); - - var mg = physics.pos_query(input.mouse.worldpos()); - - if (mg && mg._ed?.selectable) { - var p = mg.path_from(thiso); - render.text(p, input.mouse.screenpos(), 1, Color.teal); - } - - if (this.rotlist.length === 1) render.text(Math.places(this.rotlist[0].angle, 3), input.mouse.screenpos(), 1, Color.teal); - - if (this.selectlist.length === 1) { - var i = 1; - for (var key in this.selectlist[0].components) { - var selected = this.sel_comp === this.selectlist[0].components[key]; - var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]"; - render.text(str, this.selectlist[0].this2screen().add([0, -render.font.linegap * i++])); - } - - if (this.sel_comp) { - if ("gizmo" in this.sel_comp) this.sel_comp.gizmo(); - } - } - - editor.edit_level.objects.forEach(function (obj) { - if (!obj._ed.selectable) render.text("lock", obj, screenpos()); - }); - - render.grid(1, editor.grid_size, editor.grid_color); - var startgrid = game.camera.view2world([-20, 0]).map(function (x) { - return Math.snap(x, editor.grid_size); - }); - var endgrid = game.camera.view2world([window.width, window.height]); - - var w_step = Math.round(((editor.ruler_mark_px / window.width) * (endgrid.x - startgrid.x)) / editor.grid_size) * editor.grid_size; - if (w_step === 0) w_step = editor.grid_size; - - var h_step = Math.round(((editor.ruler_mark_px / window.height) * (endgrid.y - startgrid.y)) / editor.grid_size) * editor.grid_size; - if (h_step === 0) h_step = editor.grid_size; - - while (startgrid[0] <= endgrid[0]) { - render.text(startgrid[0], [game.camera.world2view([startgrid[0], 0])[0], 0]); - startgrid[0] += w_step; - } - - while (startgrid[1] <= endgrid[1]) { - render.text(startgrid[1], [0, game.camera.world2view([0, startgrid[1]])[1]]); - startgrid[1] += h_step; - } - - if (this.curpanel && this.curpanel.on) this.curpanel.gui(); - - this.curpanels.forEach(function (x) { - if (x.on) x.gui(); - }); - }, - - ed_debug() { - if (!debug.phys_drawing) - this.selectlist.forEach(function (x) { - debug.draw_obj_phys(x); - }); - }, - - killring: [], - killcom: [], - - lvl_history: [], - - load(urstr) { - var mur = ur[urstr]; - if (!mur) return; - var obj = editor.edit_level.spawn(mur); - obj.set_pos(input.mouse.worldpos()); - this.selectlist = [obj]; - }, - - load_prev() { - if (this.lvl_history.length === 0) return; - - var file = this.lvl_history.pop(); - this.edit_level = Level.loadfile(file); - this.unselect(); - }, - - /* Checking to save an entity as a subtype. */ - /* sub is the name of the (sub)type; obj is the object to save it as */ - /* if saving subtype of 'empty', it appears on the top level */ - saveas_check(sub, obj) { - if (!sub) { - console.warn(`Cannot save an object to an empty ur.`); - return; - } - - if (!obj) { - console.warn(`Specify an obejct to save.`); - return; - } - - if (obj.ur === "empty") { - /* make a new type path */ - if (Object.access(ur, sub)) { - console.warn(`Ur named ${sub} already exists.`); - return; - } - - var file = `${sub}.json`; - io.slurpwrite(file, json.encode(obj.json_obj(), null, 1)); - ur[sub] = { - name: sub, - data: file, - fresh: json.decode(json.encode(obj)), - }; - obj.ur = sub; - - return; - } else if (!sub.startsWith(obj.ur)) { - console.warn(`Cannot make an ur of type ${sub} from an object with the ur ${obj.ur}`); - return; - } - - var curur = Object.access(ur, sub); - - if (curur) { - notifypanel.action = editor.saveas; - this.openpanel(gen_notify("Entity already exists with that name. Delete first.")); - } else { - var path = sub.replaceAll(".", "/") + ".json"; - var saveobj = obj.json_obj(); - io.slurpwrite(path, JSON.stringify(saveobj, null, 1)); - - if (obj === editor.edit_level) { - if (obj === editor.desktop) { - obj.clear(); - var nobj = editor.edit_level.spawn(sub); - editor.selectlist = [nobj]; - return; - } - editor.edit_level = editor.edit_level.master; - } - - var t = obj.transform(); - editor.unselect(); - obj.kill(); - obj = editor.edit_level.spawn(sub); - obj.pos = t.pos; - obj.angle = t.angle; - } - }, -}; - -editor.new_object = function () { - var obj = editor.edit_level.spawn(); - obj.set_pos(input.mouse.worldpos()); - this.selectlist = [obj]; - return obj; -}; -editor.new_object.doc = "Create an empty object."; - -editor.new_from_img = function (path) { - var o = editor.new_object(); - o.add_component(component.sprite).path = path; - return o; -}; - -editor.inputs = {}; -editor.inputs["C-b"] = function () { - if (this.selectlist.length !== 1) { - console.warn(`Can only bake a single object at a time.`); - return; - } - - var obj = this.selectlist[0]; - - obj.components.forEach(function (c) { - if (typeof c.grow !== "function") return; - - c.grow(obj.scale); - c.sync?.(); - }); - obj.set_scale([1, 1, 1]); -}; - -editor.inputs.drop = function (str) { - str = str.slice(os.cwd().length + 1); - if (!Resources.is_image(str)) { - console.warn("NOT AN IMAGE"); - return; - } - - if (this.selectlist.length === 0) return editor.new_from_img(str); - - if (this.sel_comp?.comp === "sprite") { - this.sel_comp.path = str; - return; - } - - var mg = physics.pos_query(input.mouse.worldpos()); - if (!mg) return; - var img = mg.get_comp_by_name("sprite"); - if (!img) return; - img[0].path = str; -}; - -editor.inputs.f9 = function () { - os.capture("capture.bmp", 0, 0, 500, 500); -}; - -editor.inputs.release_post = function () { - editor.snapshot(); - - editor.selectlist?.forEach(x => x.check_dirty()); - - /* snap all objects to be pixel perfect */ - game.all_objects(o => (o.pos = o.pos.map(x => Math.round(x))), editor.edit_level); -}; -editor.inputs["C-a"] = function () { - if (!Object.empty(editor.selectlist)) { - editor.unselect(); - return; - } - editor.unselect(); - editor.selectlist = editor.edit_level.objects.slice(); -}; -editor.inputs["C-a"].doc = "Select all objects."; - -editor.inputs["C-`"] = function () { - editor.openpanel(replpanel); -}; -editor.inputs["C-`"].doc = "Open or close the repl."; - -editor.inputs.n = function () { - if (editor.selectlist.length !== 1) return; - var o = editor.try_select(); - if (!o) return; - if (o === editor.selectlist[0]) return; - if (o.master !== editor.selectlist[0].master) return; - - var tpos = editor.selectlist[0].get_pos(editor.selectlist[0].master); - tpos.x *= -1; - 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["M-n"] = function () { - if (editor.selectlist.length !== 1) return; - var o = editor.try_select(); - if (!o) return; - if (o === editor.selectlist[0]) return; - if (o.master !== editor.selectlist[0].master) return; - - var tpos = editor.selectlist[0].pos; - tpos.y *= -1; - o.pos = tpos; -}; -editor.inputs.n.doc = "Set the hovered object's position to mirror the selected object's position on the Y axis."; - -/* Return if selected component. */ -editor.inputs["h"] = function () { - var visible = true; - editor.selectlist.forEach(function (x) { - if (x.visible) visible = false; - }); - editor.selectlist.forEach(function (x) { - x.visible = visible; - }); -}; -editor.inputs["h"].doc = "Toggle object hidden."; - -editor.inputs["C-h"] = function () { - world.objects.forEach(function (x) { - x.visible = true; - }); -}; -editor.inputs["C-h"].doc = "Unhide all objects."; - -editor.inputs["C-e"] = function () { - editor.openpanel(assetexplorer); -}; -editor.inputs["C-e"].doc = "Open asset explorer."; - -editor.inputs["C-l"] = function () { - editor.openpanel(entitylistpanel); -}; -editor.inputs["C-l"].doc = "Open list of spawned entities."; - -editor.inputs["C-i"] = function () { - if (editor.selectlist.length !== 1) return; - objectexplorer.obj = editor.selectlist[0]; - editor.openpanel(objectexplorer); -}; -editor.inputs["C-i"].doc = "Open the object explorer for a selected object."; - -editor.inputs["C-d"] = function () { - if (editor.selectlist.length === 0) return; - var duped = editor.dup_objects(editor.selectlist); - editor.unselect(); - editor.selectlist = duped; -}; -editor.inputs["C-d"].doc = "Duplicate all selected objects."; - -editor.inputs["C-m"] = function () { - if (editor.sel_comp) { - if ("flipy" in editor.sel_comp) editor.sel_comp.flipy = !editor.sel_comp.flipy; - - return; - } - - editor.selectlist.forEach(function (x) { - x.mirror([0, 1]); - }); -}; -editor.inputs["C-m"].doc = "Mirror selected objects on the Y axis."; - -editor.inputs.m = function () { - if (editor.sel_comp) { - if ("flipx" in editor.sel_comp) editor.sel_comp.flipx = !editor.sel_comp.flipx; - - return; - } - - editor.selectlist.forEach(obj => obj.grow([-1, 1, 1])); -}; -editor.inputs.m.doc = "Mirror selected objects on the X axis."; - -editor.inputs.q = function () { - editor.comp_info = !editor.comp_info; -}; -editor.inputs.q.doc = "Toggle help for the selected component."; - -editor.inputs.f = function () { - return; - if (editor.selectlist.length === 0) return; - var bb = editor.selectlist[0].boundingbox(); - editor.selectlist.forEach(function (obj) { - bb = bbox.expand(bb, obj.boundingbox()); - }); - editor.zoom_to_bb(bb); -}; -editor.inputs.f.doc = "Find the selected objects."; - -editor.inputs["C-f"] = function () { - if (editor.selectlist.length !== 1) return; - - editor.edit_level = editor.selectlist[0]; - editor.unselect(); - editor.reset_undos(); -}; -editor.inputs["C-f"].doc = "Tunnel into the selected level object to edit it."; - -editor.inputs["M-f"] = function () { - if (editor.edit_level.master === world) return; - - editor.edit_level = editor.edit_level.master; - editor.unselect(); - editor.reset_undos(); -}; -editor.inputs["M-f"].doc = "Tunnel out of the level you are editing, saving it in the process."; -editor.inputs["C-r"] = function () { - editor.selectlist.forEach(function (x) { - x.rotate(-x.angle * 2); - }); -}; -editor.inputs["C-r"].doc = "Negate the selected's angle."; - -editor.inputs.r = function () { - if (editor.sel_comp && "angle" in editor.sel_comp) { - var relpos = input.mouse.worldpos().sub(editor.sel_comp.gameobject.pos); - return; - } - - editor.rotlist = editor.selectlist; -}; -editor.inputs.r.doc = "Rotate selected using the mouse while held down."; -editor.inputs.r.released = function () { - editor.rotlist = []; -}; - -editor.inputs.f5 = function () { - editor.start_play_ed(); -}; -editor.inputs.f5.doc = "Start game from 'debug' if it exists; otherwise, from 'game'."; - -editor.inputs.f6 = function () { - editor.start_play(); -}; -editor.inputs.f6.doc = "Start game as if the player started it."; - -editor.inputs["M-p"] = function () { - if (sim.playing()) sim.pause(); - - sim.step(); -}; -editor.inputs["M-p"].doc = "Do one time step, pausing if necessary."; - -editor.inputs["C-M-p"] = function () { - if (!sim.playing()) { - editor.start_play_ed(); - } - console.warn(`Starting edited level ...`); -}; -editor.inputs["C-M-p"].doc = "Start game from currently edited level."; - -editor.inputs["C-q"] = function () {}; -editor.inputs["C-q"].doc = "Quit simulation and return to editor."; - -var rebinder = {}; -rebinder.inputs = {}; -rebinder.inputs.any = function (cmd) {}; - -editor.inputs["C-space"] = function () {}; -editor.inputs["C-space"].doc = "Search to execute a specific command."; - -editor.inputs["M-m"] = function () { - // player[0].control(rebinder); -}; -editor.inputs["M-m"].doc = "Rebind a shortcut. Usage: M-m SHORTCUT TARGET"; - -editor.inputs["M-S-8"] = function () { - editor.camera_recall_pop(); -}; -editor.inputs["M-S-8"].doc = "Jump to last location."; - -editor.inputs.escape = function () { - editor.openpanel(quitpanel); -}; -editor.inputs.escape.doc = "Quit editor."; - -editor.inputs["C-s"] = function () { - var saveobj = undefined; - if (editor.selectlist.length === 0) { - if (editor.edit_level === editor.desktop) { - saveaspanel.stem = editor.edit_level.ur.toString(); - saveaspanel.obj = editor.edit_level; - editor.openpanel(saveaspanel); - return; - } else saveobj = editor.edit_level; - } else if (editor.selectlist.length === 1) saveobj = editor.selectlist[0]; - - saveobj.check_dirty(); - if (!saveobj._ed.dirty) { - console.warn(`Object ${saveobj.full_path()} does not need saved.`); - return; - } - - var savejs = saveobj.json_obj(); - var tur = saveobj.ur; - if (!tur) { - console.warn(`Can't save object because it has no ur.`); - return; - } - if (!tur.data) { - io.slurpwrite(tur.text.set_ext(".json"), json.encode(savejs, null, 1)); - tur.data = tur.text.set_ext(".json"); - } else { - var oldjs = json.decode(io.slurp(tur.data)); - Object.merge(oldjs, savejs); - io.slurpwrite(tur.data, json.encode(oldjs, null, 1)); - } - - Object.merge(tur.fresh, savejs); - saveobj.check_dirty(); - - // Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); }); - - return; - - game.all_objects(function (x) { - if (typeof x !== "object") return; - if (!("_ed" in x)) return; - if (x._ed.dirty) return; - x.revert(); - x.check_dirty(); - }); -}; -editor.inputs["C-s"].doc = "Save selected."; - -editor.inputs["C-S"] = function () { - if (editor.selectlist.length !== 1) return; - if (this.selectlist[0].ur !== "empty") saveaspanel.stem = this.selectlist[0].ur + "."; - else saveaspanel.stem = ""; - - saveaspanel.obj = this.selectlist[0]; - editor.openpanel(saveaspanel); -}; -editor.inputs["C-S"].doc = "Save selected as."; - -editor.inputs["C-z"] = function () { - editor.undo(); -}; -editor.inputs["C-z"].doc = "Undo the last change made."; - -editor.inputs["C-S-z"] = function () { - editor.redo(); -}; -editor.inputs["C-S-z"].doc = "Redo the last undo."; - -editor.inputs.t = function () { - editor.selectlist.forEach(function (x) { - x._ed.selectable = false; - }); -}; -editor.inputs.t.doc = "Lock selected objects to make them non selectable."; - -editor.inputs["M-t"] = function () { - editor.edit_level.objects.forEach(function (x) { - x._ed.selectable = true; - }); -}; -editor.inputs["M-t"].doc = "Unlock all objects in current level."; - -editor.inputs["C-n"] = editor.new_object; - -editor.inputs["C-o"] = function () { - editor.openpanel(openlevelpanel); -}; -editor.inputs["C-o"].doc = "Open a level."; - -editor.inputs["C-M-o"] = function () { - if (editor.selectlist.length === 1 && editor.selectlist[0].file) { - if (editor.edit_level._ed.dirty) return; - editor.load(editor.selectlist[0].file); - } -}; -editor.inputs["C-M-o"].doc = "Revert opened level back to its disk form."; - -editor.inputs["C-S-o"] = function () { - if (!editor.edit_level._ed.dirty) editor.load_prev(); -}; -editor.inputs["C-S-o"].doc = "Open previous level."; - -editor.inputs["C-y"] = function () { - texteditor.on_close = function () { - editor.edit_level.script = texteditor.value; - }; - - editor.openpanel(texteditor); - texteditor.value = ""; - texteditor.start(); -}; -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"].doc = "Toggle program mode."; - -editor.inputs.minus = function () { - if (!Object.empty(editor.selectlist)) { - editor.selectlist.forEach(function (x) { - x.draw_layer--; - }); - return; - } - - if (editor.working_layer > -1) editor.working_layer--; -}; -editor.inputs.minus.doc = "Go down one working layer, or, move selected objects down one layer."; - -editor.inputs.plus = function () { - if (!Object.empty(editor.selectlist)) { - editor.selectlist.forEach(x => x.draw_layer++); - return; - } - - if (editor.working_layer < 4) editor.working_layer++; -}; - -editor.inputs.plus.doc = "Go up one working layer, or, move selected objects down one layer."; - -editor.inputs["C-f1"] = function () { - editor.edit_mode = "basic"; -}; -editor.inputs["C-f1"].doc = "Enter basic edit mode."; -editor.inputs["C-f2"] = function () { - editor.edit_mode = "brush"; -}; -editor.inputs["C-f2"].doc = "Enter brush mode."; - -editor.inputs.f2 = function () { - if (this.selectlist.length !== 1) return; - objectexplorer.obj = this.selectlist[0]; - this.openpanel(objectexplorer); -}; -editor.inputs.f2.doc = "Open configurations object."; - -editor.inputs.f3 = function () { - if (this.selectlist.length !== 1) return; - this.openpanel(componentexplorer); -}; - -editor.inputs.lm = function () { - editor.sel_start = input.mouse.worldpos(); -}; -editor.inputs.lm.doc = "Selection box."; - -editor.inputs.lm.released = function () { - input.mouse.normal(); - editor.unselect(); - - if (!editor.sel_start) return; - - if (editor.sel_comp) { - editor.sel_start = undefined; - return; - } - - var selects = []; - - /* TODO: selects somehow gets undefined objects in here */ - if (Vector.equal(input.mouse.worldpos(), editor.sel_start, 5)) { - var sel = editor.try_select(); - if (sel) selects.push(sel); - } else { - var box = bbox.frompoints([editor.sel_start, input.mouse.worldpos()]); - - physics.box_query(bbox.tocwh(box), function (entity) { - var obj = editor.do_select(entity); - if (obj) selects.push(obj); - }); - } - - this.sel_start = undefined; - selects = selects.flat(); - selects = selects.unique(); - - if (Object.empty(selects)) return; - - if (input.keyboard.down("shift")) { - selects.forEach(function (x) { - this.selectlist.push_unique(x); - }, this); - - return; - } - - if (input.keyboard.down("ctrl")) { - selects.forEach(function (x) { - delete this.selectlist[x.toString()]; - }, this); - - return; - } - - editor.selectlist = []; - selects.forEach(function (x) { - if (x !== undefined) this.selectlist.push(x); - }, this); -}; - -editor.inputs.rm = function () { - if (editor.brush_obj) editor.brush_obj = undefined; - - if (editor.sel_comp) { - editor.sel_comp = undefined; - return; - } - - editor.unselect(); -}; - -editor.try_pick = function () { - editor.grabselect = []; - - if (editor.sel_comp && "pick" in editor.sel_comp) return editor.sel_comp.pick(input.mouse.worldpos()); - - return editor.try_select(); -}; - -editor.inputs.mm = function () { - if (editor.brush_obj) { - editor.selectlist = editor.dup_objects([editor.brush_obj]); - editor.selectlist[0].pos = input.mouse.worldpos(); - editor.grabselect = editor.selectlist[0]; - return; - } - - var o = editor.try_pick(); - if (!o) return; - // editor.selectlist = [o]; - editor.grabselect = [o]; -}; -editor.inputs["C-mm"] = editor.inputs.mm; - -editor.inputs["C-M-lm"] = function () { - var go = physics.pos_query(input.mouse.worldpos()); - if (!go) return; - editor.edit_level = go.master; -}; - -editor.inputs["C-M-mm"] = function () { - editor.mousejoy = input.mouse.screenpos(); - editor.joystart = editor.camera.pos; -}; - -editor.inputs["C-M-rm"] = function () { - editor.mousejoy = input.mouse.screenpos(); - editor.z_start = editor.camera.zoom; - input.mouse.disabled(); -}; - -editor.inputs.rm.released = function () { - editor.mousejoy = undefined; - editor.z_start = undefined; - input.mouse.normal(); -}; - -editor.inputs.mm.released = function () { - input.mouse.normal(); - this.grabselect = []; - editor.mousejoy = undefined; - editor.joystart = undefined; -}; -editor.inputs.mouse = {}; -editor.inputs.mouse.move = function (pos, dpos) { - if (editor.mousejoy) { - if (editor.z_start) editor.camera.zoom -= dpos.y / 500; - else if (editor.joystart) editor.camera.pos = editor.camera.pos.sub(game.camera.dir_view2world(dpos)); - } - - editor.grabselect?.forEach(function (x) { - x.move(game.camera.dir_view2world(dpos)); - x.sync(); - }); - - var relpos = input.mouse.worldpos().sub(editor.cursor); - var lastpos = relpos.sub(dpos); - - var dist = Vector.length(relpos.add(dpos)) - Vector.length(relpos); - var scalediff = 1 + dist / editor.scaleoffset; - - editor.scalelist?.forEach(function (x) { - x.grow(scalediff); - }); - - var anglediff = Math.atan2(relpos.y, relpos.x) - Math.atan2(lastpos.y, lastpos.x); - editor.rotlist?.forEach(function (x) { - x.rotate(anglediff / (2 * Math.PI)); - if (input.keyboard.down("shift")) { - var rotate = Math.nearest(x.angle, 1 / 24) - x.angle; - x.rotate(rotate); - } - }); -}; - -editor.inputs.mouse.scroll = function (scroll) { - scroll.y *= -1; - editor.camera.move(game.camera.dir_view2world(scroll.scale(-3))); -}; - -editor.inputs.mouse["C-scroll"] = function (scroll) { - editor.camera.zoom += scroll.y / 100; -}; - -editor.inputs["C-M-S-lm"] = function () { - editor.selectlist[0].set_center(input.mouse.worldpos()); -}; -editor.inputs["C-M-S-lm"].doc = "Set world center to mouse position."; - -editor.inputs.delete = function () { - this.selectlist.forEach(x => x.kill()); - this.unselect(); -}; -editor.inputs.delete.doc = "Delete selected objects."; -editor.inputs["S-d"] = editor.inputs.delete; -editor.inputs["C-k"] = editor.inputs.delete; - -editor.inputs["C-u"] = function () { - this.selectlist.forEach(x => x.revert()); -}; -editor.inputs["C-u"].doc = "Revert selected objects back to their prefab form."; - -editor.inputs["M-u"] = function () { - this.selectlist.forEach(function (x) { - x.unique = true; - }); -}; -editor.inputs["M-u"].doc = "Make selected objects unique."; - -editor.inputs["C-S-g"] = function () { - editor.openpanel(groupsaveaspanel); -}; -editor.inputs["C-S-g"].doc = "Save selected objects as a new level."; - -editor.inputs.g = function () { - if (editor.selectlist.length === 0) { - var o = editor.try_pick(); - if (!o) return; - editor.selectlist = [o]; - } - - if (editor.sel_comp) { - if ("pick" in editor.sel_comp) { - editor.grabselect = [editor.sel_comp.pick(input.mouse.worldpos())]; - return; - } - - if ("pos" in editor.sel_comp) { - var comp = editor.sel_comp; - var o = { - pos: editor.sel_comp.pos, - move(d) { - comp.pos = comp.pos.add(comp.gameobject.dir_world2this(d)); - }, - sync: comp.sync.bind(comp), - }; - editor.grabselect = [o]; - return; - } - } - - if (editor.sel_comp && "pick" in editor.sel_comp) { - var o = editor.sel_comp.pick(input.mouse.worldpos()); - if (o) editor.grabselect = [o]; - return; - } - - editor.grabselect = editor.selectlist.slice(); -}; - -editor.inputs.g.doc = "Move selected objects."; -editor.inputs.g.released = function () { - editor.grabselect = []; - input.mouse.normal(); -}; - -editor.inputs.up = function () { - this.key_move([0, 1]); -}; -editor.inputs.up.rep = true; - -editor.inputs.left = function () { - this.key_move([-1, 0]); -}; -editor.inputs.left.rep = true; - -editor.inputs.right = function () { - this.key_move([1, 0]); -}; -editor.inputs.right.rep = true; - -editor.inputs.down = function () { - this.key_move([0, -1]); -}; -editor.inputs.down.rep = true; - -editor.inputs.tab = function () { - if (!(this.selectlist.length === 1)) return; - if (!this.selectlist[0].components) return; - - var sel = this.selectlist[0].components; - - if (!this.sel_comp) this.sel_comp = sel.nth(0); - else { - var idx = sel.findIndex(this.sel_comp) + 1; - if (idx >= Object.keys(sel).length) this.sel_comp = undefined; - else this.sel_comp = sel.nth(idx); - } -}; -editor.inputs.tab.doc = "Cycle through selected object's components."; - -editor.inputs["C-g"] = function () { - if (!this.selectlist) return; - this.selectlist = this.dup_objects(this.selectlist); - editor.inputs.g(); -}; -editor.inputs["C-g"].doc = "Duplicate selected objects, then move them."; - -editor.inputs["M-g"] = function () { - if (this.sel_comp && "pick_all" in this.sel_comp) this.grabselect = this.sel_comp.pick_all(); -}; -editor.inputs["M-g"].doc = "Move all."; - -editor.inputs["C-lb"] = function () { - editor.grid_size -= input.keyboard.down("shift") ? 10 : 1; - if (editor.grid_size <= 0) editor.grid_size = 1; -}; -editor.inputs["C-lb"].doc = "Decrease grid size. Hold shift to decrease it more."; -editor.inputs["C-lb"].rep = true; - -editor.inputs["C-rb"] = function () { - editor.grid_size += input.keyboard.down("shift") ? 10 : 1; -}; -editor.inputs["C-rb"].doc = "Increase grid size. Hold shift to increase it more."; -editor.inputs["C-rb"].rep = true; - -editor.inputs["C-c"] = function () { - this.killring = []; - this.killcom = []; - this.killcom = physics.com(this.selectlist.map(x => x.pos)); - - this.selectlist.forEach(function (x) { - this.killring.push(x.instance_obj()); - }, this); -}; -editor.inputs["C-c"].doc = "Copy selected objects to killring."; - -editor.inputs["C-x"] = function () { - editor.inputs["C-c"].call(editor); - this.selectlist.forEach(function (x) { - x.kill(); - }); - editor.unselect(); -}; -editor.inputs["C-x"].doc = "Cut objects to killring."; - -editor.inputs["C-v"] = function () { - this.unselect(); - this.killring.forEach(function (x) { - editor.selectlist.push(editor.edit_level.spawn(x)); - }); - - this.selectlist.forEach(function (x) { - x.pos = x.pos.sub(this.killcom).add(this.cursor); - }, this); -}; -editor.inputs["C-v"].doc = "Pull objects from killring to world."; - -editor.inputs.char = function (c) { - if (c === "0") { - this.camera.pos = [0, 0]; - this.camera.zoom = 1; - } -}; - -var brushmode = {}; -brushmode.inputs = {}; -brushmode.inputs.lm = function () { - editor.inputs["C-v"].call(editor); -}; -brushmode.inputs.lm.doc = "Paste selected brush."; - -brushmode.inputs.b = function () { - if (editor.brush_obj) { - editor.brush_obj = undefined; - return; - } - - if (editor.selectlist.length !== 1) return; - editor.brush_obj = editor.seliectlist[0]; - editor.unselect(); -}; -brushmode.inputs.b.doc = "Clear brush, or set a new one."; - -var compmode = {}; -compmode.inputs = {}; -compmode.inputs["C-c"] = function () {}; /* Simply a blocker */ -compmode.inputs["C-x"] = function () {}; - -editor.scalelist = []; -editor.inputs.s = function () { - editor.scaleoffset = Vector.length(input.mouse.worldpos().sub(editor.cursor)); - editor.scalelist = []; - - if (editor.sel_comp) { - if (!("scale" in editor.sel_comp)) return; - editor.scalelist.push(editor.sel_comp); - return; - } - - editor.scalelist = editor.selectlist; -}; -editor.inputs.s.doc = "Scale selected."; - -editor.inputs.s.released = function () { - this.scalelist = []; -}; - -var replpanel = Object.copy(inputpanel, { - title: "", - closeonsubmit: false, - wh: [700, 300], - pos: [50, 50], - anchor: [0, 1], - padding: [0, 0], - scrolloffset: [0, 0], - - guibody() { - this.win.selectable = true; - var log = console.transcript; - }, - prevmark: -1, - prevthis: [], - - action() { - if (!this.value) return; - this.prevthis.unshift(this.value); - this.prevmark = -1; - var ecode = ""; - var repl_obj = editor.get_this(); - ecode += `var $ = repl_obj.objects;`; - for (var key in repl_obj.objects) ecode += `var ${key} = editor.edit_level.objects['${key}'];`; - - ecode += this.value; - say(this.value); - this.value = ""; - this.caret = 0; - var ret = function () { - return eval(ecode); - }.call(repl_obj); - if (typeof ret === "object") ret = json.encode(ret, null, 1); - if (typeof ret !== "undefined") say(ret); - }, - - resetscroll() { - this.scrolloffset.y = 0; - }, -}); - -replpanel.inputs = Object.create(inputpanel.inputs); -replpanel.inputs.block = true; -replpanel.inputs.lm = function () { - var mg = physics.pos_query(input.mouse.worldpos()); - if (!mg) return; - var p = mg.path_from(editor.get_this()); - this.value = p; - this.caret = this.value.length; -}; -replpanel.inputs.tab = function () { - this.resetscroll(); - if (!this.value) return; - var obj = globalThis; - var keys = []; - var keyobj = this.value.tolast("."); - var o = this.value.tolast("."); - var stub = this.value.fromlast("."); - var replobj = editor.selectlist.length === 1 ? "editor.selectlist[0]" : "editor.edit_level"; - - if (this.value.startsWith("this.")) keyobj = keyobj.replace("this", replobj); - - if (!this.value.includes(".")) keys.push("this"); - - if (eval(`typeof ${keyobj.tofirst(".")}`) === "object" && eval(`typeof ${keyobj.replace(".", "?.")}`) === "object") obj = eval(keyobj); - else if (this.value.includes(".")) { - say(`${this.value} is not an object.`); - return; - } - - for (var k in obj) keys.push(k); - - for (var k in editor.get_this()) keys.push(k); - - var comp = ""; - if (stub) comp = input.tabcomplete(stub, keys); - else if (!this.value.includes(".")) comp = input.tabcomplete(o, keys); - else comp = input.tabcomplete("", keys); - - if (stub) this.value = o + "." + comp; - else if (this.value.endsWith(".")) this.value = o + "." + comp; - else this.value = comp; - - this.caret = this.value.length; - - keys = keys.sort(); - - keys = keys.map(function (x) { - if (typeof obj[x] === "function") return esc.color(Color.Apple.orange) + x + esc.reset; - if (Object.isObject(obj[x])) return esc.color(Color.Apple.purple) + x + esc.reset; - if (Array.isArray(obj[x])) return esc.color(Color.Apple.green) + x + esc.reset; - - return x; - }); - - if (keys.length > 1) say(keys.join(", ")); -}; -replpanel.inputs["C-p"] = function () { - if (this.prevmark >= this.prevthis.length) return; - this.prevmark++; - this.value = this.prevthis[this.prevmark]; - this.inputs["C-e"].call(this); -}; - -replpanel.inputs["C-n"] = function () { - this.prevmark--; - if (this.prevmark < 0) { - this.prevmark = -1; - this.value = ""; - } else this.value = this.prevthis[this.prevmark]; - - this.inputs["C-e"].call(this); -}; - -replpanel.inputs.mouse = {}; -replpanel.inputs.mouse.scroll = function (scroll) { - if (!this.win.selected) return; - - this.scrolloffset.y += scroll.y; - if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; -}; - -replpanel.inputs.mm = function () { - this.mm = true; -}; -replpanel.inputs.mm.released = function () { - this.mm = false; -}; - -replpanel.inputs.mouse.move = function (pos, dpos) { - if (this.mm) this.scrolloffset.y -= dpos.y; -}; - -replpanel.inputs.up = function () { - this.scrolloffset.y += 40; -}; -replpanel.inputs.up.rep = true; -replpanel.inputs.down = function () { - this.scrolloffset.y -= 40; - if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; -}; -replpanel.inputs.down.rep = true; - -replpanel.inputs.pgup = function () { - this.scrolloffset.y += 300; -}; -replpanel.inputs.pgup.rep = true; - -replpanel.inputs.pgdown = function () { - this.scrolloffset.y -= 300; - if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; -}; -replpanel.inputs.pgdown.rep = true; - -var openlevelpanel = Object.copy(inputpanel, { - title: "open entity", - action() { - editor.load(this.value); - }, - - assets: [], - allassets: [], - - submit_check() { - if (this.assets.length === 0) return false; - - this.value = this.assets[0]; - return true; - }, - - start() { - this.allassets = ur._list.sort(); - this.assets = this.allassets.slice(); - this.caret = 0; - var click_ur = function (btn) { - this.value = btn.str; - this.keycb(); - this.submit(); - }; - click_ur = click_ur.bind(this); - }, - - keycb() { - if (this.value) this.assets = this.allassets.filter(x => x.startsWith(this.value)); - else this.assets = this.allassets.slice(); - }, this); - }, - - guibody() { - }, -}); - -/* Should set stem to the ur path folloed by a '.' before opening */ -var saveaspanel = Object.copy(inputpanel, { - get title() { - var full = this.stem ? this.stem : ""; - return `save level as: ${full}.`; - }, - - action() { - var saveur = this.value; - if (this.stem) saveur = this.stem + saveur; - editor.saveas_check(saveur, this.obj); - }, -}); - -var groupsaveaspanel = Object.copy(inputpanel, { - title: "group save as", - action() { - editor.groupsaveas(editor.selectlist, this.value); - }, -}); - -var allfiles = []; -allfiles.push(Resources.scripts, Resources.images, Resources.sounds); -allfiles = allfiles.flat(); - -var assetexplorer = Object.copy(openlevelpanel, { - title: "asset explorer", - extensions: allfiles, - closeonsubmit: false, - allassets: [], - action() { - if (editor.sel_comp && "asset" in editor.sel_comp) editor.sel_comp.asset = this.value; - else editor.viewasset(this.value); - }, -}); - -var entitylistpanel = Object.copy(inputpanel, { - title: "Level object list", - level: {}, - start() { - this.master = editor.edit_level; - }, -}); - -var limited_editor = {}; - -limited_editor.inputs = {}; - -limited_editor.inputs["C-p"] = function () { - if (sim.playing()) sim.pause(); - else sim.play(); -}; - -limited_editor.inputs["M-p"] = function () { - sim.pause(); - sim.step(); -}; - -limited_editor.inputs["C-q"] = function () { - world.clear(); - global.mixin("editorconfig.js"); - global.mixin("dbgret.js"); - - editor.enter_editor(); -}; - -/* This is used for editing during a paused game */ -var limited_editing = {}; -limited_editing.inputs = {}; - -/* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */ -sim.pause(); -window.editor = true; -debug.draw_phys = true; - -return { - editor, -}; diff --git a/scripts/engine.js b/scripts/engine.js index ba83cfc9..3a715f27 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -497,6 +497,5 @@ var search = use('search') actor[UNDERLINGS] = new Set() - globalThis.mixin("color"); globalThis.mixin("std") diff --git a/scripts/gizmos.js b/scripts/gizmos.js deleted file mode 100644 index 4756661d..00000000 --- a/scripts/gizmos.js +++ /dev/null @@ -1,26 +0,0 @@ -var ex = {} - -ex.pick_gameobject_points = function pick_gameobject_points(worldpos, gameobject, points) { - var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world, gameobject), 25); - if (idx === -1) return undefined; - return idx; -} - -ex.normalizeSpacing = function normalizeSpacing(spacing) { - if (typeof spacing === 'number') { - return {l: spacing, r: spacing, t: spacing, b: spacing}; - } else if (Array.isArray(spacing)) { - if (spacing.length === 2) { - return {l: spacing[0], r: spacing[0], t: spacing[1], b: spacing[1]}; - } else if (spacing.length === 4) { - return {l: spacing[0], r: spacing[1], t: spacing[2], b: spacing[3]}; - } - } else if (typeof spacing === 'object') { - return {l: spacing.l || 0, r: spacing.r || 0, t: spacing.t || 0, b: spacing.b || 0}; - } else { - return {l:0, r:0, t:0, b:0}; - } -} - - -return ex diff --git a/scripts/layout.js b/scripts/layout.js index 88c5d5d2..a3c85e4f 100644 --- a/scripts/layout.js +++ b/scripts/layout.js @@ -4,7 +4,7 @@ var geometry = use('geometry') var render = use('render') var graphics = use('graphics') -var gizmo = use('gizmos') +var util = use('util') var lay_ctx = layout.make_context(); @@ -50,7 +50,7 @@ layout.draw = function draw(size, fn, config = {}) box.content = lay_ctx.get_rect(box.id); box.boundingbox = Object.assign({}, box.content); - var padding = gizmo.normalizeSpacing(box.config.padding || 0); + var padding = util.normalizeSpacing(box.config.padding || 0); if (padding.l || padding.r || padding.t || padding.b) { // Adjust the boundingbox to include the padding box.boundingbox.x -= padding.l; @@ -59,7 +59,7 @@ layout.draw = function draw(size, fn, config = {}) box.boundingbox.height += padding.t + padding.b; } box.marginbox = Object.assign({}, box.content); - var margin = gizmo.normalizeSpacing(box.config.margin || 0); + var margin = util.normalizeSpacing(box.config.margin || 0); box.marginbox.x -= margin.l; box.marginbox.y -= margin.t; box.marginbox.width += margin.l+margin.r; @@ -113,8 +113,8 @@ function image_size(img) function add_item(config) { // Normalize the child's margin - var margin = gizmo.normalizeSpacing(config.margin || 0); - var padding = gizmo.normalizeSpacing(config.padding || 0); + var margin = util.normalizeSpacing(config.margin || 0); + var padding = util.normalizeSpacing(config.padding || 0); var childGap = root_config.child_gap || 0; // Adjust for child_gap diff --git a/scripts/log.js b/scripts/log.js deleted file mode 100644 index 4a136de9..00000000 --- a/scripts/log.js +++ /dev/null @@ -1,38 +0,0 @@ -var io = use('io') - -var log = { - // Holds config per log name - config: {}, - - // Enable a named log, generating a method if needed - enable(name, outputs) { - if (!this.config[name]) this.config[name] = { enabled: false, outputs: [] } - this.config[name].enabled = true - if (!Array.isArray(outputs) && outputs != null) outputs = [outputs] - if (outputs) outputs.forEach(o => this.config[name].outputs.push(o)) - - // Dynamically add log method if it doesn't exist - if (!this[name]) { - this[name] = msg => this._write(name, msg) - } - }, - - // Disable a named log - disable(name) { - if (this.config[name]) this.config[name].enabled = false - }, - - // Internal method to actually write the log - _write(name, msg) { - let c = this.config[name] - if (!c || !c.enabled) return - let entry = '[' + name + '] ' + msg - c.outputs.forEach(o => { - if (o.console) console.print(entry + '\n') - if (o.file) o.file.write(entry + '\n') - if (o.buffer) o.buffer.push(entry) - }) - } -} - -return log diff --git a/scripts/parseq.js b/scripts/parseq.js deleted file mode 100644 index ae69821e..00000000 --- a/scripts/parseq.js +++ /dev/null @@ -1,590 +0,0 @@ -// parseq.js -// Douglas Crockford -// 2020-11-09 - -// Better living thru eventuality! - -// You can access the parseq object in your module by importing it. -// import parseq from "./parseq.js"; - -/*jslint node */ - -/*property - concat, create, evidence, fallback, forEach, freeze, isArray, isSafeInteger, - keys, length, min, parallel, parallel_object, pop, push, race, sequence, - some -*/ - -function make_reason(factory_name, excuse, evidence) { - -// Make a reason object. These are used for exceptions and cancellations. -// They are made from Error objects. - - const reason = new Error("parseq." + factory_name + ( - excuse === undefined - ? "" - : ": " + excuse - )); - reason.evidence = evidence; - return reason; -} - -function get_array_length(array, factory_name) { - if (Array.isArray(array)) { - return array.length; - } - if (array === undefined) { - return 0; - } - throw make_reason(factory_name, "Not an array.", array); -} - -function check_callback(callback, factory_name) { - if (typeof callback !== "function" || callback.length !== 2) { - throw make_reason(factory_name, "Not a callback function.", callback); - } -} - -function check_requestors(requestor_array, factory_name) { - -// A requestor array contains only requestors. A requestor is a function that -// takes wun or two arguments: 'callback' and optionally 'initial_value'. - - if (requestor_array.some(function (requestor) { - return ( - typeof requestor !== "function" - || requestor.length < 1 - || requestor.length > 2 - ); - })) { - throw make_reason( - factory_name, - "Bad requestors array.", - requestor_array - ); - } -} - -function run( - factory_name, - requestor_array, - initial_value, - action, - timeout, - time_limit, - throttle = 0 -) { - -// The 'run' function does the work that is common to all of the Parseq -// factories. It takes the name of the factory, an array of requestors, an -// initial value, an action callback, a timeout callback, a time limit in -// milliseconds, and a throttle. - -// If all goes well, we call all of the requestor functions in the array. Each -// of them might return a cancel function that is kept in the 'cancel_array'. - - let cancel_array = new Array(requestor_array.length); - let next_number = 0; - let timer_id; - -// We need 'cancel' and 'start_requestor' functions. - - function cancel(reason = make_reason(factory_name, "Cancel.")) { - -// Stop all unfinished business. This can be called when a requestor fails. -// It can also be called when a requestor succeeds, such as 'race' stopping -// its losers, or 'parallel' stopping the unfinished optionals. - -// If a timer is running, stop it. - - if (timer_id !== undefined) { - clearTimeout(timer_id); - timer_id = undefined; - } - -// If anything is still going, cancel it. - - if (cancel_array !== undefined) { - cancel_array.forEach(function (cancel) { - try { - if (typeof cancel === "function") { - return cancel(reason); - } - } catch (ignore) {} - }); - cancel_array = undefined; - } - } - - function start_requestor(value) { - -// The 'start_requestor' function is not recursive, exactly. It does not -// directly call itself, but it does return a function that might call -// 'start_requestor'. - -// Start the execution of a requestor, if there are any still waiting. - - if ( - cancel_array !== undefined - && next_number < requestor_array.length - ) { - -// Each requestor has a number. - - let number = next_number; - next_number += 1; - -// Call the next requestor, passing in a callback function, -// saving the cancel function that the requestor might return. - - const requestor = requestor_array[number]; - try { - cancel_array[number] = requestor( - function start_requestor_callback(value, reason) { - -// This callback function is called by the 'requestor' when it is done. -// If we are no longer running, then this call is ignored. -// For example, it might be a result that is sent back after the time -// limit has expired. This callback function can only be called wunce. - - if ( - cancel_array !== undefined - && number !== undefined - ) { - -// We no longer need the cancel associated with this requestor. - - cancel_array[number] = undefined; - -// Call the 'action' function to let the requestor know what happened. - - action(value, reason, number); - -// Clear 'number' so this callback can not be used again. - - number = undefined; - -// If there are any requestors that are still waiting to start, then -// start the next wun. If the next requestor is in a sequence, then it -// gets the most recent 'value'. The others get the 'initial_value'. - - setTimeout(start_requestor, 0, ( - factory_name === "sequence" - ? value - : initial_value - )); - } - }, - value - ); - -// Requestors are required to report their failure thru the callback. -// They are not allowed to throw exceptions. If we happen to catch wun, -// it is treated as a failure. - - } catch (exception) { - action(undefined, exception, number); - number = undefined; - start_requestor(value); - } - } - } - -// With the 'cancel' and the 'start_requestor' functions in hand, -// we can now get to work. - -// If a timeout was requested, start the timer. - - if (time_limit !== undefined) { - if (typeof time_limit === "number" && time_limit >= 0) { - if (time_limit > 0) { - timer_id = setTimeout(timeout, time_limit); - } - } else { - throw make_reason(factory_name, "Bad time limit.", time_limit); - } - } - -// If we are doing 'race' or 'parallel', we want to start all of the requestors -// at wunce. However, if there is a 'throttle' in place then we start as many -// as the 'throttle' allows, and then as each requestor finishes, another is -// started. - -// The 'sequence' and 'fallback' factories set 'throttle' to 1 because they -// process wun at a time and always start another requestor when the -// previous requestor finishes. - - if (!Number.isSafeInteger(throttle) || throttle < 0) { - throw make_reason(factory_name, "Bad throttle.", throttle); - } - let repeat = Math.min(throttle || Infinity, requestor_array.length); - while (repeat > 0) { - setTimeout(start_requestor, 0, initial_value); - repeat -= 1; - } - -// We return 'cancel' which allows the requestor to cancel this work. - - return cancel; -} - -// The factories /////////////////////////////////////////////////////////////// - -function parallel( - required_array, - optional_array, - time_limit, - time_option, - throttle, - factory_name = "parallel" -) { - -// The parallel factory is the most complex of these factories. It can take -// a second array of requestors that get a more forgiving failure policy. -// It returns a requestor that produces an array of values. - - let requestor_array; - -// There are four cases because 'required_array' and 'optional_array' -// can both be empty. - - let number_of_required = get_array_length(required_array, factory_name); - if (number_of_required === 0) { - if (get_array_length(optional_array, factory_name) === 0) { - -// If both are empty, then 'requestor_array' is empty. - - requestor_array = []; - } else { - -// If there is only 'optional_array', then it is the 'requestor_array'. - - requestor_array = optional_array; - time_option = true; - } - } else { - -// If there is only 'required_array', then it is the 'requestor_array'. - - if (get_array_length(optional_array, factory_name) === 0) { - requestor_array = required_array; - time_option = undefined; - -// If both arrays are provided, we concatenate them together. - - } else { - requestor_array = required_array.concat(optional_array); - if (time_option !== undefined && typeof time_option !== "boolean") { - throw make_reason( - factory_name, - "Bad time_option.", - time_option - ); - } - } - } - -// We check the array and return the requestor. - - check_requestors(requestor_array, factory_name); - return function parallel_requestor(callback, initial_value) { - check_callback(callback, factory_name); - let number_of_pending = requestor_array.length; - let number_of_pending_required = number_of_required; - let results = []; - if (number_of_pending === 0) { - callback( - factory_name === "sequence" - ? initial_value - : results - ); - return; - } - -// 'run' gets it started. - - let cancel = run( - factory_name, - requestor_array, - initial_value, - function parallel_action(value, reason, number) { - -// The action function gets the result of each requestor in the array. -// 'parallel' wants to return an array of all of the values it sees. - - results[number] = value; - number_of_pending -= 1; - -// If the requestor was wun of the requireds, make sure it was successful. -// If it failed, then the parallel operation fails. If an optionals requestor -// fails, we can still continue. - - if (number < number_of_required) { - number_of_pending_required -= 1; - if (value === undefined) { - cancel(reason); - callback(undefined, reason); - callback = undefined; - return; - } - } - -// If all have been processed, or if the requireds have all succeeded -// and we do not have a 'time_option', then we are done. - - if ( - number_of_pending < 1 - || ( - time_option === undefined - && number_of_pending_required < 1 - ) - ) { - cancel(make_reason(factory_name, "Optional.")); - callback( - factory_name === "sequence" - ? results.pop() - : results - ); - callback = undefined; - } - }, - function parallel_timeout() { - -// When the timer fires, work stops unless we were under the 'false' -// time option. The 'false' time option puts no time limits on the -// requireds, allowing the optionals to run until the requireds finish -// or the time expires, whichever happens last. - - const reason = make_reason( - factory_name, - "Timeout.", - time_limit - ); - if (time_option === false) { - time_option = undefined; - if (number_of_pending_required < 1) { - cancel(reason); - callback(results); - } - } else { - -// Time has expired. If all of the requireds were successful, -// then the parallel operation is successful. - - cancel(reason); - if (number_of_pending_required < 1) { - callback(results); - } else { - callback(undefined, reason); - } - callback = undefined; - } - }, - time_limit, - throttle - ); - return cancel; - }; -} - -function parallel_object( - required_object, - optional_object, - time_limit, - time_option, - throttle -) { - -// 'parallel_object' is similar to 'parallel' except that it takes and -// produces objects of requestors instead of arrays of requestors. This -// factory converts the objects to arrays, and the requestor it returns -// turns them back again. It lets 'parallel' do most of the work. - - const names = []; - let required_array = []; - let optional_array = []; - -// Extract the names and requestors from 'required_object'. -// We only collect functions with an arity of 1 or 2. - - if (required_object) { - if (typeof required_object !== "object") { - throw make_reason( - "parallel_object", - "Type mismatch.", - required_object - ); - } - Object.keys(required_object).forEach(function (name) { - let requestor = required_object[name]; - if ( - typeof requestor === "function" - && (requestor.length === 1 || requestor.length === 2) - ) { - names.push(name); - required_array.push(requestor); - } - }); - } - -// Extract the names and requestors from 'optional_object'. -// Look for duplicate keys. - - if (optional_object) { - if (typeof optional_object !== "object") { - throw make_reason( - "parallel_object", - "Type mismatch.", - optional_object - ); - } - Object.keys(optional_object).forEach(function (name) { - let requestor = optional_object[name]; - if ( - typeof requestor === "function" - && (requestor.length === 1 || requestor.length === 2) - ) { - if (required_object && required_object[name] !== undefined) { - throw make_reason( - "parallel_object", - "Duplicate name.", - name - ); - } - names.push(name); - optional_array.push(requestor); - } - }); - } - -// Call 'parallel' to get a requestor. - - const parallel_requestor = parallel( - required_array, - optional_array, - time_limit, - time_option, - throttle, - "parallel_object" - ); - -// Return the parallel object requestor. - - return function parallel_object_requestor(callback, initial_value) { - -// When our requestor is called, we return the result of our parallel requestor. - - return parallel_requestor( - -// We pass our callback to the parallel requestor, -// converting its value into an object. - - function parallel_object_callback(value, reason) { - if (value === undefined) { - return callback(undefined, reason); - } - const object = Object.create(null); - names.forEach(function (name, index) { - object[name] = value[index]; - }); - return callback(object); - }, - initial_value - ); - }; -} - -function race(requestor_array, time_limit, throttle) { - -// The 'race' factory returns a requestor that starts all of the -// requestors in 'requestor_array' at wunce. The first success wins. - - const factory_name = ( - throttle === 1 - ? "fallback" - : "race" - ); - - if (get_array_length(requestor_array, factory_name) === 0) { - throw make_reason(factory_name, "No requestors."); - } - check_requestors(requestor_array, factory_name); - return function race_requestor(callback, initial_value) { - check_callback(callback, factory_name); - let number_of_pending = requestor_array.length; - let cancel = run( - factory_name, - requestor_array, - initial_value, - function race_action(value, reason, number) { - number_of_pending -= 1; - if (value !== undefined) { - -// We have a winner. Cancel the losers and pass the value to the 'callback'. - - cancel(make_reason(factory_name, "Loser.", number)); - callback(value); - callback = undefined; - } else if (number_of_pending < 1) { - -// There was no winner. Signal a failure. - - cancel(reason); - callback(undefined, reason); - callback = undefined; - } - }, - function race_timeout() { - let reason = make_reason( - factory_name, - "Timeout.", - time_limit - ); - cancel(reason); - callback(undefined, reason); - callback = undefined; - }, - time_limit, - throttle - ); - return cancel; - }; -} - -function fallback(requestor_array, time_limit) { - -// The 'fallback' factory returns a requestor that tries each requestor -// in 'requestor_array', wun at a time, until it finds a successful wun. - - return race(requestor_array, time_limit, 1); -} - -function sequence(requestor_array, time_limit) { - -// A sequence runs each requestor in order, passing results to the next, -// as long as they are all successful. A sequence is a throttled parallel. - - return parallel( - requestor_array, - undefined, - time_limit, - undefined, - 1, - "sequence" - ); - -} - -function devnull(value, reason){} - -function imm(fn) { return function imm(callback,value) { fn?.(); callback(true); } } - -return { - fallback:fallback, - parallel:parallel, - parallel_object:parallel_object, - race:race, - sequence:sequence, - devnull:devnull, - imm:imm -}; diff --git a/scripts/path.js b/scripts/path.js deleted file mode 100644 index 3930b662..00000000 --- a/scripts/path.js +++ /dev/null @@ -1,22 +0,0 @@ -var path = {} - -path.name = function name(str) -{ - var idx = str.indexOf("/"); - if (idx === -1) return str.tolast("."); - return str.fromlast("/").tolast("."); -} - -path.dir = function (str) { - if (!str.includes("/")) return ""; - var idx = str.lastIndexOf(s - return str.tolast("/"); -} - -path.folder = function(str) { - var dir = this.dir(); - if (!dir) return ""; - else return dir + "/"; -} - -return path diff --git a/scripts/physics.js b/scripts/physics.js deleted file mode 100644 index 03ba3abb..00000000 --- a/scripts/physics.js +++ /dev/null @@ -1,62 +0,0 @@ -/* On collisions, entities are sent a 'hit' object, which looks like this: -var HIT = { - normal: "The normal of the collision point.", - obj: "The gameobject of the object that collided.", - sensor: "Boolean for if the colliding object was a sensor.", - velocity: "Velocity of the contact.", - pos: "Position in world space of the contact.", - depth: "Depth of the contact.", -}; -*/ - -var vector = use('vector') - -var phys = {}; - -phys.pos_query = function pos_query(pos, start = world, give = 10) { - var ret; - ret = physics.point_query_nearest(pos, 0); - - if (ret) return ret.entity; - - return game.all_objects(function (o) { - var dist = vector.length(o.pos.sub(pos)); - if (dist <= give) return o; - }); -}; - -phys.box_point_query = function box_point_query(box, points) { -/* if (!box || !points) return []; - var bbox = bbox.fromcwh(box.pos, box.wh); - var inside = []; - for (var i in points) if (bbox.pointin(bbox, points[i])) inside.push[i]; - return inside;*/ -}; - -Object.assign(physics, { - dynamic: 0, - kinematic: 1, - static: 2, - - com(pos) { - if (!Array.isArray(pos)) return [0, 0]; - return pos.reduce((a, i) => a.add(i)).map(g => g / pos.length); - }, -}); - -physics.doc = {}; -physics.doc.pos_query = "Returns any object colliding with the given point."; -physics.doc.box_query = "Calls a given function on every shape object in the given bbox."; -physics.doc.box_point_query = "Returns the subset of points from a given list that are inside a given box."; - -physics.gravity = physics.make_gravity(); -physics.gravity.mask = ~1; -physics.gravity.strength = 500; -physics.damp = physics.make_damp(); -physics.damp.mask = ~1; - -physics.delta = 1 / 240; - -return { - physics, -}; diff --git a/scripts/profile.js b/scripts/profile.js deleted file mode 100644 index ef4427a7..00000000 --- a/scripts/profile.js +++ /dev/null @@ -1,392 +0,0 @@ -var profile = this - -var pmath = use('pmath') - -/* - TYPES OF PROFILING - report - can see specific events that happened. Includes inclusive vs noninclusive times. When used on top of each other, also generates a callstack. - snapshot - See the amount of something every amount of time - memory - can see how much memory is allocated and from where [not implemented yet] -*/ - -var graphics = use('graphics') - -function calc_cpu(fn, times, diff = 0) { - var series = []; - - for (var i = 0; i < times; i++) { - var st = profile.now(); - fn(i); - series.push(profile.now() - st - diff); - } - - return series; -} - -function empty_fn() {} - -// Measure how long a fn takes to run, ignoring the overhead of a function call -profile.cpu = function profile_cpu(fn, times = 1, q = fn) { - var empty = calc_cpu(empty_fn, 100000); - var mean = Math.mean(empty); - var series = calc_cpu(fn, times, mean); - - var elapsed = Math.sum(series); - var avgt = profile.best_t(elapsed / series.length); - var totalt = profile.best_t(elapsed); - - say(`profile [${q}]: ${avgt} ± ${profile.best_t(Math.ci(series))} [${totalt} for ${times} loops]`); - say(`result of function is ${fn()}`); -}; - -profile.ms = function (t) { - return profile.secs(t) * 1000; -}; - -var callgraph = {}; -profile.rawstacks = {}; - -function add_callgraph_from_stack(err, time) -{ - var stack = err.stack.split("\n").slice(1); - var rawstack = stack.join("\n"); - profile.rawstacks[rawstack] ??= { - time: 0, - hits: 0, - }; - profile.rawstacks[rawstack].hits++; - profile.rawstacks[rawstack].time += time; - - stack = stack.map(x => x.slice(7).split(" ")); - - var fns = stack.map(x => x[0]).filter(x => x); - var lines = stack.map(x => x[1]).filter(x => x); - lines = lines.map(x => x.slice(1, x.length - 1)); - - add_callgraph(fns[0], lines[0], time, true); - for (var i = 1; i < fns.length; i++) add_callgraph(fns[i], lines[i], time, false); -} - -function add_callgraph(fn, line, time, alone) { - var cc = callgraph[line]; - if (!cc) { - var cc = {}; - callgraph[line] = cc; - cc.time = 0; - cc.hits = 0; - cc.fn = fn; - cc.line = line; - cc.alone = { - time: 0, - hits: 0, - }; - } - cc.time += time; - cc.hits++; - - if (alone) { - cc.alone.time += time; - cc.alone.hits++; - } -} - -var hittar = 500; // number of call instructions before getting a new frame -var hitpct = 0.2; // amount to randomize it - -profile.cpu_start = undefined; - -profile.clear_cpu = function () { - callgraph = {}; - profile.cpu_instr = undefined; - profile.gather_stop(); - profile.cpu_start = undefined; -}; - -function cpu_record_frame() -{ - -} - -// These values are set to get the most amount of frames without causing a stack overflow -var hittar = 450; -var hitpct = 0.2; - -profile.start_cpu_gather_fn = function() -{ - if (profile.cpu_start) return; - profile.clear_cpu(); - - profile.cpu_start = profile.now(); - var st = profile.cpu_start; - - profile.gather(pmath.variate(hittar,hitpct), function() { - var time = profile.now() - st; - var err = new Error(); - add_callgraph_from_stack(err, time); - st = profile.now(); - profile.gather_rate(pmath.variate(hittar,hitpct)); - }); -} - -profile.start_cpu_gather = function (gathertime = 5) { - if (profile.cpu_start) return; - profile.clear_cpu(); - - // gather cpu frames for 'gathertime' seconds - profile.cpu_start = profile.now(); - var st = profile.cpu_start; - - profile.gather(hittar, function () { - var time = profile.now() - st; - - var err = new Error(); - add_callgraph_from_stack(err, time); - st = profile.now(); - - if (profile.secs(st - profile.cpu_start) < gathertime) - profile.gather_rate(pmath.variate(hittar, hitpct)); - else - profile.stop_cpu_measure(); - }); -}; - -profile.stop_cpu_measure = function() -{ - if (!profile.cpu_start) return; - profile.gather_stop(); - var gathertime = profile.now()-profile.cpu_start; - console.info(`gathered for ${profile.best_t(gathertime)}`); - profile.cpu_start = undefined; - var e = Object.values(callgraph); - e = e.filter(x => x.line); - - for (var x of e) { - var ffs = x.line.split(":"); - - x.timeper = x.time / x.hits; - x.pct = x.time/gathertime * 100; - x.alone.timeper = x.alone.time / x.alone.hits; - x.alone.pct = x.alone.time / gathertime * 100; - x.fncall = get_line(ffs[0], ffs[1]); - x.log = x.line + " " + x.fn + " " + x.fncall; - x.incl = { - time: x.time, - timeper: x.timeper, - hits: x.hits, - pct: x.pct, - }; - } - profile.cpu_instr = e; -} - -var filecache = {}; -function get_line(file, line) { - var text = filecache[file]; - if (!text) { - var f = io.slurp(file); - if (!f) { - filecache[file] = "undefined"; - return filecache[file]; - } - filecache[file] = io.slurp(file).split("\n"); - text = filecache[file]; - } - - if (typeof text === "string") return text; - text = text[Number(line) - 1]; - if (!text) return "NULL"; - return text.trim(); -} - -profile.stop_cpu_instr = function () { - return; -}; - -/* - Frame averages are an instrumented profiling technique. Place frame() calls - in your code to get a call graph for things you are interested in. -*/ - -var frame_avg = false; - -profile.start_frame_avg = function () { - if (frame_avg) return; - profile_frames = {}; - profile_frame_ts = []; - profile_cframe = profile_frames; - pframe = 0; - frame_avg = true; -}; - -profile.stop_frame_avg = function () { - frame_avg = false; -}; - -profile.toggle_frame_avg = function () { - if (frame_avg) profile.stop_frame_avg(); - else profile.start_frame_avg(); -}; - -var profile_framer = { - series: [], - avg: {}, - frame: 72000, -}; -var profile_cframe = undefined; -var pframe = 0; -var profile_stack = []; - -profile.frame = function profile_frame(title) { - return; - if (profile.cpu_start) return; - if (!frame_avg) return; - - if (!profile_cframe) { - profile_cframe = {}; - profile_framer.series.push({ - time: profile.now(), - data: profile_cframe, - }); - } else profile_stack.push(profile_cframe); - - profile_cframe[title] ??= {}; - profile_cframe = profile_cframe[title]; - profile_cframe.time = profile.now(); -}; - -profile.endframe = function profile_endframe() { - return; - if (!frame_avg) return; - profile_cframe.time = profile.now() - profile_cframe.time; - profile_cframe = profile_frame_ts.pop(); -}; - -profile.data = {}; -profile.curframe = 0; -profile.snapshot = {}; - -var get_snapshot = function() -{ - var snap = profile.snapshot; - - for (var monitor of monitors) { - var stat = monitor.fn(); - monitor.hook?.(stat); - snap[monitor.path] = stat; - } - - snap.actors = actor.__stats(); - snap.memory.textures = graphics.texture.total_size(); - snap.memory.texture_vram = graphics.texture.total_vram(); - - snap.particles = stat_emitters(); -} - -var monitors = []; - -profile.add_custom_monitor = function(path, fn, hook) -{ - monitors.push({ - path:path, - fn:fn, - hook:hook - }); -} - -profile.add_custom_monitor('rusage', os.rusage, stat => stat.ru_maxrss *= 1024); -profile.add_custom_monitor('mallinfo', os.mallinfo); -profile.add_custom_monitor('memory', os.mem); - -var fps = []; -var frame_lead = 1; -var fps_t = 0; -profile.report_frame = function (t) { - fps.push(t); - if (profile.secs(profile.now() - fps_t) > frame_lead) { - profile.snapshot.fps = Math.mean(fps); - fps.length = 0; - fps_t = profile.now(); - get_snapshot(); - } -} - -profile.reports = {}; - -profile.report = function(path) -{ - profile.reports[path] ??= { - report: path, - time: 0, - hits: 0, - avg: 0 - }; - if (profile.reports[path].st) return; - profile.reports[path].st = profile.now(); -} - -profile.endreport = function endreport(path) -{ - var rep = profile.reports[path]; - if (!rep || !rep.st) return; - rep.hits++; - rep.time += profile.now()-rep.st; - delete rep.st; - rep.avg = rep.time/rep.hits; - - profile.report_cache = Object.values(profile.reports); -} - -function prof_add_stats(obj, stat) { - for (var i in stat) { - obj[i] ??= []; - if (obj[i].last() !== stat[i]) obj[i][profile.curframe] = stat[i]; - } -} - -profile.pushdata = function (arr, val) { - if (arr.last() !== val) arr[profile.curframe] = val; -}; - -profile.capturing = false; -profile.capture_data = function () { - if (!profile.capturing && profile.data.memory.malloc_size) return; - prof_add_stats(profile.data.memory, os.mem()); - prof_add_stats(profile.data.gfx, imgui.framestats()); - prof_add_stats(profile.data.actors, actor.__stats()); - profile.curframe++; -}; - -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.cleardata = function () { - profile.data.gpu = {}; - profile.data.physics = {}; - profile.data.script = {}; - profile.data.memory = {}; - profile.data.gfx = {}; - profile.data.actors = {}; - profile.data.cpu = { - scripts: [], - render: [], - physics: [], - }; -}; - -profile.cleardata(); - -profile.last_mem = undefined; -profile.mems = []; -profile.gcs = []; -profile.print_gc = function () { - var gc = os.check_gc(); - if (!gc) return; - profile.data.gc ??= []; - profile.data.gc[profile.curframe] = gc; -}; - -return profile diff --git a/scripts/render.js b/scripts/render.js index 4396d353..9a513e18 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -1,13 +1,12 @@ var render = {} -var profile = use('profile') var config = use('config.js') -var gizmo = use('gizmos') var vector = use('vector') -var search = use('search') var io = use('io') var os = use('os') - +var util = use('util') +var emitter = use('emitter') var input = use('input') +var sprite = use('sprite') var appy = {}; appy.inputs = {}; @@ -15,19 +14,6 @@ if (os.sys() === "macos") { appy.inputs["S-q"] = os.exit; } -appy.inputs.f7 = function () { - debug.meta = !debug.meta; -}; -appy.inputs.f8 = function () { - debug.cheat = !debug.cheat; -}; -appy.inputs.f9 = function () { - debug.console = !debug.console; -}; -appy.inputs.f10 = function () { - debug.show = !debug.show; -}; - appy.inputs["M-f4"] = os.exit; input.player[0].control(appy); @@ -58,12 +44,6 @@ var graphics = use('graphics') var unit_transform = os.make_transform(); -render.doc = { - doc: "Functions for rendering modes.", - normal: "Final render with all lighting.", - wireframe: "Show only wireframes of models.", -}; - var cur = {}; cur.images = []; cur.samplers = []; @@ -763,13 +743,13 @@ function gpupresent() }); // imgui - cmds.push_debug_group("imgui") +/* cmds.push_debug_group("imgui") imgui.prepend(cmds); var pass = cmds.render_pass({ color_targets:[{texture:swapchain_tex}]}); imgui.endframe(cmds,pass); pass.end(); - cmds.pop_debug_group() + cmds.pop_debug_group()*/ } cmds.submit() } @@ -785,7 +765,6 @@ render.draw_sprites = true; render.draw_particles = true; render.draw_hud = true; render.draw_gui = true; -render.draw_gizmos = true; function insertion_sort(arr, cmp) { @@ -799,7 +778,7 @@ function insertion_sort(arr, cmp) return arr } -var sprite = use('sprite') + function sprites_to_queue(ysort = false) { @@ -1101,12 +1080,13 @@ var slice9_info = { tile_center_x:true, tile_center_right:true }; + render.slice9 = function slice9(image, rect = [0,0], slice = 0, color = Color.white, info = slice9_info, pipeline = sprite_pipeline) { if (!image) throw Error ('Need an image to render.') if (typeof image === "string") image = graphics.texture(image); - var mesh = render._main.slice9(image.texture, rect, gizmo.normalizeSpacing(slice), info); + var mesh = render._main.slice9(image.texture, rect, util.normalizeSpacing(slice), info); current_queue.push({ type: 'geometry', mesh, @@ -1115,8 +1095,6 @@ render.slice9 = function slice9(image, rect = [0,0], slice = 0, color = Color.wh first_index:0, num_indices:mesh.num_indices }); -// render.image(image,rect,undefined,color); -// render._main.slice9(image.texture, rect, slice); }; var textssbos = []; @@ -1167,12 +1145,6 @@ function screen2cam(pos) { screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera."; -prosperon.gizmos = function gizmos() { - search.all_objects(o => { - if (o.gizmo) render.image(graphics.texture(o.gizmo), o.pos); - }); -}; - function screen2hud(pos) { var campos = this.screen2cam(pos); @@ -1215,7 +1187,6 @@ var replstr = ""; var imdebug = function imdebug() { imtoggle("Physics", debug, "draw_phys"); imtoggle("Bouning boxes", debug, "draw_bb"); - imtoggle("Gizmos", debug, "draw_gizmos"); imtoggle("Names", debug, "draw_names"); imtoggle("Sprite nums", debug, "sprite_nums"); imtoggle("Debug overlay", debug, "show"); @@ -1227,6 +1198,7 @@ var observed_tex = undefined; var debug = {} debug.console = false var imgui_fn = function imgui_fn() { + return imgui.newframe(); if (debug.console) debug.console = imgui.window("console", _ => { @@ -1251,15 +1223,10 @@ var imgui_fn = function imgui_fn() { }); imgui.menu("Debug", imdebug); imgui.menu("View", _ => { - imtoggle("Profiler", debug, "showprofiler"); imtoggle("Terminal out", debug, "termout"); imtoggle("Meta [f7]", debug, "meta"); imtoggle("Cheats [f8]", debug, "cheat"); imtoggle("Console [f9]", debug, "console"); - if (profile.tracing) - imgui.button("stop trace", profile.trace_stop); - else - imgui.button('start trace', profile.trace_start); }); imgui.sokol_gfx(); @@ -1269,7 +1236,6 @@ var imgui_fn = function imgui_fn() { imtoggle("Draw particles", render, "draw_particles"); imtoggle("Draw HUD", render, "draw_hud"); imtoggle("Draw GUI", render, "draw_gui"); - imtoggle("Draw gizmos", render, "draw_gizmos"); imgui.menu("Window", _ => { prosperon.fullscreen = imgui.checkbox("fullscreen", prosperon.fullscreen); @@ -1308,30 +1274,6 @@ var imgui_fn = function imgui_fn() { // imgui.endframe(render._main); }; -var dmon -/*try { - dmon = use('dmon') -} catch (e) { - console.log(`could not use dmon`) - console.error(e) -} -if (dmon) dmon.watch('.'); -*/ -function dmon_cb(e) -{ - io.invalidate(); - if (e.file.startsWith('.')) return; - if (e.file.endsWith('.js')) - use.hotreload(e.file); - if (e.file.endsWith('.hlsl')) - shader_hotreload(e.file); - else if (Resources.is_image(e.file)) - graphics.tex_hotreload(e.file); -} - -var sim = use('sim') -var emitter = use('emitter') - var waittime = 1/240; var last_frame_time = 0; var frame_t = 0; @@ -1339,17 +1281,14 @@ var frame_t = 0; var fpses = []; var timescale = 1 render.process = function process() { - var now = profile.now(); + var now = os.now(); var dt = now - last_frame_time; if (dt < waittime) os.sleep(waittime-dt); - last_frame_time = profile.now(); + last_frame_time = os.now(); - // check for hot reloading - if (dmon) dmon.poll(dmon_cb); var dt = last_frame_time - frame_t; frame_t = last_frame_time; - os.engine_input(e => { prosperon[e.type]?.(e); }); @@ -1363,19 +1302,6 @@ render.process = function process() { os.update_timers(dt * timescale) prosperon.update(dt*timescale) - if (sim.mode === "step") sim.pause(); - if (sim.mode === "play" || sim.mode === "step") { -/* - physlag += dt; - - while (physlag > physics.delta) { - physlag -= physics.delta; - prosperon.phys2d_step(physics.delta * timescale); - prosperon.physupdate(physics.delta * timescale); - } - */ - } - current_queue = render_queue; prosperon.draw() emitter.emitters.forEach(e => render.particles(e)) @@ -1390,7 +1316,6 @@ render.process = function process() { // Some initialization shader_type = render._main.shader_format()[0]; - std_sampler = render._main.make_sampler({ min_filter: "nearest", mag_filter: "nearest", diff --git a/scripts/sim.js b/scripts/sim.js deleted file mode 100644 index 7135d187..00000000 --- a/scripts/sim.js +++ /dev/null @@ -1,29 +0,0 @@ -var sim = {}; -sim.mode = "play"; -sim.play = function () { - this.mode = "play"; -// os.reindex_static(); - game.all_objects(o => { - if (!o._started) { - o._started = true; - o.start?.(); - } - }); -}; -sim.playing = function () { - return this.mode === "play"; -}; -sim.pause = function () { - this.mode = "pause"; -}; -sim.paused = function () { - return this.mode === "pause"; -}; -sim.step = function () { - this.mode = "step"; -}; -sim.stepping = function () { - return this.mode === "step"; -}; - -return sim diff --git a/scripts/sound.js b/scripts/sound.js index d8d2a49a..962cf942 100644 --- a/scripts/sound.js +++ b/scripts/sound.js @@ -2,7 +2,6 @@ var tween = use('tween') var io = use('io') var res = use('resources') - var doc = use('doc') soloud.init(); diff --git a/scripts/spline.js b/scripts/spline.js deleted file mode 100644 index 6d37dd20..00000000 --- a/scripts/spline.js +++ /dev/null @@ -1,122 +0,0 @@ -var Spline = {}; -var vector = use('vector') -Spline.sample_angle = function (type, points, angle) { - if (type === 0) return spline.catmull(points, angle); - else if (type === 1) return spline.bezier(points, angle); - return undefined; -}; - -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.bezier_node_count = function (cp) { - if (cp.length === 4) return 2; - return 2 + (cp.length - 4) / 3; -}; - -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 = []; - for (var i = 0; i < b.length; i += 3) c.push(b[i]); - return c; -}; - -Spline.catmull2bezier = function (c) { - var b = []; - for (var i = 1; i < c.length - 2; i++) { - b.push(c[i].slice()); - b.push( - c[i + 1] - .sub(c[i - 1]) - .scale(0.25) - .add(c[i]), - ); - b.push( - c[i] - .sub(c[i + 2]) - .scale(0.25) - .add(c[i + 1]), - ); - } - b.push(c[c.length - 2]); - return b; -}; - -Spline.catmull_loop = function (cp) { - cp = cp.slice(); - cp.unshift(cp.last()); - cp.push(cp[1]); - cp.push(cp[2]); - return cp; -}; - -Spline.catmull_caps = function (cp) { - if (cp.length < 2) return; - cp = cp.slice(); - cp.unshift(cp[0].sub(cp[1]).add(cp[0])); - cp.push(cp.last().sub(cp.at(-2).add(cp.last()))); - return cp; -}; - -Spline.catmull_caps.doc = "Given a set of control points cp, return the necessary caps added to the spline."; - -Spline.catmull2bezier.doc = "Given a set of control points C for a camtull-rom type curve, return a set of cubic bezier points to give the same curve."; - -Spline.type = { - catmull: 0, - bezier: 1, - bspline: 2, - cubichermite: 3, -}; - -Spline.bezier_tan_partner = function (points, i) { - if (i % 3 === 0) return undefined; - var partner_i = i % 3 === 2 ? i - 1 : i + 1; - return points[i]; -}; - -Spline.bezier_cp_mirror = function (points, i) { - if (i % 3 === 0) return undefined; - var partner_i = i % 3 === 2 ? i + 2 : i - 2; - var node_i = i % 3 === 2 ? i + 1 : i - 1; - if (partner_i >= points.length || node_i >= points.length) return; - points[partner_i] = points[node_i].sub(points[i]).add(points[node_i]); -}; - -Spline.bezier_point_handles = function (points, i) { - if (!Spline.bezier_is_node(points, i)) return []; - var a = i - 1; - var b = i + 1; - var c = []; - if (a > 0) c.push(a); - - if (b < points.length) c.push(b); - - return c; -}; - -Spline.bezier_nodes = function (points) { - var c = []; - for (var i = 0; i < points.length; i += 3) c.push(points[i].slice()); - - return c; -}; - -Spline.bezier_is_node = function (points, i) { - return i % 3 === 0; -}; -Spline.bezier_is_handle = function (points, i) { - return !Spline.bezier_is_node(points, i); -}; - -return Spline diff --git a/scripts/stats.js b/scripts/stats.js deleted file mode 100644 index dd8a4077..00000000 --- a/scripts/stats.js +++ /dev/null @@ -1,38 +0,0 @@ -var stats = {} -var vector = use('vector') - -/* -Math.variance = function (series) { - var mean = Math.mean(series); - var vnce = 0; - for (var i = 0; i < series.length; i++) vnce += Math.pow(series[i] - mean, 2); - return vnce / series.length; -}; - -Math.ci = function (series) { - return (3 * Math.sigma(series)) / Math.sqrt(series.length); -}; - -Math.grab_from_points = function (pos, points, slop) { - var shortest = slop; - var idx = -1; - points.forEach(function (x, i) { - if (vector.length(pos.sub(x)) < shortest) { - shortest = vector.length(pos.sub(x)); - idx = i; - } - }); - return idx; -}; - -Math.nearest = function (n, incr) { - return Math.round(n / incr) * incr; -}; - -Math.places = function (n, digits) { - var div = Math.pow(10, digits); - return Math.round(n * div) / div; -}; -*/ - -return stats diff --git a/scripts/std.js b/scripts/std.js index c6b1ef17..f2e4f628 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -1,4 +1,3 @@ -var profile = use('profile') var io = use('io') var util = use('util') diff --git a/scripts/stdprofile.js b/scripts/stdprofile.js deleted file mode 100644 index 0054277e..00000000 --- a/scripts/stdprofile.js +++ /dev/null @@ -1,69 +0,0 @@ -var aa = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - -/* -var ta = [1,2,3,4,5,6,7,8,9,10]; - -function tadd(a,b) -{ - var c = a.slice(); - for (var i = 0; i < a.length; i++) - c[i] += b[i]; - return c; -} - -say(vector.angle_between([0,1], [1,0])); - -function test_arrays(ta, tb) -{ - profile.cpu(_=> ta.add(tb), 100000, "add two arrays"); - say(ta.add(tb)); -} -*/ -//for (var i = 2; i <= 10; i++) { -// say(`TESTING FOR ${i} ARRAY`); -// test_arrays(ta.slice(0,i), ta.slice(0,i)); -//} -/* -say(os.guid()); -say(os.guid()); -var aa = []; -var ao = {}; - -var amt = 10000; - -profile.cpu(_ => os.guid(), 10000, "guid generation"); - -profile.cpu(_ => aa.push(1), amt, "add one to array"); -profile.cpu(_ => ao[os.guid()] = 1, amt, "add one via guid"); - -var aos = Object.keys(ao); - -say(aa.length); - -var useguid = aos[amt/2]; - -say(useguid); - -var tries = []; -for (var i = 0; i < amt; i++) - tries[i] = aa.slice(); - -var rmamt = amt/2; -profile.cpu(x => tries[x].remove(rmamt), amt, "remove from array"); - -for (var i = 0; i < amt; i++) { - tries[i] = {}; - for (var j in ao) tries[i][j] = ao[j]; -} - - -profile.cpu(x => delete tries[x][useguid], amt, "delete with guid"); - -//profile.cpu(_ => Object.values(ao), 10000, "make array from objects"); -var dofn = function(x) { x += 1; } -profile.cpu(_ => aa.forEach(dofn), 1000, "iterate array"); -profile.cpu(_ => ao.forEach(dofn), 1000, "iterate object foreach"); -profile.cpu(_ => { - for (var i in ao) ao[i] += 1; -}, 1000, "iterate in object values"); -*/ diff --git a/scripts/stdtest.js b/scripts/stdtest.js deleted file mode 100644 index 67f0f884..00000000 --- a/scripts/stdtest.js +++ /dev/null @@ -1,6 +0,0 @@ -test.run("set transform scale", _ => { - var t = os.make_transform(); - var s1 = t.scale.slice(); - t.scale = s1; - return t.scale.equal(s1); -}); diff --git a/scripts/test.js b/scripts/test.js deleted file mode 100644 index 1466d6a4..00000000 --- a/scripts/test.js +++ /dev/null @@ -1,46 +0,0 @@ -/* Tests for prosperon */ - -var test = {}; - -var tests = []; -var pass = 0; -var fail = 0; -var failed = []; - -test.run_suite = function (file) { - test = []; - pass = 0; - fail = 0; - failed = []; -}; - -test.run = function (name, fn) { - var func = function () { - print(`${pass + fail + 1}/${tests.length}: ${name} ... `); - var p = profile.now(); - var b = fn(); - p = profile.lap(p); - print(`${b ? "pass" : "fail"} [${p}]`); - return b; - }; - func.testname = name; - tests.push(func); -}; - -say(`Testing ${tests.length} tests.`); -for (var t of tests) { - if (t()) pass++; - else { - fail++; - failed.push(t.testname); - } - print("\n"); -} - -say(`Passed ${pass} tests and failed ${fail} [${((pass * 100) / (pass + fail)).toPrecision(4)}%].`); -say(`Failed tests are:`); -for (var f of failed) say(f); - -os.exit(0); - -return { test }; diff --git a/scripts/textedit.js b/scripts/textedit.js deleted file mode 100644 index b89ddabf..00000000 --- a/scripts/textedit.js +++ /dev/null @@ -1,343 +0,0 @@ -var texteditor = Object.copy(inputpanel, { - title: "text editor", - wh: [700, 500], - _cursor: 0 /* Text cursor: [char,line] */, - get cursor() { - return this._cursor; - }, - set cursor(x) { - if (x > this.value.length) x = this.value.length; - if (x < 0) x = 0; - - this._cursor = x; - this.line = this.get_line(); - }, - - submit() {}, - - line: 0, - killring: [], - undos: [], - startbuffer: "", - - savestate() { - this.undos.push(this.value.slice()); - }, - - popstate() { - if (this.undos.length === 0) return; - this.value = this.undos.pop(); - this.cursor = this.cursor; - }, - - copy(start, end) { - return this.value.slice(start, end); - }, - - delete_line(p) { - var ls = this.line_start(p); - var le = this.line_end(p) + 1; - this.cut_span(ls, le); - this.to_line_start(); - }, - - line_blank(p) { - var ls = this.line_start(p); - var le = this.line_end(p); - var line = this.value.slice(ls, le); - if (line.search(/[^\s]/g) === -1) return true; - else return false; - }, - - get_line() { - var line = 0; - for (var i = 0; i < this.cursor; i++) if (this.value[i] === "\n") line++; - - return line; - }, - - start() { - this.cursor = 0; - this.startbuffer = this.value.slice(); - }, - - get dirty() { - return this.startbuffer !== this.value; - }, - - src: "NEW FILE", - - guibody() { - // TODO: new render here - }, - - insert_char(char) { - this.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor); - this.cursor++; - }, - - line_starting_whitespace(p) { - var white = 0; - var l = this.line_start(p); - - while (this.value[l] === " ") { - white++; - l++; - } - - return white; - }, - - cut_span(start, end) { - if (end < start) return; - this.savestate(); - var ret = this.value.slice(start, end); - this.value = this.value.slice(0, start) + this.value.slice(end); - if (start > this.cursor) return ret; - - this.cursor -= ret.length; - return ret; - }, - - next_word(pos) { - var v = this.value.slice(pos + 1).search(/[^\w]\w/g); - if (v === -1) return pos; - return pos + v + 2; - }, - - prev_word(pos) { - while (this.value.slice(pos, pos + 2).search(/[^\w]\w/g) === -1 && pos > 0) pos--; - - return pos + 1; - }, - - end_of_word(pos) { - var l = this.value.slice(pos).search(/\w[^\w]/g); - return l + pos; - }, - - get inset() { - return this.cursor - this.value.prev("\n", this.cursor) - 1; - }, - - line_start(p) { - return this.value.prev("\n", p) + 1; - }, - - line_end(p) { - return this.value.next("\n", p); - }, - - next_line(p) { - return this.value.next("\n", p) + 1; - }, - - prev_line(p) { - return this.line_start(this.value.prev("\n", p)); - }, - - to_line_start() { - this.cursor = this.value.prev("\n", this.cursor) + 1; - }, - - to_line_end() { - var p = this.value.next("\n", this.cursor); - if (p === -1) this.to_file_end(); - else this.cursor = p; - }, - - line_width(pos) { - var start = this.line_start(pos); - var end = this.line_end(pos); - if (end === -1) end = this.value.length; - - return end - start; - }, - - to_file_end() { - this.cursor = this.value.length; - }, - - to_file_start() { - this.cursor = 0; - }, - - desired_inset: 0, -}); - -texteditor.inputs = {}; - -(texteditor.inputs.char = function (char) { - this.insert_char(char); - this.keycb(); -}), - (texteditor.inputs.enter = function () { - var white = this.line_starting_whitespace(this.cursor); - this.insert_char("\n"); - - for (var i = 0; i < white; i++) this.insert_char(" "); - }); -texteditor.inputs.enter.rep = true; - -texteditor.inputs.backspace = function () { - this.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor); - this.cursor--; -}; -texteditor.inputs.backspace.rep = true; - -texteditor.inputs["C-s"] = function () { - if (this.srctype === "function") { - eval(`${this.src} = ${this.value}`); - } -}; -texteditor.inputs["C-s"].doc = "Save edited text."; - -texteditor.inputs["C-u"] = function () { - this.popstate(); -}; -texteditor.inputs["C-u"].doc = "Undo."; - -texteditor.inputs["C-q"] = function () { - var ws = this.prev_word(this.cursor); - var we = this.end_of_word(this.cursor) + 1; - var find = this.copy(ws, we); - var obj = editor.edit_level.varname2obj(find); - - if (obj) { - editor.unselect(); - editor.selectlist.push(obj); - } -}; -texteditor.inputs["C-q"].doc = "Select object of selected word."; - -texteditor.inputs["C-o"] = function () { - this.insert_char("\n"); - this.cursor--; -}; -texteditor.inputs["C-o"].doc = "Insert newline."; -texteditor.inputs["C-o"].rep = true; - -texteditor.inputs["M-o"] = function () { - while (this.line_blank(this.next_line(this.cursor))) this.delete_line(this.next_line(this.cursor)); - - while (this.line_blank(this.prev_line(this.cursor))) this.delete_line(this.prev_line(this.cursor)); -}; -texteditor.inputs["M-o"].doc = "Delete surround blank lines."; - -texteditor.inputs["C-d"] = function () { - this.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1); -}; -texteditor.inputs["C-d"].doc = "Delete character."; - -texteditor.inputs["M-d"] = function () { - this.cut_span(this.cursor, this.end_of_word(this.cursor) + 1); -}; -texteditor.inputs["M-d"].doc = "Delete word."; - -texteditor.inputs["C-a"] = function () { - this.to_line_start(); - this.desired_inset = this.inset; -}; -texteditor.inputs["C-a"].doc = "To start of line."; - -texteditor.inputs["C-y"] = function () { - if (this.killring.length === 0) return; - this.insert_char(this.killring.pop()); -}; -texteditor.inputs["C-y"].doc = "Insert from killring."; - -texteditor.inputs["C-e"] = function () { - this.to_line_end(); - this.desired_inset = this.inset; -}; -texteditor.inputs["C-e"].doc = "To line end."; - -texteditor.inputs["C-k"] = function () { - if (this.cursor === this.value.length - 1) return; - var killamt = this.value.next("\n", this.cursor) - this.cursor; - var killed = this.cut_span(this.cursor - 1, this.cursor + killamt); - this.killring.push(killed); -}; -texteditor.inputs["C-k"].doc = "Kill from cursor to end of line."; - -texteditor.inputs["M-k"] = function () { - var prevn = this.value.prev("\n", this.cursor); - var killamt = this.cursor - prevn; - var killed = this.cut_span(prevn + 1, prevn + killamt); - this.killring.push(killed); - this.to_line_start(); -}; -texteditor.inputs["M-k"].doc = "Kill entire line the cursor is on."; - -texteditor.inputs["C-b"] = function () { - this.cursor--; - this.desired_inset = this.inset; -}; -texteditor.inputs["C-b"].rep = true; -texteditor.inputs["M-b"] = function () { - this.cursor = this.prev_word(this.cursor - 2); - this.desired_inset = this.inset; -}; -texteditor.inputs["M-b"].rep = true; - -texteditor.inputs["C-f"] = function () { - this.cursor++; - this.desired_inset = this.inset; -}; -texteditor.inputs["C-f"].rep = true; -texteditor.inputs["M-f"] = function () { - this.cursor = this.next_word(this.cursor); - this.desired_inset = this.inset; -}; -texteditor.inputs["M-f"].rep = true; - -texteditor.inputs["C-p"] = function () { - if (this.cursor === 0) return; - this.desired_inset = Math.max(this.desired_inset, this.inset); - this.cursor = this.prev_line(this.cursor); - var newlinew = this.line_width(this.cursor); - this.cursor += Math.min(this.desired_inset, newlinew); -}; -texteditor.inputs["C-p"].rep = true; - -texteditor.inputs["M-p"] = function () { - while (this.line_blank(this.cursor)) this.cursor = this.prev_line(this.cursor); - - while (!this.line_blank(this.cursor)) this.cursor = this.prev_line(this.cursor); -}; -texteditor.inputs["M-p"].doc = "Go up to next line with text on it."; -texteditor.inputs["M-p"].rep = true; - -texteditor.inputs["C-n"] = function () { - if (this.cursor === this.value.length - 1) return; - if (this.value.next("\n", this.cursor) === -1) { - this.to_file_end(); - return; - } - - this.desired_inset = Math.max(this.desired_inset, this.inset); - this.cursor = this.next_line(this.cursor); - var newlinew = this.line_width(this.cursor); - this.cursor += Math.min(this.desired_inset, newlinew); -}; -texteditor.inputs["C-n"].rep = true; - -texteditor.inputs["M-n"] = function () { - while (this.line_blank(this.cursor)) this.cursor = this.next_line(this.cursor); - while (!this.line_blank(this.cursor)) this.cursor = this.next_line(this.cursor); -}; -texteditor.inputs["M-n"].doc = "Go down to next line with text on it."; -texteditor.inputs["M-n"].rep = true; - -texteditor.open_fn = function (fnstr) { - var fn = eval(fnstr); - if (!fn) { - console.warn(`${fnstr} is not a function.`); - return; - } - this.src = fnstr; - this.srctype = "function"; - editor.openpanel(this); - this.value = fn; - this.cursor = 0; -}; diff --git a/scripts/tween.js b/scripts/tween.js index db65b0ca..cd09f466 100644 --- a/scripts/tween.js +++ b/scripts/tween.js @@ -1,4 +1,3 @@ -var profile = use('profile') var util = use('util') /* Take numbers from 0 to 1 and remap them to easing functions */ @@ -116,7 +115,7 @@ Ease.elastic.c4 = (2 * Math.PI) / 3; Ease.elastic.c5 = (2 * Math.PI) / 4.5; var tween = function (from, to, time, fn, cb) { - var start = profile.now() + var start = os.now() function cleanup() { stop() @@ -127,7 +126,7 @@ var tween = function (from, to, time, fn, cb) { } var update = function tween_update(dt) { - var elapsed = profile.now() - start; + var elapsed = os.now() - start; fn(util.obj_lerp(from,to,elapsed/time)); if (elapsed >= time) { fn(to) diff --git a/scripts/util.js b/scripts/util.js index 57eddf92..9fd36b2f 100644 --- a/scripts/util.js +++ b/scripts/util.js @@ -99,4 +99,20 @@ util.obj_lerp = function(a,b,t) return obj; } +util.normalizeSpacing = function normalizeSpacing(spacing) { + if (typeof spacing === 'number') { + return {l: spacing, r: spacing, t: spacing, b: spacing}; + } else if (Array.isArray(spacing)) { + if (spacing.length === 2) { + return {l: spacing[0], r: spacing[0], t: spacing[1], b: spacing[1]}; + } else if (spacing.length === 4) { + return {l: spacing[0], r: spacing[1], t: spacing[2], b: spacing[3]}; + } + } else if (typeof spacing === 'object') { + return {l: spacing.l || 0, r: spacing.r || 0, t: spacing.t || 0, b: spacing.b || 0}; + } else { + return {l:0, r:0, t:0, b:0}; + } +} + return util diff --git a/scripts/yaml.js b/scripts/yaml.js deleted file mode 100644 index 59656d6e..00000000 --- a/scripts/yaml.js +++ /dev/null @@ -1,51 +0,0 @@ -var yaml = {}; - -yaml.tojson = function (yaml) { - // Replace key value pairs that are strings with quotation marks around them - yaml = yaml.replace(/(\w+):/g, '"$1":'); - yaml = yaml.replace(/: ([\w\.\/]+)/g, ': "$1"'); // TODO: make this more general - - yaml = yaml.split("\n"); - var cont = {}; - var cur = 0; - for (var i = 0; i < yaml.length; i++) { - var line = yaml[i]; - var indent = line.search(/\S/); - - if (indent > cur) { - if (line[indent] == "-") { - cont[indent] = "array"; - yaml[i] = line.sub(indent, "["); - } else { - cont[indent] = "obj"; - yaml[i] = line.sub(indent - 1, "{"); - } - } - - if (indent < cur) { - while (cur > indent) { - if (cont[cur] === "obj") yaml[i - 1] = yaml[i - 1] + "}"; - else if (cont[cur] === "array") yaml[i - 1] = yaml[i - 1] + "]"; - - delete cont[cur]; - cur--; - } - } - - if (indent === cur) { - if (yaml[i][indent] === "-") yaml[i] = yaml[i].sub(indent, ","); - else yaml[i - 1] = yaml[i - 1] + ","; - } - - cur = indent; - } - yaml = "{" + yaml.join("\n") + "}"; - yaml = yaml.replace(/\s/g, ""); - yaml = yaml.replace(/,}/g, "}"); - yaml = yaml.replace(/,]/g, "]"); - yaml = yaml.replace(/,"[^"]+"\:,/g, ","); - yaml = yaml.replace(/,"[^"]+"\:}/g, "}"); - return yaml; -}; - -return yaml diff --git a/source/jsffi.c b/source/jsffi.c index 6fdb1f63..5d8f1e18 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -5541,10 +5541,7 @@ JSC_CCALL(profile_best_t, return JS_NewString(js,result); ) -JSC_CCALL(profile_now, return number2js(js, SDL_GetTicksNS()/1000000000.f)) - static const JSCFunctionListEntry js_profile_funcs[] = { - MIST_FUNC_DEF(profile,now,0), MIST_FUNC_DEF(profile,best_t, 1), MIST_FUNC_DEF(profile,gather_rate,1), MIST_FUNC_DEF(profile,gather_stop,0), @@ -7303,13 +7300,13 @@ static ModuleEntry module_registry[] = { MISTLINE(os), MISTLINE(input), MISTLINE(time), - MISTLINE(profile), - MISTLINE(debug), +// MISTLINE(profile), +// MISTLINE(debug), MISTLINE(vector), MISTLINE(spline), - MISTLINE(performance), +// MISTLINE(performance), MISTLINE(geometry), - MISTLINE(camera), +// MISTLINE(camera), }; JSC_SCALL(os_use_embed,