From 174a9ed5862ddebc8f5289f071d6f078596773f1 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sat, 23 Sep 2023 17:35:02 +0000 Subject: [PATCH] Fix Object.merge; add many color palettes, normalize color fns --- scripts/base.js | 74 +++++++++++--------------------- scripts/components.js | 71 ++++++++++++++---------------- scripts/debug.js | 4 +- scripts/editor.js | 4 +- scripts/engine.js | 76 ++++++++++++++++++++++++++------- scripts/entity.js | 3 +- scripts/gui.js | 13 +++--- source/engine/debug/debugdraw.c | 4 +- source/engine/ffi.c | 10 ++--- source/engine/render.h | 10 +++-- source/engine/resources.c | 21 ++++++--- source/engine/script.c | 2 +- 12 files changed, 157 insertions(+), 135 deletions(-) diff --git a/scripts/base.js b/scripts/base.js index ad2a2db..a993408 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -19,23 +19,15 @@ URIError = {}; Object.complete_assign = function(target, source) { -var descriptors = {}; - var assigns = {}; if (typeof source === 'undefined') return target; + Object.keys(source).forEach(function (k) { - var desc = Object.getOwnPropertyDescriptor(source, k); - - if (desc.value) { - if (typeof desc.value === 'object' && desc.value.hasOwn('value')) - descriptors[k] = desc.value; - else - assigns[k] = desc.value; - } else - descriptors[k] = desc; + if (Object.isAccessor(source,k)) + Object.defineProperty(target, k, Object.getOwnPropertyDescriptor(source,k)); + else + target[k] = source[k]; }); - Object.defineProperties(target, descriptors); - Object.assign(target, assigns); return target; }; @@ -72,54 +64,36 @@ Object.dainty_assign = function(target, source) Object.isAccessor = function(obj, prop) { - var prop = Object.getOwnPropertyDescriptor(obj,prop); - if (prop) return false; - return true; + var desc = Object.getOwnPropertyDescriptor(obj,prop); + if (!desc) return false; + if (desc.get || desc.set) return true; + return false; } +Object.mergekey = function(o1,o2,k) +{ + if (typeof(o2[k]) === 'object') { + if (Array.isArray(o2[k])) + o1[k] = o2[k].slice(); + else + Object.merge(o1[k], o2[k]); + } else + o1[k] = o2[k]; +} /* Same as merge from Ruby */ Object.merge = function(target, ...objs) { - var objmerge = function(tar, obj) - { - for (var key of Object.keys(obj)) { - if (typeof obj[key] === 'object') { - if (tar[key]) { - objmerge(tar[key], obj[key]); - continue; - } - else { - tar[key] = obj[key]; - continue; - } - } - tar[key] = obj[key]; - } - } - for (var obj of objs) - objmerge(target,obj); + for (var key of Object.keys(obj)) + Object.mergekey(target,obj,key); } Object.totalmerge = function(target, ...objs) { - for (var obj of objs) { - for (var key in obj) { - if (typeof obj[key] === 'object') { - if (typeof target[key] === 'object') { - if (Object.isAccessor(target,key)) - target[key] = obj[key]; - else - Object.merge(target[key], obj[key]); - } - else - target[key] = obj[key]; - - } else - target[key] = obj[key]; - } - } + for (var obj of objs) + for (var key in obj) + Object.mergekey(target,obj,key); } /* Returns a new object with undefined, null, and empty values removed. */ diff --git a/scripts/components.js b/scripts/components.js index 461eca8..8d2a96d 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -35,14 +35,12 @@ component.sprite = { make(go) { var nsprite = Object.create(component.sprite.maker); Object.assign(nsprite, make_sprite(go)); - Object.assign(nsprite, this); nsprite.ur = this; return nsprite; }, }; component.sprite.maker = Object.copy(component, { - name: "sprite", set path(x) { cmd(12,this.id,x,this.rect); }, get visible() { return this.enabled; }, set visible(x) { this.enabled = x; }, @@ -73,6 +71,8 @@ component.sprite.maker = Object.copy(component, { height() { return cmd(64,this.path).y; }, }); +Object.freeze(sprite); + var sprite = component.sprite.maker; sprite.inputs = {}; @@ -85,11 +85,10 @@ sprite.inputs.kp4 = function() { this.pos = [-1,-0.5]; }; sprite.inputs.kp3 = function() { this.pos = [0, -1]; }; sprite.inputs.kp2 = function() { this.pos = [-0.5,-1]; }; sprite.inputs.kp1 = function() { this.pos = [-1,-1]; }; +Object.seal(sprite); /* Container to play sprites and anim2ds */ component.char2d = Object.copy(sprite, { - name: "char 2d", - frame2rect(frames, frame) { var rect = {s0:0,s1:1,t0:0,t1:1}; @@ -99,17 +98,15 @@ component.char2d = Object.copy(sprite, { return rect; }, - - make(go) { - var char = Object.copy(this, { - 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; }, + 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; }, + boundingbox() { var dim = cmd(64,this.path); dim = dim.scale(this.gameobject.scale); @@ -128,8 +125,12 @@ component.char2d = Object.copy(sprite, { }, kill() { cmd(9,this.id); }, - }); - + ur: { + + }, + + make(go) { + var char = Object.create(this); char.curplaying = char.anims.array()[0]; char.obscure('curplaying'); char.id = make_sprite(go, char.curplaying.path, this.pos); @@ -247,29 +248,26 @@ collider2d.inputs['M-t'] = function() { this.enabled = !this.enabled; } collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled."; component.polygon2d = Object.copy(collider2d, { - name: "polygon 2d", points: [], - flipx: false, - flipy: false, + + ur: { + flipx: false, + flipy: false + }, + + sync() { + cmd_poly2d(0, this.id, this.spoints); + }, + + boundingbox() { + return points2bb(this.spoints); + }, make(go) { var poly = Object.create(this); Object.assign(poly, make_poly2d(go, this.points)); - - Object.assign(poly, this.make_fns); - Object.assign(poly, { - boundingbox() { - return points2bb(this.spoints); - }, - - sync() { cmd_poly2d(0, this.id, this.spoints); } - }); - poly.defn('points', this.points.copy()); - Object.defineProperty(poly, 'id', {enumerable:false}); - Object.defineProperty(poly, 'shape', {enumerable:false}); - poly.sync(); return poly; @@ -604,10 +602,12 @@ bucket.inputs.rb.doc = "Rotate the points CW."; bucket.inputs.rb.rep = true; component.circle2d = Object.copy(collider2d, { - name: "circle 2d", set radius(x) { cmd_circle2d(0,this.id,x); }, get radius() { return cmd_circle2d(2,this.id); }, + set scale(x) { this.radius = x; }, + get scale() { return this.radius; }, + set offset(x) { cmd_circle2d(1,this.id,x); }, get offset() { return cmd_circle2d(3,this.id); }, @@ -619,9 +619,6 @@ component.circle2d = Object.copy(collider2d, { make(go) { var circle = Object.create(this); Object.assign(circle, make_circle2d(go, circle.radius, circle.offset)); - circle.radius = 10; - circle.offset = [0,0]; - return circle; }, @@ -669,5 +666,3 @@ var Resources = { }, }; - -Log.warn("bottom of components"); diff --git a/scripts/debug.js b/scripts/debug.js index d5ebb87..a4acd6a 100644 --- a/scripts/debug.js +++ b/scripts/debug.js @@ -85,7 +85,7 @@ var Debug = { draw() { if (this.draw_bb) - Game.objects.forEach(function(x) { Debug.boundingbox(x.boundingbox(), [255,255,255,10]); }); + Game.objects.forEach(function(x) { Debug.boundingbox(x.boundingbox(), Color.Debug.boundingbox.alpha(0.05)); }); if (Game.paused()) gui_text("PAUSED", [0,0],1); @@ -97,7 +97,7 @@ var Debug = { if (this.draw_names) Game.objects.forEach(function(x) { - GUI.text(x, world2screen(x.pos).add([0,32]), 1, [84,110,255]); + GUI.text(x, world2screen(x.pos).add([0,32]), 1, Color.Debug.names); }); if (Debug.Options.gif.rec) { diff --git a/scripts/editor.js b/scripts/editor.js index 5fa3802..54e2529 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -561,7 +561,7 @@ return; GUI.image("icons/icons8-lock-16.png", world2screen(obj.pos)); }); - Debug.draw_grid(1, editor_config.grid_size/editor.camera.zoom, editor_config.grid_color); + Debug.draw_grid(1, editor_config.grid_size/editor.camera.zoom, Color.Editor.grid.alpha(0.3)); var startgrid = screen2world([-20,Window.height]).map(function(x) { return Math.snap(x, editor_config.grid_size); }); var endgrid = screen2world([Window.width, 0]); @@ -595,7 +595,7 @@ return; wh[0] /= editor.camera.zoom; wh[1] /= editor.camera.zoom; var bb = cwh2bb(world2screen(c),wh); - Debug.boundingbox(bb, [255,255,55,10]); + Debug.boundingbox(bb, Color.Editor.select.alpha(0.1)); Debug.line(bb2points(bb).wrapped(1), Color.white); } diff --git a/scripts/engine.js b/scripts/engine.js index 637db6c..a4a5e8e 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -31,25 +31,25 @@ load("scripts/diff.js"); Log.level = 1; var Color = { - white: [255,255,255,255], - black: [0,0,0,255], - blue: [84,110,255,255], - green: [120,255,10,255], - yellow: [251,255,43,255], - red: [255,36,20,255], - teal: [96, 252, 237,255], - gray: [181,181,181,255], + white: [255,255,255], + black: [0,0,0], + blue: [84,110,255], + green: [120,255,10], + yellow: [251,255,43], + red: [255,36,20], + teal: [96, 252, 237], + gray: [181,181,181], cyan: [0,255,255], purple: [162,93,227], }; Color.Arkanoid = { - orange: [255,143,0,255], - teal: [0,255,255,255], - green: [0,255,0,255], - red: [255,0,0,255], - blue: [0,112,255,255], - purple: [255,0,255,255], + orange: [255,143,0], + teal: [0,255,255], + green: [0,255,0], + red: [255,0,0], + blue: [0,112,255], + purple: [255,0,255], yellow: [255,255,0], silver: [157,157,157], gold: [188,174,0], @@ -81,6 +81,50 @@ Color.Apple = { blue: [0,156,223] }; +Color.Debug = { + boundingbox: Color.white, + names: [84,110,255], +}; + +Color.Editor = { + grid: [99,255,128], + select: [255,255,55], + newgroup: [120,255,10], +}; + +/* Detects the format of all colors and munges them into a floating point format */ +Color.normalize = function(c) { + var add_a = function(a) { + var n = this.slice(); + n.a = a; + return n; + }; + + for (var p of Object.keys(c)) { + var fmt = "nrm"; + if (typeof c[p] !== 'object') continue; + if (!Array.isArray(c[p])) { + Color.normalize(c[p]); + continue; + } + + for (var color of c[p]) { + if (color > 1) { + fmt = "8b"; + break; + } + } + + switch(fmt) { + case "8b": + c[p] = c[p].map(function(x) { return x/255; }); + } + c[p].alpha = add_a; + } +}; + +Color.normalize(Color); + Object.deepfreeze(Color); var ColorMap = {}; @@ -140,6 +184,8 @@ ColorMap.Viridis = ColorMap.makemap({ 1: [253,231,37] }); +Color.normalize(ColorMap); + ColorMap.sample = function(t, map) { map ??= this; @@ -634,7 +680,7 @@ var Game = { }; if (newgroup.file) - newgroup.color = [120,255,10]; + newgroup.color = Color.Editor.newgroup; return newgroup; }, diff --git a/scripts/entity.js b/scripts/entity.js index 28e6961..382c852 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -347,7 +347,7 @@ var gameobject = { obj.components[prop] = obj[prop]; } }; - + Object.totalmerge(obj,ur); obj.check_registers(obj); @@ -497,7 +497,6 @@ prototypes.from_obj = function(name, obj) { var newobj = Object.copy(gameobject.ur, obj); prototypes.ur[name] = newobj; - Log.say(Object.keys(newobj)); newobj.toString = function() { return name; }; return prototypes.ur[name]; } diff --git a/scripts/gui.js b/scripts/gui.js index 3070153..39184cd 100644 --- a/scripts/gui.js +++ b/scripts/gui.js @@ -1,9 +1,8 @@ var GUI = { text(str, pos, size, color, wrap) { - size = size ? size : 1; - - color = color ? color : [255,255,255,255]; - wrap = wrap ? wrap : -1; + size ??= 1; + color ??= Color.white; + wrap ??= -1; var bb = cmd(118, str, size, wrap); var opos = [bb.r, bb.t]; @@ -14,7 +13,7 @@ var GUI = { }, text_cursor(str, pos, size, cursor) { - cursor_text(str,pos,size,[255,255,255],cursor); + cursor_text(str,pos,size,Color.white,cursor); }, image(path,pos) { @@ -70,10 +69,10 @@ var GUI = { anchor: [0,0], text_shadow: { pos: [0,0], - color: [255,255,255,255] + color: Color.white, }, text_outline: 1, /* outline in pixels */ - color: [255,255,255,255], + color: Color.white, margin: [5,5], /* Distance between elements for things like columns */ width: 0, height: 0, diff --git a/source/engine/debug/debugdraw.c b/source/engine/debug/debugdraw.c index edea6c9..ae26d68 100644 --- a/source/engine/debug/debugdraw.c +++ b/source/engine/debug/debugdraw.c @@ -559,8 +559,8 @@ void draw_grid(float width, float span, struct rgba color) sg_apply_pipeline(grid_pipe); sg_apply_bindings(&grid_bind); - - float col[4] = { color.r/255.0 ,color.g/255.0 ,color.b/255.0 ,color.a/255.0 }; + float col[4]; + rgba2floats(col,color); fs_params_t pt; pt.thickness = (float)width; diff --git a/source/engine/ffi.c b/source/engine/ffi.c index 4ce2897..2aac380 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -161,12 +161,12 @@ struct rgba js2color(JSValue v) { JSValue c[4]; for (int i = 0; i < 4; i++) c[i] = js_arridx(v,i); - unsigned char a = JS_IsUndefined(c[3]) ? 255 : js2int(c[3]); + float a = JS_IsUndefined(c[3]) ? 1.0 : js2number(c[3]); struct rgba color = { - .r = js2int(c[0]), - .g = js2int(c[1]), - .b = js2int(c[2]), - .a = a, + .r = js2number(c[0])*RGBA_MAX, + .g = js2number(c[1])*RGBA_MAX, + .b = js2number(c[2])*RGBA_MAX, + .a = a*RGBA_MAX, }; return color; diff --git a/source/engine/render.h b/source/engine/render.h index 418fcd3..10051ad 100644 --- a/source/engine/render.h +++ b/source/engine/render.h @@ -15,6 +15,8 @@ #include "sokol/sokol_gfx.h" #include "HandmadeMath.h" +#define RGBA_MAX 255 + struct mCamera; struct window; @@ -126,10 +128,10 @@ static struct boundingbox cwh2bb(HMM_Vec2 c, HMM_Vec2 wh) { static float *rgba2floats(float *r, struct rgba c) { - r[0] = c.r / 255.0; - r[1] = c.g / 255.0; - r[2] = c.b / 255.0; - r[3] = c.a / 255.0; + r[0] = (float)c.r / RGBA_MAX; + r[1] = (float)c.g / RGBA_MAX; + r[2] = (float)c.b / RGBA_MAX; + r[3] = (float)c.a / RGBA_MAX; return r; } diff --git a/source/engine/resources.c b/source/engine/resources.c index 62f03ff..94566eb 100644 --- a/source/engine/resources.c +++ b/source/engine/resources.c @@ -202,17 +202,12 @@ int fexists(char *path) return 0; } -void *slurp_file(const char *filename, size_t *size) +void *os_slurp(const char *file, size_t *size) { - if (cdb_find(&game_cdb, filename, strlen(filename))) - return cdb_slurp(&game_cdb, filename, size); - else if (cdb_find(&corecdb, filename, strlen(filename))) - return cdb_slurp(&corecdb, filename, size); - FILE *f; jump: - f = fopen(filename, "rb"); + f = fopen(file, "rb"); if (!f) return NULL; @@ -228,6 +223,18 @@ void *slurp_file(const char *filename, size_t *size) return slurp; } +void *slurp_file(const char *filename, size_t *size) +{ + if (!access(filename, R_OK)) + return os_slurp(filename, size); + else if (cdb_find(&game_cdb, filename, strlen(filename))) + return cdb_slurp(&game_cdb, filename, size); + else if (cdb_find(&corecdb, filename, strlen(filename))) + return cdb_slurp(&corecdb, filename, size); + + return NULL; +} + char *slurp_text(const char *filename, size_t *size) { size_t len; diff --git a/source/engine/script.c b/source/engine/script.c index a6de1de..8de2884 100644 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -98,7 +98,7 @@ void script_evalf(const char *format, ...) } uint8_t *compile_script(const char *file, size_t *len) { - const char *script = slurp_text(file, len); + char *script = slurp_text(file, len); JSValue obj = JS_Eval(js, script, *len, file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS); free(script); size_t out_len;