From a8f7f20d6e1621dba7b747abaaec954c53e44ae4 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sat, 27 May 2023 12:01:17 +0000 Subject: [PATCH] rendering --- source/engine/2dphysics.c | 8 +- source/engine/debug/debugdraw.c | 25 ++-- source/engine/ffi.c | 40 +++++- source/engine/gameobject.c | 3 +- source/engine/gameobject.h | 2 + source/engine/openglrender.c | 1 + source/engine/yugine.c | 2 +- source/scripts/base.js | 23 ++++ source/scripts/components.js | 221 +++++++++++++++++--------------- source/scripts/engine.js | 60 +++------ 10 files changed, 227 insertions(+), 158 deletions(-) diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index 0cf934f..04e1b6d 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -430,6 +430,7 @@ struct phys2d_edge *Make2DEdge(int go) { new->shape.moi = phys2d_edge_moi; new->shape.shape = NULL; new->draws = 0; + new->closed = 0; phys2d_applyedge(new); return new; @@ -572,8 +573,12 @@ void shape_set_sensor(struct phys2d_shape *shape, int sensor) { int shape_get_sensor(struct phys2d_shape *shape) { if (!shape->shape) { - return cpShapeGetSensor(((struct phys2d_edge *)(shape->data))->shapes[0]); + struct phys2d_edge *edge = shape->data; + if (arrlen(edge->shapes) > 0) return cpShapeGetSensor(edge->shapes[0]); + + return 0; } + return cpShapeGetSensor(shape->shape); } @@ -593,6 +598,7 @@ void duk_call_phys_cb(cpVect norm, struct callee c, int hit, cpArbiter *arb) { JS_SetPropertyStr(js, obj, "velocity", vec2js(cpArbiterGetSurfaceVelocity(arb))); JS_SetPropertyStr(js, obj, "pos", vec2js(cpArbiterGetPointA(arb, 0))); JS_SetPropertyStr(js, obj, "id", JS_NewInt32(js,hit)); + JS_SetPropertyStr(js,obj,"obj", JS_DupValue(js,id2go(hit)->ref)); script_callee(c, 1, &obj); } diff --git a/source/engine/debug/debugdraw.c b/source/engine/debug/debugdraw.c index 8ec95c3..4844403 100644 --- a/source/engine/debug/debugdraw.c +++ b/source/engine/debug/debugdraw.c @@ -81,17 +81,6 @@ static struct circle_vertex circle_b[v_amt]; void debug_flush() { - if (circle_count != 0) { - sg_apply_pipeline(circle_pipe); - sg_apply_bindings(&circle_bind); - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection)); - sg_update_buffer(circle_bind.vertex_buffers[0], &(sg_range){ - .ptr = circle_b, - .size = sizeof(struct circle_vertex)*circle_count - }); - sg_draw(0,4,circle_count); - circle_count = 0; - } if (poly_c != 0) { sg_apply_pipeline(poly_pipe); @@ -135,6 +124,19 @@ void debug_flush() line_c = 0; line_v = 0; } + + if (circle_count != 0) { + sg_apply_pipeline(circle_pipe); + sg_apply_bindings(&circle_bind); + sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection)); + sg_update_buffer(circle_bind.vertex_buffers[0], &(sg_range){ + .ptr = circle_b, + .size = sizeof(struct circle_vertex)*circle_count + }); + sg_draw(0,4,circle_count); + circle_count = 0; + } + } static sg_shader_uniform_block_desc projection_ubo = { @@ -311,6 +313,7 @@ void debugdraw_init() void draw_line(cpVect *a_points, int a_n, struct rgba color, float seg_len, int closed, float seg_speed) { if (a_n < 2) return; + seg_speed = 1; int n = closed ? a_n+1 : a_n; cpVect points[n]; diff --git a/source/engine/ffi.c b/source/engine/ffi.c index 7556b6e..94f22e9 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -85,6 +85,11 @@ int js2bool(JSValue v) { return JS_ToBool(js, v); } +JSValue bool2js(int b) +{ + return JS_NewBool(js,b); +} + JSValue float2js(double g) { return JS_NewFloat64(js, g); } @@ -97,6 +102,8 @@ struct gameobject *js2go(JSValue v) { return id2go(js2int(v)); } +struct sprite *js2sprite(JSValue v) { return id2go(js2int(v)); } + void *js2ptr(JSValue v) { void *p; JS_ToInt64(js, &p, v); @@ -212,6 +219,12 @@ JSValue vec2js(cpVect v) { return array; } +JSValue v22js(HMM_Vec2 v) +{ + cpVect c = { v.X, v.Y }; + return vec2js(c); +} + JSValue vecarr2js(cpVect *points, int n) { JSValue array = JS_NewArray(js); for (int i = 0; i < n; i++) @@ -978,19 +991,32 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) return bool2js(js2go(argv[1])->flipy); case 106: - js2go(argv[1])->e = js2num(argv[2]); + js2go(argv[1])->e = js2number(argv[2]); break; case 107: return num2js(js2go(argv[1])->e); case 108: - js2go(argv[1])->f = js2num(argv[2]); + js2go(argv[1])->f = js2number(argv[2]); break; case 109: return num2js(js2go(argv[1])->f); case 110: - return num2js(js2go(argv[1]) + return num2js(js2go(argv[1])->e); + + case 111: + return v22js(js2sprite(argv[1])->pos); + + case 112: + return num2js(((struct phys2d_edge*)js2ptr(argv[1]))->thickness); + + case 113: + js2go(argv[1])->ref = JS_DupValue(js,argv[2]); + break; + + case 114: + return bool2js(js2sprite(argv[1])->enabled); } if (str) @@ -1186,6 +1212,8 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a case 1: go->bodytype = js2int(argv[2]); + cpBodySetType(go->body, go->bodytype); + gameobject_apply(go); break; case 2: @@ -1209,7 +1237,11 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a break; case 7: - cpBodySetMass(go->body, js2number(argv[2])); + if (go->bodytype == CP_BODY_TYPE_DYNAMIC) + cpBodySetMass(go->body, js2number(argv[2])); + else + YughWarn("Cannot set mass of a non dynamic body."); + break; case 8: diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 3b45ba0..dd1e757 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -105,7 +105,7 @@ void go_shape_moi(cpBody *body, cpShape *shape, struct gameobject *go) { } moment += s->moi(s->data, go->mass); - if (moment < 0) moment = 0; + if (moment < 0) moment = 1; cpBodySetMoment(go->body, moment); } @@ -145,6 +145,7 @@ int MakeGameobject() { .next = -1, .sensor = 0, .shape_cbs = NULL, + .ref = JS_NULL, }; go.cbs.begin.obj = JS_NULL; diff --git a/source/engine/gameobject.h b/source/engine/gameobject.h index 57003c7..b9c0abd 100644 --- a/source/engine/gameobject.h +++ b/source/engine/gameobject.h @@ -6,6 +6,7 @@ #include #include #include +#include "quickjs/quickjs.h" struct shader; struct sprite; @@ -27,6 +28,7 @@ struct gameobject { int id; struct phys_cbs cbs; struct shape_cb *shape_cbs; + JSValue ref; }; extern struct gameobject *gameobjects; diff --git a/source/engine/openglrender.c b/source/engine/openglrender.c index 997b53e..f048965 100644 --- a/source/engine/openglrender.c +++ b/source/engine/openglrender.c @@ -331,6 +331,7 @@ void openglRender(struct window *window) { sprite_flush(); call_draw(); +// debug_flush(); //// DEBUG if (debugDrawPhysics) { diff --git a/source/engine/yugine.c b/source/engine/yugine.c index cd9b2f1..25d4a99 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -221,7 +221,7 @@ int main(int argc, char **args) { phys_step = 1; physlag -= physMS; phys2d_update(physMS * timescale); - call_physics(physMS * timescale); + call_physics(physMS * timescale); if (sim_play == SIM_STEP) sim_pause(); phys_step = 0; } diff --git a/source/scripts/base.js b/source/scripts/base.js index a9dc894..0bc6508 100644 --- a/source/scripts/base.js +++ b/source/scripts/base.js @@ -71,6 +71,17 @@ Object.defineProperty(Object.prototype, 'nulldef', { } }); +/*Object.defineProperty(Object.prototype, 'writable', { + value: function(name) { + return Object.getPropertyDescriptor(this, name).writable; + } +}); +*/ + +Object.defineProperty(Object.prototype, 'prop_obj', { + value: function() { return JSON.parse(JSON.stringify(this)); } +}); + /* defc 'define constant'. Defines a value that is not writable. */ Object.defineProperty(Object.prototype, 'defc', { value: function(name, val) { @@ -83,6 +94,18 @@ Object.defineProperty(Object.prototype, 'defc', { } }); +Object.defineProperty(Object.prototype, 'stick', { + value: function(prop) { + Object.defineProperty(this, prop, {writable:false}); + } +}); + +Object.defineProperty(Object.prototype, 'harden', { + value: function(prop) { + Object.defineProperty(this, prop, {writable:false, configurable:false, enumerable: false}); + } +}); + Object.defineProperty(Object.prototype, 'deflock', { value: function(prop) { Object.defineProperty(this,prop, {configurable:false}); diff --git a/source/scripts/components.js b/source/scripts/components.js index 29f35b4..904fd04 100644 --- a/source/scripts/components.js +++ b/source/scripts/components.js @@ -7,8 +7,7 @@ var component = { }, name: "component", component: true, - set enabled(x) { }, - get enabled() { }, + enabled: true, enable() { this.enabled = true; }, disable() { this.enabled = false; }, @@ -29,7 +28,6 @@ var sprite = clone(component, { path: "", layer: 0, pos: [0,0], - enabled: true, get visible() { return this.enabled; }, set visible(x) { this.enabled = x; }, angle: 0, @@ -43,34 +41,34 @@ var sprite = clone(component, { input_kp2_pressed() { this.pos = [-0.5,-1]; }, input_kp1_pressed() { this.pos = [-1,-1]; }, - get boundingbox() { - if (!this.gameobject) return null; - var dim = cmd(64, this.path); - dim = dim.scale(this.gameobject.scale); - var realpos = this.pos.copy(); - realpos.x *= dim.x; - realpos.y *= dim.y; - realpos.x += (dim.x/2); - realpos.y += (dim.y/2); - return cwh2bb(realpos, dim); - }, - make(go) { var old = this; var sprite = clone(this, { - get enabled() { return cmd(21,this.id); }, + get enabled() { return cmd(114,this.id); }, set enabled(x) { cmd(20,this.id,x); }, set color(x) { cmd(96,this.id,x); }, + get pos() { return cmd(111, this.id); }, set pos(x) { cmd(37,this.id,x); }, set layer(x) { cmd(60, this.id, x); }, get layer() { return this.gameobject.draw_layer; }, set path(x) { cmd(12,this.id,x,this.rect); }, + get boundingbox() { + var dim = cmd(64,this.path); + dim = dim.scale(this.gameobject.scale); + var realpos = this.pos.copy(); + realpos.x = realpos.x * dim.x + (dim.x/2); + realpos.y = realpos.y * dim.y + (dim.y/2); + return cwh2bb(realpos,dim); + }, + kill() { cmd(9,this.id); }, }); + sprite.obscure('boundingbox'); + var id = make_sprite(go,old.path,old.pos); - + Object.defineProperty(sprite, 'id', {value:id}); Object.assign(sprite, this); @@ -177,6 +175,23 @@ var char2d = clone(sprite, { }, }); +/* Returns points specifying this geometry, with ccw */ +var Geometry = { + box(w, h) { + w /= 2; + h /= 2; + + var points = [ + [w,h], + [-w,h], + [-w,-h], + [w,-h] + ]; + + return points; + } +}; + /* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */ var collider2d = clone(component, { name: "collider 2d", @@ -194,8 +209,6 @@ var collider2d = clone(component, { this.enabled = !this.enabled; }, - enabled: true, - get enabled() { return this._enabled; }, kill() {}, /* No killing is necessary - it is done through the gameobject's kill */ register_hit(fn, obj) { @@ -204,11 +217,22 @@ var collider2d = clone(component, { make_fns: { set sensor(x) { cmd(18,this.shape,x); }, - set enabled(x) { cmd(22,this.id,x); } + get sensor() { return cmd(21,this.shape); }, + set enabled(x) { cmd(22,this.shape,x); }, + get enabled() { + Log.warn("getting enabled"); + return cmd(23,this.shape); } }, }); +var sync_proxy = { + set(t,p,v) { + t[p] = v; + t.sync(); + return true; + } +}; var polygon2d = clone(collider2d, { name: "polygon 2d", @@ -225,32 +249,35 @@ var polygon2d = clone(collider2d, { make(go) { var poly = Object.create(this); - complete_assign(poly, this.make_fns); Object.assign(poly, make_poly2d(go, this.points)); + + complete_assign(poly, this.make_fns); + complete_assign(poly, { + get boundingbox() { + return points2bb(this.points.map(x => x.scale(this.gameobject.scale))); + }, + + sync() { cmd_poly2d(0, this.id, this.spoints); } + }); + poly.obscure('boundingbox'); + + poly.defn('points', this.points.copy()); + + poly = new Proxy(poly, sync_proxy); + Object.defineProperty(poly, 'id', {enumerable:false}); Object.defineProperty(poly, 'shape', {enumerable:false}); return poly; }, - - get boundingbox() { - if (!this.gameobject) return null; - var scaledpoints = []; - this.points.forEach(function(x) { scaledpoints.push(x.scale(this.gameobject.scale)); }, this); - return points2bb(scaledpoints); - }, + /* EDITOR */ help: "Ctrl-click Add a point\nShift-click Remove a point", input_f10_pressed() { this.points = sortpointsccw(this.points); }, - sync() { - if (!this.id) return; - cmd_poly2d(0, this.id, this.spoints); - this.coll_sync(); - }, input_b_pressed() { if (!Keys.ctrl()) return; @@ -278,7 +305,7 @@ var polygon2d = clone(collider2d, { spoints.push(newpoint); }); } - + return spoints; }, @@ -292,9 +319,6 @@ var polygon2d = clone(collider2d, { this.points.forEach(function(x, i) { Debug.numbered_point(this.gameobject.this2world(x), i); }, this); - - - this.sync(); }, input_lmouse_pressed() { @@ -325,7 +349,6 @@ var polygon2d = clone(collider2d, { var bucket = clone(collider2d, { name: "bucket", - help: "Ctrl-click Add a point\nShift-click Remove a point\n+,- Increase/decrease spline segs\nCtrl-+,- Inc/dec spline degrees\nCtrl-b,v Inc/dec spline thickness", clone(spec) { var obj = Object.create(this); obj.cpoints = this.cpoints.copy(); @@ -343,30 +366,11 @@ var bucket = clone(collider2d, { */ type: 3, - get boundingbox() { - if (!this.gameobject) return null; - var scaledpoints = []; - this.points.forEach(function(x) { scaledpoints.push(x.scale(this.gameobject.scale)); }, this); - return points2bb(scaledpoints); - }, - mirrorx: false, mirrory: false, - input_m_pressed() { - if (Keys.ctrl()) { - this.mirrory = !this.mirrory; - } else { - this.mirrorx = !this.mirrorx; - } - - this.sync(); - }, - hollow: false, - input_h_pressed() { - this.hollow = !this.hollow; - }, + hollowt: 0, get spoints() { var spoints = this.cpoints.slice(); @@ -391,8 +395,8 @@ var bucket = clone(collider2d, { if (this.hollow) { var hpoints = []; - var inflatep = inflate_cpv(spoints, spoints.length, this.hollowt); - inflatep[0].slice().reverse().forEach(function(x) { hpoints.push(x); }); + var inflatep = inflate_cpv(spoints, spoints.length, this.hollowt); + inflatep[0].slice().reverse().forEach(function(x) { hpoints.push(x); }); inflatep[1].forEach(function(x) { hpoints.push(x); }); return hpoints; @@ -401,19 +405,6 @@ var bucket = clone(collider2d, { return spoints; }, - hollowt: 0, - - input_g_pressed() { - if (!Keys.ctrl()) return; - this.hollowt--; - if (this.hollowt < 0) this.hollowt = 0; - }, - - input_f_pressed() { - if (!Keys.ctrl()) return; - this.hollowt++; - }, - sample(n) { var spoints = this.spoints; @@ -449,30 +440,38 @@ var bucket = clone(collider2d, { make(go) { var edge = Object.create(this); Object.assign(edge, make_edge2d(go, this.points, this.thickness)); - Object.defineProperty(edge, 'id', {enumerable:false}); - Object.defineProperty(edge, 'shape', {enumerable:false}); + edge = new Proxy(edge, sync_proxy); complete_assign(edge, { set thickness(x) { cmd_edge2d(1,this.id,x); - } - }); - edge.defn('points', []); - - edge.sync(); + }, + get thickness() { return cmd(112,this.id); }, - var synctriggers = ['samples', 'thickness']; + get boundingbox() { + return points2bb(this.points.map(x => x.scale(this.gameobject.scale))); + }, + + sync() { + var sensor = this.sensor; + this.points = this.sample(this.samples); + cmd_edge2d(0,this.id,this.points); + this.sensor = sensor; + }, + }); + + edge.obscure('boundingbox'); + + complete_assign(edge, this.make_fns); + + Object.defineProperty(edge, 'id', {enumerable:false}); + Object.defineProperty(edge, 'shape', {enumerable:false}); + + edge.defn('points', []); return edge; }, - sync() { - if (!this.gameobject) return; - this.points = this.sample(this.samples); - cmd_edge2d(0, this.id, this.points); - cmd_edge2d(1, this.id, this._thickness * this.gameobject.scale); - this.coll_sync(); - }, - + /* EDITOR */ gizmo() { if (!this.hasOwn('cpoints')) this.cpoints = this.__proto__.cpoints.copy(); @@ -483,10 +482,32 @@ var bucket = clone(collider2d, { this.cpoints.forEach(function(x, i) { Debug.numbered_point(this.gameobject.this2world(x), i); }, this); - - this.sync(); }, - + + help: "Ctrl-click Add a point\nShift-click Remove a point\n+,- Increase/decrease spline segs\nCtrl-+,- Inc/dec spline degrees\nCtrl-b,v Inc/dec spline thickness", + + input_h_pressed() { + this.hollow = !this.hollow; + }, + + input_m_pressed() { + if (Keys.ctrl()) { + this.mirrory = !this.mirrory; + } else { + this.mirrorx = !this.mirrorx; + } + }, + + input_g_pressed() { + if (!Keys.ctrl()) return; + this.hollowt--; + if (this.hollowt < 0) this.hollowt = 0; + }, + + input_f_pressed() { + if (!Keys.ctrl()) return; + this.hollowt++; + }, input_v_pressrep() { if (!Keys.alt()) return; @@ -505,9 +526,7 @@ var bucket = clone(collider2d, { finish_center(change) { this.cpoints = this.cpoints.map(function(x) { return x.sub(change); }); - this.sync(); }, - input_plus_pressrep() { if (Keys.ctrl()) @@ -602,12 +621,6 @@ var circle2d = clone(collider2d, { name: "circle 2d", radius: 10, offset: [0,0], - - get boundingbox() { - if (!this.gameobject) return null; - var radius = this.radius*2*this.gameobject.scale; - return cwh2bb(this.offset.scale(this.gameobject.scale), [radius, radius]); - }, get scale() { return this.radius; }, set scale(x) { this.radius = x; }, @@ -628,10 +641,16 @@ var circle2d = clone(collider2d, { set offset(x) { cmd_circle2d(1,this.id,this.offset); }, get offset() { return cmd_circle2d(4,this.id); }, - + + get boundingbox() { + var diameter = this.radius*2*this.gameobject.scale; + return cwh2bb(this.offset.scale(this.gameobject.scale), [radius,radius]); + }, }); complete_assign(circle, this.make_fns); + + circle.obscure('boundingbox'); return circle; }, diff --git a/source/scripts/engine.js b/source/scripts/engine.js index 300dfcf..de503b6 100644 --- a/source/scripts/engine.js +++ b/source/scripts/engine.js @@ -462,7 +462,11 @@ var Register = { }, physupdates: [], + postphys_cbs: [], physupdate(dt) { + this.postphys_cbs.forEach(x => x()); + this.postphys_cbs = []; + this.physupdates.forEach(x => x[0].call(x[1], dt)); }, @@ -1071,6 +1075,11 @@ var Level = { this.objects.push(loadedlevel); return; } + var prototype = gameobjects[x.from]; + if (!prototype) { + Log.error(`Prototype for ${x.from} does not exist.`); + return; + } var newobj = this.spawn(gameobjects[x.from]); @@ -1263,14 +1272,8 @@ var gameobject = { this.layer = Nuke.radio(i, this.layer, i); }, - _draw_layer: 1, - set draw_layer(x) { - if (x < 0) x = 0; - if (x > 4) x = 4; - this._draw_layer = x; - this.sync(); - }, - _draw_layer_nuke() { + draw_layer: 1, + draw_layer_nuke() { Nuke.label("Draw layer"); Nuke.newline(5); for (var i = 0; i < 5; i++) @@ -1281,8 +1284,6 @@ var gameobject = { return q_body(7, this.body); }, - get draw_layer() { return this._draw_layer; }, - name: "gameobject", toString() { return this.name; }, @@ -1294,6 +1295,7 @@ var gameobject = { obj.defc('name', name); obj.from = this.name; obj.defn('instances', []); + obj.obscure('from'); return obj; }, @@ -1338,26 +1340,6 @@ var gameobject = { body: -1, controlled: false, - get properties() { - var keys = []; - for (var key of Object.keys(this)) { - if (key.startsWith("_")) - keys.push(key.substring(1)); - else - keys.push(key); - } - - return keys; - }, - - toJSON() { - var obj = {}; - for (var key of this.properties) - obj[key] = this[key]; - - return obj; - }, - set_center(pos) { var change = pos.sub(this.pos); this.pos = pos; @@ -1479,6 +1461,8 @@ var gameobject = { return bb ? bb : cwh2bb([0,0], [0,0]); }, + stop() {}, + kill() { Log.warn(`Killing ${this.toString()}`); cmd(2, this.body); @@ -1502,13 +1486,6 @@ var gameobject = { this.stop(); }, - prop_obj() { - var obj = JSON.parse(JSON.stringify(this)); - delete obj.name; - delete obj.from; - return obj; - }, - get up() { return [0,1].rotate(Math.deg2rad(this.angle)); }, @@ -1552,7 +1529,7 @@ var gameobject = { obj.toString = function() { var props = obj.prop_obj(); for (var key in props) - if (typeof props[key] === 'object' && props[key].empty) + if (typeof props[key] === 'object' && !props[key] === null && props[key].empty) delete props[key]; var edited = !props.empty; @@ -1569,6 +1546,8 @@ var gameobject = { obj.sync(); obj.defn('components', {}); + cmd(113, obj.body, obj); + complete_assign(obj, { set scale(x) { cmd(36, this.body, x); }, get scale() { return cmd(103, this.body); }, @@ -1590,7 +1569,10 @@ var gameobject = { set friction(x) { cmd(108,this.body,x); }, set mass(x) { set_body(7,this.body,x); }, - get mass() { return cmd( + get mass() { return q_body(5, this.body); }, + + set phys(x) { set_body(1, this.body, x); }, + get phys() { return q_body(0,this.body); }, }); for (var prop in obj) {