diff --git a/doc/prosperon.org b/doc/prosperon.org index 60c07bd..4f3a621 100644 --- a/doc/prosperon.org +++ b/doc/prosperon.org @@ -212,7 +212,9 @@ Components only work in the context of an entity. They have no meaning outside o While components can be added via scripting, it is easier to add them via the editor, as we will later see. *** Ur system -The ur[fn::A German prefix meaning primitive, original, or earliest.] system is a prototypical inheritence system used by the actor files. When actor files are loaded, they are stored as an ur. An *ur* represents a set of instructions to create the (text, config) needed to spawn an actor or entity. +The ur[fn::A German prefix meaning primitive, original, or earliest.] system is a prototypical inheritence system used by the actor files. When actor files are loaded, they are stored as an ur. An *ur* holds a list of (text, config) required to create an entity. + +When prosperon starts, it searches for urs by name. Any file ending in ".jso" or ".json" will be interpereted as an ur, with same named jso and json being applied as (text, config) for an ur. A jso or json alone also constitute an ur. #+begin_scholium Create an ur from the *hello* files above, and then spawn it. diff --git a/scripts/camera2d.jso b/scripts/camera2d.jso index 7bdbc48..f852dc6 100644 --- a/scripts/camera2d.jso +++ b/scripts/camera2d.jso @@ -1,5 +1,5 @@ this.phys = physics.kinematic; -this.dir_view2world = function(dir) { return dir.scale(this.realzoom()); }; +this.dir_view2world = function(dir) { return dir.scale(this.zoom); }; this.view2world = function(pos) { pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]); pos = pos.sub(window.rendersize.scale(0.5)); @@ -10,14 +10,11 @@ this.view2world = function(pos) { this.world2view = function(pos) { pos = pos.sub(this.pos); pos = pos.scale(1.0/this.zoom); - pos = pos.add(window.rendersize); + pos = pos.add(window.rendersize.scale(0.5)); return pos; }; -this.realzoom = function() { return render.get_zoom(); }; -this.screenright = function() { - return this.view2world(window.size).x; -} +this.screenright = function() { return this.view2world(window.size).x; } this.screenleft = function() { return this.pos.x - (window.rendersize.x/2); } this.zoom = 1; diff --git a/scripts/components.js b/scripts/components.js index 0f8a40f..47e988f 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -489,6 +489,7 @@ component.edge2d = Object.copy(collider2d, { 'points', 'hollow', 'hollowt', + 'angle', ]), dimensions:2, thickness:0, @@ -516,7 +517,7 @@ component.edge2d = Object.copy(collider2d, { for (var i = spoints.length-1; i >= 0; i--) { var newpoint = spoints[i].slice(); - newpoint.x = -newpoint.x; + newpoint.x = -newpoint.x; spoints.push(newpoint); } } @@ -527,8 +528,8 @@ component.edge2d = Object.copy(collider2d, { for (var i = spoints.length-1; i >= 0; i--) { var newpoint = spoints[i].slice(); - newpoint.y = -newpoint.y; - spoints.push(newpoint); + newpoint.y = -newpoint.y; + spoints.push(newpoint); } } @@ -585,7 +586,7 @@ component.edge2d = Object.copy(collider2d, { gizmo() { if (this.type === Spline.type.catmull || this.type === -1) { this.spoints().forEach(x => render.point(this.gameobject.this2screen(x), 3, Color.teal)); - this.points.forEach((x,i) => render.coordinate(this.gameobject.this2screen(x), i)); + this.points.forEach((x,i) => render.coordinate(this.gameobject.this2screen(x))); } else { for (var i = 0; i < this.points.length; i += 3) render.coordinate(this.gameobject.this2screen(this.points[i]), i, Color.teal); @@ -614,23 +615,23 @@ component.edge2d = Object.copy(collider2d, { if (p) { var o = { pos: p, - sync: me.sync.bind(me) + sync: me.sync.bind(me) }; if (Spline.bezier_is_handle(this.points,i)) - o.move = function(d) { - d = that.dir_world2this(d); - p.x += d.x; - p.y += d.y; - Spline.bezier_cp_mirror(me.points,i); - }; + o.move = function(d) { + d = that.dir_world2this(d); + p.x += d.x; + p.y += d.y; + Spline.bezier_cp_mirror(me.points,i); + }; else o.move = function(d) { - d = that.dir_world2this(d); - p.x += d.x; - p.y += d.y; - var pp = Spline.bezier_point_handles(me.points,i); - pp.forEach(ph => me.points[ph] = me.points[ph].add(d)); - } + d = that.dir_world2this(d); + p.x += d.x; + p.y += d.y; + var pp = Spline.bezier_point_handles(me.points,i); + pp.forEach(ph => me.points[ph] = me.points[ph].add(d)); + } return o; } }, diff --git a/scripts/debug.js b/scripts/debug.js index 8ebfe20..c39f985 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -22,7 +22,7 @@ debug.draw = function() { if (this.draw_gizmos) game.all_objects(function(x) { if (!x.icon) return; - GUI.image(x.icon, game.camera.world2view(x.pos)); + gui.image(x.icon, game.camera.world2view(x.pos)); }); if (this.draw_names) @@ -143,12 +143,11 @@ debug.inputs.f9 = function() { 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.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."; diff --git a/scripts/diff.js b/scripts/diff.js index ad1e729..3261b35 100644 --- a/scripts/diff.js +++ b/scripts/diff.js @@ -36,8 +36,8 @@ function ediff(from,to) 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; + if (r) ret[key] = Object.values(r); + return; } var diff = ediff(from[key], to[key]); @@ -47,14 +47,14 @@ function ediff(from,to) return; } - if (typeof v === 'object') { + if (typeof v === 'object' && v !== null) { var diff = ediff(v, to[key]); if (diff && !Object.empty(diff)) - ret[key] = diff; + ret[key] = diff; return; } - if (typeof v === 'number') { + if (typeof v === 'number' || v === null) { if (!isFinite(v)) v = null; // Squash infinity to null if (v !== to[key]) ret[key] = v; diff --git a/scripts/editor.js b/scripts/editor.js index b3ef2ec..c60b912 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -6,6 +6,8 @@ window.mode = window.modetypes.full; game.loadurs(); +console.info(`window size: ${window.size}, render size: ${window.rendersize}`); + player[0].control(debug); Register.gui.register(debug.draw, debug); @@ -222,7 +224,7 @@ var 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)); + editor.cbs.push(Register.update.register(gui.controls.update, gui.controls)); this.desktop = world.spawn(); world.rename_obj(this.desktop.toString(), "desktop"); @@ -392,7 +394,6 @@ var editor = { gui() { /* Clean out killed objects */ - this.selectlist = this.selectlist.filter(function(x) { return x.alive; }); render.text([0,0], game.camera.world2view([0,0])); render.text("WORKING LAYER: " + this.working_layer, [0,520]); @@ -422,9 +423,11 @@ var editor = { var depth = 0; var alldirty = false; for (var lvl of lvlchain) { + if (!lvl._ed) continue; if (alldirty) lvl._ed.dirty = true; else { + if (!lvl._ed) continue; lvl.check_dirty(); if (lvl._ed.dirty) alldirty = true; } @@ -442,7 +445,6 @@ var editor = { depth++; render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]); - this.selectlist.forEach(function(x) { render.text(x.urstr(), x.screenpos().add([0, 32]), 1, Color.editor.ur); render.text(x.worldpos().map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white); @@ -452,7 +454,8 @@ var editor = { Object.entries(thiso.objects).forEach(function(x) { var p = x[1].namestr(); render.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]); - render.circle(x[1].screenpos(),10,Color.blue.alpha(0.3)); + render.point(x[1].screenpos(),5,Color.blue.alpha(0.3)); + render.point(x[1].screenpos(), 1, Color.red); }); var mg = physics.pos_query(input.mouse.worldpos(),10); @@ -522,9 +525,12 @@ var editor = { lvl_history: [], load(urstr) { - var obj = editor.edit_level.spawn(urstr); + var mur = ur[urstr]; + if (!mur) return; + var obj = editor.edit_level.spawn(mur); obj.set_worldpos(input.mouse.worldpos()); this.selectlist = [obj]; + console.warn(`made something and now the selected objects is ${this.selectlist.length} long.`); }, load_prev() { @@ -553,15 +559,15 @@ var editor = { /* make a new type path */ if (Object.access(ur,sub)) { console.warn(`Ur named ${sub} already exists.`); - return; + return; } var file = `${sub}.json`; io.slurpwrite(file, json.encode(obj.json_obj(),null,1)); ur[sub] = { name: sub, - data: file, - proto: json.decode(json.encode(obj)) + data: file, + proto: json.decode(json.encode(obj)) } obj.ur = sub; @@ -583,12 +589,12 @@ var editor = { 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; + obj.clear(); + var nobj = editor.edit_level.spawn(sub); + editor.selectlist = [nobj]; + return; + } + editor.edit_level = editor.edit_level.master; } var t = obj.transform(); @@ -664,7 +670,7 @@ editor.inputs.release_post = function() { editor.edit_level.check_dirty(); /* snap all objects to be pixel perfect */ - editor.edit_level.obj_descend(o => o.pos = o.pos.map(x => Math.round(x))); + 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; } @@ -1404,7 +1410,7 @@ var inputpanel = { toString() { return this.title; }, value: "", on: false, - pos:[100,window.height-50], + pos:[100,window.size.y-50], wh:[350,600], anchor: [0,1], padding:[5,-15], @@ -1422,7 +1428,7 @@ var inputpanel = { ]; else this.win.items = itms; - this.win.draw(this.pos.slice()); + this.win.draw([100, window.size.y-50]); }, guibody() { @@ -1479,10 +1485,7 @@ var inputpanel = { inputpanel.inputs = {}; -inputpanel.inputs.post = function() -{ - this.keycb(); -} +inputpanel.inputs.post = function() { this.keycb(); } inputpanel.inputs.char = function(c) { this.value = this.value.slice(0,this.caret) + c + this.value.slice(this.caret); @@ -1524,26 +1527,20 @@ inputpanel.inputs['C-k'] = function() { this.value = this.value.slice(0,this.caret); }; -inputpanel.inputs.lm = function() -{ - GUI.controls.check_submit(); -} - -//load("scripts/textedit.js"); +inputpanel.inputs.lm = function() { gui.controls.check_submit(); } var replpanel = Object.copy(inputpanel, { title: "", closeonsubmit:false, wh: [700,300], pos: [50,50], - anchor: [0,0], + anchor: [0,1], padding: [0,0], scrolloffset: [0,0], guibody() { this.win.selectable = true; - var log = ""; - log = log.slice(-5000); + var log = console.transcript; return [ Mum.text({str:log, anchor:[0,0], offset:[0,-300].sub(this.scrolloffset), selectable: true}), Mum.text({str:this.value,color:Color.green, offset:[0,-290], caret: this.caret}) @@ -1801,8 +1798,6 @@ var objectexplorer = Object.copy(inputpanel, { return items; }, - - }); var openlevelpanel = Object.copy(inputpanel, { @@ -2005,9 +2000,6 @@ limited_editor.inputs['C-q'] = function() var limited_editing = {}; limited_editing.inputs = {}; -if (io.exists("editor.config")) - load_configs("editor.config"); - /* This is the editor level & camera - NOT the currently edited level, but a level to hold editor things */ sim.pause(); window.editor = true; diff --git a/scripts/engine.js b/scripts/engine.js index bf9e5b2..ba34f43 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -120,53 +120,53 @@ qq = 'ms'; return `${t.toPrecision(4)} ${qq}`; } -Object.assign(console, { - say(msg) { console.print(msg + "\n"); }, - - pprint(msg, lvl = 0) { - if (typeof msg === 'object') - msg = JSON.stringify(msg, null, 2); - - var file = "nofile"; - var line = 0; - - var caller = (new Error()).stack.split('\n')[2]; - if (caller) { - var md = caller.match(/\((.*)\:/); - var m = md ? md[1] : "SCRIPT"; - if (m) file = m; - md = caller.match(/\:(\d*)\)/); - m = md ? md[1] : 0; - if (m) line = m; - } - - console.rec(lvl, msg, file, line); - }, - - spam(msg) { console.pprint (msg,0); }, - debug(msg) { console.pprint(msg,1); }, - info(msg) { console.pprint(msg, 2); }, - warn(msg) { console.pprint(msg, 3); }, - error(msg) { console.pprint(msg + "\n" + console.stackstr(2), 4);}, - panic(msg) { console.pprint(msg + "\n" + console.stackstr(2), 5); }, - - stackstr(skip=0) { - var err = new Error(); - var stack = err.stack.split('\n'); - return stack.slice(skip,stack.length).join('\n'); - }, - - stack(skip = 0) { - console.log(console.stackstr(skip+1)); - }, -}); - -console.stdout_lvl = 1; +console.transcript = ""; +console.say = function(msg) { + msg += "\n"; + console.print(msg); + console.transcript += msg; +}; console.log = console.say; -console.trace = console.stack; var say = console.say; var print = console.print; +console.pprint = function(msg,lvl = 0) { + if (typeof msg === 'object') + msg = JSON.stringify(msg, null, 2); + + var file = "nofile"; + var line = 0; + + var caller = (new Error()).stack.split('\n')[2]; + if (caller) { + var md = caller.match(/\((.*)\:/); + var m = md ? md[1] : "SCRIPT"; + if (m) file = m; + md = caller.match(/\:(\d*)\)/); + m = md ? md[1] : 0; + if (m) line = m; + } + + console.rec(lvl, msg, file, line); +}; + +console.spam = function(msg) { console.pprint (msg,0); }; +console.debug = function(msg) { console.pprint(msg,1); }; +console.info = function(msg) { console.pprint(msg, 2); }; +console.warn = function(msg) { console.pprint(msg, 3); }; +console.error = function(msg) { console.pprint(msg + "\n" + console.stackstr(2), 4);}; +console.panic = function(msg) { console.pprint(msg + "\n" + console.stackstr(2), 5); }; +console.stackstr = function(skip=0) { + var err = new Error(); + var stack = err.stack.split('\n'); + return stack.slice(skip,stack.length).join('\n'); +}; + +console.stack = function(skip = 0) { console.log(console.stackstr(skip+1)); }; + +console.stdout_lvl = 1; +console.trace = console.stack; + console.doc = { level: "Set level to output logging to console.", info: "Output info level message.", @@ -243,15 +243,14 @@ global.mixin("scripts/debug"); var frame_t = profile.secs(profile.now()); var phys_step = 1/60; -var sim = { - mode: "play", - play() { this.mode = "play"; os.reindex_static(); }, - playing() { return this.mode === 'play'; }, - pause() { this.mode = "pause"; console.stack(); }, - paused() { return this.mode === 'pause'; }, - step() { this.mode = 'step'; }, - stepping() { return this.mode === 'step'; } -} +var sim = {}; +sim.mode = "play"; +sim.play = function() { this.mode = "play"; os.reindex_static(); }; +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'; } var physlag = 0; @@ -313,7 +312,8 @@ function process() game.timescale = 1; -game.all_objects = function(fn) { +game.all_objects = function(fn, startobj) { + startobj ??= world; var eachobj = function(obj,fn) { fn(obj); @@ -321,7 +321,7 @@ game.all_objects = function(fn) { eachobj(obj.objects[o],fn); } - eachobj(world,fn); + eachobj(startobj,fn); }; game.tags = {}; diff --git a/scripts/entity.js b/scripts/entity.js index ef75e2b..3c95249 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -83,15 +83,10 @@ var gameobject = { else this._ed.inst = false; }, - - _ed: { - selectable: false, - dirty: false - }, namestr() { var s = this.toString(); - if (this._ed.dirty) + if (this._ed?.dirty) if (this._ed.inst) s += "#"; else s += "*"; return s; @@ -259,17 +254,11 @@ var gameobject = { ent.components = {}; ent.objects = {}; ent.timers = []; - ent.reparent(this); - ent._ed = { - selectable: true, - dirty: false, - inst: false, - urdiff: {}, - }; - if (typeof text === 'object') // assume it's an ur + if (typeof text === 'object' && text) // assume it's an ur { config = text.data; + ent.ur = text.name; text = text.text; } @@ -278,7 +267,8 @@ var gameobject = { if (config) Object.assign(ent, json.decode(io.slurp(config))); - ent.ur = text + "+" + config; + ent.ur ??= text + "+" + config; + ent.reparent(this); for (var [prop, p] of Object.entries(ent)) { if (!p) continue; @@ -300,11 +290,17 @@ var gameobject = { if (sim.playing()) if (typeof ent.start === 'function') ent.start(); - Object.hide(ent, 'ur', 'components', 'objects', '_ed', 'timers', 'master'); + Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master'); - var mur = ent.get_ur(); - if (mur && !mur.proto) - mur.proto = json.decode(json.encode(ent)); + ent._ed = { + selectable: true, + dirty: false, + inst: false, + urdiff: {}, + fresh: json.decode(json.encode(ent)), + }; + + Object.hide(ent, '_ed'); ent.sync(); @@ -450,22 +446,19 @@ var gameobject = { /* The unique components of this object. Its diff. */ json_obj() { - var u = this.get_ur(); - if (!u) return {}; - var proto = u.proto; + var fresh = this._ed.fresh; var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components. - - var d = ediff(thiso, proto); + var d = ediff(thiso, fresh); d ??= {}; var objects = {}; - proto.objects ??= {}; + fresh.objects ??= {}; var curobjs = {}; for (var o in this.objects) curobjs[o] = this.objects[o].instance_obj(); - var odiff = ediff(curobjs, proto.objects); + var odiff = ediff(curobjs, fresh.objects); if (odiff) d.objects = curobjs; @@ -484,12 +477,6 @@ var gameobject = { return t; }, - proto() { - var u = this.get_ur(); - if (!u) return {}; - return u.proto; - }, - transform() { var t = {}; t.pos = this.pos; @@ -497,7 +484,7 @@ var gameobject = { t.angle = Math.places(this.angle, 4); if (t.angle === 0) delete t.angle; t.scale = this.scale; - t.scale = t.scale.map((x, i) => x / this.proto().scale[i]); + t.scale = t.scale.map((x, i) => x / this._ed.fresh.scale[i]); t.scale = t.scale.map(x => Math.places(x, 3)); if (t.scale.every(x => x === 1)) delete t.scale; return t; @@ -600,12 +587,6 @@ var gameobject = { Object.assign(this[name], data); return this[name]; }, - - obj_descend(fn) { - fn(this); - for (var o in this.objects) - this.objects[o].obj_descend(fn); - }, } function go_init() { diff --git a/scripts/gui.js b/scripts/gui.js index 73b2dc7..bb15716 100644 --- a/scripts/gui.js +++ b/scripts/gui.js @@ -1,64 +1,41 @@ /* - GUI functions take screen space coordinates + gui functions take screen space coordinates */ gui.scissor_win = function() { gui.scissor(0,0,window.width,window.height); } -var GUI = { - newmg(img) { - var def = { - path: "", - pos: [0,0], - size:[0,0], - frame: { - x: 0, - y: 0, - w: 1, - h: 1 - }, - angle: 0, - anchor: [0,0], - color: Color.white, - } - for (var i in def) - img[i] ??= def[i]; - - gui_newmg - }, +gui.input_lmouse_pressed = function() { + if (gui.selected) + gui.selected.action(); +}; - input_lmouse_pressed() { - if (GUI.selected) - GUI.selected.action(); - }, - - input_s_pressed() { - if (GUI.selected?.down) { - GUI.selected.selected = false; - GUI.selected = GUI.selected.down; - GUI.selected.selected = true; - } - }, - - input_w_pressed() { - if (GUI.selected?.up) { - GUI.selected.selected = false; - GUI.selected = GUI.selected.up; - GUI.selected.selected = true; - } - }, - - input_enter_pressed() { - if (GUI.selected) { - GUI.selected.action(); - } +gui.input_s_pressed = function() { + if (gui.selected?.down) { + gui.selected.selected = false; + gui.selected = gui.selected.down; + gui.selected.selected = true; } }; -GUI.controls = {}; -GUI.controls.toString = function() { return "GUI controls"; }; -GUI.controls.update = function() { }; +gui.input_w_pressed = function() { + if (gui.selected?.up) { + gui.selected.selected = false; + gui.selected = gui.selected.up; + gui.selected.selected = true; + } +}; -GUI.controls.set_mum = function(mum) +gui.input_enter_pressed = function() { + if (gui.selected) { + gui.selected.action(); + } +} + +gui.controls = {}; +gui.controls.toString = function() { return "gui controls"; }; +gui.controls.update = function() { }; + +gui.controls.set_mum = function(mum) { mum.selected = true; @@ -67,22 +44,22 @@ GUI.controls.set_mum = function(mum) this.selected = mum; } -GUI.controls.check_bb = function(mum) +gui.controls.check_bb = function(mum) { if (bbox.pointin(mum.bb, input.mouse.screenpos())) - GUI.controls.set_mum(mum); + gui.controls.set_mum(mum); } -GUI.controls.inputs = {}; -GUI.controls.inputs.fallthru = false; -GUI.controls.inputs.mouse = {}; -GUI.controls.inputs.mouse.move = function(pos,dpos) +gui.controls.inputs = {}; +gui.controls.inputs.fallthru = false; +gui.controls.inputs.mouse = {}; +gui.controls.inputs.mouse.move = function(pos,dpos) { } -GUI.controls.inputs.mouse.scroll = function(scroll) +gui.controls.inputs.mouse.scroll = function(scroll) { } -GUI.controls.check_submit = function() { +gui.controls.check_submit = function() { if (this.selected && this.selected.action) this.selected.action(this.selected); } @@ -145,7 +122,7 @@ Mum.text = Mum.extend({ cursor ??= [0,0]; cnt ??= Mum; if (this.hide) return; - if (this.selectable) GUI.controls.check_bb(this); + if (this.selectable) gui.controls.check_bb(this); this.caret ??= -1; /* if (!this.bb) @@ -162,7 +139,7 @@ Mum.text = Mum.extend({ var aa = [0,1].sub(params.anchor); var pos = cursor.add(params.wh.scale(aa)).add(params.offset); gui.font_set(params.font); - gui.text(params.str, pos, params.font_size, params.color, this.width, params.caret); + render.text(params.str, pos, params.font_size, params.color, this.width, undefined, params.caret); }, update_bb(cursor) { @@ -198,12 +175,12 @@ Mum.window = Mum.extend({ cursor ??= [0,0]; cnt ??= Mum; var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding); - GUI.window(p,this.wh, this.color); + render.window(p,this.wh, this.color); this.bb = bbox.blwh(p, this.wh); gui.flush(); gui.scissor(p.x,p.y,this.wh.x,this.wh.y); this.max_width = this.width; - if (this.selectable) GUI.controls.check_bb(this); + if (this.selectable) gui.controls.check_bb(this); var pos = [this.bb.l, this.bb.t].add(this.padding); this.items.forEach(function(item) { if (item.hide) return; @@ -259,14 +236,6 @@ Mum.column = Mum.extend({ }, }); -GUI.window = function(pos, wh, color) -{ - var p = pos.slice(); - p.x += wh.x/2; - p.y += wh.y/2; - render.box(p,wh,color); -} - Mum.debug_colors = { bounds: Color.red.slice(), margin: Color.blue.slice(), @@ -275,7 +244,4 @@ Mum.debug_colors = { Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; }); -return { - GUI, - Mum -}; +return { Mum }; diff --git a/scripts/input.js b/scripts/input.js index 69b342f..16ac62a 100644 --- a/scripts/input.js +++ b/scripts/input.js @@ -1,5 +1,5 @@ input.keycodes = { - 259: "back", + 259: "backspace", 258: "tab", 257: "enter", 256: "escape", @@ -111,7 +111,9 @@ prosperon.droppedfile = function(path) var mousepos = [0,0]; -prosperon.textinput = function(l){}; +prosperon.textinput = function(c){ + player[0].raw_input("char", "pressed", c); +}; prosperon.mousemove = function(pos, dx){ mousepos = pos; player[0].mouse_input(modstr() + "move", pos, dx); @@ -126,48 +128,46 @@ prosperon.mouseup = function(b){ player[0].raw_input(modstr() + input.mouse.button[b], "released"); }; -input.mouse = { - screenpos() { return mousepos.slice(); }, - worldpos() { return game.camera.view2world(mousepos); }, - disabled() { input.mouse_mode(1); }, - normal() { input.mouse_mode(0); }, - - mode(m) { - if (input.mouse.custom[m]) - input.cursor_img(input.mouse.custom[m]); - else - input.mouse_cursor(m); - }, +input.mouse = {}; +input.mouse.screenpos = function() { return mousepos.slice(); }; +input.mouse.worldpos = function() { return game.camera.view2world(mousepos); }; +input.mouse.disabled = function() { input.mouse_mode(1); }; +input.mouse.normal = function() { input.mouse_mode(0); }; +input.mouse.mode = function(m) { + if (input.mouse.custom[m]) + input.cursor_img(input.mouse.custom[m]); + else + input.mouse_cursor(m); +}; - set_custom_cursor(img, mode) { - mode ??= input.mouse.cursor.default; - if (!img) - delete input.mouse.custom[mode]; - else { - input.cursor_img(img); - input.mouse.custom[mode] = img; - } - }, +input.mouse.set_custom_cursor = function(img, mode) { + mode ??= input.mouse.cursor.default; + if (!img) + delete input.mouse.custom[mode]; + else { + input.cursor_img(img); + input.mouse.custom[mode] = img; + } +}; - button: { /* left, right, middle mouse */ - 0: "lm", - 1: "rm", - 2: "mm" - }, - custom:[], - cursor: { - default: 0, - arrow: 1, - ibeam: 2, - cross: 3, - hand: 4, - ew: 5, - ns: 6, - nwse: 7, - nesw: 8, - resize: 9, - no: 10 - }, +input.mouse.button = { /* left, right, middle mouse */ + 0: "lm", + 1: "rm", + 2: "mm" +}; +input.mouse.custom = []; +input.mouse.cursor = { + default: 0, + arrow: 1, + ibeam: 2, + cross: 3, + hand: 4, + ew: 5, + ns: 6, + nwse: 7, + nesw: 8, + resize: 9, + no: 10 }; input.mouse.doc = {}; diff --git a/scripts/physics.js b/scripts/physics.js index 2292698..b143381 100644 --- a/scripts/physics.js +++ b/scripts/physics.js @@ -12,7 +12,7 @@ var HIT = { var pq = physics.pos_query; physics.pos_query = function(pos,give) { give ??= 25; - pq(pos,give); + return pq(pos,give); } physics.box_point_query = function(box,points) { diff --git a/scripts/render.js b/scripts/render.js index 4fb8e47..24de33e 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -88,14 +88,13 @@ render.arrow = function(start, end, color, wingspan, wingangle) { }; render.coordinate = function(pos, size, color) { - color ??= Color.white; - render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); - render.point(pos, 2, color); + render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); + render.point(pos, 2, color); } render.boundingbox = function(bb, color) { color ??= Color.white; - cmd_points(0, bbox.topoints(bb), color); + render.poly(bbox.topoints(bb), color); } render.rectangle = function(lowerleft, upperright, color) { @@ -110,6 +109,12 @@ render.box = function(pos, wh, color) { render.rectangle(lower,upper,color); }; +render.window = function(pos, wh, color) { + var p = pos.slice(); + p = p.add(wh.scale(0.5)); + render.box(p,wh,color); +}; + render.text = function(str, pos, size, color, wrap, anchor, cursor) { size ??= 1; color ??= Color.white; @@ -122,7 +127,7 @@ render.text = function(str, pos, size, color, wrap, anchor, cursor) { var w = bb.r*2; var h = bb.t*2; - //gui.text draws with an anchor on top left corner + //render.text draws with an anchor on top left corner var p = pos.slice(); p.x -= w * anchor.x; bb.r += (w*anchor.x); diff --git a/scripts/std.js b/scripts/std.js index 3598064..9589205 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -190,6 +190,8 @@ Cmdline.register_order("edit", function() { say("No game to edit. Try making one with 'prosperon init'."); return; } + + window.size = [1280, 720]; game.engine_start(function() { global.mixin("scripts/editor.js"); diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index 1c246c5..4a7314f 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -48,13 +48,7 @@ cpTransform m3_to_cpt(HMM_Mat3 m) } cpShape *phys2d_query_pos(cpVect pos) { - cpShapeFilter filter; - filter.group = CP_NO_GROUP; - filter.mask = CP_ALL_CATEGORIES; - filter.categories = CP_ALL_CATEGORIES; - cpShape *find = cpSpacePointQueryNearest(space, pos, 0.f, filter, NULL); - - return find; + return cpSpacePointQueryNearest(space, pos, 0.f, allfilter, NULL); } diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 2175f1c..0bb3edf 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -51,10 +51,7 @@ gameobject *pos2gameobject(HMM_Vec2 pos, float give) { return shape2go(hit); for (int i = 0; i < arrlen(gameobjects); i++) { - if (!gameobjects[i]->body) continue; - HMM_Vec2 gpos = go_pos(gameobjects[i]); - float dist = HMM_DistV2(gpos,pos); - + float dist = HMM_DistV2(go_pos(gameobjects[i]),pos); if (dist <= give) return gameobjects[i]; } diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 5a9246c..aec39ed 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -608,111 +608,6 @@ JSC_CCALL(emitter_start, start_emitter(js2emitter(this))) JSC_CCALL(emitter_stop, stop_emitter(js2emitter(this))) JSC_CCALL(emitter_emit, emitter_emit(js2emitter(this), js2number(argv[0]))) -JSValue js_os_cwd(JSContext *js, JSValue this, int argc, JSValue *argv) -{ - char cwd[PATH_MAX]; - #ifndef __EMSCRIPTEN__ - getcwd(cwd, sizeof(cwd)); - #else - cwd[0] = '.'; - cwd[1] = 0; - #endif - return str2js(cwd); -} - -JSC_SCALL(os_env, ret = str2js(getenv(str))) - -JSValue js_os_sys(JSContext *js, JSValue this, int argc, JSValue *argv) -{ - #ifdef __linux__ - return str2js("linux"); - #elif defined(_WIN32) || defined(_WIN64) - return str2js("windows"); - #elif defined(__APPLE__) - return str2js("macos"); - #endif - return JS_UNDEFINED; -} - -JSC_CCALL(os_quit, quit();) -JSC_CCALL(os_exit, exit(js2number(argv[0]));) -JSC_CCALL(os_reindex_static, cpSpaceReindexStatic(space)); -JSC_CCALL(os_gc, script_gc()); -JSC_SSCALL(os_eval, ret = script_eval(str, str2)) -JSC_SCALL(os_capture, capture_screen(js2number(argv[1]), js2number(argv[2]), js2number(argv[4]), js2number(argv[5]), str)) - -JSC_CCALL(os_sprite, - if (js2boolean(argv[0])) return JS_GetClassProto(js,js_sprite_id); - return sprite2js(sprite_make()); -) - -JSC_CCALL(os_make_gameobject, return gameobject2js(MakeGameobject())) -JSC_CCALL(os_make_circle2d, - gameobject *go = js2gameobject(argv[0]); - struct phys2d_circle *circle = Make2DCircle(go); - JSValue circleval = JS_NewObject(js); - js_setprop_str(circleval, "id", ptr2js(circle)); - js_setprop_str(circleval, "shape", ptr2js(&circle->shape)); - return circleval; -) - -JSC_CCALL(os_make_model, - gameobject *go = js2gameobject(argv[0]); - struct drawmodel *dm = make_drawmodel(go); - JSValue ret = JS_NewObject(js); - js_setprop_str(ret, "id", ptr2js(dm)); - return ret; -) - -JSC_CCALL(os_make_poly2d, - gameobject *go = js2gameobject(argv[0]); - struct phys2d_poly *poly = Make2DPoly(go); - phys2d_poly_setverts(poly, NULL); - JSValue polyval = JS_NewObject(js); - js_setprop_str(polyval, "id", ptr2js(poly)); - js_setprop_str(polyval, "shape", ptr2js(&poly->shape)); - return polyval; -) - -JSC_CCALL(os_make_edge2d, - gameobject *go = js2gameobject(argv[0]); - struct phys2d_edge *edge = Make2DEdge(go); - HMM_Vec2 *points = js2cpvec2arr(argv[1]); - phys2d_edge_update_verts(edge, points); - arrfree(points); - - JSValue edgeval = JS_NewObject(js); - js_setprop_str(edgeval, "id", ptr2js(edge)); - js_setprop_str(edgeval, "shape", ptr2js(&edge->shape)); - return edgeval; -) - -JSC_SCALL(os_make_texture, - ret = texture2js(texture_from_file(str)); - YughInfo("Made texture with %s", str); - JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0])); -) -JSC_SCALL(os_system, system(str); ) - -static const JSCFunctionListEntry js_os_funcs[] = { - MIST_FUNC_DEF(os,sprite,1), - MIST_FUNC_DEF(os, cwd, 0), - MIST_FUNC_DEF(os, env, 1), - MIST_FUNC_DEF(os, sys, 0), - MIST_FUNC_DEF(os, system, 1), - MIST_FUNC_DEF(os, quit, 0), - MIST_FUNC_DEF(os, exit, 1), - MIST_FUNC_DEF(os, reindex_static, 0), - MIST_FUNC_DEF(os, gc, 0), - MIST_FUNC_DEF(os, capture, 5), - MIST_FUNC_DEF(os, eval, 2), - MIST_FUNC_DEF(os, make_gameobject, 0), - MIST_FUNC_DEF(os, make_circle2d, 1), - MIST_FUNC_DEF(os, make_poly2d, 1), - MIST_FUNC_DEF(os, make_edge2d, 1), - MIST_FUNC_DEF(os, make_model, 2), - MIST_FUNC_DEF(os, make_texture, 1), -}; JSC_CCALL(render_grid, draw_grid(js2number(argv[0]), js2number(argv[1]), js2color(argv[2]));) JSC_CCALL(render_point, draw_cppoint(js2vec2(argv[0]), js2number(argv[1]), js2color(argv[2]))) @@ -1030,8 +925,7 @@ JSC_CCALL(physics_set_cat_mask, set_cat_mask(js2number(argv[0]), js2bitmask(argv JSC_CCALL(physics_pos_query, gameobject *go = pos2gameobject(js2vec2(argv[0]), js2number(argv[1])); - JSValue ret = go ? JS_DupValue(js,go->ref) : JS_UNDEFINED; - return ret; + return go ? JS_DupValue(js,go->ref) : JS_UNDEFINED; ) JSC_CCALL(physics_closest_point, @@ -1207,8 +1101,14 @@ static JSValue js_window_set_size(JSContext *js, JSValue this, JSValue v) { return JS_UNDEFINED; } - -JSC_GETSET_APPLY(window, rendersize, vec2) +static JSValue js_window_get_rendersize(JSContext *js, JSValue this) { + window *w = js2window(this); + if (w->rendersize.x == 0 || w->rendersize.y == 0) return vec22js(w->size); + return vec22js(w->rendersize); +} +static JSValue js_window_set_rendersize(JSContext *js, JSValue this, JSValue v) { + js2window(this)->rendersize = js2vec2(v); +} JSC_GETSET(window, mode, number) static JSValue js_window_get_fullscreen(JSContext *js, JSValue this) { return boolean2js(js2window(this)->fullscreen); } static JSValue js_window_set_fullscreen(JSContext *js, JSValue this, JSValue v) { window_setfullscreen(js2window(this), js2boolean(v)); } @@ -1235,12 +1135,13 @@ static const JSCFunctionListEntry js_window_funcs[] = { }; JSValue js_gameobject_set_pos(JSContext *js, JSValue this, JSValue val) { - gameobject *go = js2gameobject(this); - cpBodySetPosition(go->body, js2vec2(val).cp); - if (go->phys == CP_BODY_TYPE_STATIC) - cpSpaceReindexShapesForBody(space, go->body); + cpBody *b = js2gameobject(this)->body; + cpBodySetPosition(b, js2cvec2(val)); + if (cpBodyGetType(b) == CP_BODY_TYPE_STATIC) + cpSpaceReindexShapesForBody(space, b); + return JS_UNDEFINED; } -JSValue js_gameobject_get_pos(JSContext *js, JSValue this) { return vec22js((HMM_Vec2)cpBodyGetPosition(js2gameobject(this)->body)); } +JSValue js_gameobject_get_pos(JSContext *js, JSValue this) { return cvec22js(cpBodyGetPosition(js2gameobject(this)->body)); } JSValue js_gameobject_set_angle (JSContext *js, JSValue this, JSValue val) { cpBodySetAngle(js2gameobject(this)->body, HMM_TurnToRad*js2number(val)); } JSValue js_gameobject_get_angle (JSContext *js, JSValue this) { return number2js(HMM_RadToTurn*cpBodyGetAngle(js2gameobject(this)->body)); } JSC_GETSET_BODY(velocity, Velocity, cvec2) @@ -1511,6 +1412,117 @@ static const JSCFunctionListEntry js_nota_funcs[] = { MIST_FUNC_DEF(nota, decode, 1) }; + +JSValue js_os_cwd(JSContext *js, JSValue this, int argc, JSValue *argv) +{ + char cwd[PATH_MAX]; + #ifndef __EMSCRIPTEN__ + getcwd(cwd, sizeof(cwd)); + #else + cwd[0] = '.'; + cwd[1] = 0; + #endif + return str2js(cwd); +} + +JSC_SCALL(os_env, ret = str2js(getenv(str))) + +JSValue js_os_sys(JSContext *js, JSValue this, int argc, JSValue *argv) +{ + #ifdef __linux__ + return str2js("linux"); + #elif defined(_WIN32) || defined(_WIN64) + return str2js("windows"); + #elif defined(__APPLE__) + return str2js("macos"); + #endif + return JS_UNDEFINED; +} + +JSC_CCALL(os_quit, quit();) +JSC_CCALL(os_exit, exit(js2number(argv[0]));) +JSC_CCALL(os_reindex_static, cpSpaceReindexStatic(space)); +JSC_CCALL(os_gc, script_gc()); +JSC_SSCALL(os_eval, ret = script_eval(str, str2)) +JSC_SCALL(os_capture, capture_screen(js2number(argv[1]), js2number(argv[2]), js2number(argv[4]), js2number(argv[5]), str)) + +JSC_CCALL(os_sprite, + if (js2boolean(argv[0])) return JS_GetClassProto(js,js_sprite_id); + return sprite2js(sprite_make()); +) + +JSC_CCALL(os_make_gameobject, + ret = gameobject2js(MakeGameobject()); + JS_SetPropertyFunctionList(js, ret, js_gameobject_funcs, countof(js_gameobject_funcs)); + return ret; +) +JSC_CCALL(os_make_circle2d, + gameobject *go = js2gameobject(argv[0]); + struct phys2d_circle *circle = Make2DCircle(go); + JSValue circleval = JS_NewObject(js); + js_setprop_str(circleval, "id", ptr2js(circle)); + js_setprop_str(circleval, "shape", ptr2js(&circle->shape)); + return circleval; +) + +JSC_CCALL(os_make_model, + gameobject *go = js2gameobject(argv[0]); + struct drawmodel *dm = make_drawmodel(go); + JSValue ret = JS_NewObject(js); + js_setprop_str(ret, "id", ptr2js(dm)); + return ret; +) + +JSC_CCALL(os_make_poly2d, + gameobject *go = js2gameobject(argv[0]); + struct phys2d_poly *poly = Make2DPoly(go); + phys2d_poly_setverts(poly, NULL); + JSValue polyval = JS_NewObject(js); + js_setprop_str(polyval, "id", ptr2js(poly)); + js_setprop_str(polyval, "shape", ptr2js(&poly->shape)); + return polyval; +) + +JSC_CCALL(os_make_edge2d, + gameobject *go = js2gameobject(argv[0]); + struct phys2d_edge *edge = Make2DEdge(go); + HMM_Vec2 *points = js2cpvec2arr(argv[1]); + phys2d_edge_update_verts(edge, points); + arrfree(points); + + JSValue edgeval = JS_NewObject(js); + js_setprop_str(edgeval, "id", ptr2js(edge)); + js_setprop_str(edgeval, "shape", ptr2js(&edge->shape)); + return edgeval; +) + +JSC_SCALL(os_make_texture, + ret = texture2js(texture_from_file(str)); + YughInfo("Made texture with %s", str); + JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0])); +) +JSC_SCALL(os_system, system(str); ) + +static const JSCFunctionListEntry js_os_funcs[] = { + MIST_FUNC_DEF(os,sprite,1), + MIST_FUNC_DEF(os, cwd, 0), + MIST_FUNC_DEF(os, env, 1), + MIST_FUNC_DEF(os, sys, 0), + MIST_FUNC_DEF(os, system, 1), + MIST_FUNC_DEF(os, quit, 0), + MIST_FUNC_DEF(os, exit, 1), + MIST_FUNC_DEF(os, reindex_static, 0), + MIST_FUNC_DEF(os, gc, 0), + MIST_FUNC_DEF(os, capture, 5), + MIST_FUNC_DEF(os, eval, 2), + MIST_FUNC_DEF(os, make_gameobject, 0), + MIST_FUNC_DEF(os, make_circle2d, 1), + MIST_FUNC_DEF(os, make_poly2d, 1), + MIST_FUNC_DEF(os, make_edge2d, 1), + MIST_FUNC_DEF(os, make_model, 2), + MIST_FUNC_DEF(os, make_texture, 1), +}; + #include "steam.h" void ffi_load() { diff --git a/source/engine/jsffi.h b/source/engine/jsffi.h index e8be117..d57f34b 100644 --- a/source/engine/jsffi.h +++ b/source/engine/jsffi.h @@ -114,7 +114,6 @@ JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYP JS_SetPropertyStr(js, TYPE##_proto, "memid", JS_NewCFunction(js, &js_##TYPE##_memid, "memid", 0)); \ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ - #define countof(x) (sizeof(x)/sizeof((x)[0])) void ffi_load(); diff --git a/source/engine/render.h b/source/engine/render.h index db78956..69f8ef9 100644 --- a/source/engine/render.h +++ b/source/engine/render.h @@ -29,15 +29,8 @@ extern HMM_Vec3 dirl_pos; extern HMM_Mat4 projection; extern HMM_Mat4 hudproj; - extern HMM_Mat4 useproj; -struct camera3d { - -}; - -typedef struct camera3d camera3d; - struct draw_p { float x; float y; @@ -61,12 +54,8 @@ void openglRender(struct window *window, gameobject *cam, float zoom); void opengl_rendermode(enum RenderMode r); void openglInit3d(struct window *window); -void openglRender3d(struct window *window, camera3d *camera); void capture_screen(int x, int y, int w, int h, const char *path); -HMM_Vec2 world2screen(HMM_Vec2 pos); -HMM_Vec2 screen2world(HMM_Vec2 pos); - void gif_rec_start(int w, int h, int cpf, int bitdepth); void gif_rec_end(const char *path); diff --git a/source/engine/yugine.c b/source/engine/yugine.c index 2ff5b9a..c971570 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -92,6 +92,7 @@ void c_clean() { void c_event(const sapp_event *e) { + char lcfmt[5]; switch (e->type) { case SAPP_EVENTTYPE_MOUSE_MOVE: script_evalf("prosperon.mousemove([%g, %g], [%g, %g]);", e->mouse_x, mainwin.size.y -e->mouse_y, e->mouse_dx, -e->mouse_dy); @@ -118,7 +119,8 @@ void c_event(const sapp_event *e) break; case SAPP_EVENTTYPE_CHAR: - script_evalf("prosperon.textinput(`\\%lc`);", e->char_code); + snprintf(lcfmt, 5, "%lc", e->char_code); + script_evalf("prosperon.textinput(`%s`);", lcfmt); break; case SAPP_EVENTTYPE_RESIZED: