Add many C based math and statistic functions

This commit is contained in:
John Alanbrook 2024-08-02 21:52:50 -04:00
parent 05bc965d10
commit 570c12e3db
12 changed files with 592 additions and 359 deletions

View file

@ -512,7 +512,7 @@ Object.copy = function(proto, ...objs)
return c; return c;
} }
/* OBJECT DEFININTioNS */ /* OBJECT DEFININTIONS */
Object.defHidden = function(obj, prop) Object.defHidden = function(obj, prop)
{ {
Object.defineProperty(obj, prop, {enumerable:false, writable:true}); Object.defineProperty(obj, prop, {enumerable:false, writable:true});
@ -657,19 +657,6 @@ Object.defineProperty(Object.prototype, 'push', {
} }
}); });
Object.defineProperty(Object.prototype, 'findIndex', {
value: function(x) {
var i = 0;
for (var key in this) {
if (this[key] === x) return i;
i++;
}
return -1;
}
});
/* STRING DEFS */ /* STRING DEFS */
Object.defineProperty(String.prototype, 'next', { Object.defineProperty(String.prototype, 'next', {
@ -763,12 +750,6 @@ Object.defineProperty(String.prototype, 'up_path', {
} }
}); });
Object.defineProperty(String.prototype, 'resolve', {
value: function(path) {
},
});
Object.defineProperty(String.prototype, 'fromlast', { Object.defineProperty(String.prototype, 'fromlast', {
value: function(val) { value: function(val) {
var idx = this.lastIndexOf(val); var idx = this.lastIndexOf(val);
@ -836,23 +817,7 @@ Object.defineProperty(String.prototype, 'updir', {
Object.defineProperty(String.prototype, 'trimchr', { Object.defineProperty(String.prototype, 'trimchr', {
value: function(chars) { value: function(chars) {
var start = this.length; return vector.trimchr(this, chars);
var end = 0;
for (var i = 0; i < this.length; i++) {
if (!chars.includes(this[i])) {
start = i;
break;
}
}
for (var i = this.length-1; i >= 0; i--) {
if (!chars.includes(this[i])) {
end = i+1;
break;
}
}
return this.substring(start,end);
} }
}); });
@ -860,11 +825,6 @@ Object.defineProperty(String.prototype, 'uc', { value: function() { return this.
Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }}); Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }});
/* ARRAY DEFS */ /* ARRAY DEFS */
Object.defineProperty(Array.prototype, 'aspect', {
value: function() {
return this.x/this.y;
}
});
Object.defineProperty(Array.prototype, 'copy', { Object.defineProperty(Array.prototype, 'copy', {
value: function() { value: function() {
var c = []; var c = [];
@ -1015,13 +975,6 @@ swizz.forEach(function(x) {
}; };
make_swizz(); make_swizz();
Object.defineProperty(Array.prototype, 'add', {
value: function(b) {
var c = [];
for (var i = 0; i < this.length; i++) { c[i] = this[i] + b[i]; }
return c;
}});
Object.defineProperty(Array.prototype, 'normalized', { Object.defineProperty(Array.prototype, 'normalized', {
value: function() { value: function() {
var c = this.slice(); var c = this.slice();
@ -1056,13 +1009,6 @@ Object.defineProperty(Array.prototype, 'doubleup', {
} }
}); });
Object.defineProperty(Array.prototype, 'sub', {
value: function(b) {
var c = [];
for (var i = 0; i < this.length; i++) { c[i] = this[i] - b[i]; }
return c;
}});
Object.defineProperty(Array.prototype, 'mult', { Object.defineProperty(Array.prototype, 'mult', {
value: function(arr) { value: function(arr) {
var c = []; var c = [];
@ -1076,16 +1022,6 @@ Object.defineProperty(Array.prototype, 'apply', {
} }
}); });
Object.defineProperty(Array.prototype, 'scale', {
value: function(s) {
if (Array.isArray(s)) {
var c = this.slice();
c.forEach(function(x,i) { c[i] = x * s[i]; });
return c;
}
return this.map(function(x) { return x*s; });
}});
Object.defineProperty(Array.prototype, 'sorted', { Object.defineProperty(Array.prototype, 'sorted', {
value: function() { value: function() {
return this.toSorted(); return this.toSorted();
@ -1120,7 +1056,6 @@ Object.defineProperty(Array.prototype, 'mapvec', {
} }
}); });
Object.defineProperty(Array.prototype, 'remove', { Object.defineProperty(Array.prototype, 'remove', {
value: function(b) { value: function(b) {
var idx = this.indexOf(b); var idx = this.indexOf(b);
@ -1257,19 +1192,23 @@ Object.defineProperty(Array.prototype, 'mirrored', {
} }
}); });
Object.defineProperty(Array.prototype, 'lerp', { Math.lerp = vector.lerp;
value: function(to, t) { Math.gcd = vector.gcd;
var c = []; Math.lcm = vector.lcm;
this.forEach(function(x,i) { Math.sum = vector.sum;
c[i] = (to[i] - x) * t + x; Math.mean = vector.mean;
}); Math.sigma = vector.sigma;
return c; Math.median = vector.median;
}
});
Math.lerp = function(s,f,t) { return (f-s)*t + s; }; Math.variance = function(series) {
Math.gcd = function(a,b) { return b === 0 ? a : gcd(b,a%b); } var mean = Math.mean(series);
Math.lcm = function(a,b) { return (a*b)/gcd(a,b); } 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) { Math.grab_from_points = function(pos, points, slop) {
var shortest = slop; var shortest = slop;
@ -1313,22 +1252,18 @@ Object.defineProperty(Object.prototype, 'lerp',{
return obj; return obj;
}}); }});
/* MATH EXTENSioNS */ /* MATH EXTENSIONS */
Object.defineProperty(Number.prototype, 'lerp', { Object.defineProperty(Number.prototype, 'lerp', {
value: function(to, t) { value: function(to, t) { return Math.lerp(this, to, t); }
var s = this;
return (to - this) * t + this;
}
}); });
Object.defineProperty(Number.prototype, 'clamp', { Object.defineProperty(Number.prototype, 'clamp', {
value: function(from,to) { value: function(from,to) { return Math.clamp(this,from,to); }
return Math.clamp(this,from,to);
}
}); });
Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; } Math.clamp = vector.clamp;
Math.random_range = function(min,max) { return Math.random() * (max-min) + min; }; Math.random_range = vector.random_range;
Math.rand_int = function(max) { return Math.floor(Math.random()*max); }; Math.rand_int = function(max) { return Math.floor(Math.random()*max); };
Math.snap = function(val, grid) { Math.snap = function(val, grid) {
@ -1340,33 +1275,17 @@ Math.snap = function(val, grid) {
return d+i; return d+i;
} }
Math.angledist = function (a1, a2) { Math.angledist = vector.angledist;
a1 = a1%1;
a2 = a2%1;
var dist = a2 - a1;
if (dist == 0) return dist;
if (dist > 0) {
if (dist > 0.5) return dist-1;
return dist;
}
if (dist < -0.5) return dist+1;
return dist;
};
Math.angledist.doc = "Find the shortest angle between two angles."; Math.angledist.doc = "Find the shortest angle between two angles.";
Math.TAU = Math.PI*2; Math.TAU = Math.PI*2;
Math.deg2rad = function(deg) { return deg * 0.0174533; }; Math.deg2rad = function(deg) { return deg * 0.0174533; };
Math.rad2deg = function(rad) { return rad / 0.0174533; }; Math.rad2deg = function(rad) { return rad / 0.0174533; };
Math.deg2rad = function(x) { return x; };
Math.rad2deg = function(x) { return x; };
Math.turn2rad = function(x) { return x*Math.TAU; }; Math.turn2rad = function(x) { return x*Math.TAU; };
Math.rad2turn = function(x) { return x/Math.TAU; }; Math.rad2turn = function(x) { return x/Math.TAU; };
Math.turn2deg = function(x) { return x*360; }; Math.turn2deg = function(x) { return x*360; };
Math.deg2turn = function(x) { return x/360; }; Math.deg2turn = function(x) { return x/360; };
Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); }; Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * max), 0, max-1); };
Math.variate = function(n, pct) { return n + (Math.random_range(-pct,pct)*n); } Math.variate = vector.variate;
/* BOUNDINGBOXES */ /* BOUNDINGBOXES */
var bbox = {}; var bbox = {};
@ -1501,38 +1420,16 @@ bbox.fromobjs = function(objs)
var Vector = {}; var Vector = {};
Vector.length = function(v) { return Math.hypot(...v); } Vector.length = function(v) { return Math.hypot(...v); }
Vector.norm = function(v) { Vector.norm = vector.norm;
var len = Vector.length(v); Vector.project = vector.project;
if (!len) return [0,0]; Vector.dot = vector.dot;
return [v.x/len, v.y/len];
}
Vector.project = function(a, b) { return vector.project(a,b); }
Vector.dot = function(a, b) { return vector.dot(a,b); },
Vector.random = function() { Vector.random = function() {
var vec = [Math.random()-0.5, Math.random()-0.5]; var vec = [Math.random()-0.5, Math.random()-0.5];
return Vector.norm(vec); return Vector.norm(vec);
} }
Vector.midpoint = function(a,b) { return [(a.x+b.x)/2, (a.y+b.y)/2]; } Vector.angle_between = vector.angle_between;
Vector.distance = function(a,b) { return Math.hypot(b.x-a.x, b.y-a.y); } Vector.rotate = vector.rotate;
Vector.angle_between = function(a,b)
{
var dot = Vector.dot(a,b);
var am = Vector.length(a);
var bm = Vector.length(b);
var cos_a = dot / (am*bm);
var angle = Math.acos(cos_a);
return Math.rad2turn(angle);
}
Vector.angle = function(v) { return Math.rad2turn(Math.atan2(v.y, v.x)); }
Vector.rotate = function(v,angle) {
var r = Vector.length(v);
angle += Vector.angle(v);
angle = Math.turn2rad(angle);
return [r*Math.cos(angle), r*Math.sin(angle)];
}
Vector.equal = function(v1, v2, tol) { Vector.equal = function(v1, v2, tol) {
if (!tol) if (!tol)

View file

@ -17,20 +17,17 @@ var fullrect = [0,0,1,1];
var sprite_addbucket = function(sprite) var sprite_addbucket = function(sprite)
{ {
return; var layer = sprite.gameobject.drawlayer;
var pp = sprite.gameobject.drawlayer.toString(); sprite_buckets[layer] ??= {};
sprite_buckets[pp] ??= {}; sprite_buckets[layer][sprite.path] ??= {};
sprite_buckets[pp][sprite.path] ??= {}; sprite_buckets[layer][sprite.path][sprite.guid] = sprite;
sprite_buckets[pp][sprite.path][sprite.guid] = sprite;
} }
var sprite_rmbucket = function(sprite) var sprite_rmbucket = function(sprite)
{ {
return; for (var layer of Object.values(sprite_buckets))
var pp = sprite.gameobject.drawlayer.toString(); for (var path of Object.values(layer))
if (!sprite_buckets[pp]) return; delete path[sprite.guid];
if (!sprite_buckets[pp][sprite.path]) return;
delete sprite_buckets[pp][sprite.path][sprite.guid];
} }
var sprite = { var sprite = {
@ -59,6 +56,7 @@ var sprite = {
//self.path = playing.path; //self.path = playing.path;
self.frame = playing.frames[f].rect; self.frame = playing.frames[f].rect;
self.rect = [self.frame.x, self.frame.y, self.frame.w, self.frame.h]; self.rect = [self.frame.x, self.frame.y, self.frame.w, self.frame.h];
self.update_dimensions();
f = (f+1)%playing.frames.length; f = (f+1)%playing.frames.length;
if (f === 0) { if (f === 0) {
self.anim_done?.(); self.anim_done?.();
@ -88,6 +86,8 @@ var sprite = {
this.rect = fullrect; this.rect = fullrect;
var anim = SpriteAnim.make(p); var anim = SpriteAnim.make(p);
this.update_dimensions();
this.sync();
if (!anim) return; if (!anim) return;
this.anim = anim; this.anim = anim;
@ -99,6 +99,7 @@ var sprite = {
return this._p; return this._p;
}, },
kill() { kill() {
sprite_rmbucket(this);
this.del_anim?.(); this.del_anim?.();
this.anim = undefined; this.anim = undefined;
this.gameobject = undefined; this.gameobject = undefined;
@ -111,7 +112,10 @@ var sprite = {
this.pos = this.pos.scale(x); this.pos = this.pos.scale(x);
}, },
anchor:[0,0], anchor:[0,0],
sync() { }, sync() {
sprite_rmbucket(this);
sprite_addbucket(this);
},
pick() { return this; }, pick() { return this; },
boundingbox() { boundingbox() {
var dim = this.dimensions(); var dim = this.dimensions();
@ -120,17 +124,21 @@ var sprite = {
return bbox.fromcwh(realpos,dim); return bbox.fromcwh(realpos,dim);
}, },
update_dimensions() {
this._dimensions = [this.texture.width*this.rect[2], this.texture.height*this.rect[3]];
component.sprite_dim_hook?.(this);
},
dimensions() { dimensions() {
var dim = [this.texture.width, this.texture.height]; return this._dimensions;
dim.x *= this.frame.w;
dim.y *= this.frame.h;
return dim;
}, },
width() { return this.dimensions().x; }, width() { return this.dimensions().x; },
height() { return this.dimensions().y; }, height() { return this.dimensions().y; },
}; };
globalThis.allsprites = {}; globalThis.allsprites = {};
globalThis.sprite_buckets = []; var sprite_buckets = {};
component.sprite_buckets = function() { return sprite_buckets; }
sprite.doc = { sprite.doc = {
path: "Path to the texture.", path: "Path to the texture.",
@ -173,6 +181,7 @@ component.sprite = function(obj) {
sp.guid = prosperon.guid(); sp.guid = prosperon.guid();
allsprites[sp.guid] = sp; allsprites[sp.guid] = sp;
if (component.sprite.make_hook) component.sprite.make_hook(sp); if (component.sprite.make_hook) component.sprite.make_hook(sp);
sprite_addbucket(sp);
return sp; return sp;
} }

View file

@ -29,7 +29,7 @@ Object.defineProperty(String.prototype, "folder", {
globalThis.Resources = {}; globalThis.Resources = {};
Resources.rm_fn = function(fn, text) Resources.rm_fn = function rm_fn(fn, text)
{ {
var reg = new RegExp(fn.source + "\\s*\\("); var reg = new RegExp(fn.source + "\\s*\\(");
var match; var match;
@ -48,7 +48,7 @@ Resources.rm_fn = function(fn, text)
} }
Resources.rm_fn.doc = "Remove calls to a given function from a given text script."; Resources.rm_fn.doc = "Remove calls to a given function from a given text script.";
Resources.replpath = function (str, path) { Resources.replpath = function replpath(str, path) {
if (!str) return str; if (!str) return str;
if (str[0] === "/") return str.rm(0); if (str[0] === "/") return str.rm(0);
@ -66,7 +66,7 @@ Resources.replpath = function (str, path) {
return str; return str;
}; };
Resources.replstrs = function (path) { Resources.replstrs = function replstrs(path) {
if (!path) return; if (!path) return;
var script = io.slurp(path); var script = io.slurp(path);
var regexp = /"[^"\s]*?\.[^"\s]+?"/g; var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
@ -223,7 +223,7 @@ globalThis.global = globalThis;
var use_cache = {}; var use_cache = {};
globalThis.use = function(file, env = {}, script) { globalThis.use = function use(file, env = {}, script) {
file = Resources.find_script(file); file = Resources.find_script(file);
profile.cache("USE", file); profile.cache("USE", file);
@ -238,6 +238,7 @@ globalThis.use = function(file, env = {}, script) {
use_cache[file] = fn; use_cache[file] = fn;
var ret = fn.call(env); var ret = fn.call(env);
profile.endcache(); profile.endcache();
return ret; return ret;
} }
@ -254,6 +255,7 @@ function stripped_use (file, env = {}, script) {
var fn = os.eval(file, script); var fn = os.eval(file, script);
var ret = fn.call(env); var ret = fn.call(env);
profile.endcache(); profile.endcache();
return ret; return ret;
} }
@ -274,6 +276,13 @@ debug.enabled = true;
bare_use("scripts/base.js"); bare_use("scripts/base.js");
bare_use("scripts/profile.js"); bare_use("scripts/profile.js");
prosperon.release = function()
{
profile.enabled = false;
console.enabled = false;
debug.enabled = false;
}
bare_use("preconfig.js"); bare_use("preconfig.js");
if (!profile.enabled) if (!profile.enabled)

View file

@ -1,5 +1,11 @@
globalThis.entityreport = {}; globalThis.entityreport = {};
var timer_update = function(dt)
{
this.fn();
}
function obj_unique_name(name, obj) { function obj_unique_name(name, obj) {
name = name.replaceAll('.', '_'); name = name.replaceAll('.', '_');
if (!(name in obj)) return name; if (!(name in obj)) return name;
@ -68,7 +74,7 @@ var entity = {
delay(fn, seconds) { delay(fn, seconds) {
var timers = this.timers; var timers = this.timers;
var stop = function() { var stop = function() {
timers.remove(stop); delete timers[guid];
execute = undefined; execute = undefined;
stop = undefined; stop = undefined;
rm?.(); rm?.();
@ -91,7 +97,8 @@ var entity = {
} }
var rm = Register.update.register(update); var rm = Register.update.register(update);
timers.push(stop); var guid = prosperon.guid();
timers[guid] = (stop);
return stop; return stop;
}, },
@ -146,7 +153,7 @@ var entity = {
ent.components = {}; ent.components = {};
ent.objects = {}; ent.objects = {};
ent.timers = []; ent.timers = {};
if (!text) if (!text)
ent.ur = emptyur; ent.ur = emptyur;
@ -339,8 +346,8 @@ dup(diff) {
this.__kill = true; this.__kill = true;
console.spam(`Killing entity of type ${this.ur}`); console.spam(`Killing entity of type ${this.ur}`);
for (var t of this.timers) t(); this.timers.forEach(x => x());
this.timers = []; delete this.timers;
Event.rm_obj(this); Event.rm_obj(this);
input.do_uncontrol(this); input.do_uncontrol(this);

View file

@ -202,8 +202,6 @@ mum.image = function(path, data = {})
else else
data.height = tex.height; data.height = tex.height;
if (!data.width) data.width = tex.width; if (!data.width) data.width = tex.width;
if (!data.height) data.height = tex.height; if (!data.height) data.height = tex.height;

View file

@ -108,7 +108,7 @@ var make_emitter = function()
var e = Object.create(emitter); var e = Object.create(emitter);
e.ssbo = render.make_textssbo(); e.ssbo = render.make_textssbo();
e.shape = shape.centered_quad; e.shape = shape.centered_quad;
e.shader = render.make_shader("shaders/baseparticle.cg"); e.shader = "shaders/baseparticle.cg";
e.dead = []; e.dead = [];
return e; return e;
} }

View file

@ -1,15 +1,32 @@
var t_units = ["ns", "us", "ms", "s", "ks", "Ms"]; var t_units = ["ns", "us", "ms", "s", "ks", "Ms"];
profile.cpu = function(fn, times = 1, q = "unnamed") { function calc_cpu(fn, times, diff=0)
var start = profile.now(); {
for (var i = 0; i < times; i++) var series = [];
fn();
var elapsed = profile.now() - start; for (var i = 0; i < times; i++) {
var avgt = profile.best_t(elapsed/times); var st = profile.now();
fn(i);
series.push(profile.now()-st-diff);
}
return series;
}
function empty_fn() {}
profile.cpu = function profile_cpu(fn, times = 1, q = "unnamed") {
profile.gather_stop();
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); var totalt = profile.best_t(elapsed);
say(`profile [${q}]: ${profile.best_t(avgt)} average [${profile.best_t(totalt)} for ${times} loops]`); say(`profile [${q}]: ${avgt} ± ${profile.best_t(Math.ci(series))} [${totalt} for ${times} loops]`);
start_prof_gather();
} }
profile.ms = function(t) { return t/1000000; } profile.ms = function(t) { return t/1000000; }
@ -35,27 +52,33 @@ function add_callgraph(fn, line, time) {
var hittar = 500; var hittar = 500;
var hitpct = 0.2; var hitpct = 0.2;
var start_gather = profile.now(); var start_gather = profile.now();
function start_prof_gather()
{
profile.gather(hittar, function() {
var time = profile.now()-st;
var err = new Error();
var stack = err.stack.split("\n");
stack = stack.slice(1);
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));
for (var i = 0; i < fns.length; i++)
add_callgraph(fns[i], lines[i], time);
st = profile.now();
profile.gather_rate(Math.variate(hittar,hitpct));
});
}
if (profile.enabled) if (profile.enabled)
profile.gather(hittar, function() { start_prof_gather();
var time = profile.now()-st;
var err = new Error();
var stack = err.stack.split("\n");
stack = stack.slice(1);
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));
for (var i = 0; i < fns.length; i++)
add_callgraph(fns[i], lines[i], time);
st = profile.now();
profile.gather_rate(Math.variate(hittar,hitpct));
});
var filecache = {}; var filecache = {};
function get_line(file, line) { function get_line(file, line) {
@ -96,6 +119,7 @@ profile.print_cpu_instr = function()
profile.best_t = function (t) { profile.best_t = function (t) {
var qq = 0; var qq = 0;
while (t > 1000 && qq < t_units.length-1) { while (t > 1000 && qq < t_units.length-1) {
t /= 1000; t /= 1000;
qq++; qq++;
@ -109,28 +133,29 @@ profile.report = function (start, msg = "[undefined report]") { console.info(`${
var profile_frames = {}; var profile_frames = {};
var profile_frame_ts = []; var profile_frame_ts = [];
var profile_cframe = profile_frames; var profile_cframe = profile_frames;
var profile_frame = 0; var pframe = 0;
profile.frame = function(title)
profile.frame = function profile_frame(title)
{ {
profile_frame_ts.push(profile_cframe); profile_frame_ts.push(profile_cframe);
profile_cframe[title] ??= {}; profile_cframe[title] ??= {};
profile_cframe = profile_cframe[title]; profile_cframe = profile_cframe[title];
profile_cframe._times ??= []; profile_cframe._times ??= [];
profile_cframe._times[profile_frame] = profile.now(); profile_cframe._times[pframe] ??= 0;
profile_cframe._times[pframe] = profile.now() - profile_cframe._times[pframe];
} }
profile.endframe = function() profile.endframe = function profile_endframe()
{ {
if (profile_cframe === profile_frames) return; if (profile_cframe === profile_frames) return;
profile_cframe._times[profile_frame] = profile.now() - profile_cframe._times[profile_frame]; profile_cframe._times[pframe] = profile.now() - profile_cframe._times[pframe];
profile_cframe = profile_frame_ts.pop(); profile_cframe = profile_frame_ts.pop();
if (profile_cframe === profile_frames) profile_frame++; if (profile_cframe === profile_frames) pframe++;
} }
var print_frame = function(frame, indent, title) var print_frame = function(frame, indent, title)
{ {
var avg = frame._times.reduce((sum, e) => sum += e)/frame._times.length; say(indent + `${title} ::::: ${profile.best_t(Math.mean(frame._times))} ± ${profile.best_t(Math.ci(frame._times))} (${frame._times.length} hits)`);
say(indent + `${title} ::::: ${profile.best_t(avg)} (${frame._times.length} hits)`);
for (var i in frame) { for (var i in frame) {
if (i === '_times') continue; if (i === '_times') continue;
@ -150,14 +175,14 @@ var report_cache = {};
var cachest = 0; var cachest = 0;
var cachegroup; var cachegroup;
var cachetitle; var cachetitle;
profile.cache = function(group, title) profile.cache = function profile_cache(group, title)
{ {
cachest = profile.now(); cachest = profile.now();
cachegroup = group; cachegroup = group;
cachetitle = title; cachetitle = title;
} }
profile.endcache = function(tag = "") profile.endcache = function profile_endcache(tag = "")
{ {
addreport(cachegroup, cachetitle + tag, cachest); addreport(cachegroup, cachetitle + tag, cachest);
} }

View file

@ -316,21 +316,23 @@ var Register = {
add_cb(name, e_event = false) { add_cb(name, e_event = false) {
var n = {}; var n = {};
var fns = []; var fns = {};
n.register = function (fn, oname) { n.register = function (fn, oname) {
if (!(fn instanceof Function)) return; if (!(fn instanceof Function)) return;
var guid = prosperon.guid();
var dofn = function(...args) { var dofn = function(...args) {
profile.cache(name,oname); profile.cache(name,oname);
var st = profile.now(); var st = profile.now();
fn(...args); fn(...args);
profile.endcache(); profile.endcache();
} }
fns.push(dofn); fns[guid] = dofn;
return function () { return function () {
fns.remove(dofn); delete fns[guid];
}; };
}; };

View file

@ -6,24 +6,24 @@ render.doc = {
var cur = {}; var cur = {};
render.use_shader = function(shader) render.use_shader = function use_shader(shader)
{ {
if (typeof shader === 'string') if (typeof shader === 'string')
shader = render.make_shader(shader); shader = make_shader(shader);
if (cur.shader === shader) return; if (cur.shader === shader) return;
cur.shader = shader; cur.shader = shader;
cur.globals = {};
cur.bind = undefined; cur.bind = undefined;
cur.mesh = undefined; cur.mesh = undefined;
render.setpipeline(shader.pipe); render.setpipeline(shader.pipe);
shader_globals(cur.shader);
} }
render.use_mat = function(mat) render.use_mat = function use_mat(mat)
{ {
if (!cur.shader) return; if (!cur.shader) return;
if (cur.mat === mat) return; if (cur.mat === mat) return;
render.shader_apply_material(cur.shader, mat, cur.mat); shader_apply_material(cur.shader, mat, cur.mat);
cur.mat = mat; cur.mat = mat;
@ -38,7 +38,7 @@ render.use_mat = function(mat)
var models_array = []; var models_array = [];
render.set_model = function(t) function set_model(t)
{ {
if (cur.shader.vs.unimap.model) if (cur.shader.vs.unimap.model)
render.setunim4(0, cur.shader.vs.unimap.model.slot, t); render.setunim4(0, cur.shader.vs.unimap.model.slot, t);
@ -96,7 +96,7 @@ var face_map = {
ccw: 1 ccw: 1
} }
render.poly_prim = function(verts) render.poly_prim = function poly_prim(verts)
{ {
var index = []; var index = [];
if (verts.length < 1) return undefined; if (verts.length < 1) return undefined;
@ -131,31 +131,15 @@ function shader_directive(shader, name, map)
return ff; return ff;
} }
function global_uni(uni, stage) var uni_globals = {
{ time(stage, slot) { render.setuniv(stage, slot, profile.secs(profile.now())); },
cur.globals[stage] ??= {}; projection(stage,slot) { render.setuniproj(stage, slot); },
if (cur.globals[stage][uni.name]) return true; view(stage,slot) { render.setuniview(stage, slot); },
switch(uni.name) { vp(stage,slot) { render.setunivp(stage,slot); },
case "time": }
cur.globals[stage][uni.name]
render.setuniv(stage, uni.slot, profile.secs(profile.now()));
cur.globals[stage][uni.name] = true;
return true;
case "projection":
render.setuniproj(stage, uni.slot);
cur.globals[stage][uni.name] = true;
return true;
case "view":
render.setuniview(stage, uni.slot);
cur.globals[stage][uni.name] = true;
return true;
case "vp":
render.setunivp(stage, uni.slot);
cur.globals[stage][uni.name] = true;
return true;
}
return false; function set_global_uni(uni, stage) {
uni_globals[uni.name]?.(stage, uni.slot);
} }
var setcam = render.set_camera; var setcam = render.set_camera;
@ -171,7 +155,13 @@ render.set_camera = function(cam)
var shader_cache = {}; var shader_cache = {};
render.make_shader = function(shader) function strip_shader_inputs(shader)
{
for (var a of shader.vs.inputs)
a.name = a.name.slice(2);
}
function make_shader(shader)
{ {
if (shader_cache[shader]) return shader_cache[shader]; if (shader_cache[shader]) return shader_cache[shader];
@ -198,6 +188,7 @@ render.make_shader = function(shader)
profile.endcache(" [cached]"); profile.endcache(" [cached]");
var shaderobj = json.decode(io.slurp(writejson)); var shaderobj = json.decode(io.slurp(writejson));
var obj = shaderobj[os.sys()]; var obj = shaderobj[os.sys()];
strip_shader_inputs(obj);
obj.pipe = render.pipeline(obj); obj.pipe = render.pipeline(obj);
shader_cache[shader] = obj; shader_cache[shader] = obj;
return obj; return obj;
@ -314,6 +305,7 @@ render.make_shader = function(shader)
profile.endcache(); profile.endcache();
var obj = compiled[os.sys()]; var obj = compiled[os.sys()];
strip_shader_inputs(obj);
obj.pipe = render.pipeline(obj); obj.pipe = render.pipeline(obj);
shader_cache[shader] = obj; shader_cache[shader] = obj;
@ -327,10 +319,19 @@ var shader_unisize = {
16: render.setuniv4 16: render.setuniv4
}; };
render.shader_apply_material = function(shader, material = {}, old = {}) function shader_globals(shader)
{
for (var p in shader.vs.unimap)
set_global_uni(shader.vs.unimap[p], 0);
for (var p in shader.fs.unimap)
set_global_uni(shader.fs.unimap[p], 1);
}
function shader_apply_material(shader, material = {}, old = {})
{ {
for (var p in shader.vs.unimap) { for (var p in shader.vs.unimap) {
if (global_uni(shader.vs.unimap[p], 0)) continue; if (!(p in material)) continue;
if (material[p] === old[p]) continue; if (material[p] === old[p]) continue;
assert(p in material, `shader ${shader.name} has no uniform for ${p}`); assert(p in material, `shader ${shader.name} has no uniform for ${p}`);
var s = shader.vs.unimap[p]; var s = shader.vs.unimap[p];
@ -338,7 +339,7 @@ render.shader_apply_material = function(shader, material = {}, old = {})
} }
for (var p in shader.fs.unimap) { for (var p in shader.fs.unimap) {
if (global_uni(shader.fs.unimap[p], 1)) continue; if (!(p in material)) continue;
if (material[p] === old[p]) continue; if (material[p] === old[p]) continue;
assert(p in material, `shader ${shader.name} has no uniform for ${p}`); assert(p in material, `shader ${shader.name} has no uniform for ${p}`);
var s = shader.fs.unimap[p]; var s = shader.fs.unimap[p];
@ -355,7 +356,7 @@ render.shader_apply_material = function(shader, material = {}, old = {})
render.setuniv2(0, shader.vs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]); render.setuniv2(0, shader.vs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]);
} }
render.sg_bind = function(mesh, ssbo) function sg_bind(mesh, ssbo)
{ {
if (cur.mesh === mesh && cur.bind) { if (cur.mesh === mesh && cur.bind) {
cur.bind.inst = 1; cur.bind.inst = 1;
@ -371,13 +372,10 @@ render.sg_bind = function(mesh, ssbo)
if (cur.shader.vs.inputs) if (cur.shader.vs.inputs)
for (var a of cur.shader.vs.inputs) { for (var a of cur.shader.vs.inputs) {
if (!(a.name in mesh)) { if (!(a.name in mesh)) {
if (!(a.name.slice(2) in mesh)) { console.error(`cannot draw shader ${cur.shader.name}; there is no attrib ${a.name} in the given mesh.`);
console.error(`cannot draw shader ${cur.shader.name}; there is no attrib ${a.name} in the given mesh.`); return undefined;
return undefined;
} else
bind.attrib.push(mesh[a.name.slice(2)]);
} else } else
bind.attrib.push(mesh[a.name]); bind.attrib.push(mesh[a.name]);
} }
if (cur.shader.indexed) { if (cur.shader.indexed) {
@ -448,15 +446,15 @@ var polyssboshader;
var sprite_ssbo; var sprite_ssbo;
render.init = function() { render.init = function() {
textshader = render.make_shader("shaders/text_base.cg"); textshader = make_shader("shaders/text_base.cg");
render.spriteshader = render.make_shader("shaders/sprite.cg"); render.spriteshader = make_shader("shaders/sprite.cg");
spritessboshader = render.make_shader("shaders/sprite_ssbo.cg"); spritessboshader = make_shader("shaders/sprite_ssbo.cg");
render.postshader = render.make_shader("shaders/simplepost.cg"); render.postshader = make_shader("shaders/simplepost.cg");
slice9shader = render.make_shader("shaders/9slice.cg"); slice9shader = make_shader("shaders/9slice.cg");
circleshader = render.make_shader("shaders/circle.cg"); circleshader = make_shader("shaders/circle.cg");
polyshader = render.make_shader("shaders/poly.cg"); polyshader = make_shader("shaders/poly.cg");
parshader = render.make_shader("shaders/baseparticle.cg"); parshader = make_shader("shaders/baseparticle.cg");
polyssboshader = render.make_shader("shaders/poly_ssbo.cg"); polyssboshader = make_shader("shaders/poly_ssbo.cg");
textssbo = render.make_textssbo(); textssbo = render.make_textssbo();
poly_ssbo = render.make_textssbo(); poly_ssbo = render.make_textssbo();
sprite_ssbo = render.make_textssbo(); sprite_ssbo = render.make_textssbo();
@ -493,47 +491,55 @@ render.init = function() {
} }
} }
render.sprites = function(gridsize = 1) render.sprites = function render_sprites(gridsize = 1)
{ {
/*
profile.frame("bucketing"); profile.frame("bucketing");
var sps = Object.values(allsprites); var sps = Object.values(allsprites);
var sprite_buckets = {};
var buckets = [];
for (var i = 0; i <= 20; i++)
buckets[i] = {};
for (var sprite of sps) { for (var sprite of sps) {
var pp = sprite.gameobject.drawlayer; var layer = sprite.gameobject.drawlayer+10;
sprite_buckets[pp] ??= {}; if (buckets[layer][sprite.path])
sprite_buckets[pp][sprite.path] ??= {}; buckets[layer][sprite.path].push(sprite);
sprite_buckets[pp][sprite.path][sprite.guid] = sprite; else
render.sprite_hook?.(sprite); buckets[layer][sprite.path] = [sprite];
} }
profile.endframe(); profile.endframe();
*/
profile.frame("sorting"); profile.frame("sorting");
var sprite_buckets = component.sprite_buckets();
var buckets = Object.entries(sprite_buckets).sort((a,b) => { var buckets = Object.entries(sprite_buckets).sort((a,b) => {
var na = Number(a[0]); var na = Number(a[0]);
var ba = Number(b[0]); var nb = Number(b[0]);
if (na < ba) return -1; if (na < nb) return -1;
if (na === ba) return 0;
return 1; return 1;
}); });
profile.endframe(); profile.endframe();
profile.frame("drawing"); profile.frame("drawing");
render.use_shader(spritessboshader); render.use_shader(spritessboshader);
for (var bucket of buckets) { for (var layer of buckets) {
for (var img of Object.values(bucket[1])) { for (var img of Object.values(layer[1])) {
var sparray = Object.values(img); var sparray = Object.values(img);
if (sparray.length === 0) continue; if (sparray.length === 0) continue;
var ss = sparray[0]; var ss = sparray[0];
render.use_mat(ss); render.use_mat(ss);
render.make_sprite_ssbo(Object.values(sparray), sprite_ssbo); render.make_sprite_ssbo(sparray, sprite_ssbo);
render.draw(shape.quad, sprite_ssbo, sparray.length); render.draw(shape.quad, sprite_ssbo, sparray.length);
} }
} }
profile.endframe(); profile.endframe();
} }
render.circle = function(pos, radius, color) { render.circle = function render_circle(pos, radius, color) {
check_flush(); flush();
var mat = { var mat = {
radius: radius, radius: radius,
coord: pos, coord: pos,
@ -544,56 +550,71 @@ render.circle = function(pos, radius, color) {
render.draw(shape.quad); render.draw(shape.quad);
} }
render.poly = function(points, color, transform) { render.poly = function render_poly(points, color, transform) {
var buffer = render.poly_prim(points); var buffer = render.poly_prim(points);
var mat = { shade: color}; var mat = { shade: color};
render.use_shader(polyshader); render.use_shader(polyshader);
render.set_model(transform); set_model(transform);
render.use_mat(mat); render.use_mat(mat);
render.draw(buffer); render.draw(buffer);
} }
var nextflush = undefined; var nextflush = undefined;
var check_flush = function(flush_fn) function flush()
{
nextflush?.();
nextflush = undefined;
}
function check_flush(flush_fn)
{ {
if (!flush_fn) {
if (!nextflush) return;
nextflush();
nextflush = undefined;
}
if (!nextflush) if (!nextflush)
nextflush = flush_fn; nextflush = flush_fn;
else if (nextflush !== flush_fn) { else if (nextflush !== flush_fn) {
nextflush(); nextflush();
nextflush = flush_fn; nextflush = flush_fn;
} }
} }
var poly_cache = []; var poly_cache = [];
var poly_idx = 0;
var poly_ssbo; var poly_ssbo;
render.flush_poly = function() function poly_e()
{ {
if (poly_cache.length === 0) return; var e;
render.use_shader(polyssboshader); poly_idx++;
render.use_mat({}); if (poly_idx > poly_cache.length) {
render.make_particle_ssbo(poly_cache, poly_ssbo); e = {
render.draw(shape.centered_quad, poly_ssbo, poly_cache.length); transform:os.make_transform(),
poly_cache = []; color: Color.white
};
poly_cache.push(e);
return e;
}
var e = poly_cache[poly_idx-1];
e.transform.unit();
return e;
} }
render.line = function(points, color = Color.white, thickness = 1) { function flush_poly()
var transform = os.make_transform(); {
var dist = Vector.distance(points[0],points[1]); if (poly_idx === 0) return;
transform.move(Vector.midpoint(points[0],points[1])); render.use_shader(polyssboshader);
transform.rotate([0,0,-1], Vector.angle([points[1].x-points[0].x, points[1].y-points[0].y])); render.use_mat({});
transform.scale = [dist, thickness, 1]; render.make_particle_ssbo(poly_cache.slice(0,poly_idx), poly_ssbo);
poly_cache.push({ render.draw(shape.centered_quad, poly_ssbo, poly_cache.length);
transform:transform, poly_idx = 0;
color:color }
});
check_flush(render.flush_poly); render.line = function render_line(points, color = Color.white, thickness = 1) {
var poly = poly_e();
var dist = vector.distance(points[0],points[1]);
poly.transform.move(vector.midpoint(points[0],points[1]));
poly.transform.rotate([0,0,-1], vector.angle([points[1].x-points[0].x, points[1].y-points[0].y]));
poly.transform.scale = [dist, thickness, 1];
poly.color = color;
check_flush(flush_poly);
} }
/* All draw in screen space */ /* All draw in screen space */
@ -601,7 +622,7 @@ render.point = function(pos,size,color = Color.blue) {
render.circle(pos,size,size,color); render.circle(pos,size,size,color);
}; };
render.cross = function(pos, size, color = Color.red, thickness = 1) { render.cross = function render_cross(pos, size, color = Color.red, thickness = 1) {
var a = [ var a = [
pos.add([0,size]), pos.add([0,size]),
pos.add([0,-size]) pos.add([0,-size])
@ -614,7 +635,7 @@ render.cross = function(pos, size, color = Color.red, thickness = 1) {
render.line(b,color,thickness); render.line(b,color,thickness);
}; };
render.arrow = function(start, end, color = Color.red, wingspan = 4, wingangle = 10) { render.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10) {
var dir = end.sub(start).normalized(); var dir = end.sub(start).normalized();
var wing1 = [ var wing1 = [
Vector.rotate(dir, wingangle).scale(wingspan).add(end), Vector.rotate(dir, wingangle).scale(wingspan).add(end),
@ -629,39 +650,34 @@ render.arrow = function(start, end, color = Color.red, wingspan = 4, wingangle =
render.line(wing2,color); render.line(wing2,color);
}; };
render.coordinate = function(pos, size, color) { render.coordinate = function render_coordinate(pos, size, color) {
render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color);
render.point(pos, 2, color); render.point(pos, 2, color);
} }
render.boundingbox = function(bb, color = Color.white) { render.boundingbox = function render_boundingbox(bb, color = Color.white) {
render.line(bbox.topoints(bb).wrapped(1), color); render.line(bbox.topoints(bb).wrapped(1), color);
} }
render.rectangle = function(lowerleft, upperright, color) { render.rectangle = function render_rectangle(lowerleft, upperright, color) {
var transform = os.make_transform(); var transform = os.make_transform();
var wh = [upperright.x-lowerleft.x, upperright.y-lowerleft.y]; var wh = [upperright.x-lowerleft.x, upperright.y-lowerleft.y];
transform.move(Vector.midpoint(lowerleft,upperright)); var poly = poly_e();
transform.scale = [wh.x,wh.y,1]; poly.transform.move(vector.midpoint(lowerleft,upperright));
poly_cache.push({ poly.transform.scale = [wh.x,wh.y,1];
transform:transform, poly.color = color;
color:color check_flush(flush_poly);
});
check_flush(render.flush_poly);
}; };
render.box = function(pos, wh, color = Color.white) { render.box = function render_box(pos, wh, color = Color.white) {
var transform = os.make_transform(); var poly = poly_e();
transform.move(pos); poly.transform.move(pos);
transform.scale = [wh.x,wh.y,1]; poly.transform.scale = [wh.x,wh.y,1];
poly_cache.push({ poly.color = color;
transform:transform, check_flush(flush_poly);
color:color
});
check_flush(render.flush_poly);
}; };
render.window = function(pos, wh, color) { render.box(pos.add(wh.scale(0.5)),wh,color); }; render.window = function render_window(pos, wh, color) { render.box(pos.add(wh.scale(0.5)),wh,color); };
render.text_bb = function(str, size = 1, wrap = -1, pos = [0,0]) render.text_bb = function(str, size = 1, wrap = -1, pos = [0,0])
{ {
@ -693,12 +709,12 @@ render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, ancho
}; };
render.image = function(tex, pos, scale = [tex.width, tex.height], rotation = 0, color = Color.white) { render.image = function(tex, pos, scale = [tex.width, tex.height], rotation = 0, color = Color.white) {
check_flush(); flush();
var t = os.make_transform(); var t = os.make_transform();
t.pos = pos; t.pos = pos;
t.scale = [scale.x/tex.width,scale.y/tex.height,1]; t.scale = [scale.x/tex.width,scale.y/tex.height,1];
render.use_shader(render.spriteshader); render.use_shader(render.spriteshader);
render.set_model(t); set_model(t);
render.use_mat({ render.use_mat({
shade: color, shade: color,
diffuse: tex, diffuse: tex,
@ -729,7 +745,7 @@ render.slice9 = function(tex, pos, bb, scale = [tex.width,tex.height], color = C
border = [bb.l/tex.width, bb.b/tex.height, bb.r/tex.width, bb.t/tex.height]; border = [bb.l/tex.width, bb.b/tex.height, bb.r/tex.width, bb.t/tex.height];
render.use_shader(slice9shader); render.use_shader(slice9shader);
render.set_model(t); set_model(t);
render.use_mat({ render.use_mat({
shade: color, shade: color,
diffuse:tex, diffuse:tex,
@ -768,16 +784,16 @@ render.flush_text = function()
render.draw(shape.quad, textssbo, amt); render.draw(shape.quad, textssbo, amt);
} }
render.fontcache = {}; var fontcache = {};
render.set_font = function(path, size) { render.set_font = function(path, size) {
var fontstr = `${path}-${size}`; var fontstr = `${path}-${size}`;
if (render.font && render.fontcache[fontstr] === render.font) return; if (render.font && fontcache[fontstr] === render.font) return;
if (!render.fontcache[fontstr]) render.fontcache[fontstr] = os.make_font(path, size); if (!fontcache[fontstr]) fontcache[fontstr] = os.make_font(path, size);
render.flush_text(); render.flush_text();
gui.font_set(render.fontcache[fontstr]); gui.font_set(fontcache[fontstr]);
render.font = render.fontcache[fontstr]; render.font = fontcache[fontstr];
} }
render.doc = "Draw shapes in screen space."; render.doc = "Draw shapes in screen space.";
@ -786,15 +802,14 @@ render.cross.doc = "Draw a cross centered at pos, with arm length size.";
render.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle."; render.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle.";
render.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright."; render.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright.";
render.draw = function(mesh, ssbo, inst = 1) render.draw = function render_draw(mesh, ssbo, inst = 1)
{ {
render.sg_bind(mesh, ssbo); sg_bind(mesh, ssbo);
profile.frame("gpu");
render.spdraw(cur.bind.count, inst); render.spdraw(cur.bind.count, inst);
profile.endframe();
} }
// Returns an array in the form of [left, bottom, right, top] in pixels of the camera to render to // Returns an array in the form of [left, bottom, right, top] in pixels of the camera to render to
// Camera viewport is [left,bottom,right,top] in relative values // Camera viewport is [left,bottom,right,top] in relative values
function camviewport() function camviewport()
@ -947,7 +962,7 @@ prosperon.render = function()
render.commit(); render.commit();
} }
prosperon.process = function() { prosperon.process = function process() {
profile.frame("frame"); profile.frame("frame");
var dt = profile.secs(profile.now()) - frame_t; var dt = profile.secs(profile.now()) - frame_t;
frame_t = profile.secs(profile.now()); frame_t = profile.secs(profile.now());

View file

@ -3,6 +3,7 @@
const HMM_Vec2 v2zero = {0,0}; const HMM_Vec2 v2zero = {0,0};
const HMM_Vec2 v2one = {1,1}; const HMM_Vec2 v2one = {1,1};
const HMM_Vec3 v3zero = {0,0,0}; const HMM_Vec3 v3zero = {0,0,0};
const HMM_Vec3 v3one = {1,1,1};
const HMM_Vec4 v4zero = {0,0,0,0}; const HMM_Vec4 v4zero = {0,0,0,0};
const HMM_Vec3 vX = {1.0,0.0,0.0}; const HMM_Vec3 vX = {1.0,0.0,0.0};
@ -17,7 +18,7 @@ const HMM_Vec3 vLEFT = {-1,0,0};
const HMM_Vec3 vRIGHT = {1,0,0}; const HMM_Vec3 vRIGHT = {1,0,0};
const HMM_Mat4 MAT1 = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; const HMM_Mat4 MAT1 = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
const HMM_Quat QUAT1 = {1,0,0,0}; const HMM_Quat QUAT1 = {0,0,0,1};
/* /*
* Angle unit conversion functions * Angle unit conversion functions
@ -262,14 +263,9 @@ HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right) {
return Result; return Result;
} }
HMM_Vec2 HMM_ScaleV2(HMM_Vec2 v, double s) HMM_Vec2 HMM_ScaleV2(HMM_Vec2 v, double s)
{
return HMM_V2(v.X*s, v.Y*s);
}
HMM_Vec3 HMM_ScaleV3(HMM_Vec3 v, double s)
{ {
return HMM_V3(v.x*s,v.y*s,v.z*s); return HMM_V2(v.X*s, v.Y*s);
} }
HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right) { HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right) {
@ -529,7 +525,6 @@ float HMM_AngleV4(HMM_Vec4 a, HMM_Vec4 b)
} }
HMM_Vec2 HMM_NormV2(HMM_Vec2 A) { HMM_Vec2 HMM_NormV2(HMM_Vec2 A) {
// HMM_MulV2F(A, 1.0/HMM_LenV2(A)+FLOAT_MIN);
return HMM_MulV2F(A, HMM_InvSqrtF(HMM_DotV2(A, A))); return HMM_MulV2F(A, HMM_InvSqrtF(HMM_DotV2(A, A)));
} }

View file

@ -416,6 +416,7 @@ typedef union HMM_Mat4 {
extern const HMM_Vec2 v2zero; extern const HMM_Vec2 v2zero;
extern const HMM_Vec2 v2one; extern const HMM_Vec2 v2one;
extern const HMM_Vec3 v3zero; extern const HMM_Vec3 v3zero;
extern const HMM_Vec3 v3one;
extern const HMM_Vec4 v4zero; extern const HMM_Vec4 v4zero;
typedef signed int HMM_Bool; typedef signed int HMM_Bool;
@ -477,7 +478,6 @@ HMM_Vec4 HMM_AddV4(HMM_Vec4 Left, HMM_Vec4 Right);
HMM_Vec2 HMM_SubV2(HMM_Vec2 Left, HMM_Vec2 Right); HMM_Vec2 HMM_SubV2(HMM_Vec2 Left, HMM_Vec2 Right);
HMM_Vec3 HMM_SubV3(HMM_Vec3 Left, HMM_Vec3 Right); HMM_Vec3 HMM_SubV3(HMM_Vec3 Left, HMM_Vec3 Right);
HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right); HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right);
HMM_Vec3 HMM_ScaleV3(HMM_Vec3 v, double s);
HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right); HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right);
HMM_Vec2 HMM_MulV2F(HMM_Vec2 Left, float Right); HMM_Vec2 HMM_MulV2F(HMM_Vec2 Left, float Right);
HMM_Vec3 HMM_MulV3(HMM_Vec3 Left, HMM_Vec3 Right); HMM_Vec3 HMM_MulV3(HMM_Vec3 Left, HMM_Vec3 Right);

View file

@ -1142,6 +1142,25 @@ JSValue js_vector_dot(JSContext *js, JSValue self, int argc, JSValue *argv) { re
JSC_CCALL(vector_project, return vec22js(HMM_ProjV2(js2vec2(argv[0]), js2vec2(argv[1])))) JSC_CCALL(vector_project, return vec22js(HMM_ProjV2(js2vec2(argv[0]), js2vec2(argv[1]))))
JSC_CCALL(vector_midpoint,
HMM_Vec2 a = js2vec2(argv[0]);
HMM_Vec2 b = js2vec2(argv[1]);
// HMM_Vec2 c = HMM_AddV2(a,b);
// c = HMM_DivV2F(c, 2);
return vec22js((HMM_Vec2){(a.x+b.x)/2, (a.y+b.y)/2});
)
JSC_CCALL(vector_distance,
HMM_Vec2 a = js2vec2(argv[0]);
HMM_Vec2 b = js2vec2(argv[1]);
return number2js(HMM_DistV2(a,b));
)
JSC_CCALL(vector_angle,
HMM_Vec2 a = js2vec2(argv[0]);
return angle2js(atan2(a.y,a.x));
)
/* Given a series of points p, computes a new series with them expanded on either side by d */ /* Given a series of points p, computes a new series with them expanded on either side by d */
HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n) HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n)
{ {
@ -1204,11 +1223,251 @@ JSC_CCALL(vector_rotate,
return vec22js(vec); return vec22js(vec);
) )
JSC_CCALL(vector_add,
HMM_Vec4 a = js2vec4(argv[0]);
HMM_Vec4 b = js2vec4(argv[1]);
HMM_Vec4 c = HMM_AddV4(a,b);
return vec42js(c);
)
JSC_CCALL(vector_norm,
int len = js_arrlen(argv[0]);
switch(len) {
case 2: return vec22js(HMM_NormV2(js2vec2(argv[0])));
case 3: return vec32js(HMM_NormV3(js2vec3(argv[0])));
case 4: return vec42js(HMM_NormV4(js2vec4(argv[0])));
}
return argv[0];
)
JSC_CCALL(vector_angle_between,
int len = js_arrlen(argv[0]);
switch(len) {
case 2: return angle2js(HMM_AngleV2(js2vec2(argv[0]), js2vec2(argv[1])));
case 3: return angle2js(HMM_AngleV3(js2vec3(argv[0]), js2vec3(argv[1])));
case 4: return angle2js(HMM_AngleV4(js2vec4(argv[0]), js2vec4(argv[1])));
}
return angle2js(0);
)
JSC_CCALL(vector_lerp,
double s = js2number(argv[0]);
double f = js2number(argv[1]);
double t = js2number(argv[2]);
return number2js((f-s)*t+s);
)
int gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
JSC_CCALL(vector_gcd,
return number2js(gcd(js2number(argv[0]), js2number(argv[1])));
)
JSC_CCALL(vector_lcm,
double a = js2number(argv[0]);
double b = js2number(argv[1]);
return number2js((a*b)/gcd(a,b));
)
JSC_CCALL(vector_clamp,
double x = js2number(argv[0]);
double l = js2number(argv[1]);
double h = js2number(argv[2]);
return number2js(x > h ? h : x < l ? l : x);
)
JSC_SSCALL(vector_trimchr,
int len = js2number(js_getpropstr(argv[0], "length"));
char *start = str;
while (*start == *str2)
start++;
char *end = str + len-1;
while(*end == *str2)
end--;
ret = JS_NewStringLen(js, start, end-start+1);
)
JSC_CCALL(vector_angledist,
double a1 = js2number(argv[0]);
double a2 = js2number(argv[1]);
a1 = fmod(a1,1);
a2 = fmod(a2,1);
double dist = a2-a1;
if (dist == 0) return number2js(dist);
if (dist > 0) {
if (dist > 0.5) return number2js(dist-1);
return number2js(dist);
}
if (dist < -0.5) return number2js(dist+1);
return number2js(dist);
)
double r2()
{
return (double)rand() / (double)RAND_MAX ;
}
double rand_range(double min, double max) {
return r2() * (max-min) + min;
}
JSC_CCALL(vector_variate,
double n = js2number(argv[0]);
double pct = js2number(argv[1]);
return number2js(n + (rand_range(-pct,pct)*n));
)
JSC_CCALL(vector_random_range, return number2js(rand_range(js2number(argv[0]), js2number(argv[1]))))
JSC_CCALL(vector_mean,
double len = js_arrlen(argv[0]);
double sum;
for (int i = 0; i < len; i++)
sum += js2number(js_getpropidx(argv[0], i));
return number2js(sum/len);
)
JSC_CCALL(vector_sum,
double sum;
int len = js_arrlen(argv[0]);
for (int i = 0; i < len; i++)
sum += js2number(js_getpropidx(argv[0], i));
return number2js(sum);
)
JSC_CCALL(vector_sigma,
int len = js_arrlen(argv[0]);
double sum;
for (int i = 0; i < len; i++)
sum += js2number(js_getpropidx(argv[0], i));
double mean = sum/(double)len;
double sq_diff = 0;
for (int i = 0; i < len; i++) {
double x = js2number(js_getpropidx(argv[0],i));
sq_diff += pow(x-mean, 2);
}
double variance = sq_diff/((double)len);
return number2js(sqrt(variance));
)
JSC_CCALL(vector_median,
int len = js_arrlen(argv[0]);
double arr[len];
double temp;
for (int i = 0; i < len; i++)
arr[i] = js2number(js_getpropidx(argv[0], i));
for (int i = 0; i < len-1; i++) {
for (int j = i+1; j < len; j++) {
if (arr[i] > arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
if (len % 2 == 0) return number2js((arr[len/2-1] + arr[len/2])/2.0);
return number2js(arr[len/2]);
)
static const JSCFunctionListEntry js_vector_funcs[] = { static const JSCFunctionListEntry js_vector_funcs[] = {
MIST_FUNC_DEF(vector,dot,2), MIST_FUNC_DEF(vector, dot,2),
MIST_FUNC_DEF(vector,project,2), MIST_FUNC_DEF(vector, project,2),
MIST_FUNC_DEF(vector, inflate, 2), MIST_FUNC_DEF(vector, inflate, 2),
MIST_FUNC_DEF(vector, rotate, 2) MIST_FUNC_DEF(vector, rotate, 2),
MIST_FUNC_DEF(vector, add, 2),
MIST_FUNC_DEF(vector, midpoint, 2),
MIST_FUNC_DEF(vector, distance, 2),
MIST_FUNC_DEF(vector, angle, 1),
MIST_FUNC_DEF(vector, norm, 1),
MIST_FUNC_DEF(vector, angle_between, 2),
MIST_FUNC_DEF(vector, lerp, 3),
MIST_FUNC_DEF(vector, gcd, 2),
MIST_FUNC_DEF(vector, lcm, 2),
MIST_FUNC_DEF(vector, clamp, 3),
MIST_FUNC_DEF(vector, trimchr, 2),
MIST_FUNC_DEF(vector, angledist, 2),
MIST_FUNC_DEF(vector, variate, 2),
MIST_FUNC_DEF(vector, random_range, 2),
MIST_FUNC_DEF(vector, mean, 1),
MIST_FUNC_DEF(vector, sum, 1),
MIST_FUNC_DEF(vector, sigma, 1),
MIST_FUNC_DEF(vector, median, 1)
};
#define JS_HMM_FN(OP, HMM, SIGN) \
JSC_CCALL(array_##OP, \
int len = js_arrlen(self); \
if (!JS_IsArray(js, argv[0])) { \
double n = js2number(argv[0]); \
JSValue arr = JS_NewArray(js); \
for (int i = 0; i < len; i++) \
js_setprop_num(arr, i, number2js(js2number(js_getpropidx(self,i)) SIGN n)); \
return arr; \
} \
switch(len) { \
case 2: \
return vec22js(HMM_##HMM##V2(js2vec2(self), js2vec2(argv[0]))); \
case 3: \
return vec32js(HMM_##HMM##V3(js2vec3(self), js2vec3(argv[0]))); \
case 4: \
return vec42js(HMM_##HMM##V4(js2vec4(self), js2vec4(argv[0]))); \
} \
\
JSValue arr = JS_NewArray(js); \
for (int i = 0; i < len; i++) { \
double a = js2number(js_getpropidx(self,i)); \
double b = js2number(js_getpropidx(argv[0],i)); \
js_setprop_num(arr, i, number2js(a SIGN b)); \
} \
return arr; \
) \
JS_HMM_FN(add, Add, +)
JS_HMM_FN(sub, Sub, -)
JS_HMM_FN(div, Div, /)
JS_HMM_FN(scale, Mul, *)
JSC_CCALL(array_lerp,
int len = js_arrlen(self);
JSValue arr = JS_NewArray(js);
double t = js2number(argv[1]);
for (int i = 0; i < len; i++) {
double from = js2number(js_getpropidx(self, i));
double to = js2number(js_getpropidx(argv[0], i));
js_setprop_num(arr, i, number2js((to - from) * t + from));
}
return arr;
)
static const JSCFunctionListEntry js_array_funcs[] = {
MIST_FUNC_DEF(array, add, 1),
MIST_FUNC_DEF(array, sub, 1),
MIST_FUNC_DEF(array, div,1),
MIST_FUNC_DEF(array, scale, 1),
MIST_FUNC_DEF(array, lerp, 2)
}; };
JSC_CCALL(game_engine_start, engine_start(argv[0],argv[1], js2number(argv[2]), js2number(argv[3]))) JSC_CCALL(game_engine_start, engine_start(argv[0],argv[1], js2number(argv[2]), js2number(argv[3])))
@ -1234,13 +1493,18 @@ static const JSCFunctionListEntry js_input_funcs[] = {
JSC_CCALL(prosperon_phys2d_step, phys2d_update(js2number(argv[0]))) JSC_CCALL(prosperon_phys2d_step, phys2d_update(js2number(argv[0])))
JSC_CCALL(prosperon_window_render, openglRender(js2vec2(argv[0]))) JSC_CCALL(prosperon_window_render, openglRender(js2vec2(argv[0])))
JSC_CCALL(prosperon_guid, JSC_CCALL(prosperon_guid,
uint8_t bytes[16]; int bits = 32;
for (int i = 0; i < 16; i++) bytes[i] = rand()%256; char guid[33];
char uuid[37]; for (int i = 0; i < 4; i++) {
snprintf(uuid, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", int r = rand();
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], for (int j = 0; j < 8; j++) {
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]); guid[i*8+j] = "0123456789abcdef"[r%16];
return str2js(uuid); r /= 16;
}
}
guid[32] = 0;
return str2js(guid);
) )
static const JSCFunctionListEntry js_prosperon_funcs[] = { static const JSCFunctionListEntry js_prosperon_funcs[] = {
@ -1613,6 +1877,13 @@ JSC_CCALL(transform_phys2d,
t->rotation = HMM_MulQ(t->rotation, rot); t->rotation = HMM_MulQ(t->rotation, rot);
) )
JSC_CCALL(transform_unit,
transform *t = js2transform(self);
t->pos = v3zero;
t->rotation = QUAT1;
t->scale = v3one;
)
static const JSCFunctionListEntry js_transform_funcs[] = { static const JSCFunctionListEntry js_transform_funcs[] = {
CGETSET_ADD(transform, pos), CGETSET_ADD(transform, pos),
CGETSET_ADD(transform, scale), CGETSET_ADD(transform, scale),
@ -1623,6 +1894,7 @@ static const JSCFunctionListEntry js_transform_funcs[] = {
MIST_FUNC_DEF(transform, angle, 1), MIST_FUNC_DEF(transform, angle, 1),
MIST_FUNC_DEF(transform, lookat, 1), MIST_FUNC_DEF(transform, lookat, 1),
MIST_FUNC_DEF(transform, direction, 1), MIST_FUNC_DEF(transform, direction, 1),
MIST_FUNC_DEF(transform, unit, 0),
}; };
JSC_GETSET(dsp_node, pass, boolean) JSC_GETSET(dsp_node, pass, boolean)
@ -2741,6 +3013,10 @@ void ffi_load() {
JSSTATIC(damped_spring, cpConstraint_proto) JSSTATIC(damped_spring, cpConstraint_proto)
JSSTATIC(groove, cpConstraint_proto) JSSTATIC(groove, cpConstraint_proto)
JSValue array_proto = js_getpropstr(globalThis, "Array");
array_proto = js_getpropstr(array_proto, "prototype");
JS_SetPropertyFunctionList(js, array_proto, js_array_funcs, 4);
JS_FreeValue(js,globalThis); JS_FreeValue(js,globalThis);
} }