Compare commits
20 commits
845ee6ade3
...
33d4ebf14a
Author | SHA1 | Date | |
---|---|---|---|
John Alanbrook | 33d4ebf14a | ||
John Alanbrook | 570c12e3db | ||
John Alanbrook | 05bc965d10 | ||
John Alanbrook | 1142bfb896 | ||
John Alanbrook | 6047452b62 | ||
John Alanbrook | 0a7f5a5cdd | ||
John Alanbrook | 55ae7e2171 | ||
John Alanbrook | cb6f64925e | ||
John Alanbrook | 90940b42f5 | ||
John Alanbrook | ef802bb6f2 | ||
John Alanbrook | 08725d474d | ||
John Alanbrook | f905dbc571 | ||
John Alanbrook | 531cc1b43e | ||
John Alanbrook | 9d51858266 | ||
John Alanbrook | d4b057dc6f | ||
John Alanbrook | ff71ee9db6 | ||
John Alanbrook | 2eb75491ea | ||
John Alanbrook | cf6feffda2 | ||
John Alanbrook | 066b213fbe | ||
John Alanbrook | 63239fa51a |
169
docs/api/mum.md
169
docs/api/mum.md
|
@ -1,9 +1,172 @@
|
|||
# mum
|
||||
#### screengui()
|
||||
# Mum
|
||||
#### padding
|
||||
**array**
|
||||
|
||||
[
|
||||
0,
|
||||
0
|
||||
]
|
||||
|
||||
#### offset
|
||||
**array**
|
||||
|
||||
[
|
||||
0,
|
||||
0
|
||||
]
|
||||
|
||||
#### font
|
||||
**string**
|
||||
|
||||
|
||||
|
||||
#### prompt(msg = "prompt", value = "", list = [], cb = function()
|
||||
#### selectable
|
||||
**boolean**
|
||||
|
||||
|
||||
|
||||
#### selected
|
||||
**boolean**
|
||||
|
||||
|
||||
|
||||
#### font_size
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### text_align
|
||||
**string**
|
||||
|
||||
|
||||
|
||||
#### scale
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### angle
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### anchor
|
||||
**array**
|
||||
|
||||
[
|
||||
0,
|
||||
1
|
||||
]
|
||||
|
||||
#### hovered
|
||||
**object**
|
||||
|
||||
|
||||
|
||||
#### text_shadow
|
||||
**object**
|
||||
|
||||
|
||||
|
||||
#### text_outline
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### color
|
||||
**array**
|
||||
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
|
||||
#### margin
|
||||
**array**
|
||||
|
||||
[
|
||||
0,
|
||||
0
|
||||
]
|
||||
|
||||
#### width
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### height
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### max_width
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### max_height
|
||||
**number**
|
||||
|
||||
|
||||
|
||||
#### image_repeat
|
||||
**boolean**
|
||||
|
||||
|
||||
|
||||
#### image_repeat_offset
|
||||
**array**
|
||||
|
||||
[
|
||||
0,
|
||||
0
|
||||
]
|
||||
|
||||
#### debug
|
||||
**boolean**
|
||||
|
||||
|
||||
|
||||
#### make(def)
|
||||
|
||||
|
||||
|
||||
#### prestart()
|
||||
|
||||
|
||||
|
||||
#### start()
|
||||
|
||||
|
||||
|
||||
#### extend(def)
|
||||
|
||||
|
||||
|
||||
#### text(def)
|
||||
|
||||
|
||||
|
||||
#### button(def)
|
||||
|
||||
|
||||
|
||||
#### window(def)
|
||||
|
||||
|
||||
|
||||
#### image(def)
|
||||
|
||||
|
||||
|
||||
#### column(def)
|
||||
|
||||
|
||||
|
||||
#### debug_colors
|
||||
**object**
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1 +1,15 @@
|
|||
scripts/debug.js:205: [2024-07-03 12:13:12] [22;33mwarn[0m, script: Cannot print the API of something that isn't an object.
|
||||
# Tween
|
||||
#### default
|
||||
**object**
|
||||
|
||||
|
||||
|
||||
#### start(obj, target, tvals, options)
|
||||
|
||||
|
||||
|
||||
#### make(obj, target, tvals, options)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
9
docs/engine_tour/profiling.md
Normal file
9
docs/engine_tour/profiling.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Profiling
|
||||
|
||||
There are a handful of profiling methods available to you.
|
||||
|
||||
## Frame by frame profile
|
||||
|
||||
## Cpu instrumentation
|
||||
|
||||
## Game stats
|
|
@ -12,11 +12,18 @@ actor.spawn = function(script, config, callback){
|
|||
padawan.timers = [];
|
||||
padawan.master = this;
|
||||
Object.hide(padawan, "master", "timers", "padawans");
|
||||
padawan.toString = function() { return script; }
|
||||
check_registers(padawan);
|
||||
this.padawans.push(padawan);
|
||||
return padawan;
|
||||
};
|
||||
|
||||
actor.tween = function(from,to,time,fn) {
|
||||
var stop = tween(from,to,time,fn);
|
||||
this.timers.push(stop);
|
||||
return stop;
|
||||
}
|
||||
|
||||
actor.spawn.doc = `Create a new actor, using this actor as the master, initializing it with 'script' and with data (as a JSON or Nota file) from 'config'.`;
|
||||
|
||||
actor.rm_pawn = function(pawn)
|
||||
|
@ -36,26 +43,11 @@ actor.kill = function(){
|
|||
this.__dead__ = true;
|
||||
if (typeof this.die === 'function') this.die();
|
||||
if (typeof this.stop === 'function') this.stop();
|
||||
if (typeof this.garbage === 'function') this.garbage();
|
||||
};
|
||||
|
||||
actor.kill.doc = `Remove this actor and all its padawans from existence.`;
|
||||
|
||||
actor.interval = function(fn, seconds) {
|
||||
var cur;
|
||||
var stop = function() {
|
||||
cur();
|
||||
}
|
||||
|
||||
var f = function() {
|
||||
fn.call(this);
|
||||
cur = this.delay(f,seconds);
|
||||
}
|
||||
|
||||
cur = this.delay(f,seconds);
|
||||
|
||||
return stop;
|
||||
}
|
||||
|
||||
actor.delay = function(fn, seconds) {
|
||||
var timers = this.timers;
|
||||
var stop = function() {
|
||||
|
@ -64,7 +56,8 @@ actor.delay = function(fn, seconds) {
|
|||
}
|
||||
|
||||
function execute() {
|
||||
fn();
|
||||
if (fn) fn();
|
||||
if (stop.then) stop.then();
|
||||
stop();
|
||||
}
|
||||
|
||||
|
@ -73,9 +66,10 @@ actor.delay = function(fn, seconds) {
|
|||
stop.pct = function() { return 1-(stop.remain / stop.seconds); };
|
||||
|
||||
function update(dt) {
|
||||
profile.frame("timer");
|
||||
stop.remain -= dt;
|
||||
if (stop.remain <= 0)
|
||||
execute();
|
||||
if (stop.remain <= 0) execute();
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
var rm = Register.appupdate.register(update);
|
||||
|
|
205
scripts/base.js
205
scripts/base.js
|
@ -409,7 +409,7 @@ Object.dainty_assign = function(target, source)
|
|||
|
||||
Object.isObject = function(o)
|
||||
{
|
||||
return (typeof o === 'object' && !Array.isArray(o));
|
||||
return (o instanceof Object && !(o instanceof Array));
|
||||
}
|
||||
|
||||
Object.setter_assign = function(target, source)
|
||||
|
@ -512,7 +512,7 @@ Object.copy = function(proto, ...objs)
|
|||
return c;
|
||||
}
|
||||
|
||||
/* OBJECT DEFININTioNS */
|
||||
/* OBJECT DEFININTIONS */
|
||||
Object.defHidden = function(obj, prop)
|
||||
{
|
||||
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 */
|
||||
|
||||
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', {
|
||||
value: function(val) {
|
||||
var idx = this.lastIndexOf(val);
|
||||
|
@ -824,10 +805,6 @@ Object.defineProperty(String.prototype, 'sub', {
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'rm', {
|
||||
value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); }
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'updir', {
|
||||
value: function() {
|
||||
if (this.lastIndexOf('/') === this.length-1)
|
||||
|
@ -840,42 +817,7 @@ Object.defineProperty(String.prototype, 'updir', {
|
|||
|
||||
Object.defineProperty(String.prototype, 'trimchr', {
|
||||
value: function(chars) {
|
||||
var start = this.length;
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'startswith', {
|
||||
value: function(val) {
|
||||
if (!val) return false;
|
||||
return this.startsWith(val);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'endswith', {
|
||||
value: function(val) {
|
||||
if (!val) return false;
|
||||
return this.endsWith(val);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'pct', {
|
||||
value: function(val) {
|
||||
return vector.trimchr(this, chars);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -883,11 +825,6 @@ Object.defineProperty(String.prototype, 'uc', { value: function() { return this.
|
|||
Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }});
|
||||
|
||||
/* ARRAY DEFS */
|
||||
Object.defineProperty(Array.prototype, 'aspect', {
|
||||
value: function() {
|
||||
return this.x/this.y;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(Array.prototype, 'copy', {
|
||||
value: function() {
|
||||
var c = [];
|
||||
|
@ -900,6 +837,18 @@ Object.defineProperty(Array.prototype, 'copy', {
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'forFrom', {
|
||||
value: function(n, fn) {
|
||||
for (var i = n; i < this.length; i++) fn(this[i]);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'forTo', {
|
||||
value: function(n, fn) {
|
||||
for (var i = 0; i < n; i++) fn(this[i]);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'dofilter', {
|
||||
value: function(fn) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
|
@ -1026,13 +975,6 @@ swizz.forEach(function(x) {
|
|||
};
|
||||
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', {
|
||||
value: function() {
|
||||
var c = this.slice();
|
||||
|
@ -1067,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', {
|
||||
value: function(arr) {
|
||||
var c = [];
|
||||
|
@ -1087,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', {
|
||||
value: function() {
|
||||
return this.toSorted();
|
||||
|
@ -1131,7 +1056,6 @@ Object.defineProperty(Array.prototype, 'mapvec', {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
Object.defineProperty(Array.prototype, 'remove', {
|
||||
value: function(b) {
|
||||
var idx = this.indexOf(b);
|
||||
|
@ -1268,19 +1192,23 @@ Object.defineProperty(Array.prototype, 'mirrored', {
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'lerp', {
|
||||
value: function(to, t) {
|
||||
var c = [];
|
||||
this.forEach(function(x,i) {
|
||||
c[i] = (to[i] - x) * t + x;
|
||||
});
|
||||
return c;
|
||||
}
|
||||
});
|
||||
Math.lerp = vector.lerp;
|
||||
Math.gcd = vector.gcd;
|
||||
Math.lcm = vector.lcm;
|
||||
Math.sum = vector.sum;
|
||||
Math.mean = vector.mean;
|
||||
Math.sigma = vector.sigma;
|
||||
Math.median = vector.median;
|
||||
|
||||
Math.lerp = function(s,f,t) { return (f-s)*t + s; };
|
||||
Math.gcd = function(a,b) { return b === 0 ? a : gcd(b,a%b); }
|
||||
Math.lcm = function(a,b) { return (a*b)/gcd(a,b); }
|
||||
Math.variance = function(series) {
|
||||
var mean = Math.mean(series);
|
||||
var vnce = 0;
|
||||
for (var i = 0; i < series.length; i++)
|
||||
vnce += Math.pow(series[i]-mean, 2);
|
||||
return vnce/(series.length);
|
||||
}
|
||||
|
||||
Math.ci = function(series) { return 3*Math.sigma(series)/Math.sqrt(series.length); }
|
||||
|
||||
Math.grab_from_points = function(pos, points, slop) {
|
||||
var shortest = slop;
|
||||
|
@ -1324,22 +1252,18 @@ Object.defineProperty(Object.prototype, 'lerp',{
|
|||
return obj;
|
||||
}});
|
||||
|
||||
/* MATH EXTENSioNS */
|
||||
/* MATH EXTENSIONS */
|
||||
Object.defineProperty(Number.prototype, 'lerp', {
|
||||
value: function(to, t) {
|
||||
var s = this;
|
||||
return (to - this) * t + this;
|
||||
}
|
||||
value: function(to, t) { return Math.lerp(this, to, t); }
|
||||
});
|
||||
|
||||
Object.defineProperty(Number.prototype, 'clamp', {
|
||||
value: function(from,to) {
|
||||
return Math.clamp(this,from,to);
|
||||
}
|
||||
value: function(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.snap = function(val, grid) {
|
||||
|
@ -1351,32 +1275,17 @@ Math.snap = function(val, grid) {
|
|||
return d+i;
|
||||
}
|
||||
|
||||
Math.angledist = function (a1, a2) {
|
||||
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 = vector.angledist;
|
||||
Math.angledist.doc = "Find the shortest angle between two angles.";
|
||||
Math.TAU = Math.PI*2;
|
||||
Math.deg2rad = function(deg) { return deg * 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.rad2turn = function(x) { return x/Math.TAU; };
|
||||
Math.turn2deg = 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.variate = vector.variate;
|
||||
|
||||
/* BOUNDINGBOXES */
|
||||
var bbox = {};
|
||||
|
@ -1509,39 +1418,18 @@ bbox.fromobjs = function(objs)
|
|||
|
||||
/* VECTORS */
|
||||
var Vector = {};
|
||||
Vector.length = function(v) {
|
||||
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
Vector.norm = function(v) {
|
||||
var len = Vector.length(v);
|
||||
if (!len) return [0,0];
|
||||
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.length = function(v) { return Math.hypot(...v); }
|
||||
|
||||
Vector.norm = vector.norm;
|
||||
Vector.project = vector.project;
|
||||
Vector.dot = vector.dot;
|
||||
Vector.random = function() {
|
||||
var vec = [Math.random()-0.5, Math.random()-0.5];
|
||||
return Vector.norm(vec);
|
||||
}
|
||||
|
||||
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.angle_between = vector.angle_between;
|
||||
Vector.rotate = vector.rotate;
|
||||
|
||||
Vector.equal = function(v1, v2, tol) {
|
||||
if (!tol)
|
||||
|
@ -1652,7 +1540,6 @@ Math.sign = function(n) { return n >= 0 ? 1 : -1; }
|
|||
return {
|
||||
convert,
|
||||
time,
|
||||
json,
|
||||
Vector,
|
||||
bbox,
|
||||
yaml
|
||||
|
|
|
@ -15,6 +15,21 @@ var make_point_obj = function(o, p)
|
|||
|
||||
var fullrect = [0,0,1,1];
|
||||
|
||||
var sprite_addbucket = function(sprite)
|
||||
{
|
||||
var layer = sprite.gameobject.drawlayer;
|
||||
sprite_buckets[layer] ??= {};
|
||||
sprite_buckets[layer][sprite.path] ??= {};
|
||||
sprite_buckets[layer][sprite.path][sprite.guid] = sprite;
|
||||
}
|
||||
|
||||
var sprite_rmbucket = function(sprite)
|
||||
{
|
||||
for (var layer of Object.values(sprite_buckets))
|
||||
for (var path of Object.values(layer))
|
||||
delete path[sprite.guid];
|
||||
}
|
||||
|
||||
var sprite = {
|
||||
loop: true,
|
||||
rect: fullrect,
|
||||
|
@ -41,6 +56,7 @@ var sprite = {
|
|||
//self.path = playing.path;
|
||||
self.frame = playing.frames[f].rect;
|
||||
self.rect = [self.frame.x, self.frame.y, self.frame.w, self.frame.h];
|
||||
self.update_dimensions();
|
||||
f = (f+1)%playing.frames.length;
|
||||
if (f === 0) {
|
||||
self.anim_done?.();
|
||||
|
@ -62,6 +78,7 @@ var sprite = {
|
|||
}
|
||||
if (p === this.path) return;
|
||||
this._p = p;
|
||||
|
||||
this.del_anim?.();
|
||||
this.texture = game.texture(p);
|
||||
|
||||
|
@ -69,17 +86,20 @@ var sprite = {
|
|||
this.rect = fullrect;
|
||||
|
||||
var anim = SpriteAnim.make(p);
|
||||
this.update_dimensions();
|
||||
this.sync();
|
||||
|
||||
if (!anim) return;
|
||||
this.anim = anim;
|
||||
this.play();
|
||||
|
||||
this.pos = this.dimensions().scale(this.anchor);
|
||||
|
||||
},
|
||||
get path() {
|
||||
return this._p;
|
||||
},
|
||||
kill() {
|
||||
sprite_rmbucket(this);
|
||||
this.del_anim?.();
|
||||
this.anim = undefined;
|
||||
this.gameobject = undefined;
|
||||
|
@ -92,7 +112,10 @@ var sprite = {
|
|||
this.pos = this.pos.scale(x);
|
||||
},
|
||||
anchor:[0,0],
|
||||
sync() { },
|
||||
sync() {
|
||||
sprite_rmbucket(this);
|
||||
sprite_addbucket(this);
|
||||
},
|
||||
pick() { return this; },
|
||||
boundingbox() {
|
||||
var dim = this.dimensions();
|
||||
|
@ -101,16 +124,21 @@ var sprite = {
|
|||
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() {
|
||||
var dim = [this.texture.width, this.texture.height];
|
||||
dim.x *= this.frame.w;
|
||||
dim.y *= this.frame.h;
|
||||
return dim;
|
||||
return this._dimensions;
|
||||
},
|
||||
width() { return this.dimensions().x; },
|
||||
height() { return this.dimensions().y; },
|
||||
};
|
||||
globalThis.allsprites = {};
|
||||
var sprite_buckets = {};
|
||||
|
||||
component.sprite_buckets = function() { return sprite_buckets; }
|
||||
|
||||
sprite.doc = {
|
||||
path: "Path to the texture.",
|
||||
|
@ -149,10 +177,14 @@ sprite.inputs.kp1 = function() { this.setanchor("ul"); }
|
|||
component.sprite = function(obj) {
|
||||
var sp = Object.create(sprite);
|
||||
sp.gameobject = obj;
|
||||
sp.transform = obj.transform;
|
||||
sp.guid = prosperon.guid();
|
||||
allsprites[sp.guid] = sp;
|
||||
if (component.sprite.make_hook) component.sprite.make_hook(sp);
|
||||
sprite_addbucket(sp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
sprite.shade = [1,1,1,1];
|
||||
|
||||
Object.mixin(os.make_seg2d(), {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
var debug = {};
|
||||
|
||||
debug.build = function(fn) { fn(); }
|
||||
|
||||
debug.fn_break = function(fn,obj = globalThis) {
|
||||
|
@ -50,7 +48,7 @@ debug.draw = function() {
|
|||
"EDIT", [0, 0], 1);
|
||||
}
|
||||
|
||||
function assert(op, str = `assertion failed [value '${op}']`)
|
||||
var assert = function(op, str = `assertion failed [value '${op}']`)
|
||||
{
|
||||
if (!op)
|
||||
console.panic(str);
|
||||
|
@ -64,21 +62,6 @@ var Gizmos = {
|
|||
},
|
||||
};
|
||||
|
||||
profile.cpu = function(fn, times = 1, q = "unnamed") {
|
||||
var start = profile.now();
|
||||
for (var i = 0; i < times; i++)
|
||||
fn();
|
||||
|
||||
var elapsed = profile.now() - start;
|
||||
var avgt = profile.best_t(elapsed/times);
|
||||
var totalt = profile.best_t(elapsed);
|
||||
|
||||
say(`profile [${q}]: ${profile.best_t(avgt)} average [${profile.best_t(totalt)} for ${times} loops]`);
|
||||
}
|
||||
|
||||
profile.ms = function(t) { return t/1000000; }
|
||||
profile.secs = function(t) { return t/1000000000; }
|
||||
|
||||
/* These controls are available during editing, and during play of debug builds */
|
||||
debug.inputs = {};
|
||||
debug.inputs.f1 = function () { debug.draw_phys = !debug.draw_phys; };
|
||||
|
@ -226,23 +209,6 @@ debug.api.print_doc = function(name)
|
|||
return mdoc;
|
||||
}
|
||||
|
||||
debug.log = {};
|
||||
|
||||
debug.log.time = function(fn, name, avg=0)
|
||||
{
|
||||
debug.log.time[name] ??= [];
|
||||
var start = profile.now();
|
||||
fn();
|
||||
debug.log.time[name].push(profile.now()-start);
|
||||
}
|
||||
|
||||
debug.kill = function()
|
||||
{
|
||||
assert = function() {};
|
||||
debug.build = function() {};
|
||||
debug.fn_break = function() {};
|
||||
}
|
||||
|
||||
return {
|
||||
debug,
|
||||
Gizmos,
|
||||
|
|
|
@ -569,7 +569,7 @@ var editor = {
|
|||
obj.ur = sub;
|
||||
|
||||
return;
|
||||
} else if (!sub.startswith(obj.ur)) {
|
||||
} else if (!sub.startsWith(obj.ur)) {
|
||||
console.warn(`Cannot make an ur of type ${sub} from an object with the ur ${obj.ur}`);
|
||||
return;
|
||||
}
|
||||
|
@ -1433,7 +1433,7 @@ replpanel.inputs.tab = function() {
|
|||
var stub = this.value.fromlast('.');
|
||||
var replobj = (editor.selectlist.length === 1) ? "editor.selectlist[0]" : "editor.edit_level";
|
||||
|
||||
if (this.value.startswith("this."))
|
||||
if (this.value.startsWith("this."))
|
||||
keyobj = keyobj.replace("this", replobj);
|
||||
|
||||
if (!this.value.includes('.')) keys.push("this");
|
||||
|
@ -1461,7 +1461,7 @@ replpanel.inputs.tab = function() {
|
|||
|
||||
if (stub)
|
||||
this.value = o + '.' + comp;
|
||||
else if (this.value.endswith('.'))
|
||||
else if (this.value.endsWith('.'))
|
||||
this.value = o + '.' + comp;
|
||||
else
|
||||
this.value = comp;
|
||||
|
@ -1677,7 +1677,7 @@ var openlevelpanel = Object.copy(inputpanel, {
|
|||
|
||||
keycb() {
|
||||
if(this.value)
|
||||
this.assets = this.allassets.filter(x => x.startswith(this.value));
|
||||
this.assets = this.allassets.filter(x => x.startsWith(this.value));
|
||||
else
|
||||
this.assets = this.allassets.slice();
|
||||
for (var m in this.mumlist)
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
"use math";
|
||||
|
||||
Object.defineProperty(String.prototype, 'rm', {
|
||||
value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); }
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, "tolast", {
|
||||
value: function (val) {
|
||||
var idx = this.lastIndexOf(val);
|
||||
|
@ -25,7 +29,26 @@ Object.defineProperty(String.prototype, "folder", {
|
|||
|
||||
globalThis.Resources = {};
|
||||
|
||||
Resources.replpath = function (str, path) {
|
||||
Resources.rm_fn = function rm_fn(fn, text)
|
||||
{
|
||||
var reg = new RegExp(fn.source + "\\s*\\(");
|
||||
var match;
|
||||
while (match = text.match(reg)) {
|
||||
var last = match.index+match[0].length;
|
||||
var par = 1;
|
||||
while (par !== 0) {
|
||||
if (text[last] === '(') par++;
|
||||
if (text[last] === ')') par--;
|
||||
last++;
|
||||
}
|
||||
text = text.rm(match.index, last);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
Resources.rm_fn.doc = "Remove calls to a given function from a given text script.";
|
||||
|
||||
Resources.replpath = function replpath(str, path) {
|
||||
if (!str) return str;
|
||||
if (str[0] === "/") return str.rm(0);
|
||||
|
||||
|
@ -43,12 +66,24 @@ Resources.replpath = function (str, path) {
|
|||
return str;
|
||||
};
|
||||
|
||||
Resources.replstrs = function (path) {
|
||||
Resources.replstrs = function replstrs(path) {
|
||||
if (!path) return;
|
||||
var script = io.slurp(path);
|
||||
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
|
||||
var stem = path.dir();
|
||||
|
||||
// remove console statements
|
||||
if (!console.enabled)
|
||||
script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script);
|
||||
|
||||
if (!profile.enabled)
|
||||
script = Resources.rm_fn(/profile\.(cache|frame|endcache|endframe)/, script);
|
||||
|
||||
if (!debug.enabled) {
|
||||
script = Resources.rm_fn(/assert/, script);
|
||||
script = Resources.rm_fn(/debug\.(build|fn_break)/, script);
|
||||
}
|
||||
|
||||
script = script.replace(regexp, function (str) {
|
||||
var newstr = Resources.replpath(str.trimchr('"'), path);
|
||||
return `"${newstr}"`;
|
||||
|
@ -110,38 +145,6 @@ Resources.find_script = function (file) {
|
|||
return find_ext(file, Resources.scripts);
|
||||
};
|
||||
|
||||
profile.best_t = function (t) {
|
||||
var qq = "ns";
|
||||
if (t > 1000) {
|
||||
t /= 1000;
|
||||
qq = "us";
|
||||
if (t > 1000) {
|
||||
t /= 1000;
|
||||
qq = "ms";
|
||||
}
|
||||
}
|
||||
return `${t.toPrecision(4)} ${qq}`;
|
||||
};
|
||||
|
||||
profile.report = function (start, msg = "[undefined report]") {
|
||||
console.info(`${msg} in ${profile.best_t(profile.now() - start)}`);
|
||||
};
|
||||
|
||||
profile.addreport = function (cache, line, start) {
|
||||
cache ??= profcache;
|
||||
cache[line] ??= [];
|
||||
cache[line].push(profile.now() - start);
|
||||
return profile.now();
|
||||
};
|
||||
|
||||
profile.printreport = function (cache, name) {
|
||||
var report = name + "\n";
|
||||
for (var i in cache)
|
||||
report += `${i} ${profile.best_t(cache[i].reduce((a, b) => a + b) / cache[i].length)}\n`;
|
||||
|
||||
return report;
|
||||
};
|
||||
|
||||
console.transcript = "";
|
||||
console.say = function (msg) {
|
||||
msg += "\n";
|
||||
|
@ -218,425 +221,71 @@ console.doc = {
|
|||
|
||||
globalThis.global = globalThis;
|
||||
|
||||
var profcache = {};
|
||||
var use_cache = {};
|
||||
|
||||
function use(file, env = {}, script) {
|
||||
globalThis.use = function use(file, env = {}, script) {
|
||||
file = Resources.find_script(file);
|
||||
var st = profile.now();
|
||||
profile.cache("USE", file);
|
||||
|
||||
profcache[file] ??= [];
|
||||
|
||||
if (use.cache[file]) {
|
||||
var ret = use.cache[file].call(env);
|
||||
profile.addreport(profcache, file, st);
|
||||
if (use_cache[file]) {
|
||||
var ret = use_cache[file].call(env);
|
||||
return;
|
||||
}
|
||||
script ??= Resources.replstrs(file);
|
||||
|
||||
script = `(function() { var self = this; ${script}; })`;
|
||||
var fn = os.eval(file, script);
|
||||
use.cache[file] = fn;
|
||||
use_cache[file] = fn;
|
||||
var ret = fn.call(env);
|
||||
profile.addreport(profcache, file, st);
|
||||
profile.endcache();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
use.cache = {};
|
||||
function stripped_use (file, env = {}, script) {
|
||||
file = Resources.find_script(file);
|
||||
|
||||
global.check_registers = function (obj) {
|
||||
for (var reg in Register.registries)
|
||||
if (typeof obj[reg] === 'function')
|
||||
obj.timers.push(Register.registries[reg].register(obj[reg].bind(obj)));
|
||||
for (var k in obj) {
|
||||
if (!k.startswith("on_")) continue;
|
||||
var signal = k.fromfirst("on_");
|
||||
Event.observe(signal, obj, obj[k]);
|
||||
if (use_cache[file]) {
|
||||
var ret = use_cache[file].call(env);
|
||||
return;
|
||||
}
|
||||
};
|
||||
script ??= Resources.replstrs(file);
|
||||
|
||||
Object.assign(global, use("scripts/base"));
|
||||
global.obscure("global");
|
||||
global.mixin("scripts/render");
|
||||
global.mixin("scripts/debug");
|
||||
script = `(function() { var self = this; ${script}; })`;
|
||||
var fn = os.eval(file, script);
|
||||
var ret = fn.call(env);
|
||||
profile.endcache();
|
||||
|
||||
var frame_t = profile.secs(profile.now());
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
var gggstart = game.engine_start;
|
||||
game.engine_start = function (s) {
|
||||
game.startengine = 1;
|
||||
gggstart(
|
||||
function () {
|
||||
global.mixin("scripts/sound.js");
|
||||
world_start();
|
||||
window.set_icon(os.make_texture("icons/moon.gif"));
|
||||
Object.readonly(window.__proto__, "vsync");
|
||||
Object.readonly(window.__proto__, "enable_dragndrop");
|
||||
Object.readonly(window.__proto__, "enable_clipboard");
|
||||
Object.readonly(window.__proto__, "high_dpi");
|
||||
Object.readonly(window.__proto__, "sample_count");
|
||||
s();
|
||||
|
||||
shape.quad = {
|
||||
pos: os.make_buffer([0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0], 0),
|
||||
verts: 4,
|
||||
uv: os.make_buffer([0, 1, 1, 1, 0, 0, 1, 0], 2),
|
||||
index: os.make_buffer([0, 1, 2, 2, 1, 3], 1),
|
||||
count: 6,
|
||||
};
|
||||
|
||||
shape.triangle = {
|
||||
pos: os.make_buffer([0, 0, 0, 0.5, 1, 0, 1, 0, 0], 0),
|
||||
uv: os.make_buffer([0, 0, 0.5, 1, 1, 0], 2),
|
||||
verts: 3,
|
||||
count: 3,
|
||||
index: os.make_buffer([0, 2, 1], 1),
|
||||
};
|
||||
|
||||
render.init();
|
||||
},
|
||||
process,
|
||||
window.size.x,
|
||||
window.size.y,
|
||||
);
|
||||
};
|
||||
|
||||
game.startengine = 0;
|
||||
var frames = [];
|
||||
|
||||
prosperon.release_mode = function()
|
||||
function bare_use(file)
|
||||
{
|
||||
prosperon.debug = false;
|
||||
mum.debug = false;
|
||||
debug.kill();
|
||||
}
|
||||
prosperon.debug = true;
|
||||
|
||||
function process() {
|
||||
var startframe = profile.now();
|
||||
var dt = profile.secs(profile.now()) - frame_t;
|
||||
frame_t = profile.secs(profile.now());
|
||||
|
||||
prosperon.appupdate(dt);
|
||||
input.procdown();
|
||||
|
||||
if (sim.mode === "play" || sim.mode === "step") {
|
||||
prosperon.update(dt * game.timescale);
|
||||
if (sim.mode === "step") sim.pause();
|
||||
|
||||
physlag += dt;
|
||||
|
||||
while (physlag > physics.delta) {
|
||||
physlag -= physics.delta;
|
||||
var st = profile.now();
|
||||
prosperon.phys2d_step(physics.delta * game.timescale);
|
||||
prosperon.physupdate(physics.delta * game.timescale);
|
||||
profile.addreport(profcache, "physics step", st);
|
||||
}
|
||||
}
|
||||
var st = profile.now();
|
||||
prosperon.window_render(window.size);
|
||||
prosperon.render();
|
||||
profile.addreport(profcache, "render frame", st);
|
||||
frames.push(profile.secs(profile.now() - startframe));
|
||||
if (frames.length > 20) frames.shift();
|
||||
var script = io.slurp(file);
|
||||
if (!script) return;
|
||||
script = `(function() { var self = this; ${script}; })`;
|
||||
Object.assign(globalThis, os.eval(file, script).call(globalThis));
|
||||
}
|
||||
|
||||
globalThis.fps = function () {
|
||||
var sum = 0;
|
||||
for (var i = 0; i < frames.length; i++) sum += frames[i];
|
||||
return frames.length / sum;
|
||||
};
|
||||
globalThis.debug = {};
|
||||
|
||||
game.timescale = 1;
|
||||
profile.enabled = true;
|
||||
console.enabled = true;
|
||||
debug.enabled = true;
|
||||
|
||||
var eachobj = function (obj, fn) {
|
||||
var val = fn(obj);
|
||||
if (val) return val;
|
||||
for (var o in obj.objects) {
|
||||
if (obj.objects[o] === obj)
|
||||
console.error(`Object ${obj.toString()} is referenced by itself.`);
|
||||
val = eachobj(obj.objects[o], fn);
|
||||
if (val) return val;
|
||||
}
|
||||
};
|
||||
bare_use("scripts/base.js");
|
||||
bare_use("scripts/profile.js");
|
||||
|
||||
game.all_objects = function (fn, startobj = world) {
|
||||
return eachobj(startobj, fn);
|
||||
};
|
||||
game.find_object = function (fn, startobj = world) {};
|
||||
|
||||
game.tags = {};
|
||||
game.tag_add = function (tag, obj) {
|
||||
game.tags[tag] ??= {};
|
||||
game.tags[tag][obj.guid] = obj;
|
||||
};
|
||||
|
||||
game.tag_rm = function (tag, obj) {
|
||||
delete game.tags[tag][obj.guid];
|
||||
};
|
||||
|
||||
game.tag_clear_guid = function (guid) {
|
||||
for (var tag in game.tags) delete game.tags[tag][guid];
|
||||
};
|
||||
|
||||
game.objects_with_tag = function (tag) {
|
||||
if (!game.tags[tag]) return [];
|
||||
return Object.values(game.tags[tag]);
|
||||
};
|
||||
|
||||
game.doc = {};
|
||||
game.doc.object = "Returns the entity belonging to a given id.";
|
||||
game.doc.pause = "Pause game simulation.";
|
||||
game.doc.play = "Resume or start game simulation.";
|
||||
game.doc.camera = "Current camera.";
|
||||
|
||||
game.texture = function (path, force = false) {
|
||||
if (force && game.texture.cache[path]) return game.texture.cache[path];
|
||||
|
||||
if (!io.exists(path)) {
|
||||
console.warn(`Missing texture: ${path}`);
|
||||
game.texture.cache[path] = game.texture("icons/no_tex.gif");
|
||||
} else game.texture.cache[path] ??= os.make_texture(path);
|
||||
|
||||
return game.texture.cache[path];
|
||||
};
|
||||
game.texture.cache = {};
|
||||
|
||||
prosperon.semver = {};
|
||||
prosperon.semver.valid = function (v, range) {
|
||||
v = v.split(".");
|
||||
range = range.split(".");
|
||||
if (v.length !== 3) return undefined;
|
||||
if (range.length !== 3) return undefined;
|
||||
|
||||
if (range[0][0] === "^") {
|
||||
range[0] = range[0].slice(1);
|
||||
if (parseInt(v[0]) >= parseInt(range[0])) return true;
|
||||
|
||||
return false;
|
||||
prosperon.release = function()
|
||||
{
|
||||
profile.enabled = false;
|
||||
console.enabled = false;
|
||||
debug.enabled = false;
|
||||
}
|
||||
|
||||
if (range[0] === "~") {
|
||||
range[0] = range[0].slice(1);
|
||||
for (var i = 0; i < 2; i++)
|
||||
if (parseInt(v[i]) < parseInt(range[i])) return false;
|
||||
return true;
|
||||
}
|
||||
bare_use("preconfig.js");
|
||||
|
||||
return prosperon.semver.cmp(v.join("."), range.join(".")) === 0;
|
||||
};
|
||||
if (!profile.enabled)
|
||||
use = stripped_use;
|
||||
|
||||
prosperon.semver.cmp = function (v1, v2) {
|
||||
var ver1 = v1.split(".");
|
||||
var ver2 = v2.split(".");
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var n1 = parseInt(ver1[i]);
|
||||
var n2 = parseInt(ver2[i]);
|
||||
if (n1 > n2) return 1;
|
||||
else if (n1 < n2) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
prosperon.semver.doc =
|
||||
"Functions for semantic versioning numbers. Semantic versioning is given as a triple digit number, as MAJOR.MINOR.PATCH.";
|
||||
prosperon.semver.cmp.doc =
|
||||
"Compare two semantic version numbers, given like X.X.X.";
|
||||
prosperon.semver.valid.doc = `Test if semantic version v is valid, given a range.
|
||||
Range is given by a semantic versioning number, prefixed with nothing, a ~, or a ^.
|
||||
~ means that MAJOR and MINOR must match exactly, but any PATCH greater or equal is valid.
|
||||
^ means that MAJOR must match exactly, but any MINOR and PATCH greater or equal is valid.`;
|
||||
|
||||
prosperon.iconified = function (icon) {};
|
||||
prosperon.focus = function (focus) {};
|
||||
prosperon.resize = function (dimensions) {
|
||||
window.size.x = dimensions.x;
|
||||
window.size.y = dimensions.y;
|
||||
};
|
||||
prosperon.suspended = function (sus) {};
|
||||
prosperon.mouseenter = function () {};
|
||||
prosperon.mouseleave = function () {};
|
||||
prosperon.touchpress = function (touches) {};
|
||||
prosperon.touchrelease = function (touches) {};
|
||||
prosperon.touchmove = function (touches) {};
|
||||
prosperon.clipboardpaste = function (str) {};
|
||||
prosperon.quit = function () {
|
||||
say(profile.printreport(profcache, "USE REPORT"));
|
||||
say(profile.printreport(entityreport, "ENTITY REPORT"));
|
||||
|
||||
console.info("QUITTING");
|
||||
for (var i in debug.log.time)
|
||||
say(debug.log.time[i].map((x) => profile.ms(x)));
|
||||
};
|
||||
|
||||
window.size = [640, 480];
|
||||
window.mode = "keep";
|
||||
window.toggle_fullscreen = function() { window.fullscreen = !window.fullscreen; }
|
||||
|
||||
window.set_icon.doc = "Set the icon of the window using the PNG image at path.";
|
||||
|
||||
window.doc = {};
|
||||
window.doc.dimensions = "Window width and height packaged in an array [width,height]";
|
||||
window.doc.title = "Name in the title bar of the window.";
|
||||
window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width.";
|
||||
|
||||
global.mixin("scripts/input");
|
||||
global.mixin("scripts/std");
|
||||
global.mixin("scripts/diff");
|
||||
global.mixin("scripts/color");
|
||||
global.mixin("scripts/gui");
|
||||
global.mixin("scripts/tween");
|
||||
global.mixin("scripts/ai");
|
||||
|
||||
var timer = {
|
||||
update(dt) {
|
||||
this.remain -= dt;
|
||||
if (this.remain <= 0) {
|
||||
this.fn();
|
||||
this.kill();
|
||||
}
|
||||
},
|
||||
|
||||
kill() {
|
||||
this.end();
|
||||
delete this.fn;
|
||||
},
|
||||
|
||||
delay(fn, secs) {
|
||||
var t = Object.create(this);
|
||||
t.time = secs;
|
||||
t.remain = secs;
|
||||
t.fn = fn;
|
||||
t.end = Register.update.register(timer.update.bind(t));
|
||||
var returnfn = timer.kill.bind(t);
|
||||
returnfn.remain = secs;
|
||||
return returnfn;
|
||||
},
|
||||
};
|
||||
|
||||
global.mixin("scripts/physics");
|
||||
global.mixin("scripts/geometry");
|
||||
|
||||
/*
|
||||
Factory for creating registries. Register one with 'X.register',
|
||||
which returns a function that, when invoked, cancels the registry.
|
||||
*/
|
||||
var Register = {
|
||||
registries: [],
|
||||
|
||||
add_cb(name, e_event = false) {
|
||||
var n = {};
|
||||
var fns = [];
|
||||
|
||||
n.register = function (fn, obj) {
|
||||
if (typeof fn !== "function") return;
|
||||
if (typeof obj === "object") fn = fn.bind(obj);
|
||||
fns.push(fn);
|
||||
return function () {
|
||||
fns.remove(fn);
|
||||
};
|
||||
};
|
||||
prosperon[name] = function (...args) {
|
||||
fns.forEach((x) => x(...args));
|
||||
};
|
||||
prosperon[name].fns = fns;
|
||||
n.clear = function () {
|
||||
fns = [];
|
||||
};
|
||||
|
||||
Register[name] = n;
|
||||
Register.registries[name] = n;
|
||||
|
||||
return n;
|
||||
},
|
||||
};
|
||||
|
||||
Register.add_cb("appupdate", true);
|
||||
Register.add_cb("update", true).doc = "Called once per frame.";
|
||||
Register.add_cb("physupdate", true);
|
||||
Register.add_cb("gui", true);
|
||||
Register.add_cb("hud", true);
|
||||
Register.add_cb("draw_dbg", true);
|
||||
Register.add_cb("gui_dbg", true);
|
||||
Register.add_cb("hud_dbg", true);
|
||||
Register.add_cb("draw", true);
|
||||
|
||||
var Event = {
|
||||
events: {},
|
||||
|
||||
observe(name, obj, fn) {
|
||||
this.events[name] ??= [];
|
||||
this.events[name].push([obj, fn]);
|
||||
},
|
||||
|
||||
unobserve(name, obj) {
|
||||
this.events[name] = this.events[name].filter((x) => x[0] !== obj);
|
||||
},
|
||||
|
||||
rm_obj(obj) {
|
||||
Object.keys(this.events).forEach((name) => Event.unobserve(name, obj));
|
||||
},
|
||||
|
||||
notify(name, ...args) {
|
||||
if (!this.events[name]) return;
|
||||
this.events[name].forEach(function (x) {
|
||||
x[1].call(x[0], ...args);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
global.mixin("scripts/spline");
|
||||
global.mixin("scripts/components");
|
||||
global.mixin("scripts/actor");
|
||||
global.mixin("scripts/entity");
|
||||
|
||||
function world_start() {
|
||||
globalThis.world = Object.create(entity);
|
||||
world.transform = os.make_transform();
|
||||
world.objects = {};
|
||||
world.toString = function () {
|
||||
return "world";
|
||||
};
|
||||
world.ur = "world";
|
||||
world.kill = function () {
|
||||
this.clear();
|
||||
};
|
||||
world.phys = 2;
|
||||
world.zoom = 1;
|
||||
world._ed = { selectable: false };
|
||||
world.ur = {};
|
||||
world.ur.fresh = {};
|
||||
game.cam = world;
|
||||
}
|
||||
|
||||
global.mixin("scripts/physics");
|
||||
global.mixin("scripts/widget");
|
||||
global.mixin("scripts/mum");
|
||||
|
||||
window.title = `Prosperon v${prosperon.version}`;
|
||||
window.size = [500, 500];
|
||||
Object.assign(globalThis, use("scripts/prosperon.js"));
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
globalThis.entityreport = {};
|
||||
|
||||
var timer_update = function(dt)
|
||||
{
|
||||
this.fn();
|
||||
}
|
||||
|
||||
function obj_unique_name(name, obj) {
|
||||
name = name.replaceAll('.', '_');
|
||||
if (!(name in obj)) return name;
|
||||
|
@ -24,6 +29,7 @@ function unique_name(list, name = "new_object") {
|
|||
};
|
||||
|
||||
var entity = {
|
||||
drawlayer: -1,
|
||||
get_comp_by_name(name) {
|
||||
var comps = [];
|
||||
for (var c of Object.values(this.components))
|
||||
|
@ -37,7 +43,6 @@ var entity = {
|
|||
this.body = os.make_body(this.transform);
|
||||
},
|
||||
|
||||
|
||||
path_from(o) {
|
||||
var p = this.toString();
|
||||
var c = this.master;
|
||||
|
@ -61,14 +66,14 @@ var entity = {
|
|||
},
|
||||
|
||||
sync() {
|
||||
this.components.forEach(function(x) { x.sync?.(); });
|
||||
this.objects.forEach(function(x) { x.sync(); });
|
||||
for (var c of Object.values(this.components)) c.sync?.();
|
||||
for (var o of Object.values(this.objects)) o.sync();
|
||||
},
|
||||
|
||||
delay(fn, seconds) {
|
||||
var timers = this.timers;
|
||||
var stop = function() {
|
||||
timers.remove(stop);
|
||||
delete timers[guid];
|
||||
execute = undefined;
|
||||
stop = undefined;
|
||||
rm?.();
|
||||
|
@ -86,12 +91,15 @@ var entity = {
|
|||
stop.pct = function() { return 1 - (stop.remain/stop.seconds); };
|
||||
|
||||
function update(dt) {
|
||||
profile.frame("timer");
|
||||
stop.remain -= dt;
|
||||
if (stop.remain <= 0) execute();
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
var rm = Register.update.register(update);
|
||||
timers.push(stop);
|
||||
var guid = prosperon.guid();
|
||||
timers[guid] = (stop);
|
||||
return stop;
|
||||
},
|
||||
|
||||
|
@ -138,7 +146,7 @@ var entity = {
|
|||
},
|
||||
|
||||
spawn(text, config, callback) {
|
||||
var st = profile.now();
|
||||
|
||||
var ent = Object.create(entity);
|
||||
ent.transform = os.make_transform();
|
||||
|
||||
|
@ -146,11 +154,11 @@ var entity = {
|
|||
|
||||
ent.components = {};
|
||||
ent.objects = {};
|
||||
ent.timers = [];
|
||||
ent.timers = {};
|
||||
|
||||
if (!text)
|
||||
ent.ur = emptyur;
|
||||
else if (typeof text === 'object' && text) {// assume it's an ur
|
||||
else if (text instanceof Object) {// assume it's an ur
|
||||
ent.ur = text;
|
||||
text = ent.ur.text;
|
||||
config = [ent.ur.data, config].filter(x => x).flat();
|
||||
|
@ -164,19 +172,20 @@ var entity = {
|
|||
if (typeof text === 'string')
|
||||
use(text, ent);
|
||||
else if (Array.isArray(text))
|
||||
text.forEach(path => use(path,ent));
|
||||
|
||||
for (var path of text) use(path,ent);
|
||||
profile.cache("ENTITY TIME", ent.ur.name);
|
||||
var st = profile.now();
|
||||
if (typeof config === 'string')
|
||||
Object.merge(ent, json.decode(Resources.replstrs(config)));
|
||||
else if (Array.isArray(config))
|
||||
config.forEach(function(path) {
|
||||
for (var path of config) {
|
||||
if (typeof path === 'string') {
|
||||
console.info(`ingesting ${path} ...`);
|
||||
Object.merge(ent, json.decode(Resources.replstrs(path)));
|
||||
}
|
||||
else if (typeof path === 'object')
|
||||
else if (path instanceof Object)
|
||||
Object.merge(ent,path);
|
||||
});
|
||||
};
|
||||
|
||||
ent.reparent(this);
|
||||
|
||||
|
@ -191,9 +200,9 @@ var entity = {
|
|||
|
||||
check_registers(ent);
|
||||
|
||||
if (typeof ent.load === 'function') ent.load();
|
||||
if (ent.load instanceof Function) ent.load();
|
||||
if (sim.playing())
|
||||
if (typeof ent.start === 'function') ent.start();
|
||||
if (ent.start instanceof Function) ent.start();
|
||||
|
||||
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master');
|
||||
|
||||
|
@ -230,13 +239,13 @@ var entity = {
|
|||
for (var i in ent.objects)
|
||||
ent.ur.fresh.objects[i] = ent.objects[i].instance_obj();
|
||||
|
||||
profile.addreport(entityreport, ent.ur.name, st);
|
||||
profile.endcache();
|
||||
|
||||
return ent;
|
||||
},
|
||||
|
||||
disable() { this.components.forEach(function(x) { x.disable(); }); },
|
||||
enable() { this.components.forEach(function(x) { x.enable(); }); },
|
||||
disable() { for (var x of this.components) x.disable(); },
|
||||
enable() { for (var x of this.components) x.enable(); },
|
||||
|
||||
this2screen(pos) { return game.camera.world2view(this.this2world(pos)); },
|
||||
screen2this(pos) { return this.world2this(game.camera.view2world(pos)); },
|
||||
|
@ -280,7 +289,7 @@ var entity = {
|
|||
|
||||
var bb = boxes.shift();
|
||||
|
||||
boxes.forEach(function(x) { bb = bbox.expand(bb, x); });
|
||||
for (var x of boxes) bb = bbox.expand(bb, x);
|
||||
|
||||
bb = bbox.move(bb, this.pos);
|
||||
|
||||
|
@ -338,8 +347,8 @@ dup(diff) {
|
|||
this.__kill = true;
|
||||
console.spam(`Killing entity of type ${this.ur}`);
|
||||
|
||||
this.timers.forEach(t => t());
|
||||
this.timers = [];
|
||||
this.timers.forEach(x => x());
|
||||
delete this.timers;
|
||||
Event.rm_obj(this);
|
||||
input.do_uncontrol(this);
|
||||
|
||||
|
@ -354,20 +363,19 @@ dup(diff) {
|
|||
this.components[key].enabled = false;
|
||||
delete this.components[key];
|
||||
}
|
||||
|
||||
delete this.components;
|
||||
|
||||
this.clear();
|
||||
if (typeof this.stop === 'function') this.stop();
|
||||
if (this.stop instanceof Function) this.stop();
|
||||
|
||||
game.tag_clear_guid(this.guid);
|
||||
|
||||
for (var i in this) {
|
||||
if (typeof this[i] === 'object') delete this[i];
|
||||
if (typeof this[i] === 'function') delete this[i];
|
||||
if (this[i] instanceof Object || this[i] instanceof Function) delete this[i];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
make_objs(objs) {
|
||||
for (var prop in objs) {
|
||||
say(`spawning ${json.encode(objs[prop])}`);
|
||||
|
@ -482,17 +490,17 @@ var gameobject = {
|
|||
var newpos = relative.this2world(x);
|
||||
var move = newpos.sub(this.pos);
|
||||
this.rpos = newpos;
|
||||
this.objects.forEach(x => x.move(move));
|
||||
for (var o of this.objects) o.move(move);
|
||||
},
|
||||
|
||||
set_angle(x, relative = world) {
|
||||
var newangle = relative.angle + x;
|
||||
var diff = newangle - this.angle;
|
||||
this.rangle = newangle;
|
||||
this.objects.forEach(obj => {
|
||||
for (var obj of this.objects) {
|
||||
obj.rotate(diff);
|
||||
obj.set_pos(Vector.rotate(obj.get_pos(obj.master), diff), obj.master);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
set_scale(x, relative = world) {
|
||||
|
@ -500,10 +508,10 @@ var gameobject = {
|
|||
var newscale = relative.scale.map((s,i) => x[i]*s);
|
||||
var pct = this.scale.map((s,i) => newscale[i]/s);
|
||||
this.rscale = newscale;
|
||||
this.objects.forEach(obj => {
|
||||
for (var obj of this.objects) {
|
||||
obj.grow(pct);
|
||||
obj.set_pos(obj.get_pos(obj.master).map((x,i) => x*pct[i]), obj.master);
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
get_pos(relative = world) {
|
||||
|
@ -650,17 +658,17 @@ function apply_ur(u, ent) {
|
|||
if (typeof text === 'string')
|
||||
use(text, ent);
|
||||
else if (Array.isArray(text))
|
||||
text.forEach(path => use(path,ent));
|
||||
for (var path of text) use(path,ent);
|
||||
|
||||
if (typeof data === 'string')
|
||||
Object.merge(ent, json.decode(Resources.replstrs(data)));
|
||||
else if (Array.isArray(data)) {
|
||||
data.forEach(function(path) {
|
||||
for (var path of data) {
|
||||
if (typeof path === 'string')
|
||||
Object.merge(ent, json.decode(Resources.replstrs(data)));
|
||||
else if (typeof path === 'object')
|
||||
else if (path instanceof Object)
|
||||
Object.merge(ent,path);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -677,7 +685,10 @@ var getur = function(text, data)
|
|||
name: "empty"
|
||||
};
|
||||
}
|
||||
var urstr = text + "+" + data;
|
||||
var urstr = text;
|
||||
if (data)
|
||||
urstr += "+" + data;
|
||||
|
||||
if (!ur[urstr]) {
|
||||
ur[urstr] = {
|
||||
name: urstr,
|
||||
|
@ -726,16 +737,6 @@ game.loadurs = function() {
|
|||
newur.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
for (var file of io.glob("**.json").filter(f => !ur[f.name()])) {
|
||||
if (file[0] === '.' || file[0] === '_') continue;
|
||||
var newur = ur_from_file(file);
|
||||
if (!newur) continue;
|
||||
Object.assign(newur, {
|
||||
data: file
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
game.ur = {};
|
||||
|
|
|
@ -190,18 +190,28 @@ mum.image = function(path, data = {})
|
|||
if (typeof path === 'string')
|
||||
tex = game.texture(path);
|
||||
|
||||
data.width ??= tex.width;
|
||||
data.height ??= tex.height;
|
||||
if (!data.height)
|
||||
if (data.width)
|
||||
data.height = tex.height * (data.width/tex.width);
|
||||
else
|
||||
data.height = tex.height;
|
||||
|
||||
var aa = [0,0].sub(data.anchor);
|
||||
if (!data.width)
|
||||
if (data.height)
|
||||
data.width = tex.width * (data.height/tex.height);
|
||||
else
|
||||
data.height = tex.height;
|
||||
|
||||
if (!data.width) data.width = tex.width;
|
||||
if (!data.height) data.height = tex.height;
|
||||
|
||||
var aa = [0,1].sub(data.anchor);
|
||||
data.drawpos = data.drawpos.add(aa.scale([data.width,data.height]));
|
||||
|
||||
if (data.slice)
|
||||
render.slice9(tex, data.drawpos, data.slice, [data.width,data.height]);
|
||||
else {
|
||||
cursor.y -= tex.height*data.scale;
|
||||
data.bb = render.image(tex, data.drawpos, [data.scale*tex.width, data.scale*tex.height]);
|
||||
}
|
||||
else
|
||||
data.bb = render.image(tex, data.drawpos, [data.width, data.height]);
|
||||
|
||||
end(data);
|
||||
}
|
||||
|
@ -262,3 +272,41 @@ mum.ex_hud = function()
|
|||
mum.label("TOP RIGHT", {pos:game.size, anchor:[1,1]});
|
||||
mum.label("BOTTOM RIGHT", {pos:[game.size.x, 0], anchor:[1,0]});
|
||||
}
|
||||
|
||||
mum.drawinput = undefined;
|
||||
var ptext = "";
|
||||
var panpan = {
|
||||
draw() {
|
||||
mum.rectangle({pos:[0,0], anchor:[0,0], height:20, width: window.size.x, padding:[10,16], color:Color.black});
|
||||
mum.label("input level: ");
|
||||
mum.label(ptext, {offset:[50,0], color:Color.red});
|
||||
},
|
||||
inputs: {
|
||||
block: true,
|
||||
char(c) {
|
||||
ptext += c
|
||||
},
|
||||
enter() {
|
||||
delete mum.drawinput;
|
||||
player[0].uncontrol(panpan);
|
||||
},
|
||||
escape() {
|
||||
delete mum.drawinput;
|
||||
player[0].uncontrol(panpan);
|
||||
},
|
||||
backspace() {
|
||||
ptext = ptext.slice(0,ptext.length-1);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
mum.textinput = function (fn, str = "") {
|
||||
mum.drawinput = panpan.draw;
|
||||
ptext = str;
|
||||
player[0].control(panpan);
|
||||
panpan.inputs.enter = function() {
|
||||
fn(ptext);
|
||||
delete mum.drawinput;
|
||||
player[0].uncontrol(panpan);
|
||||
}
|
||||
}
|
||||
|
|
116
scripts/particle.js
Normal file
116
scripts/particle.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
var emitter = {};
|
||||
emitter.particles = {};
|
||||
emitter.life = 10;
|
||||
emitter.scale = 1;
|
||||
emitter.grow_for = 0;
|
||||
emitter.spawn_timer = 0;
|
||||
emitter.pps = 0;
|
||||
emitter.color = Color.white;
|
||||
|
||||
emitter.draw = function()
|
||||
{
|
||||
var amt = Object.values(this.particles).length;
|
||||
if (amt === 0) return;
|
||||
render.use_shader(this.shader);
|
||||
render.use_mat(this);
|
||||
render.make_particle_ssbo(Object.values(this.particles), this.ssbo);
|
||||
render.draw(this.shape, this.ssbo, amt);
|
||||
}
|
||||
|
||||
var std_spawn = function(par)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
var std_step = function(p)
|
||||
{
|
||||
if (p.time < this.grow_for) {
|
||||
var s = Math.lerp(0, this.scale, p.time/this.grow_for);
|
||||
p.transform.scale = [s,s,s];
|
||||
}
|
||||
else if (p.time > (p.life - this.shrink_for)) {
|
||||
var s = Math.lerp(0,this.scale,(p.life-p.time)/this.shrink_for);
|
||||
p.transform.scale=[s,s,s];
|
||||
} else
|
||||
p.transform.scale = [this.scale,this.scale,this.scale];
|
||||
}
|
||||
|
||||
var std_die = function(par)
|
||||
{
|
||||
}
|
||||
|
||||
emitter.spawn_hook = std_spawn;
|
||||
emitter.step_hook = std_step;
|
||||
emitter.die_hook = std_die;
|
||||
|
||||
emitter.spawn = function(t)
|
||||
{
|
||||
t ??= this.transform;
|
||||
|
||||
var par = this.dead.shift();
|
||||
if (par) {
|
||||
par.body.pos = t.pos;
|
||||
par.transform.scale = [this.scale,this.scale,this.scale];
|
||||
this.particles[par.id] = par;
|
||||
par.time = 0;
|
||||
this.spawn_hook(par);
|
||||
return;
|
||||
}
|
||||
|
||||
par = {
|
||||
transform: os.make_transform(),
|
||||
life: this.life,
|
||||
time: 0,
|
||||
color: this.color
|
||||
};
|
||||
|
||||
par.body = os.make_body(par.transform);
|
||||
|
||||
par.body.pos = t.pos;
|
||||
par.transform.scale = [this.scale,this.scale,this.scale];
|
||||
par.id = prosperon.guid();
|
||||
this.particles[par.id] = par;
|
||||
|
||||
this.spawn_hook(par);
|
||||
}
|
||||
|
||||
emitter.step = function(dt)
|
||||
{
|
||||
// update spawning particles
|
||||
if (this.on && this.pps > 0) {
|
||||
this.spawn_timer += dt;
|
||||
var pp = 1/this.pps;
|
||||
while (this.spawn_timer > pp) {
|
||||
this.spawn_timer -= pp;
|
||||
this.spawn();
|
||||
}
|
||||
}
|
||||
|
||||
// update all particles
|
||||
for (var p of Object.values(this.particles)) {
|
||||
p.time += dt;
|
||||
this.step_hook?.(p);
|
||||
|
||||
if (p.time >= p.life) {
|
||||
this.die_hook(p);
|
||||
this.dead.push(this.particles[p.id]);
|
||||
delete this.particles[p.id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitter.burst = function(count, t) {
|
||||
for (var i = 0; i < count; i++) this.spawn(t);
|
||||
}
|
||||
|
||||
var make_emitter = function()
|
||||
{
|
||||
var e = Object.create(emitter);
|
||||
e.ssbo = render.make_textssbo();
|
||||
e.shape = shape.centered_quad;
|
||||
e.shader = "shaders/baseparticle.cg";
|
||||
e.dead = [];
|
||||
return e;
|
||||
}
|
||||
|
||||
return {make_emitter};
|
279
scripts/profile.js
Normal file
279
scripts/profile.js
Normal file
|
@ -0,0 +1,279 @@
|
|||
var t_units = ["ns", "us", "ms", "s", "ks", "Ms"];
|
||||
|
||||
function calc_cpu(fn, times, diff=0)
|
||||
{
|
||||
var series = [];
|
||||
|
||||
for (var i = 0; i < times; i++) {
|
||||
var st = profile.now();
|
||||
fn(i);
|
||||
series.push(profile.now()-st-diff);
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
function empty_fn() {}
|
||||
|
||||
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);
|
||||
|
||||
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.secs = function(t) { return t/1000000000; }
|
||||
|
||||
var callgraph = {};
|
||||
var st = profile.now();
|
||||
|
||||
function add_callgraph(fn, line, time) {
|
||||
var cc = callgraph[line];
|
||||
if (!cc) {
|
||||
var cc = {};
|
||||
callgraph[line] = cc;
|
||||
cc.time = 0;
|
||||
cc.hits = 0;
|
||||
cc.fn = fn;
|
||||
cc.line = line;
|
||||
}
|
||||
cc.time += time;
|
||||
cc.hits++;
|
||||
}
|
||||
|
||||
var hittar = 500;
|
||||
var hitpct = 0.2;
|
||||
var start_gather = profile.now();
|
||||
|
||||
var gathering_cpu = false;
|
||||
|
||||
profile.start_cpu_gather = function()
|
||||
{
|
||||
if (gathering_cpu) return;
|
||||
gathering_cpu = true;
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
profile.cpu_frame = function()
|
||||
{
|
||||
if (gathering_cpu) return;
|
||||
|
||||
profile.gather(Math.random_range(300,600), function() {
|
||||
console.stack(2);
|
||||
profile.gather_stop();
|
||||
});
|
||||
}
|
||||
|
||||
var filecache = {};
|
||||
function get_line(file, line) {
|
||||
var text = filecache[file];
|
||||
if (!text) {
|
||||
var f = io.slurp(file);
|
||||
if (!f) {
|
||||
filecache[file] = "undefined";
|
||||
return filecache[file];
|
||||
}
|
||||
filecache[file] = io.slurp(file).split('\n');
|
||||
text = filecache[file];
|
||||
}
|
||||
|
||||
if (typeof text === 'string') return text;
|
||||
text = text[Number(line)-1];
|
||||
if (!text) return "NULL";
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
profile.stop_cpu_instr = function()
|
||||
{
|
||||
if (!gathering_cpu) return;
|
||||
|
||||
say("===CPU INSTRUMENTATION===\n");
|
||||
var gather_time = profile.now()-start_gather;
|
||||
var e = Object.values(callgraph);
|
||||
e = e.sort((a,b) => {
|
||||
if (a.time > b.time) return -1;
|
||||
return 1;
|
||||
});
|
||||
|
||||
e.forEach(x => {
|
||||
var ffs = x.line.split(':');
|
||||
var time = profile.best_t(x.time);
|
||||
var pct = x.time/gather_time*100;
|
||||
say(`${x.line}::${x.fn}:: ${time} (${pct.toPrecision(3)}%) (${x.hits} hits) --> ${get_line(ffs[0], ffs[1])}`);
|
||||
});
|
||||
}
|
||||
|
||||
profile.best_t = function (t) {
|
||||
var qq = 0;
|
||||
|
||||
while (t > 1000 && qq < t_units.length-1) {
|
||||
t /= 1000;
|
||||
qq++;
|
||||
}
|
||||
|
||||
return `${t.toPrecision(4)} ${t_units[qq]}`;
|
||||
};
|
||||
|
||||
profile.report = function (start, msg = "[undefined report]") { console.info(`${msg} in ${profile.best_t(profile.now() - start)}`); };
|
||||
|
||||
var frame_avg = false;
|
||||
|
||||
profile.start_frame_avg = function()
|
||||
{
|
||||
if (frame_avg) return;
|
||||
say("===STARTING FRAME AVERAGE MEASUREMENTS===");
|
||||
profile_frames = {};
|
||||
profile_frame_ts = [];
|
||||
profile_cframe = profile_frames;
|
||||
pframe = 0;
|
||||
frame_avg = true;
|
||||
}
|
||||
|
||||
profile.stop_frame_avg = function()
|
||||
{
|
||||
if (!frame_avg) return;
|
||||
|
||||
frame_avg = false;
|
||||
profile.print_frame_avg();
|
||||
}
|
||||
|
||||
profile.toggle_frame_avg = function()
|
||||
{
|
||||
if (frame_avg) profile.stop_frame_avg();
|
||||
else profile.start_frame_avg();
|
||||
}
|
||||
|
||||
var profile_frames = {};
|
||||
var profile_frame_ts = [];
|
||||
var profile_cframe = profile_frames;
|
||||
var pframe = 0;
|
||||
|
||||
profile.frame = function profile_frame(title)
|
||||
{
|
||||
if (!frame_avg) return;
|
||||
|
||||
profile_frame_ts.push(profile_cframe);
|
||||
profile_cframe[title] ??= {};
|
||||
profile_cframe = profile_cframe[title];
|
||||
profile_cframe._times ??= [];
|
||||
profile_cframe._times[pframe] ??= 0;
|
||||
profile_cframe._times[pframe] = profile.now() - profile_cframe._times[pframe];
|
||||
}
|
||||
|
||||
profile.endframe = function profile_endframe()
|
||||
{
|
||||
if (!frame_avg) return;
|
||||
|
||||
if (profile_cframe === profile_frames) return;
|
||||
profile_cframe._times[pframe] = profile.now() - profile_cframe._times[pframe];
|
||||
profile_cframe = profile_frame_ts.pop();
|
||||
if (profile_cframe === profile_frames) pframe++;
|
||||
}
|
||||
|
||||
var print_frame = function(frame, indent, title)
|
||||
{
|
||||
say(indent + `${title} ::::: ${profile.best_t(Math.mean(frame._times))} ± ${profile.best_t(Math.ci(frame._times))} (${frame._times.length} hits)`);
|
||||
|
||||
for (var i in frame) {
|
||||
if (i === '_times') continue;
|
||||
print_frame(frame[i], indent + " ", i);
|
||||
}
|
||||
}
|
||||
|
||||
profile.print_frame_avg = function()
|
||||
{
|
||||
say("===FRAME AVERAGES===\n");
|
||||
|
||||
var indent = "";
|
||||
for (var i in profile_frames)
|
||||
print_frame(profile_frames[i], "", 'frame');
|
||||
|
||||
say("\n");
|
||||
}
|
||||
|
||||
var report_cache = {};
|
||||
|
||||
var cachest = 0;
|
||||
var cachegroup;
|
||||
var cachetitle;
|
||||
profile.cache = function profile_cache(group, title)
|
||||
{
|
||||
cachest = profile.now();
|
||||
cachegroup = group;
|
||||
cachetitle = title;
|
||||
}
|
||||
|
||||
profile.endcache = function profile_endcache(tag = "")
|
||||
{
|
||||
addreport(cachegroup, cachetitle + tag, cachest);
|
||||
}
|
||||
|
||||
profile.print_cache_report = function()
|
||||
{
|
||||
var str = "===START CACHE REPORTS===\n";
|
||||
for (var i in report_cache)
|
||||
str += printreport(report_cache[i], i) + "\n";
|
||||
|
||||
say(str);
|
||||
}
|
||||
|
||||
function addreport(group, line, start) {
|
||||
if (typeof group !== 'string') group = 'UNGROUPED';
|
||||
report_cache[group] ??= {};
|
||||
var cache = report_cache[group];
|
||||
cache[line] ??= [];
|
||||
var t = profile.now();
|
||||
cache[line].push(t - start);
|
||||
return t;
|
||||
};
|
||||
|
||||
function printreport(cache, name) {
|
||||
var report = `==${name}==` + "\n";
|
||||
|
||||
var reports = [];
|
||||
for (var i in cache) {
|
||||
var time = cache[i].reduce((a,b)=>a+b);
|
||||
reports.push({
|
||||
time:time,
|
||||
name:i,
|
||||
hits:cache[i].length,
|
||||
avg:time/cache[i].length
|
||||
});
|
||||
}
|
||||
reports = reports.sort((a,b) => {
|
||||
if (a.avg<b.avg) return 1;
|
||||
return -1;
|
||||
});
|
||||
|
||||
for (var rep of reports)
|
||||
report += `${rep.name} ${profile.best_t(rep.avg)} (${rep.hits} hits) (total ${profile.best_t(rep.time)})\n`;
|
||||
|
||||
return report;
|
||||
};
|
396
scripts/prosperon.js
Normal file
396
scripts/prosperon.js
Normal file
|
@ -0,0 +1,396 @@
|
|||
globalThis.gamestate = {};
|
||||
|
||||
global.check_registers = function (obj) {
|
||||
for (var reg in Register.registries) {
|
||||
if (typeof obj[reg] === 'function') {
|
||||
var fn = obj[reg].bind(obj);
|
||||
var name = obj.ur ? obj.ur.name : obj.toString();
|
||||
obj.timers.push(Register.registries[reg].register(fn, name));
|
||||
}
|
||||
}
|
||||
|
||||
for (var k in obj) {
|
||||
if (!k.startsWith("on_")) continue;
|
||||
var signal = k.fromfirst("on_");
|
||||
Event.observe(signal, obj, obj[k]);
|
||||
}
|
||||
};
|
||||
|
||||
global.obscure("global");
|
||||
global.mixin("scripts/render");
|
||||
global.mixin("scripts/debug");
|
||||
|
||||
var frame_t = profile.secs(profile.now());
|
||||
|
||||
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;
|
||||
|
||||
var gggstart = game.engine_start;
|
||||
game.engine_start = function (s) {
|
||||
game.startengine = 1;
|
||||
gggstart(
|
||||
function () {
|
||||
global.mixin("scripts/sound.js");
|
||||
world_start();
|
||||
window.set_icon(os.make_texture("icons/moon.gif"));
|
||||
Object.readonly(window.__proto__, "vsync");
|
||||
Object.readonly(window.__proto__, "enable_dragndrop");
|
||||
Object.readonly(window.__proto__, "enable_clipboard");
|
||||
Object.readonly(window.__proto__, "high_dpi");
|
||||
Object.readonly(window.__proto__, "sample_count");
|
||||
s();
|
||||
|
||||
shape.quad = {
|
||||
pos: os.make_buffer([0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0], 0),
|
||||
verts: 4,
|
||||
uv: os.make_buffer([0, 1, 1, 1, 0, 0, 1, 0], 2),
|
||||
index: os.make_buffer([0, 1, 2, 2, 1, 3], 1),
|
||||
count: 6,
|
||||
};
|
||||
|
||||
shape.triangle = {
|
||||
pos: os.make_buffer([0, 0, 0, 0.5, 1, 0, 1, 0, 0], 0),
|
||||
uv: os.make_buffer([0, 0, 0.5, 1, 1, 0], 2),
|
||||
verts: 3,
|
||||
count: 3,
|
||||
index: os.make_buffer([0, 2, 1], 1),
|
||||
};
|
||||
|
||||
shape.centered_quad = {
|
||||
pos: os.make_buffer([-0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5], 0),
|
||||
verts: 4,
|
||||
uv: os.make_buffer([0,1,1,1,0,0,1,0],2),
|
||||
index: os.make_buffer([0,1,2,2,1,3],1),
|
||||
count: 6
|
||||
};
|
||||
|
||||
render.init();
|
||||
|
||||
prosperon.camera = prosperon.make_camera();
|
||||
var camera = prosperon.camera;
|
||||
camera.transform.pos = [0,0,-100];
|
||||
camera.mode = "keep";
|
||||
camera.break = "fit";
|
||||
camera.size = game.size;
|
||||
gamestate.camera = camera;
|
||||
|
||||
prosperon.hudcam = prosperon.make_camera();
|
||||
var hudcam = prosperon.hudcam;
|
||||
hudcam.near = 0;
|
||||
hudcam.size = camera.size;
|
||||
hudcam.mode = "keep";
|
||||
hudcam.break = "fit";
|
||||
|
||||
prosperon.appcam = prosperon.make_camera();
|
||||
var appcam = prosperon.appcam;
|
||||
appcam.near = 0;
|
||||
appcam.size = window.size;
|
||||
appcam.transform.pos = [window.size.x,window.size.y,-100];
|
||||
prosperon.screencolor = render.screencolor();
|
||||
},
|
||||
prosperon.process,
|
||||
window.size.x,
|
||||
window.size.y,
|
||||
);
|
||||
};
|
||||
|
||||
game.startengine = 0;
|
||||
var frames = [];
|
||||
|
||||
prosperon.release_mode = function()
|
||||
{
|
||||
prosperon.debug = false;
|
||||
mum.debug = false;
|
||||
debug.kill();
|
||||
}
|
||||
prosperon.debug = true;
|
||||
|
||||
globalThis.fps = function () {
|
||||
return 0;
|
||||
// var sum = 0;
|
||||
// for (var i = 0; i < frames.length; i++) sum += frames[i];
|
||||
// return frames.length / sum;
|
||||
};
|
||||
|
||||
game.timescale = 1;
|
||||
|
||||
var eachobj = function (obj, fn) {
|
||||
var val = fn(obj);
|
||||
if (val) return val;
|
||||
for (var o in obj.objects) {
|
||||
if (obj.objects[o] === obj)
|
||||
console.error(`Object ${obj.toString()} is referenced by itself.`);
|
||||
val = eachobj(obj.objects[o], fn);
|
||||
if (val) return val;
|
||||
}
|
||||
};
|
||||
|
||||
game.all_objects = function (fn, startobj = world) {
|
||||
return eachobj(startobj, fn);
|
||||
};
|
||||
game.find_object = function (fn, startobj = world) {};
|
||||
|
||||
game.tags = {};
|
||||
game.tag_add = function (tag, obj) {
|
||||
game.tags[tag] ??= {};
|
||||
game.tags[tag][obj.guid] = obj;
|
||||
};
|
||||
|
||||
game.tag_rm = function (tag, obj) {
|
||||
delete game.tags[tag][obj.guid];
|
||||
};
|
||||
|
||||
game.tag_clear_guid = function (guid) {
|
||||
for (var tag in game.tags) delete game.tags[tag][guid];
|
||||
};
|
||||
|
||||
game.objects_with_tag = function (tag) {
|
||||
if (!game.tags[tag]) return [];
|
||||
return Object.values(game.tags[tag]);
|
||||
};
|
||||
|
||||
game.doc = {};
|
||||
game.doc.object = "Returns the entity belonging to a given id.";
|
||||
game.doc.pause = "Pause game simulation.";
|
||||
game.doc.play = "Resume or start game simulation.";
|
||||
game.doc.camera = "Current camera.";
|
||||
|
||||
game.texture = function (path, force = false) {
|
||||
if (force && game.texture.cache[path]) return game.texture.cache[path];
|
||||
|
||||
if (!io.exists(path)) {
|
||||
console.warn(`Missing texture: ${path}`);
|
||||
game.texture.cache[path] = game.texture("icons/no_tex.gif");
|
||||
} else game.texture.cache[path] ??= os.make_texture(path);
|
||||
|
||||
return game.texture.cache[path];
|
||||
};
|
||||
game.texture.cache = {};
|
||||
|
||||
prosperon.semver = {};
|
||||
prosperon.semver.valid = function (v, range) {
|
||||
v = v.split(".");
|
||||
range = range.split(".");
|
||||
if (v.length !== 3) return undefined;
|
||||
if (range.length !== 3) return undefined;
|
||||
|
||||
if (range[0][0] === "^") {
|
||||
range[0] = range[0].slice(1);
|
||||
if (parseInt(v[0]) >= parseInt(range[0])) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (range[0] === "~") {
|
||||
range[0] = range[0].slice(1);
|
||||
for (var i = 0; i < 2; i++)
|
||||
if (parseInt(v[i]) < parseInt(range[i])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return prosperon.semver.cmp(v.join("."), range.join(".")) === 0;
|
||||
};
|
||||
|
||||
prosperon.semver.cmp = function (v1, v2) {
|
||||
var ver1 = v1.split(".");
|
||||
var ver2 = v2.split(".");
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var n1 = parseInt(ver1[i]);
|
||||
var n2 = parseInt(ver2[i]);
|
||||
if (n1 > n2) return 1;
|
||||
else if (n1 < n2) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
prosperon.semver.doc =
|
||||
"Functions for semantic versioning numbers. Semantic versioning is given as a triple digit number, as MAJOR.MINOR.PATCH.";
|
||||
prosperon.semver.cmp.doc =
|
||||
"Compare two semantic version numbers, given like X.X.X.";
|
||||
prosperon.semver.valid.doc = `Test if semantic version v is valid, given a range.
|
||||
Range is given by a semantic versioning number, prefixed with nothing, a ~, or a ^.
|
||||
~ means that MAJOR and MINOR must match exactly, but any PATCH greater or equal is valid.
|
||||
^ means that MAJOR must match exactly, but any MINOR and PATCH greater or equal is valid.`;
|
||||
|
||||
prosperon.iconified = function (icon) {};
|
||||
prosperon.focus = function (focus) {};
|
||||
prosperon.resize = function (dimensions) {
|
||||
window.size.x = dimensions.x;
|
||||
window.size.y = dimensions.y;
|
||||
};
|
||||
prosperon.suspended = function (sus) {};
|
||||
prosperon.mouseenter = function () {};
|
||||
prosperon.mouseleave = function () {};
|
||||
prosperon.touchpress = function (touches) {};
|
||||
prosperon.touchrelease = function (touches) {};
|
||||
prosperon.touchmove = function (touches) {};
|
||||
prosperon.clipboardpaste = function (str) {};
|
||||
prosperon.quit = function () {
|
||||
profile.print_cache_report();
|
||||
profile.stop_frame_avg()
|
||||
profile.stop_cpu_instr();
|
||||
};
|
||||
|
||||
window.size = [640, 480];
|
||||
window.mode = "keep";
|
||||
window.toggle_fullscreen = function() { window.fullscreen = !window.fullscreen; }
|
||||
|
||||
window.set_icon.doc = "Set the icon of the window using the PNG image at path.";
|
||||
|
||||
window.doc = {};
|
||||
window.doc.dimensions = "Window width and height packaged in an array [width,height]";
|
||||
window.doc.title = "Name in the title bar of the window.";
|
||||
window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width.";
|
||||
|
||||
global.mixin("scripts/input");
|
||||
global.mixin("scripts/std");
|
||||
global.mixin("scripts/diff");
|
||||
global.mixin("scripts/color");
|
||||
global.mixin("scripts/gui");
|
||||
global.mixin("scripts/tween");
|
||||
global.mixin("scripts/ai");
|
||||
global.mixin("scripts/particle");
|
||||
global.mixin("scripts/physics");
|
||||
global.mixin("scripts/geometry");
|
||||
|
||||
/*
|
||||
Factory for creating registries. Register one with 'X.register',
|
||||
which returns a function that, when invoked, cancels the registry.
|
||||
*/
|
||||
var Register = {
|
||||
registries: [],
|
||||
|
||||
add_cb(name, e_event = false) {
|
||||
var n = {};
|
||||
var fns = {};
|
||||
|
||||
n.register = function (fn, oname) {
|
||||
if (!(fn instanceof Function)) return;
|
||||
|
||||
var guid = prosperon.guid();
|
||||
|
||||
var dofn = function(...args) {
|
||||
profile.cache(name,oname);
|
||||
var st = profile.now();
|
||||
fn(...args);
|
||||
profile.endcache();
|
||||
}
|
||||
|
||||
fns[guid] = dofn;
|
||||
return function () {
|
||||
delete fns[guid];
|
||||
};
|
||||
};
|
||||
|
||||
prosperon[name] = function (...args) {
|
||||
fns.forEach(x => x(...args));
|
||||
};
|
||||
|
||||
prosperon[name].fns = fns;
|
||||
n.clear = function () {
|
||||
fns = [];
|
||||
};
|
||||
|
||||
Register[name] = n;
|
||||
Register.registries[name] = n;
|
||||
|
||||
return n;
|
||||
},
|
||||
};
|
||||
|
||||
Register.add_cb("appupdate", true);
|
||||
Register.add_cb("update", true).doc = "Called once per frame.";
|
||||
Register.add_cb("physupdate", true);
|
||||
Register.add_cb("gui", true);
|
||||
Register.add_cb("hud", true);
|
||||
Register.add_cb("draw_dbg", true);
|
||||
Register.add_cb("gui_dbg", true);
|
||||
Register.add_cb("hud_dbg", true);
|
||||
Register.add_cb("draw", true);
|
||||
Register.add_cb("imgui", true);
|
||||
|
||||
var Event = {
|
||||
events: {},
|
||||
|
||||
observe(name, obj, fn) {
|
||||
this.events[name] ??= [];
|
||||
this.events[name].push([obj, fn]);
|
||||
},
|
||||
|
||||
unobserve(name, obj) {
|
||||
this.events[name] = this.events[name].filter((x) => x[0] !== obj);
|
||||
},
|
||||
|
||||
rm_obj(obj) {
|
||||
Object.keys(this.events).forEach((name) => Event.unobserve(name, obj));
|
||||
},
|
||||
|
||||
notify(name, ...args) {
|
||||
if (!this.events[name]) return;
|
||||
this.events[name].forEach(function (x) {
|
||||
x[1].call(x[0], ...args);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
global.mixin("scripts/spline");
|
||||
global.mixin("scripts/components");
|
||||
global.mixin("scripts/actor");
|
||||
global.mixin("scripts/entity");
|
||||
|
||||
function world_start() {
|
||||
globalThis.world = Object.create(entity);
|
||||
world.transform = os.make_transform();
|
||||
world.objects = {};
|
||||
world.toString = function () {
|
||||
return "world";
|
||||
};
|
||||
world.ur = "world";
|
||||
world.kill = function () {
|
||||
this.clear();
|
||||
};
|
||||
world.phys = 2;
|
||||
world.zoom = 1;
|
||||
world._ed = { selectable: false };
|
||||
world.ur = {};
|
||||
world.ur.fresh = {};
|
||||
game.cam = world;
|
||||
}
|
||||
|
||||
global.mixin("scripts/physics");
|
||||
global.mixin("scripts/widget");
|
||||
global.mixin("scripts/mum");
|
||||
|
||||
window.title = `Prosperon v${prosperon.version}`;
|
||||
window.size = [500, 500];
|
||||
|
||||
return {
|
||||
Register,
|
||||
sim,
|
||||
frame_t,
|
||||
physlag,
|
||||
Event
|
||||
}
|
|
@ -6,22 +6,24 @@ render.doc = {
|
|||
|
||||
var cur = {};
|
||||
|
||||
render.use_shader = function(shader)
|
||||
render.use_shader = function use_shader(shader)
|
||||
{
|
||||
if (typeof shader === 'string')
|
||||
shader = make_shader(shader);
|
||||
if (cur.shader === shader) return;
|
||||
cur.shader = shader;
|
||||
cur.globals = {};
|
||||
cur.bind = undefined;
|
||||
cur.mesh = undefined;
|
||||
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.mat === mat) return;
|
||||
|
||||
render.shader_apply_material(cur.shader, mat, cur.mat);
|
||||
shader_apply_material(cur.shader, mat, cur.mat);
|
||||
|
||||
cur.mat = mat;
|
||||
|
||||
|
@ -36,7 +38,7 @@ render.use_mat = function(mat)
|
|||
|
||||
var models_array = [];
|
||||
|
||||
render.set_model = function(t)
|
||||
function set_model(t)
|
||||
{
|
||||
if (cur.shader.vs.unimap.model)
|
||||
render.setunim4(0, cur.shader.vs.unimap.model.slot, t);
|
||||
|
@ -94,7 +96,7 @@ var face_map = {
|
|||
ccw: 1
|
||||
}
|
||||
|
||||
render.poly_prim = function(verts)
|
||||
render.poly_prim = function poly_prim(verts)
|
||||
{
|
||||
var index = [];
|
||||
if (verts.length < 1) return undefined;
|
||||
|
@ -129,42 +131,40 @@ function shader_directive(shader, name, map)
|
|||
return ff;
|
||||
}
|
||||
|
||||
function global_uni(uni, stage)
|
||||
{
|
||||
cur.globals[stage] ??= {};
|
||||
if (cur.globals[stage][uni.name]) return true;
|
||||
switch(uni.name) {
|
||||
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;
|
||||
var uni_globals = {
|
||||
time(stage, slot) { render.setuniv(stage, slot, profile.secs(profile.now())); },
|
||||
projection(stage,slot) { render.setuniproj(stage, slot); },
|
||||
view(stage,slot) { render.setuniview(stage, slot); },
|
||||
vp(stage,slot) { render.setunivp(stage,slot); },
|
||||
}
|
||||
|
||||
return false;
|
||||
function set_global_uni(uni, stage) {
|
||||
uni_globals[uni.name]?.(stage, uni.slot);
|
||||
}
|
||||
|
||||
var setcam = render.set_camera;
|
||||
render.set_camera = function(cam)
|
||||
{
|
||||
if (nextflush) {
|
||||
nextflush();
|
||||
nextflush = undefined;
|
||||
}
|
||||
delete cur.shader;
|
||||
setcam(cam);
|
||||
}
|
||||
|
||||
render.make_shader = function(shader)
|
||||
var shader_cache = {};
|
||||
|
||||
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];
|
||||
|
||||
var file = shader;
|
||||
shader = io.slurp(shader);
|
||||
if (!shader) {
|
||||
|
@ -172,20 +172,25 @@ render.make_shader = function(shader)
|
|||
shader = io.slurp(`shaders/${file}`);
|
||||
}
|
||||
var writejson = `.prosperon/${file.name()}.shader.json`;
|
||||
var st = profile.now();
|
||||
|
||||
profile.cache("shader", file);
|
||||
|
||||
breakme: if (io.exists(writejson)) {
|
||||
var data = json.decode(io.slurp(writejson));
|
||||
var filemod = io.mod(writejson);
|
||||
if (!data.files) break breakme;
|
||||
for (var i of data.files)
|
||||
if (io.mod(i) > filemod)
|
||||
for (var i of data.files) {
|
||||
if (io.mod(i) > filemod) {
|
||||
break breakme;
|
||||
}
|
||||
}
|
||||
|
||||
profile.report(st, `CACHE make shader from ${file}`);
|
||||
profile.endcache(" [cached]");
|
||||
var shaderobj = json.decode(io.slurp(writejson));
|
||||
var obj = shaderobj[os.sys()];
|
||||
strip_shader_inputs(obj);
|
||||
obj.pipe = render.pipeline(obj);
|
||||
shader_cache[shader] = obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -297,11 +302,13 @@ render.make_shader = function(shader)
|
|||
compiled.files = files;
|
||||
|
||||
io.slurpwrite(writejson, json.encode(compiled));
|
||||
profile.report(st, `make shader from ${file}`);
|
||||
profile.endcache();
|
||||
|
||||
var obj = compiled[os.sys()];
|
||||
strip_shader_inputs(obj);
|
||||
obj.pipe = render.pipeline(obj);
|
||||
|
||||
shader_cache[shader] = obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -312,10 +319,19 @@ var shader_unisize = {
|
|||
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) {
|
||||
if (global_uni(shader.vs.unimap[p], 0)) continue;
|
||||
if (!(p in material)) continue;
|
||||
if (material[p] === old[p]) continue;
|
||||
assert(p in material, `shader ${shader.name} has no uniform for ${p}`);
|
||||
var s = shader.vs.unimap[p];
|
||||
|
@ -323,7 +339,7 @@ render.shader_apply_material = function(shader, material = {}, old = {})
|
|||
}
|
||||
|
||||
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;
|
||||
assert(p in material, `shader ${shader.name} has no uniform for ${p}`);
|
||||
var s = shader.fs.unimap[p];
|
||||
|
@ -340,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.sg_bind = function(mesh, ssbo)
|
||||
function sg_bind(mesh, ssbo)
|
||||
{
|
||||
if (cur.mesh === mesh && cur.bind) {
|
||||
cur.bind.inst = 1;
|
||||
|
@ -356,12 +372,9 @@ render.sg_bind = function(mesh, ssbo)
|
|||
if (cur.shader.vs.inputs)
|
||||
for (var a of cur.shader.vs.inputs) {
|
||||
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.`);
|
||||
return undefined;
|
||||
} else
|
||||
bind.attrib.push(mesh[a.name.slice(2)]);
|
||||
} else
|
||||
bind.attrib.push(mesh[a.name]);
|
||||
}
|
||||
|
||||
|
@ -426,14 +439,27 @@ var textshader;
|
|||
var circleshader;
|
||||
var polyshader;
|
||||
var slice9shader;
|
||||
var parshader;
|
||||
var spritessboshader;
|
||||
var polyssboshader;
|
||||
|
||||
var sprite_ssbo;
|
||||
|
||||
render.init = function() {
|
||||
textshader = render.make_shader("shaders/text_base.cg");
|
||||
render.spriteshader = render.make_shader("shaders/sprite.cg");
|
||||
render.postshader = render.make_shader("shaders/simplepost.cg");
|
||||
slice9shader = render.make_shader("shaders/9slice.cg");
|
||||
circleshader = render.make_shader("shaders/circle.cg");
|
||||
polyshader = render.make_shader("shaders/poly.cg");
|
||||
textshader = make_shader("shaders/text_base.cg");
|
||||
render.spriteshader = make_shader("shaders/sprite.cg");
|
||||
spritessboshader = make_shader("shaders/sprite_ssbo.cg");
|
||||
render.postshader = make_shader("shaders/simplepost.cg");
|
||||
slice9shader = make_shader("shaders/9slice.cg");
|
||||
circleshader = make_shader("shaders/circle.cg");
|
||||
polyshader = make_shader("shaders/poly.cg");
|
||||
parshader = make_shader("shaders/baseparticle.cg");
|
||||
polyssboshader = make_shader("shaders/poly_ssbo.cg");
|
||||
textssbo = render.make_textssbo();
|
||||
poly_ssbo = render.make_textssbo();
|
||||
sprite_ssbo = render.make_textssbo();
|
||||
|
||||
globalThis.imgui = render.imgui_init();
|
||||
|
||||
render.textshader = textshader;
|
||||
|
||||
|
@ -467,7 +493,55 @@ render.init = function() {
|
|||
}
|
||||
}
|
||||
|
||||
render.circle = function(pos, radius, color) {
|
||||
render.sprites = function render_sprites(gridsize = 1)
|
||||
{
|
||||
/*
|
||||
profile.frame("bucketing");
|
||||
var sps = Object.values(allsprites);
|
||||
|
||||
var buckets = [];
|
||||
for (var i = 0; i <= 20; i++)
|
||||
buckets[i] = {};
|
||||
|
||||
for (var sprite of sps) {
|
||||
var layer = sprite.gameobject.drawlayer+10;
|
||||
if (buckets[layer][sprite.path])
|
||||
buckets[layer][sprite.path].push(sprite);
|
||||
else
|
||||
buckets[layer][sprite.path] = [sprite];
|
||||
}
|
||||
|
||||
profile.endframe();
|
||||
*/
|
||||
|
||||
profile.frame("sorting");
|
||||
var sprite_buckets = component.sprite_buckets();
|
||||
|
||||
var buckets = Object.entries(sprite_buckets).sort((a,b) => {
|
||||
var na = Number(a[0]);
|
||||
var nb = Number(b[0]);
|
||||
if (na < nb) return -1;
|
||||
return 1;
|
||||
});
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("drawing");
|
||||
render.use_shader(spritessboshader);
|
||||
for (var layer of buckets) {
|
||||
for (var img of Object.values(layer[1])) {
|
||||
var sparray = Object.values(img);
|
||||
if (sparray.length === 0) continue;
|
||||
var ss = sparray[0];
|
||||
render.use_mat(ss);
|
||||
render.make_sprite_ssbo(sparray, sprite_ssbo);
|
||||
render.draw(shape.quad, sprite_ssbo, sparray.length);
|
||||
}
|
||||
}
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
render.circle = function render_circle(pos, radius, color) {
|
||||
flush();
|
||||
var mat = {
|
||||
radius: radius,
|
||||
coord: pos,
|
||||
|
@ -478,24 +552,71 @@ render.circle = function(pos, radius, color) {
|
|||
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 mat = { shade: color};
|
||||
render.use_shader(polyshader);
|
||||
render.set_model(transform);
|
||||
set_model(transform);
|
||||
render.use_mat(mat);
|
||||
render.draw(buffer);
|
||||
}
|
||||
|
||||
render.line = function(points, color = Color.white, thickness = 1, transform) {
|
||||
var buffer = os.make_line_prim(points, thickness, 0, false);
|
||||
render.use_shader(polyshader);
|
||||
var mat = {
|
||||
shade: color
|
||||
var nextflush = undefined;
|
||||
function flush()
|
||||
{
|
||||
nextflush?.();
|
||||
nextflush = undefined;
|
||||
}
|
||||
|
||||
function check_flush(flush_fn)
|
||||
{
|
||||
if (!nextflush)
|
||||
nextflush = flush_fn;
|
||||
else if (nextflush !== flush_fn) {
|
||||
nextflush();
|
||||
nextflush = flush_fn;
|
||||
}
|
||||
}
|
||||
|
||||
var poly_cache = [];
|
||||
var poly_idx = 0;
|
||||
var poly_ssbo;
|
||||
|
||||
function poly_e()
|
||||
{
|
||||
var e;
|
||||
poly_idx++;
|
||||
if (poly_idx > poly_cache.length) {
|
||||
e = {
|
||||
transform:os.make_transform(),
|
||||
color: Color.white
|
||||
};
|
||||
render.use_mat(mat);
|
||||
render.set_model(transform);
|
||||
render.draw(buffer);
|
||||
poly_cache.push(e);
|
||||
return e;
|
||||
}
|
||||
var e = poly_cache[poly_idx-1];
|
||||
e.transform.unit();
|
||||
return e;
|
||||
}
|
||||
|
||||
function flush_poly()
|
||||
{
|
||||
if (poly_idx === 0) return;
|
||||
render.use_shader(polyssboshader);
|
||||
render.use_mat({});
|
||||
render.make_particle_ssbo(poly_cache.slice(0,poly_idx), poly_ssbo);
|
||||
render.draw(shape.centered_quad, poly_ssbo, poly_cache.length);
|
||||
poly_idx = 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -503,7 +624,7 @@ render.point = function(pos,size,color = Color.blue) {
|
|||
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 = [
|
||||
pos.add([0,size]),
|
||||
pos.add([0,-size])
|
||||
|
@ -516,7 +637,7 @@ render.cross = function(pos, size, color = Color.red, thickness = 1) {
|
|||
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 wing1 = [
|
||||
Vector.rotate(dir, wingangle).scale(wingspan).add(end),
|
||||
|
@ -531,31 +652,34 @@ render.arrow = function(start, end, color = Color.red, wingspan = 4, wingangle =
|
|||
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.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.rectangle = function(lowerleft, upperright, color) {
|
||||
var points = [lowerleft, lowerleft.add([upperright.x-lowerleft.x,0]), upperright, lowerleft.add([0,upperright.y-lowerleft.y])];
|
||||
render.poly(points, color);
|
||||
render.rectangle = function render_rectangle(lowerleft, upperright, color) {
|
||||
var transform = os.make_transform();
|
||||
var wh = [upperright.x-lowerleft.x, upperright.y-lowerleft.y];
|
||||
var poly = poly_e();
|
||||
poly.transform.move(vector.midpoint(lowerleft,upperright));
|
||||
poly.transform.scale = [wh.x,wh.y,1];
|
||||
poly.color = color;
|
||||
check_flush(flush_poly);
|
||||
};
|
||||
|
||||
render.box = function(pos, wh, color = Color.white) {
|
||||
var lower = pos.sub(wh.scale(0.5));
|
||||
var upper = pos.add(wh.scale(0.5));
|
||||
render.rectangle(lower,upper,color);
|
||||
render.box = function render_box(pos, wh, color = Color.white) {
|
||||
var poly = poly_e();
|
||||
poly.transform.move(pos);
|
||||
poly.transform.scale = [wh.x,wh.y,1];
|
||||
poly.color = color;
|
||||
check_flush(flush_poly);
|
||||
};
|
||||
|
||||
render.window = function(pos, wh, color) {
|
||||
var p = pos.slice();
|
||||
p = p.add(wh.scale(0.5));
|
||||
render.box(p,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])
|
||||
{
|
||||
|
@ -573,6 +697,7 @@ render.text_bb = function(str, size = 1, wrap = -1, pos = [0,0])
|
|||
render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0,1], cursor = -1) {
|
||||
var bb = render.text_bb(str, size, wrap, pos);
|
||||
gui.text(str, pos, size, color, wrap, cursor);
|
||||
check_flush(render.flush_text);
|
||||
return bb;
|
||||
|
||||
p.x -= w * anchor.x;
|
||||
|
@ -586,11 +711,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) {
|
||||
flush();
|
||||
var t = os.make_transform();
|
||||
t.pos = pos;
|
||||
t.scale = [scale.x/tex.width,scale.y/tex.height,1];
|
||||
render.use_shader(render.spriteshader);
|
||||
render.set_model(t);
|
||||
set_model(t);
|
||||
render.use_mat({
|
||||
shade: color,
|
||||
diffuse: tex,
|
||||
|
@ -621,7 +747,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];
|
||||
|
||||
render.use_shader(slice9shader);
|
||||
render.set_model(t);
|
||||
set_model(t);
|
||||
render.use_mat({
|
||||
shade: color,
|
||||
diffuse:tex,
|
||||
|
@ -633,27 +759,43 @@ render.slice9 = function(tex, pos, bb, scale = [tex.width,tex.height], color = C
|
|||
render.draw(shape.quad);
|
||||
}
|
||||
|
||||
var textssbo = render.text_ssbo();
|
||||
render.emitter = function(emit)
|
||||
{
|
||||
var amt = Object.values(emit.particles).length;
|
||||
if (amt === 0) return;
|
||||
render.use_shader(parshader);
|
||||
render.use_mat(emit);
|
||||
var ts = [];
|
||||
for (var p of Object.values(emit.particles)) ts.push([p.transform,p.color]);
|
||||
render.make_particle_ssbo(ts, emit.ssbo);
|
||||
render.draw(shape.quad, emit.ssbo, amt);
|
||||
}
|
||||
|
||||
var textssbo;
|
||||
|
||||
render.flush_text = function()
|
||||
{
|
||||
if (!render.textshader) return;
|
||||
var amt = render.flushtext(textssbo);
|
||||
|
||||
render.use_shader(render.textshader);
|
||||
render.use_mat({text:render.font.texture});
|
||||
|
||||
render.draw(shape.quad, textssbo, render.flushtext());
|
||||
if (amt === 0) return;
|
||||
|
||||
render.draw(shape.quad, textssbo, amt);
|
||||
}
|
||||
|
||||
render.fontcache = {};
|
||||
var fontcache = {};
|
||||
render.set_font = function(path, size) {
|
||||
var fontstr = `${path}-${size}`;
|
||||
if (render.font && render.fontcache[fontstr] === render.font) return;
|
||||
if (!render.fontcache[fontstr]) render.fontcache[fontstr] = os.make_font(path, size);
|
||||
if (render.font && fontcache[fontstr] === render.font) return;
|
||||
if (!fontcache[fontstr]) fontcache[fontstr] = os.make_font(path, size);
|
||||
|
||||
render.flush_text();
|
||||
|
||||
gui.font_set(render.fontcache[fontstr]);
|
||||
render.font = render.fontcache[fontstr];
|
||||
gui.font_set(fontcache[fontstr]);
|
||||
render.font = fontcache[fontstr];
|
||||
}
|
||||
|
||||
render.doc = "Draw shapes in screen space.";
|
||||
|
@ -662,10 +804,204 @@ 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.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);
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
// 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
|
||||
function camviewport()
|
||||
{
|
||||
var aspect = (this.viewport[2]-this.viewport[0])/(this.viewport[3]-this.viewport[1])*window.size.x/window.size.y;
|
||||
var raspect = this.size.x/this.size.y;
|
||||
|
||||
var left = this.viewport[0]*window.size.x;
|
||||
var bottom = this.viewport[1]*window.size.y;
|
||||
|
||||
var usemode = this.mode;
|
||||
|
||||
if (this.break && this.size.x > window.size.x && this.size.y > window.size.y)
|
||||
usemode = this.break;
|
||||
|
||||
if (usemode === "fit")
|
||||
if (raspect < aspect) usemode = "height";
|
||||
else usemode = "width";
|
||||
|
||||
switch(usemode) {
|
||||
case "stretch":
|
||||
case "expand":
|
||||
return [0, 0, window.size.x, window.size.y];
|
||||
case "keep":
|
||||
return [left, bottom, left+this.size.x, bottom+this.size.y];
|
||||
case "height":
|
||||
var ret = [left, 0, this.size.x*(window.size.y/this.size.y), window.size.y];
|
||||
ret[0] = (window.size.x-(ret[2]-ret[0]))/2;
|
||||
return ret;
|
||||
case "width":
|
||||
var ret = [0, bottom, window.size.x, this.size.y*(window.size.x/this.size.x)];
|
||||
ret[1] = (window.size.y-(ret[3]-ret[1]))/2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return [0, 0, window.size.x, window.size.y];
|
||||
}
|
||||
|
||||
// pos is pixels on the screen, lower left[0,0]
|
||||
function camscreen2world(pos)
|
||||
{
|
||||
var view = this.screen2cam(pos);
|
||||
view.x *= this.size.x;
|
||||
view.y *= this.size.y;
|
||||
view = view.sub([this.size.x/2, this.size.y/2]);
|
||||
view = view.add(this.pos.xy);
|
||||
return view;
|
||||
}
|
||||
|
||||
camscreen2world.doc = "Convert a view position for a camera to world."
|
||||
|
||||
function screen2cam(pos)
|
||||
{
|
||||
var viewport = this.view();
|
||||
var width = viewport[2]-viewport[0];
|
||||
var height = viewport[3]-viewport[1];
|
||||
var left = pos.x-viewport[0];
|
||||
var bottom = pos.y-viewport[1];
|
||||
var p = [left/width, bottom/height];
|
||||
return p;
|
||||
}
|
||||
|
||||
screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera."
|
||||
|
||||
prosperon.make_camera = function()
|
||||
{
|
||||
var cam = world.spawn();
|
||||
cam.near = 0.1;
|
||||
cam.far = 1000;
|
||||
cam.ortho = true;
|
||||
cam.viewport = [0,0,1,1];
|
||||
cam.size = window.size.slice(); // The render size of this camera in pixels
|
||||
// In ortho mode, this determines how many pixels it will see
|
||||
cam.mode = "stretch";
|
||||
cam.screen2world = camscreen2world;
|
||||
cam.screen2cam = screen2cam;
|
||||
|
||||
cam.mousepos = function() { return this.screen2world(input.mouse.screenpos()); }
|
||||
cam.view = camviewport;
|
||||
cam.offscreen = false;
|
||||
return cam;
|
||||
}
|
||||
|
||||
var screencolor;
|
||||
|
||||
prosperon.render = function()
|
||||
{
|
||||
profile.frame("world");
|
||||
render.set_camera(prosperon.camera);
|
||||
profile.frame("sprites");
|
||||
render.sprites();
|
||||
profile.endframe();
|
||||
profile.frame("draws");
|
||||
prosperon.draw();
|
||||
profile.endframe();
|
||||
prosperon.hudcam.size = prosperon.camera.size;
|
||||
prosperon.hudcam.transform.pos = [prosperon.hudcam.size.x/2, prosperon.hudcam.size.y/2, -100];
|
||||
render.set_camera(prosperon.hudcam);
|
||||
|
||||
profile.endframe();
|
||||
profile.frame("hud");
|
||||
|
||||
prosperon.hud();
|
||||
render.flush_text();
|
||||
|
||||
render.end_pass();
|
||||
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("post process");
|
||||
/* draw the image of the game world first */
|
||||
render.glue_pass();
|
||||
render.viewport(...prosperon.camera.view());
|
||||
render.use_shader(render.postshader);
|
||||
render.use_mat({diffuse:prosperon.screencolor});
|
||||
render.draw(shape.quad);
|
||||
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("app");
|
||||
|
||||
// Flush & render
|
||||
prosperon.appcam.transform.pos = [window.size.x/2, window.size.y/2, -100];
|
||||
prosperon.appcam.size = window.size.slice();
|
||||
if (os.sys() !== 'macos')
|
||||
prosperon.appcam.size.y *= -1;
|
||||
|
||||
render.set_camera(prosperon.appcam);
|
||||
render.viewport(...prosperon.appcam.view());
|
||||
|
||||
// Call gui functions
|
||||
mum.style = mum.dbg_style;
|
||||
prosperon.gui();
|
||||
if (mum.drawinput) mum.drawinput();
|
||||
prosperon.gui_dbg();
|
||||
render.flush_text();
|
||||
mum.style = mum.base;
|
||||
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("imgui");
|
||||
|
||||
render.imgui_new(window.size.x, window.size.y, 0.01);
|
||||
prosperon.imgui();
|
||||
render.imgui_end();
|
||||
|
||||
profile.endframe();
|
||||
|
||||
render.end_pass();
|
||||
render.commit();
|
||||
}
|
||||
|
||||
prosperon.process = function process() {
|
||||
profile.frame("frame");
|
||||
var dt = profile.secs(profile.now()) - frame_t;
|
||||
frame_t = profile.secs(profile.now());
|
||||
|
||||
profile.frame("app update");
|
||||
prosperon.appupdate(dt);
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("input");
|
||||
input.procdown();
|
||||
profile.endframe();
|
||||
|
||||
if (sim.mode === "play" || sim.mode === "step") {
|
||||
profile.frame("update");
|
||||
prosperon.update(dt * game.timescale);
|
||||
profile.endframe();
|
||||
if (sim.mode === "step") sim.pause();
|
||||
|
||||
profile.frame("physics");
|
||||
physlag += dt;
|
||||
|
||||
while (physlag > physics.delta) {
|
||||
physlag -= physics.delta;
|
||||
prosperon.phys2d_step(physics.delta * game.timescale);
|
||||
prosperon.physupdate(physics.delta * game.timescale);
|
||||
}
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
profile.frame("render");
|
||||
prosperon.window_render(window.size);
|
||||
prosperon.render();
|
||||
profile.endframe();
|
||||
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {render};
|
||||
|
|
|
@ -14,8 +14,10 @@ if (os.sys() === 'macos') {
|
|||
appy.inputs['S-g'] = os.gc;
|
||||
}
|
||||
|
||||
appy.inputs.f12 = function() { mum.debug = !mum.debug; }
|
||||
//appy.inputs.f12 = function() { mum.debug = !mum.debug; }
|
||||
appy.inputs.f12 = function() { profile.cpu_frame(); }
|
||||
appy.inputs.f11 = window.toggle_fullscreen;
|
||||
appy.inputs.f10 = function() { profile.toggle_frame_avg(); }
|
||||
appy.inputs['M-f4'] = prosperon.quit;
|
||||
|
||||
player[0].control(appy);
|
||||
|
|
|
@ -103,19 +103,22 @@ Ease.elastic = {
|
|||
Ease.elastic.c4 = 2*Math.PI/3;
|
||||
Ease.elastic.c5 = 2*Math.PI / 4.5;
|
||||
|
||||
var tween = function(obj, val, to, time)
|
||||
var tween = function(from, to, time, fn)
|
||||
{
|
||||
var start = profile.secs(profile.now());
|
||||
var startval = obj[val];
|
||||
var update = function(dt) {
|
||||
profile.frame("tween");
|
||||
var elapsed = profile.secs(profile.now()) - start;
|
||||
obj[val] = startval.lerp(to, elapsed/time);
|
||||
fn(from.lerp(to,elapsed/time));
|
||||
if (elapsed >= time) {
|
||||
obj[val] = to;
|
||||
fn(to);
|
||||
if (stop.then) stop.then();
|
||||
stop();
|
||||
}
|
||||
profile.endframe();
|
||||
};
|
||||
var stop = Register.update.register(update);
|
||||
return stop;
|
||||
}
|
||||
|
||||
var Tween = {
|
||||
|
|
|
@ -171,7 +171,7 @@ var listpanel = Object.copy(inputpanel, {
|
|||
|
||||
keycb() {
|
||||
if(this.value)
|
||||
this.assets = this.allassets.filter(x => x.startswith(this.value));
|
||||
this.assets = this.allassets.filter(x => x.startsWith(this.value));
|
||||
else
|
||||
this.assets = this.allassets.slice();
|
||||
for (var m in this.mumlist)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#blend mix
|
||||
#depth off
|
||||
#primitive triangle
|
||||
#cull none
|
||||
#depth off
|
||||
|
||||
@vs vs
|
||||
in vec3 a_pos;
|
||||
|
|
49
shaders/baseparticle.cg
Normal file
49
shaders/baseparticle.cg
Normal file
|
@ -0,0 +1,49 @@
|
|||
#depth off
|
||||
#blend mix
|
||||
|
||||
@vs vs
|
||||
in vec2 a_pos;
|
||||
in vec2 a_uv;
|
||||
|
||||
uniform vec2 diffuse_size;
|
||||
|
||||
struct particle {
|
||||
mat4 model;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
readonly buffer ssbo {
|
||||
particle par[];
|
||||
};
|
||||
|
||||
out vec2 uv;
|
||||
out vec4 color0;
|
||||
|
||||
uniform mat4 vp;
|
||||
|
||||
void main()
|
||||
{
|
||||
particle p = par[gl_InstanceIndex];
|
||||
gl_Position = vp * p.model * vec4(a_pos, 0.0, 1.0);
|
||||
uv = a_uv;
|
||||
color0 = p.color;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
in vec2 uv;
|
||||
|
||||
in vec4 color0;
|
||||
out vec4 color;
|
||||
|
||||
texture2D diffuse;
|
||||
sampler smp;
|
||||
|
||||
void main()
|
||||
{
|
||||
color = texture(sampler2D(diffuse,smp),uv);
|
||||
color *= color0;
|
||||
}
|
||||
@end
|
||||
|
||||
@program text vs fs
|
|
@ -1,5 +1,5 @@
|
|||
#blend mix
|
||||
#depth off
|
||||
#blend mix
|
||||
#primitive triangle
|
||||
#cull none
|
||||
|
||||
|
|
37
shaders/poly_ssbo.cg
Normal file
37
shaders/poly_ssbo.cg
Normal file
|
@ -0,0 +1,37 @@
|
|||
#depth off
|
||||
#blend mix
|
||||
#primitive triangle
|
||||
#cull none
|
||||
|
||||
@vs vs
|
||||
in vec3 a_pos;
|
||||
uniform mat4 vp;
|
||||
out vec4 shade;
|
||||
|
||||
struct poly {
|
||||
mat4 model;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
readonly buffer ssbo {
|
||||
poly polys[];
|
||||
};
|
||||
|
||||
void main() {
|
||||
poly p = polys[gl_InstanceIndex];
|
||||
gl_Position = vp * p.model * vec4(a_pos, 1);
|
||||
shade = p.color;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
|
||||
in vec4 shade;
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = shade;
|
||||
}
|
||||
@end
|
||||
|
||||
@program sprite vs fs
|
|
@ -13,7 +13,6 @@ uniform vec4 shade;
|
|||
void frag()
|
||||
{
|
||||
color = texture(sampler2D(diffuse,smp), uv);
|
||||
if (color.a < 0.1) discard;
|
||||
color *= shade;
|
||||
}
|
||||
@end
|
||||
|
|
60
shaders/sprite_ssbo.cg
Normal file
60
shaders/sprite_ssbo.cg
Normal file
|
@ -0,0 +1,60 @@
|
|||
#blend mix
|
||||
#depth off
|
||||
#primitive triangle
|
||||
#cull none
|
||||
|
||||
@vs vs
|
||||
in vec3 a_pos;
|
||||
in vec2 a_uv;
|
||||
out vec2 uv;
|
||||
|
||||
vec3 pos;
|
||||
|
||||
struct sprite {
|
||||
mat4 model;
|
||||
vec4 rect;
|
||||
};
|
||||
|
||||
readonly buffer ssbo {
|
||||
sprite sprites[];
|
||||
};
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 vp;
|
||||
uniform vec2 diffuse_size;
|
||||
|
||||
void main()
|
||||
{
|
||||
sprite s = sprites[gl_InstanceIndex];
|
||||
pos = a_pos;
|
||||
uv = a_uv;
|
||||
pos *= vec3(diffuse_size * s.rect.zw,1);
|
||||
uv = (uv*s.rect.zw)+s.rect.xy;
|
||||
gl_Position = vp * s.model * vec4(pos, 1.0);
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
|
||||
in vec2 uv;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
texture2D diffuse;
|
||||
sampler smp;
|
||||
|
||||
uniform vec4 shade;
|
||||
void frag()
|
||||
{
|
||||
color = texture(sampler2D(diffuse,smp), uv);
|
||||
color *= shade;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
frag();
|
||||
}
|
||||
@end
|
||||
|
||||
@program sprite vs fs
|
|
@ -3,6 +3,7 @@
|
|||
const HMM_Vec2 v2zero = {0,0};
|
||||
const HMM_Vec2 v2one = {1,1};
|
||||
const HMM_Vec3 v3zero = {0,0,0};
|
||||
const HMM_Vec3 v3one = {1,1,1};
|
||||
const HMM_Vec4 v4zero = {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_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
|
||||
|
@ -267,11 +268,6 @@ HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right) {
|
|||
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);
|
||||
}
|
||||
|
||||
HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right) {
|
||||
|
||||
HMM_Vec2 Result;
|
||||
|
@ -529,7 +525,6 @@ float HMM_AngleV4(HMM_Vec4 a, HMM_Vec4 b)
|
|||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
|
@ -1769,11 +1764,6 @@ HMM_Mat4 HMM_QToM4(HMM_Quat Left) {
|
|||
|
||||
HMM_Mat4 HMM_M4TRS(HMM_Vec3 t, HMM_Quat q, HMM_Vec3 s)
|
||||
{
|
||||
HMM_Mat4 T = HMM_Translate(t);
|
||||
HMM_Mat4 R = HMM_QToM4(q);
|
||||
HMM_Mat4 S = HMM_Scale(s);
|
||||
return HMM_MulM4(T, HMM_MulM4(R, S));
|
||||
//return HMM_MulM4(T,S);
|
||||
HMM_Mat4 l;
|
||||
float *lm = (float*)&l;
|
||||
|
||||
|
|
|
@ -416,6 +416,7 @@ typedef union HMM_Mat4 {
|
|||
extern const HMM_Vec2 v2zero;
|
||||
extern const HMM_Vec2 v2one;
|
||||
extern const HMM_Vec3 v3zero;
|
||||
extern const HMM_Vec3 v3one;
|
||||
extern const HMM_Vec4 v4zero;
|
||||
|
||||
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_Vec3 HMM_SubV3(HMM_Vec3 Left, HMM_Vec3 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_MulV2F(HMM_Vec2 Left, float Right);
|
||||
HMM_Vec3 HMM_MulV3(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
struct sFont *use_font;
|
||||
|
||||
sg_buffer text_ssbo;
|
||||
|
||||
struct text_vert {
|
||||
HMM_Vec2 pos;
|
||||
HMM_Vec2 wh;
|
||||
|
@ -32,15 +30,6 @@ struct text_vert {
|
|||
|
||||
static struct text_vert *text_buffer;
|
||||
|
||||
void font_init() {
|
||||
text_ssbo = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(struct text_vert),
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "text buffer"
|
||||
});
|
||||
}
|
||||
|
||||
void font_free(font *f)
|
||||
{
|
||||
sg_destroy_image(f->texID);
|
||||
|
@ -115,7 +104,6 @@ struct sFont *MakeFont(const char *fontfile, int height) {
|
|||
newfont->descent = descent*emscale;
|
||||
newfont->linegap = linegap*emscale;
|
||||
newfont->linegap = ((newfont->ascent - newfont->descent) - newfont->linegap);
|
||||
printf("newfont : %g, %g, %g\n", newfont->ascent, newfont->descent, newfont->linegap);
|
||||
|
||||
newfont->texture = malloc(sizeof(texture));
|
||||
newfont->texture->id = sg_make_image(&(sg_image_desc){
|
||||
|
@ -177,15 +165,15 @@ void draw_char_box(struct Character c, HMM_Vec2 cursor, float scale, struct rgba
|
|||
b.y = cursor.Y + wh.y/2;
|
||||
}
|
||||
|
||||
int text_flush() {
|
||||
int text_flush(sg_buffer *buf) {
|
||||
if (arrlen(text_buffer) == 0) return 0;
|
||||
|
||||
sg_range verts;
|
||||
verts.ptr = text_buffer;
|
||||
verts.size = sizeof(struct text_vert) * arrlen(text_buffer);
|
||||
if (sg_query_buffer_will_overflow(text_ssbo, verts.size)) {
|
||||
sg_destroy_buffer(text_ssbo);
|
||||
text_ssbo = sg_make_buffer(&(sg_buffer_desc){
|
||||
if (sg_query_buffer_will_overflow(*buf, verts.size)) {
|
||||
sg_destroy_buffer(*buf);
|
||||
*buf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = verts.size,
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
|
@ -193,7 +181,7 @@ int text_flush() {
|
|||
});
|
||||
}
|
||||
|
||||
sg_append_buffer(text_ssbo, &verts);
|
||||
sg_append_buffer(*buf, &verts);
|
||||
int n = arrlen(text_buffer);
|
||||
arrsetlen(text_buffer, 0);
|
||||
return n;
|
||||
|
|
|
@ -34,7 +34,6 @@ typedef struct sFont font;
|
|||
|
||||
void font_free(font *f);
|
||||
|
||||
void font_init();
|
||||
struct sFont *MakeFont(const char *fontfile, int height);
|
||||
void font_set(font *f);
|
||||
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color);
|
||||
|
@ -42,6 +41,6 @@ void text_settype(struct sFont *font);
|
|||
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);
|
||||
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking);
|
||||
|
||||
int text_flush();
|
||||
int text_flush(sg_buffer *buf);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "render.h"
|
||||
#include "sokol/sokol_app.h"
|
||||
#include "imgui.h"
|
||||
#include "implot.h"
|
||||
#define SOKOL_IMPL
|
||||
#include "sokol/util/sokol_imgui.h"
|
||||
#include "sokol/util/sokol_gfx_imgui.h"
|
||||
|
@ -37,6 +38,22 @@ JSC_CCALL(imgui_menuitem,
|
|||
free(hotkey);
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_startplot,
|
||||
ImPlot::SetNextAxisToFit(ImAxis_X1);
|
||||
ImPlot::SetNextAxisToFit(ImAxis_Y1);
|
||||
ImPlot::BeginPlot(str);
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_endplot, ImPlot::EndPlot() )
|
||||
|
||||
JSC_SCALL(imgui_lineplot,
|
||||
double data[js_arrlen(argv[1])];
|
||||
for (int i = 0; i < js_arrlen(argv[1]); i++)
|
||||
data[i] = js2number(js_getpropidx(argv[1], i));
|
||||
|
||||
ImPlot::PlotLine(str, data, js_arrlen(argv[1]));
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_beginmenubar, ImGui::BeginMenuBar())
|
||||
JSC_CCALL(imgui_endmenubar, ImGui::EndMenuBar())
|
||||
|
||||
|
@ -55,6 +72,9 @@ static const JSCFunctionListEntry js_imgui_funcs[] = {
|
|||
MIST_FUNC_DEF(imgui, beginmenubar, 0),
|
||||
MIST_FUNC_DEF(imgui, endmenubar, 0),
|
||||
MIST_FUNC_DEF(imgui, textinput, 2),
|
||||
MIST_FUNC_DEF(imgui, startplot,1),
|
||||
MIST_FUNC_DEF(imgui,endplot,0),
|
||||
MIST_FUNC_DEF(imgui,lineplot,2)
|
||||
};
|
||||
|
||||
static int started = 0;
|
||||
|
@ -67,6 +87,8 @@ JSValue gui_init(JSContext *js)
|
|||
sgimgui_desc_t desc = {0};
|
||||
sgimgui_init(&sgimgui, &desc);
|
||||
|
||||
ImPlot::CreateContext();
|
||||
|
||||
JSValue imgui = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js, imgui, js_imgui_funcs, countof(js_imgui_funcs));
|
||||
started = 1;
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "window.h"
|
||||
#include "spline.h"
|
||||
#include "yugine.h"
|
||||
#include "particle.h"
|
||||
#include <assert.h>
|
||||
#include "resources.h"
|
||||
#include <sokol/sokol_time.h>
|
||||
|
@ -35,6 +34,7 @@
|
|||
#include "sokol_glue.h"
|
||||
#include <chipmunk/chipmunk_unsafe.h>
|
||||
#include "gui.h"
|
||||
#include "timer.h"
|
||||
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
#include <direct.h>
|
||||
|
@ -96,7 +96,6 @@ void cpConstraint_free(cpConstraint *c)
|
|||
void jsfreestr(const char *s) { JS_FreeCString(js, s); }
|
||||
QJSCLASS(gameobject)
|
||||
QJSCLASS(transform)
|
||||
QJSCLASS(emitter)
|
||||
QJSCLASS(dsp_node)
|
||||
QJSCLASS(texture)
|
||||
QJSCLASS(font)
|
||||
|
@ -107,6 +106,7 @@ QJSCLASS(sg_buffer)
|
|||
QJSCLASS(datastream)
|
||||
QJSCLASS(cpShape)
|
||||
QJSCLASS(cpConstraint)
|
||||
QJSCLASS(timer)
|
||||
|
||||
static JSValue js_circle2d;
|
||||
static JSValue js_poly2d;
|
||||
|
@ -661,32 +661,20 @@ sg_bindings js2bind(JSValue v)
|
|||
return bind;
|
||||
}
|
||||
|
||||
JSC_GETSET(emitter, life, number)
|
||||
JSC_GETSET(emitter, life_var, number)
|
||||
JSC_GETSET(emitter, speed, number)
|
||||
JSC_GETSET(emitter, variation, number)
|
||||
JSC_GETSET(emitter, divergence, number)
|
||||
JSC_GETSET(emitter, scale, number)
|
||||
JSC_GETSET(emitter, scale_var, number)
|
||||
JSC_GETSET(emitter, grow_for, number)
|
||||
JSC_GETSET(emitter, shrink_for, number)
|
||||
JSC_GETSET(emitter, max, number)
|
||||
JSC_GETSET(emitter, explosiveness, number)
|
||||
JSC_GETSET(emitter, bounce, number)
|
||||
JSC_GETSET(emitter, collision_mask, bitmask)
|
||||
JSC_GETSET(emitter, die_after_collision, boolean)
|
||||
JSC_GETSET(emitter, persist, number)
|
||||
JSC_GETSET(emitter, persist_var, number)
|
||||
JSC_GETSET(emitter, warp_mask, bitmask)
|
||||
JSC_CCALL(emitter_emit, emitter_emit(js2emitter(self), js2number(argv[0]), js2transform(argv[1])))
|
||||
JSC_CCALL(emitter_step, emitter_step(js2emitter(self), js2number(argv[0]), js2transform(argv[1])))
|
||||
JSC_CCALL(emitter_draw,
|
||||
emitter_draw(js2emitter(self));
|
||||
return number2js(arrlen(js2emitter(self)->verts));
|
||||
JSC_CCALL(render_flushtext,
|
||||
sg_buffer *buf = js2sg_buffer(argv[0]);
|
||||
int amt = text_flush(buf);
|
||||
return number2js(amt);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_flushtext,
|
||||
return number2js(text_flush());
|
||||
JSC_CCALL(render_make_textssbo,
|
||||
sg_buffer *b = malloc(sizeof(*b));
|
||||
*b = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.size = 4,
|
||||
.usage = SG_USAGE_STREAM
|
||||
});
|
||||
return sg_buffer2js(b);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_glue_pass,
|
||||
|
@ -934,15 +922,15 @@ JSC_CCALL(render_setunim4,
|
|||
JSValue arr = argv[2];
|
||||
int n = js_arrlen(arr);
|
||||
if (n == 1)
|
||||
m = transform2mat(*js2transform(js_getpropidx(arr,0)));
|
||||
m = transform2mat(js2transform(js_getpropidx(arr,0)));
|
||||
else {
|
||||
for (int i = 0; i < n; i++) {
|
||||
HMM_Mat4 p = transform2mat(*js2transform(js_getpropidx(arr, i)));
|
||||
HMM_Mat4 p = transform2mat(js2transform(js_getpropidx(arr, i)));
|
||||
m = HMM_MulM4(p,m);
|
||||
}
|
||||
}
|
||||
} else if (!JS_IsUndefined(argv[2]))
|
||||
m = transform2mat(*js2transform(argv[2]));
|
||||
m = transform2mat(js2transform(argv[2]));
|
||||
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(m.e));
|
||||
);
|
||||
|
@ -952,24 +940,101 @@ JSC_CCALL(render_setbind,
|
|||
sg_apply_bindings(&bind);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_make_t_ssbo,
|
||||
JSValue array = argv[0];
|
||||
HMM_Mat4 ms[js_arrlen(array)];
|
||||
for (int i = 0; i < js_arrlen(array); i++)
|
||||
ms[i] = transform2mat(*js2transform(js_getpropidx(array, i)));
|
||||
typedef struct particle_ss {
|
||||
HMM_Mat4 model;
|
||||
HMM_Vec4 color;
|
||||
} particle_ss;
|
||||
|
||||
sg_buffer *rr = malloc(sizeof(sg_buffer));
|
||||
*rr = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = {
|
||||
.ptr = ms,
|
||||
.size = sizeof(HMM_Mat4)*js_arrlen(array),
|
||||
},
|
||||
JSC_CCALL(render_make_particle_ssbo,
|
||||
JSValue array = argv[0];
|
||||
size_t size = js_arrlen(array)*(sizeof(particle_ss));
|
||||
sg_buffer *b = js2sg_buffer(argv[1]);
|
||||
if (!b) return JS_UNDEFINED;
|
||||
|
||||
particle_ss ms[js_arrlen(array)];
|
||||
|
||||
if (sg_query_buffer_will_overflow(*b, size)) {
|
||||
sg_destroy_buffer(*b);
|
||||
*b = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.size = size,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "transform buffer"
|
||||
});
|
||||
}
|
||||
|
||||
return sg_buffer2js(rr);
|
||||
for (int i = 0; i < js_arrlen(array); i++) {
|
||||
JSValue sub = js_getpropidx(array,i);
|
||||
ms[i].model = transform2mat(js2transform(js_getpropstr(sub, "transform")));
|
||||
ms[i].color = js2vec4(js_getpropstr(sub,"color"));
|
||||
}
|
||||
|
||||
sg_append_buffer(*b, (&(sg_range){
|
||||
.ptr = ms,
|
||||
.size = size
|
||||
}));
|
||||
)
|
||||
|
||||
typedef struct sprite_ss {
|
||||
HMM_Mat4 model;
|
||||
HMM_Vec4 rect;
|
||||
} sprite_ss;
|
||||
|
||||
JSC_CCALL(render_make_sprite_ssbo,
|
||||
JSValue array = argv[0];
|
||||
size_t size = js_arrlen(array)*(sizeof(sprite_ss));
|
||||
sg_buffer *b = js2sg_buffer(argv[1]);
|
||||
if (!b) return JS_UNDEFINED;
|
||||
|
||||
sprite_ss ms[js_arrlen(array)];
|
||||
|
||||
if (sg_query_buffer_will_overflow(*b, size)) {
|
||||
sg_destroy_buffer(*b);
|
||||
*b = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.size = size,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "transform buffer"
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < js_arrlen(array); i++) {
|
||||
JSValue sub = js_getpropidx(array,i);
|
||||
ms[i].model = transform2mat(js2transform(js_getpropstr(sub, "transform")));
|
||||
ms[i].rect = js2vec4(js_getpropstr(sub,"rect"));
|
||||
}
|
||||
|
||||
sg_append_buffer(*b, (&(sg_range){
|
||||
.ptr = ms,
|
||||
.size = size
|
||||
}));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_make_t_ssbo,
|
||||
JSValue array = argv[0];
|
||||
size_t size = js_arrlen(array)*sizeof(HMM_Mat4);
|
||||
sg_buffer *b = js2sg_buffer(argv[1]);
|
||||
if (!b) return JS_UNDEFINED;
|
||||
|
||||
HMM_Mat4 ms[js_arrlen(array)];
|
||||
|
||||
if (sg_query_buffer_will_overflow(*b, size)) {
|
||||
sg_destroy_buffer(*b);
|
||||
*b = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.size = size,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "transform buffer"
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < js_arrlen(array); i++)
|
||||
ms[i] = transform2mat(js2transform(js_getpropidx(array, i)));
|
||||
|
||||
sg_append_buffer(*b, (&(sg_range){
|
||||
.ptr = ms,
|
||||
.size = size
|
||||
}));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_spdraw,
|
||||
|
@ -982,7 +1047,6 @@ JSC_CCALL(render_setpipeline,
|
|||
sg_apply_pipeline(p);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_text_ssbo, return sg_buffer2js(&text_ssbo))
|
||||
JSC_CCALL(render_screencolor,
|
||||
texture *t = calloc(sizeof(*t), 1);
|
||||
t->id = screencolor;
|
||||
|
@ -996,14 +1060,14 @@ JSC_CCALL(render_imgui_end, gui_endframe())
|
|||
JSC_CCALL(render_imgui_init, return gui_init(js))
|
||||
|
||||
static const JSCFunctionListEntry js_render_funcs[] = {
|
||||
MIST_FUNC_DEF(render, flushtext, 0),
|
||||
MIST_FUNC_DEF(render, flushtext, 1),
|
||||
MIST_FUNC_DEF(render, camera_screen2world, 2),
|
||||
MIST_FUNC_DEF(render, make_textssbo, 0),
|
||||
MIST_FUNC_DEF(render, viewport, 4),
|
||||
MIST_FUNC_DEF(render, end_pass, 0),
|
||||
MIST_FUNC_DEF(render, commit, 0),
|
||||
MIST_FUNC_DEF(render, glue_pass, 0),
|
||||
MIST_FUNC_DEF(render, text_size, 3),
|
||||
MIST_FUNC_DEF(render, text_ssbo, 0),
|
||||
MIST_FUNC_DEF(render, set_camera, 1),
|
||||
MIST_FUNC_DEF(render, pipeline, 1),
|
||||
MIST_FUNC_DEF(render, setuniv3, 2),
|
||||
|
@ -1022,7 +1086,9 @@ static const JSCFunctionListEntry js_render_funcs[] = {
|
|||
MIST_FUNC_DEF(render, gfx_gui, 0),
|
||||
MIST_FUNC_DEF(render, imgui_end, 0),
|
||||
MIST_FUNC_DEF(render, imgui_init, 0),
|
||||
MIST_FUNC_DEF(render, make_t_ssbo, 1)
|
||||
MIST_FUNC_DEF(render, make_t_ssbo, 2),
|
||||
MIST_FUNC_DEF(render, make_particle_ssbo, 2),
|
||||
MIST_FUNC_DEF(render, make_sprite_ssbo, 2)
|
||||
};
|
||||
|
||||
JSC_CCALL(gui_scissor, sg_apply_scissor_rect(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0))
|
||||
|
@ -1078,6 +1144,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_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 */
|
||||
HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n)
|
||||
{
|
||||
|
@ -1130,10 +1215,261 @@ JSC_CCALL(vector_inflate,
|
|||
arrfree(p);
|
||||
)
|
||||
|
||||
JSC_CCALL(vector_rotate,
|
||||
HMM_Vec2 vec = js2vec2(argv[0]);
|
||||
float r = HMM_LenV2(vec);
|
||||
double angle = js2angle(argv[1]);
|
||||
angle += atan2(vec.y,vec.x);
|
||||
vec.x = r*cos(angle);
|
||||
vec.y = r*sin(angle);
|
||||
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[] = {
|
||||
MIST_FUNC_DEF(vector, dot,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, 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])))
|
||||
|
@ -1159,13 +1495,18 @@ static const JSCFunctionListEntry js_input_funcs[] = {
|
|||
JSC_CCALL(prosperon_phys2d_step, phys2d_update(js2number(argv[0])))
|
||||
JSC_CCALL(prosperon_window_render, openglRender(js2vec2(argv[0])))
|
||||
JSC_CCALL(prosperon_guid,
|
||||
uint8_t bytes[16];
|
||||
for (int i = 0; i < 16; i++) bytes[i] = rand()%256;
|
||||
char uuid[37];
|
||||
snprintf(uuid, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
|
||||
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
|
||||
return str2js(uuid);
|
||||
int bits = 32;
|
||||
char guid[33];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int r = rand();
|
||||
for (int j = 0; j < 8; j++) {
|
||||
guid[i*8+j] = "0123456789abcdef"[r%16];
|
||||
r /= 16;
|
||||
}
|
||||
}
|
||||
|
||||
guid[32] = 0;
|
||||
return str2js(guid);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_prosperon_funcs[] = {
|
||||
|
@ -1235,8 +1576,32 @@ static const JSCFunctionListEntry js_audio_funcs[] = {
|
|||
|
||||
JSC_CCALL(profile_now, return number2js(stm_now()))
|
||||
|
||||
static JSValue instr_v = JS_UNDEFINED;
|
||||
int iiihandle(JSRuntime *rt, void *data)
|
||||
{
|
||||
script_call_sym(instr_v, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSC_CCALL(profile_gather,
|
||||
int count = js2number(argv[0]);
|
||||
instr_v = JS_DupValue(js, argv[1]);
|
||||
JS_SetInterruptHandler(rt, iiihandle, NULL);
|
||||
)
|
||||
|
||||
JSC_CCALL(profile_gather_rate,
|
||||
JS_SetInterruptRate(js2number(argv[0]));
|
||||
)
|
||||
|
||||
JSC_CCALL(profile_gather_stop,
|
||||
JS_SetInterruptHandler(rt,NULL,NULL);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_profile_funcs[] = {
|
||||
MIST_FUNC_DEF(profile,now,0),
|
||||
MIST_FUNC_DEF(profile,gather,2),
|
||||
MIST_FUNC_DEF(profile,gather_rate,1),
|
||||
MIST_FUNC_DEF(profile,gather_stop,0),
|
||||
};
|
||||
|
||||
JSC_SCALL(io_exists, ret = boolean2js(fexists(str)))
|
||||
|
@ -1469,29 +1834,6 @@ static const JSCFunctionListEntry js_physics_funcs[] = {
|
|||
CGETSET_ADD(physics, collision_persistence),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_emitter_funcs[] = {
|
||||
CGETSET_ADD(emitter, life),
|
||||
CGETSET_ADD(emitter, life_var),
|
||||
CGETSET_ADD(emitter, speed),
|
||||
CGETSET_ADD(emitter, variation),
|
||||
CGETSET_ADD(emitter, divergence),
|
||||
CGETSET_ADD(emitter, scale),
|
||||
CGETSET_ADD(emitter, scale_var),
|
||||
CGETSET_ADD(emitter, grow_for),
|
||||
CGETSET_ADD(emitter, shrink_for),
|
||||
CGETSET_ADD(emitter, max),
|
||||
CGETSET_ADD(emitter, explosiveness),
|
||||
CGETSET_ADD(emitter, bounce),
|
||||
CGETSET_ADD(emitter, collision_mask),
|
||||
CGETSET_ADD(emitter, die_after_collision),
|
||||
CGETSET_ADD(emitter, persist),
|
||||
CGETSET_ADD(emitter, persist_var),
|
||||
CGETSET_ADD(emitter, warp_mask),
|
||||
MIST_FUNC_DEF(emitter, emit, 1),
|
||||
MIST_FUNC_DEF(emitter, step, 1),
|
||||
MIST_FUNC_DEF(emitter, draw, 1)
|
||||
};
|
||||
|
||||
JSC_GETSET(transform, pos, vec3)
|
||||
JSC_GETSET(transform, scale, vec3)
|
||||
JSC_GETSET(transform, rotation, quat)
|
||||
|
@ -1502,6 +1844,7 @@ JSC_CCALL(transform_lookat,
|
|||
transform *go = js2transform(self);
|
||||
HMM_Mat4 m = HMM_LookAt_LH(go->pos, point, vUP);
|
||||
go->rotation = HMM_M4ToQ_LH(m);
|
||||
go->dirty = true;
|
||||
)
|
||||
|
||||
JSC_CCALL(transform_rotate,
|
||||
|
@ -1509,6 +1852,7 @@ JSC_CCALL(transform_rotate,
|
|||
transform *t = js2transform(self);
|
||||
HMM_Quat rot = HMM_QFromAxisAngle_LH(axis, js2angle(argv[1]));
|
||||
t->rotation = HMM_MulQ(t->rotation,rot);
|
||||
t->dirty = true;
|
||||
)
|
||||
|
||||
JSC_CCALL(transform_angle,
|
||||
|
@ -1525,15 +1869,34 @@ JSC_CCALL(transform_direction,
|
|||
return vec32js(HMM_QVRot(js2vec3(argv[0]), t->rotation));
|
||||
)
|
||||
|
||||
JSC_CCALL(transform_phys2d,
|
||||
transform *t = js2transform(self);
|
||||
HMM_Vec2 v = js2vec2(argv[0]);
|
||||
float av = js2number(argv[1]);
|
||||
float dt = js2number(argv[2]);
|
||||
transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0});
|
||||
HMM_Quat rot = HMM_QFromAxisAngle_LH((HMM_Vec3){0,0,1}, av*dt);
|
||||
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[] = {
|
||||
CGETSET_ADD(transform, pos),
|
||||
CGETSET_ADD(transform, scale),
|
||||
CGETSET_ADD(transform, rotation),
|
||||
MIST_FUNC_DEF(transform, phys2d, 3),
|
||||
MIST_FUNC_DEF(transform, move, 1),
|
||||
MIST_FUNC_DEF(transform, rotate, 2),
|
||||
MIST_FUNC_DEF(transform, angle, 1),
|
||||
MIST_FUNC_DEF(transform, lookat, 1),
|
||||
MIST_FUNC_DEF(transform, direction, 1),
|
||||
MIST_FUNC_DEF(transform, unit, 0),
|
||||
};
|
||||
|
||||
JSC_GETSET(dsp_node, pass, boolean)
|
||||
|
@ -2036,6 +2399,9 @@ static const JSCFunctionListEntry js_texture_funcs[] = {
|
|||
MIST_FUNC_DEF(texture, blit, 5)
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_timer_funcs[] = {
|
||||
};
|
||||
|
||||
JSC_GETSET(font, linegap, number)
|
||||
JSC_GET(font, height, number)
|
||||
|
||||
|
@ -2380,11 +2746,6 @@ JSC_SCALL(os_make_model,
|
|||
js_setpropstr(v, "material", material2js(me->primitives[0].mat));
|
||||
return v;
|
||||
)
|
||||
JSC_CCALL(os_make_emitter,
|
||||
emitter *e = make_emitter();
|
||||
ret = emitter2js(e);
|
||||
js_setpropstr(ret, "buffer", sg_buffer2js(&e->buffer));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_buffer,
|
||||
int type = js2number(argv[1]);
|
||||
|
@ -2565,7 +2926,6 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||
MIST_FUNC_DEF(os, make_font, 2),
|
||||
MIST_FUNC_DEF(os, make_model, 1),
|
||||
MIST_FUNC_DEF(os, make_transform, 0),
|
||||
MIST_FUNC_DEF(os, make_emitter, 0),
|
||||
MIST_FUNC_DEF(os, make_buffer, 1),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 4),
|
||||
MIST_FUNC_DEF(os, make_cylinder, 2),
|
||||
|
@ -2598,7 +2958,6 @@ void ffi_load() {
|
|||
QJSCLASSPREP_FUNCS(gameobject);
|
||||
QJSCLASSPREP_FUNCS(transform);
|
||||
QJSCLASSPREP_FUNCS(dsp_node);
|
||||
QJSCLASSPREP_FUNCS(emitter);
|
||||
QJSCLASSPREP_FUNCS(warp_gravity);
|
||||
QJSCLASSPREP_FUNCS(warp_damp);
|
||||
QJSCLASSPREP_FUNCS(texture);
|
||||
|
@ -2607,6 +2966,7 @@ void ffi_load() {
|
|||
QJSCLASSPREP_FUNCS(window);
|
||||
QJSCLASSPREP_FUNCS(datastream);
|
||||
QJSCLASSPREP_FUNCS(cpShape);
|
||||
QJSCLASSPREP_FUNCS(timer);
|
||||
|
||||
QJSGLOBALCLASS(nota);
|
||||
QJSGLOBALCLASS(input);
|
||||
|
@ -2659,6 +3019,10 @@ void ffi_load() {
|
|||
JSSTATIC(damped_spring, 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ static JSClassDef js_##TYPE##_class = {\
|
|||
.finalizer = js_##TYPE##_finalizer,\
|
||||
};\
|
||||
TYPE *js2##TYPE (JSValue val) { \
|
||||
if (JS_IsUndefined(val)) return NULL; \
|
||||
assert(JS_GetClassID(val) == js_##TYPE##_id); \
|
||||
return JS_GetOpaque(val,js_##TYPE##_id); \
|
||||
}\
|
||||
|
|
|
@ -508,7 +508,7 @@ sg_bindings primitive_bind(primitive *p)
|
|||
|
||||
void model_draw_go(model *model, transform *go)
|
||||
{
|
||||
HMM_Mat4 gom = transform2mat(*go);
|
||||
HMM_Mat4 gom = transform2mat(go);
|
||||
|
||||
animation_run(&model->anim, apptime());
|
||||
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
#include "particle.h"
|
||||
#include "stb_ds.h"
|
||||
#include "render.h"
|
||||
#include "2dphysics.h"
|
||||
#include "math.h"
|
||||
#include "log.h"
|
||||
|
||||
emitter *make_emitter() {
|
||||
emitter *e = calloc(sizeof(*e),1);
|
||||
|
||||
e->max = 20;
|
||||
arrsetcap(e->particles, 10);
|
||||
for (int i = 0; i < arrlen(e->particles); i++)
|
||||
e->particles[i].life = 0;
|
||||
|
||||
e->life = 10;
|
||||
e->tte = lerp(e->explosiveness, e->life/e->max, 0);
|
||||
e->scale = 1;
|
||||
e->speed = 20;
|
||||
e->buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(struct par_vert),
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.usage = SG_USAGE_STREAM
|
||||
});
|
||||
return e;
|
||||
}
|
||||
|
||||
void emitter_free(emitter *e)
|
||||
{
|
||||
arrfree(e->particles);
|
||||
arrfree(e->verts);
|
||||
free(e);
|
||||
}
|
||||
|
||||
/* Variate a value around variance. Variance between 0 and 1. */
|
||||
|
||||
float variate(float val, float variance)
|
||||
{
|
||||
return val + val*(frand(variance)-(variance/2));
|
||||
}
|
||||
|
||||
int emitter_spawn(emitter *e, transform *t)
|
||||
{
|
||||
if (arrlen(e->particles) == e->max) return 0;
|
||||
particle p = {0};
|
||||
p.life = e->life;
|
||||
p.pos = (HMM_Vec4){t->pos.x,t->pos.y,t->pos.z,0};
|
||||
HMM_Vec3 up = transform_direction(t, vFWD);
|
||||
float newan = (frand(e->divergence)-(e->divergence/2))*HMM_TurnToRad;
|
||||
HMM_Vec2 v2n = HMM_V2Rotate((HMM_Vec2){0,1}, newan);
|
||||
HMM_Vec3 norm = (HMM_Vec3){v2n.x, v2n.y,0};
|
||||
p.v = HMM_MulV4F((HMM_Vec4){norm.x,norm.y,norm.z,0}, variate(e->speed, e->variation));
|
||||
p.angle = 0.25;
|
||||
p.scale = variate(e->scale*t->scale.x, e->scale_var);
|
||||
arrput(e->particles,p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void emitter_emit(emitter *e, int count, transform *t)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
emitter_spawn(e, t);
|
||||
}
|
||||
|
||||
void emitter_draw(emitter *e)
|
||||
{
|
||||
if (arrlen(e->particles) == 0) return;
|
||||
arrsetlen(e->verts, arrlen(e->particles));
|
||||
for (int i = 0; i < arrlen(e->particles); i++) {
|
||||
if (e->particles[i].time >= e->particles[i].life) continue;
|
||||
particle *p = e->particles+i;
|
||||
e->verts[i].pos = p->pos.xy;
|
||||
e->verts[i].angle = p->angle;
|
||||
e->verts[i].scale = p->scale;
|
||||
/* if (p->time < e->grow_for)
|
||||
e->verts[i].scale = lerp(p->time/e->grow_for, 0, p->scale);
|
||||
else if (p->time > (p->life - e->shrink_for))
|
||||
e->verts[i].scale = lerp((p->time-(p->life-e->shrink_for))/e->shrink_for, p->scale, 0);*/
|
||||
e->verts[i].color = p->color;
|
||||
}
|
||||
|
||||
sg_range verts;
|
||||
verts.ptr = e->verts;
|
||||
verts.size = sizeof(*e->verts)*arrlen(e->verts);
|
||||
if (sg_query_buffer_will_overflow(e->buffer, verts.size)) {
|
||||
sg_destroy_buffer(e->buffer);
|
||||
e->buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = verts.size,
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.usage = SG_USAGE_STREAM
|
||||
});
|
||||
}
|
||||
|
||||
sg_append_buffer(e->buffer, &verts);
|
||||
}
|
||||
|
||||
void emitter_step(emitter *e, double dt, transform *t) {
|
||||
HMM_Vec4 g_accel = HMM_MulV4F((HMM_Vec4){cpSpaceGetGravity(space).x, cpSpaceGetGravity(space).y, 0, 0}, dt);
|
||||
|
||||
for (int i = 0; i < arrlen(e->particles); i++) {
|
||||
if (e->particles[i].time >= e->particles[i].life) continue;
|
||||
|
||||
//if (e->warp_mask & gravmask)
|
||||
// e->particles[i].v = HMM_AddV4(e->particles[i].v, g_accel);
|
||||
|
||||
e->particles[i].pos = HMM_AddV4(e->particles[i].pos, HMM_MulV4F(e->particles[i].v, dt));
|
||||
e->particles[i].angle += e->particles[i].av*dt;
|
||||
e->particles[i].time += dt;
|
||||
e->particles[i].color = sample_sampler(&e->color, e->particles[i].time/e->particles[i].life);
|
||||
e->particles[i].scale = e->scale;
|
||||
|
||||
if (e->particles[i].time >= e->particles[i].life)
|
||||
arrdelswap(e->particles, i);
|
||||
// else if (query_point(e->particles[i].pos.xy))
|
||||
// arrdelswap(e->particles,i);
|
||||
}
|
||||
|
||||
e->tte-=dt;
|
||||
float step = lerp(e->explosiveness, e->life/e->max,0);
|
||||
while (e->tte <= 0) {
|
||||
e->tte += step;
|
||||
if (!emitter_spawn(e, t)) break;
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
#ifndef PARTICLE_H
|
||||
#define PARTICLE_H
|
||||
|
||||
#include "HandmadeMath.h"
|
||||
#include "warp.h"
|
||||
#include "transform.h"
|
||||
#include "texture.h"
|
||||
#include "anim.h"
|
||||
#include "gameobject.h"
|
||||
#include "render.h"
|
||||
|
||||
typedef struct particle {
|
||||
HMM_Vec4 pos;
|
||||
HMM_Vec4 v; /* velocity */
|
||||
float angle;
|
||||
float av; /* angular velocity */
|
||||
float scale;
|
||||
double time;
|
||||
double life;
|
||||
HMM_Vec4 color;
|
||||
} particle;
|
||||
|
||||
#define SPRAY 0
|
||||
#define CLOUD 1
|
||||
#define MESH 2
|
||||
|
||||
typedef struct par_vert {
|
||||
HMM_Vec2 pos;
|
||||
float angle;
|
||||
float scale;
|
||||
HMM_Vec4 color;
|
||||
} par_vert;
|
||||
|
||||
typedef struct emitter {
|
||||
struct particle *particles;
|
||||
par_vert *verts;
|
||||
HMM_Vec3 *mesh; /* list of points to optionally spawn from */
|
||||
HMM_Vec3 *norm; /* norm at each point */
|
||||
int type; /* spray, cloud, or mesh */
|
||||
float explosiveness; /* 0 for a stream, 1 for all at once. Range of values allowed. */
|
||||
int max; /* number of particles */
|
||||
double life; /* how long a particle lasts */
|
||||
double life_var;
|
||||
/* SPRAY PARTICLE GEN */
|
||||
float speed; /* initial speed of particle */
|
||||
float variation; /* variation on speed */
|
||||
float divergence; /* angular degree of variation from emitter normal, up to 1 */
|
||||
float tumble; /* amount of random rotation of particles */
|
||||
float tumble_rate; /* tumble rotation */
|
||||
sampler color; /* color over particle lifetime */
|
||||
float scale;
|
||||
float scale_var;
|
||||
float grow_for; /* seconds to grow from small until scale */
|
||||
float shrink_for; /* seconds to shrink to small prior to its death */
|
||||
/* ROTATION AND COLLISION */
|
||||
int collision_mask; /* mask for collision */
|
||||
float bounce; /* bounce back after collision */
|
||||
/* PARTICLE SPAWN */
|
||||
int die_after_collision;
|
||||
float persist; /* how long to linger after death */
|
||||
float persist_var;
|
||||
/* TRAILS */
|
||||
warpmask warp_mask;
|
||||
double tte; /* time to emit */
|
||||
sg_buffer buffer;
|
||||
} emitter;
|
||||
|
||||
emitter *make_emitter();
|
||||
void emitter_free(emitter *e);
|
||||
|
||||
void emitter_emit(emitter *e, int count, transform *t);
|
||||
void emitter_step(emitter *e, double dt, transform *t);
|
||||
void emitter_draw(emitter *e);
|
||||
|
||||
#endif
|
|
@ -5,7 +5,6 @@
|
|||
#include "font.h"
|
||||
#include "gameobject.h"
|
||||
#include "log.h"
|
||||
#include "particle.h"
|
||||
#include "window.h"
|
||||
#include "model.h"
|
||||
#include "stb_ds.h"
|
||||
|
@ -149,8 +148,6 @@ void render_init() {
|
|||
sg_trace_hooks hh = sg_install_trace_hooks(&hooks);
|
||||
#endif
|
||||
|
||||
font_init();
|
||||
|
||||
sg_features feat = sg_query_features();
|
||||
TOPLEFT = feat.origin_top_left;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "jsffi.h"
|
||||
#include "stb_ds.h"
|
||||
#include "resources.h"
|
||||
#include <sokol/sokol_time.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ extern "C" {
|
|||
#include <time.h>
|
||||
|
||||
extern JSContext *js;
|
||||
extern JSRuntime *rt;
|
||||
|
||||
struct phys_cbs {
|
||||
JSValue begin;
|
||||
|
|
5885
source/engine/thirdparty/imgui/implot.cpp
vendored
Normal file
5885
source/engine/thirdparty/imgui/implot.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
1297
source/engine/thirdparty/imgui/implot.h
vendored
Normal file
1297
source/engine/thirdparty/imgui/implot.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1669
source/engine/thirdparty/imgui/implot_internal.h
vendored
Normal file
1669
source/engine/thirdparty/imgui/implot_internal.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
2808
source/engine/thirdparty/imgui/implot_items.cpp
vendored
Normal file
2808
source/engine/thirdparty/imgui/implot_items.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
source/engine/thirdparty/quickjs/cutils.h
vendored
6
source/engine/thirdparty/quickjs/cutils.h
vendored
|
@ -51,6 +51,12 @@
|
|||
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#define minimum_length(n) static n
|
||||
#else
|
||||
#define minimum_length(n) n
|
||||
#endif
|
||||
|
||||
typedef int BOOL;
|
||||
|
||||
#ifndef FALSE
|
||||
|
|
2
source/engine/thirdparty/quickjs/libbf.c
vendored
2
source/engine/thirdparty/quickjs/libbf.c
vendored
|
@ -136,6 +136,7 @@ static inline slimb_t ceil_div(slimb_t a, slimb_t b)
|
|||
return a / b;
|
||||
}
|
||||
|
||||
#ifdef USE_BF_DEC
|
||||
/* b must be >= 1 */
|
||||
static inline slimb_t floor_div(slimb_t a, slimb_t b)
|
||||
{
|
||||
|
@ -145,6 +146,7 @@ static inline slimb_t floor_div(slimb_t a, slimb_t b)
|
|||
return (a - b + 1) / b;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */
|
||||
static inline limb_t smod(slimb_t a, slimb_t b)
|
||||
|
|
33
source/engine/thirdparty/quickjs/libregexp.c
vendored
33
source/engine/thirdparty/quickjs/libregexp.c
vendored
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "cutils.h"
|
||||
#include "libregexp.h"
|
||||
#include "libunicode.h"
|
||||
|
||||
/*
|
||||
TODO:
|
||||
|
@ -141,32 +142,6 @@ static const uint16_t char_range_s[] = {
|
|||
0xFEFF, 0xFEFF + 1,
|
||||
};
|
||||
|
||||
BOOL lre_is_space(int c)
|
||||
{
|
||||
int i, n, low, high;
|
||||
n = (countof(char_range_s) - 1) / 2;
|
||||
for(i = 0; i < n; i++) {
|
||||
low = char_range_s[2 * i + 1];
|
||||
if (c < low)
|
||||
return FALSE;
|
||||
high = char_range_s[2 * i + 2];
|
||||
if (c < high)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint32_t const lre_id_start_table_ascii[4] = {
|
||||
/* $ A-Z _ a-z */
|
||||
0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE
|
||||
};
|
||||
|
||||
uint32_t const lre_id_continue_table_ascii[4] = {
|
||||
/* $ 0-9 A-Z _ a-z */
|
||||
0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE
|
||||
};
|
||||
|
||||
|
||||
static const uint16_t char_range_w[] = {
|
||||
4,
|
||||
0x0030, 0x0039 + 1,
|
||||
|
@ -186,7 +161,7 @@ typedef enum {
|
|||
CHAR_RANGE_W,
|
||||
} CharRangeEnum;
|
||||
|
||||
static const uint16_t *char_range_table[] = {
|
||||
static const uint16_t * const char_range_table[] = {
|
||||
char_range_d,
|
||||
char_range_s,
|
||||
char_range_w,
|
||||
|
@ -1513,15 +1488,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
|
||||
if (dbuf_error(&s->byte_code))
|
||||
goto out_of_memory;
|
||||
}
|
||||
/* the spec tells that if there is no advance when
|
||||
running the atom after the first quant_min times,
|
||||
then there is no match. We remove this test when we
|
||||
are sure the atom always advances the position. */
|
||||
add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start,
|
||||
s->byte_code.size - last_atom_start);
|
||||
} else {
|
||||
add_zero_advance_check = FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
int len, pos;
|
||||
|
|
43
source/engine/thirdparty/quickjs/libregexp.h
vendored
43
source/engine/thirdparty/quickjs/libregexp.h
vendored
|
@ -25,10 +25,7 @@
|
|||
#define LIBREGEXP_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libunicode.h"
|
||||
|
||||
#define LRE_BOOL int /* for documentation purposes */
|
||||
#include <stdint.h>
|
||||
|
||||
#define LRE_FLAG_GLOBAL (1 << 0)
|
||||
#define LRE_FLAG_IGNORECASE (1 << 1)
|
||||
|
@ -50,43 +47,9 @@ int lre_exec(uint8_t **capture,
|
|||
int cbuf_type, void *opaque);
|
||||
|
||||
int lre_parse_escape(const uint8_t **pp, int allow_utf16);
|
||||
LRE_BOOL lre_is_space(int c);
|
||||
|
||||
/* must be provided by the user */
|
||||
LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
|
||||
/* must be provided by the user, return non zero if overflow */
|
||||
int lre_check_stack_overflow(void *opaque, size_t alloca_size);
|
||||
void *lre_realloc(void *opaque, void *ptr, size_t size);
|
||||
|
||||
/* JS identifier test */
|
||||
extern uint32_t const lre_id_start_table_ascii[4];
|
||||
extern uint32_t const lre_id_continue_table_ascii[4];
|
||||
|
||||
static inline int lre_js_is_ident_first(int c)
|
||||
{
|
||||
if ((uint32_t)c < 128) {
|
||||
return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
|
||||
} else {
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_start(c);
|
||||
#else
|
||||
return !lre_is_space(c);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline int lre_js_is_ident_next(int c)
|
||||
{
|
||||
if ((uint32_t)c < 128) {
|
||||
return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
|
||||
} else {
|
||||
/* ZWNJ and ZWJ are accepted in identifiers */
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
|
||||
#else
|
||||
return !lre_is_space(c) || c == 0x200C || c == 0x200D;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#undef LRE_BOOL
|
||||
|
||||
#endif /* LIBREGEXP_H */
|
||||
|
|
161
source/engine/thirdparty/quickjs/libunicode-table.h
vendored
161
source/engine/thirdparty/quickjs/libunicode-table.h
vendored
|
@ -189,9 +189,13 @@ static const uint8_t unicode_prop_Cased1_table[196] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_Cased1_index[21] = {
|
||||
0xb9, 0x02, 0xe0, 0xc0, 0x1d, 0x20, 0xe5, 0x2c,
|
||||
0x20, 0xb1, 0x07, 0x21, 0xc1, 0xd6, 0x21, 0x4a,
|
||||
0xf1, 0x01, 0x8a, 0xf1, 0x01,
|
||||
0xb9, 0x02, 0xe0, // 002B9 at 39
|
||||
0xc0, 0x1d, 0x20, // 01DC0 at 65
|
||||
0xe5, 0x2c, 0x20, // 02CE5 at 97
|
||||
0xb1, 0x07, 0x21, // 107B1 at 129
|
||||
0xc1, 0xd6, 0x21, // 1D6C1 at 161
|
||||
0x4a, 0xf1, 0x01, // 1F14A at 192
|
||||
0x8a, 0xf1, 0x01, // 1F18A at 224 (upper bound)
|
||||
};
|
||||
|
||||
static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
|
||||
|
@ -291,15 +295,29 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_Case_Ignorable_index[69] = {
|
||||
0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a,
|
||||
0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f,
|
||||
0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20,
|
||||
0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0,
|
||||
0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56,
|
||||
0xfe, 0x20, 0xb1, 0x07, 0x01, 0x75, 0x10, 0x01,
|
||||
0xeb, 0x12, 0x21, 0x41, 0x16, 0x01, 0x5c, 0x1a,
|
||||
0x01, 0x43, 0x1f, 0x01, 0x2e, 0xcf, 0x41, 0x25,
|
||||
0xe0, 0x01, 0xf0, 0x01, 0x0e,
|
||||
0xbe, 0x05, 0x00, // 005BE at 32
|
||||
0xfe, 0x07, 0x00, // 007FE at 64
|
||||
0x52, 0x0a, 0xa0, // 00A52 at 101
|
||||
0xc1, 0x0b, 0x00, // 00BC1 at 128
|
||||
0x82, 0x0d, 0x00, // 00D82 at 160
|
||||
0x3f, 0x10, 0x80, // 0103F at 196
|
||||
0xd4, 0x17, 0x40, // 017D4 at 226
|
||||
0xcf, 0x1a, 0x20, // 01ACF at 257
|
||||
0xf5, 0x1c, 0x00, // 01CF5 at 288
|
||||
0x80, 0x20, 0x00, // 02080 at 320
|
||||
0x16, 0xa0, 0x00, // 0A016 at 352
|
||||
0xc6, 0xa8, 0x00, // 0A8C6 at 384
|
||||
0xc2, 0xaa, 0x60, // 0AAC2 at 419
|
||||
0x56, 0xfe, 0x20, // 0FE56 at 449
|
||||
0xb1, 0x07, 0x01, // 107B1 at 480
|
||||
0x75, 0x10, 0x01, // 11075 at 512
|
||||
0xeb, 0x12, 0x21, // 112EB at 545
|
||||
0x41, 0x16, 0x01, // 11641 at 576
|
||||
0x5c, 0x1a, 0x01, // 11A5C at 608
|
||||
0x43, 0x1f, 0x01, // 11F43 at 640
|
||||
0x2e, 0xcf, 0x41, // 1CF2E at 674
|
||||
0x25, 0xe0, 0x01, // 1E025 at 704
|
||||
0xf0, 0x01, 0x0e, // E01F0 at 736 (upper bound)
|
||||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Start_table[1100] = {
|
||||
|
@ -444,20 +462,41 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Start_index[105] = {
|
||||
0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09,
|
||||
0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b,
|
||||
0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00,
|
||||
0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d,
|
||||
0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00,
|
||||
0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20,
|
||||
0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02,
|
||||
0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3,
|
||||
0x0c, 0x21, 0x73, 0x11, 0x61, 0x34, 0x13, 0x01,
|
||||
0x1b, 0x17, 0x21, 0x8a, 0x1a, 0x01, 0x34, 0x1f,
|
||||
0x21, 0xbf, 0x6a, 0x01, 0x23, 0xb1, 0xa1, 0xad,
|
||||
0xd4, 0x01, 0x6f, 0xd7, 0x01, 0xff, 0xe7, 0x61,
|
||||
0x5e, 0xee, 0x01, 0xe1, 0xeb, 0x22, 0xb0, 0x23,
|
||||
0x03,
|
||||
0xf6, 0x03, 0x20, // 003F6 at 33
|
||||
0xa6, 0x07, 0x00, // 007A6 at 64
|
||||
0xa9, 0x09, 0x20, // 009A9 at 97
|
||||
0xb1, 0x0a, 0x00, // 00AB1 at 128
|
||||
0xba, 0x0b, 0x20, // 00BBA at 161
|
||||
0x3b, 0x0d, 0x20, // 00D3B at 193
|
||||
0xc7, 0x0e, 0x20, // 00EC7 at 225
|
||||
0x49, 0x12, 0x00, // 01249 at 256
|
||||
0x9b, 0x16, 0x00, // 0169B at 288
|
||||
0xac, 0x19, 0x00, // 019AC at 320
|
||||
0xc0, 0x1d, 0x80, // 01DC0 at 356
|
||||
0x80, 0x20, 0x20, // 02080 at 385
|
||||
0x70, 0x2d, 0x00, // 02D70 at 416
|
||||
0x00, 0x32, 0x00, // 03200 at 448
|
||||
0xda, 0xa7, 0x00, // 0A7DA at 480
|
||||
0x4c, 0xaa, 0x20, // 0AA4C at 513
|
||||
0xc7, 0xd7, 0x20, // 0D7C7 at 545
|
||||
0xfc, 0xfd, 0x20, // 0FDFC at 577
|
||||
0x9d, 0x02, 0x21, // 1029D at 609
|
||||
0x96, 0x05, 0x01, // 10596 at 640
|
||||
0xf3, 0x08, 0x01, // 108F3 at 672
|
||||
0xb3, 0x0c, 0x21, // 10CB3 at 705
|
||||
0x73, 0x11, 0x61, // 11173 at 739
|
||||
0x34, 0x13, 0x01, // 11334 at 768
|
||||
0x1b, 0x17, 0x21, // 1171B at 801
|
||||
0x8a, 0x1a, 0x01, // 11A8A at 832
|
||||
0x34, 0x1f, 0x21, // 11F34 at 865
|
||||
0xbf, 0x6a, 0x01, // 16ABF at 896
|
||||
0x23, 0xb1, 0xa1, // 1B123 at 933
|
||||
0xad, 0xd4, 0x01, // 1D4AD at 960
|
||||
0x6f, 0xd7, 0x01, // 1D76F at 992
|
||||
0xff, 0xe7, 0x61, // 1E7FF at 1027
|
||||
0x5e, 0xee, 0x01, // 1EE5E at 1056
|
||||
0xe1, 0xeb, 0x22, // 2EBE1 at 1089
|
||||
0xb0, 0x23, 0x03, // 323B0 at 1120 (upper bound)
|
||||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Continue1_table[660] = {
|
||||
|
@ -547,14 +586,27 @@ static const uint8_t unicode_prop_ID_Continue1_table[660] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Continue1_index[63] = {
|
||||
0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a,
|
||||
0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7,
|
||||
0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00,
|
||||
0x41, 0x20, 0x00, 0x0c, 0xa8, 0x80, 0x37, 0xaa,
|
||||
0x20, 0x50, 0xfe, 0x20, 0x3a, 0x0d, 0x21, 0x74,
|
||||
0x11, 0x01, 0x5a, 0x14, 0x21, 0x44, 0x19, 0x81,
|
||||
0x5a, 0x1d, 0xa1, 0xf5, 0x6a, 0x21, 0x45, 0xd2,
|
||||
0x41, 0xaf, 0xe2, 0x21, 0xf0, 0x01, 0x0e,
|
||||
0xfa, 0x06, 0x00, // 006FA at 32
|
||||
0x70, 0x09, 0x00, // 00970 at 64
|
||||
0xf0, 0x0a, 0x40, // 00AF0 at 98
|
||||
0x57, 0x0c, 0x00, // 00C57 at 128
|
||||
0xf0, 0x0d, 0x60, // 00DF0 at 163
|
||||
0xc7, 0x0f, 0x20, // 00FC7 at 193
|
||||
0xea, 0x17, 0x40, // 017EA at 226
|
||||
0x05, 0x1b, 0x00, // 01B05 at 256
|
||||
0x41, 0x20, 0x00, // 02041 at 288
|
||||
0x0c, 0xa8, 0x80, // 0A80C at 324
|
||||
0x37, 0xaa, 0x20, // 0AA37 at 353
|
||||
0x50, 0xfe, 0x20, // 0FE50 at 385
|
||||
0x3a, 0x0d, 0x21, // 10D3A at 417
|
||||
0x74, 0x11, 0x01, // 11174 at 448
|
||||
0x5a, 0x14, 0x21, // 1145A at 481
|
||||
0x44, 0x19, 0x81, // 11944 at 516
|
||||
0x5a, 0x1d, 0xa1, // 11D5A at 549
|
||||
0xf5, 0x6a, 0x21, // 16AF5 at 577
|
||||
0x45, 0xd2, 0x41, // 1D245 at 610
|
||||
0xaf, 0xe2, 0x21, // 1E2AF at 641
|
||||
0xf0, 0x01, 0x0e, // E01F0 at 672 (upper bound)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
|
@ -676,17 +728,35 @@ static const uint8_t unicode_cc_table[899] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_cc_index[87] = {
|
||||
0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05,
|
||||
0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c,
|
||||
0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00,
|
||||
0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10,
|
||||
0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3,
|
||||
0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00,
|
||||
0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab,
|
||||
0x00, 0x39, 0x0a, 0x01, 0x51, 0x0f, 0x01, 0x73,
|
||||
0x11, 0x01, 0x75, 0x13, 0x01, 0x2b, 0x17, 0x21,
|
||||
0x3f, 0x1c, 0x21, 0x9e, 0xbc, 0x21, 0x08, 0xe0,
|
||||
0x01, 0x44, 0xe9, 0x01, 0x4b, 0xe9, 0x01,
|
||||
0x4d, 0x03, 0x00, // 0034D at 32
|
||||
0x97, 0x05, 0x20, // 00597 at 65
|
||||
0xc6, 0x05, 0x00, // 005C6 at 96
|
||||
0xe7, 0x06, 0x00, // 006E7 at 128
|
||||
0x45, 0x07, 0x00, // 00745 at 160
|
||||
0x9c, 0x08, 0x00, // 0089C at 192
|
||||
0x4d, 0x09, 0x00, // 0094D at 224
|
||||
0x3c, 0x0b, 0x00, // 00B3C at 256
|
||||
0x3d, 0x0d, 0x00, // 00D3D at 288
|
||||
0x36, 0x0f, 0x00, // 00F36 at 320
|
||||
0x38, 0x10, 0x20, // 01038 at 353
|
||||
0x3a, 0x19, 0x00, // 0193A at 384
|
||||
0xcb, 0x1a, 0x20, // 01ACB at 417
|
||||
0xd3, 0x1c, 0x00, // 01CD3 at 448
|
||||
0xcf, 0x1d, 0x00, // 01DCF at 480
|
||||
0xe2, 0x20, 0x00, // 020E2 at 512
|
||||
0x2e, 0x30, 0x20, // 0302E at 545
|
||||
0x2b, 0xa9, 0x20, // 0A92B at 577
|
||||
0xed, 0xab, 0x00, // 0ABED at 608
|
||||
0x39, 0x0a, 0x01, // 10A39 at 640
|
||||
0x51, 0x0f, 0x01, // 10F51 at 672
|
||||
0x73, 0x11, 0x01, // 11173 at 704
|
||||
0x75, 0x13, 0x01, // 11375 at 736
|
||||
0x2b, 0x17, 0x21, // 1172B at 769
|
||||
0x3f, 0x1c, 0x21, // 11C3F at 801
|
||||
0x9e, 0xbc, 0x21, // 1BC9E at 833
|
||||
0x08, 0xe0, 0x01, // 1E008 at 864
|
||||
0x44, 0xe9, 0x01, // 1E944 at 896
|
||||
0x4b, 0xe9, 0x01, // 1E94B at 928 (upper bound)
|
||||
};
|
||||
|
||||
static const uint32_t unicode_decomp_table1[699] = {
|
||||
|
@ -4484,3 +4554,4 @@ static const uint16_t unicode_prop_len_table[] = {
|
|||
};
|
||||
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
/* 62 tables / 32261 bytes, 5 index / 345 bytes */
|
||||
|
|
130
source/engine/thirdparty/quickjs/libunicode.c
vendored
130
source/engine/thirdparty/quickjs/libunicode.c
vendored
|
@ -262,11 +262,7 @@ int lre_canonicalize(uint32_t c, BOOL is_unicode)
|
|||
|
||||
static uint32_t get_le24(const uint8_t *ptr)
|
||||
{
|
||||
#if defined(__x86__) || defined(__x86_64__)
|
||||
return *(uint16_t *)ptr | (ptr[2] << 16);
|
||||
#else
|
||||
return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define UNICODE_INDEX_BLOCK_LEN 32
|
||||
|
@ -317,6 +313,14 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table,
|
|||
return FALSE; /* outside the table */
|
||||
p = table + pos;
|
||||
bit = 0;
|
||||
/* Compressed run length encoding:
|
||||
00..3F: 2 packed lengths: 3-bit + 3-bit
|
||||
40..5F: 5-bits plus extra byte for length
|
||||
60..7F: 5-bits plus 2 extra bytes for length
|
||||
80..FF: 7-bit length
|
||||
lengths must be incremented to get character count
|
||||
Ranges alternate between false and true return value.
|
||||
*/
|
||||
for(;;) {
|
||||
b = *p++;
|
||||
if (b < 64) {
|
||||
|
@ -833,6 +837,13 @@ static int unicode_get_cc(uint32_t c)
|
|||
if (pos < 0)
|
||||
return 0;
|
||||
p = unicode_cc_table + pos;
|
||||
/* Compressed run length encoding:
|
||||
- 2 high order bits are combining class type
|
||||
- 0:0, 1:230, 2:extra byte linear progression, 3:extra byte
|
||||
- 00..2F: range length (add 1)
|
||||
- 30..37: 3-bit range-length + 1 extra byte
|
||||
- 38..3F: 3-bit range-length + 2 extra byte
|
||||
*/
|
||||
for(;;) {
|
||||
b = *p++;
|
||||
type = b >> 6;
|
||||
|
@ -1185,6 +1196,15 @@ static int unicode_general_category1(CharRange *cr, uint32_t gc_mask)
|
|||
p = unicode_gc_table;
|
||||
p_end = unicode_gc_table + countof(unicode_gc_table);
|
||||
c = 0;
|
||||
/* Compressed range encoding:
|
||||
initial byte:
|
||||
bits 0..4: category number (special case 31)
|
||||
bits 5..7: range length (add 1)
|
||||
special case bits 5..7 == 7: read an extra byte
|
||||
- 00..7F: range length (add 7 + 1)
|
||||
- 80..BF: 6-bits plus extra byte for range length (add 7 + 128)
|
||||
- C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384)
|
||||
*/
|
||||
while (p < p_end) {
|
||||
b = *p++;
|
||||
n = b >> 5;
|
||||
|
@ -1238,6 +1258,14 @@ static int unicode_prop1(CharRange *cr, int prop_idx)
|
|||
p_end = p + unicode_prop_len_table[prop_idx];
|
||||
c = 0;
|
||||
bit = 0;
|
||||
/* Compressed range encoding:
|
||||
00..3F: 2 packed lengths: 3-bit + 3-bit
|
||||
40..5F: 5-bits plus extra byte for length
|
||||
60..7F: 5-bits plus 2 extra bytes for length
|
||||
80..FF: 7-bit length
|
||||
lengths must be incremented to get character count
|
||||
Ranges alternate between false and true return value.
|
||||
*/
|
||||
while (p < p_end) {
|
||||
c0 = c;
|
||||
b = *p++;
|
||||
|
@ -1786,3 +1814,97 @@ int unicode_prop(CharRange *cr, const char *prop_name)
|
|||
}
|
||||
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
|
||||
/*---- lre codepoint categorizing functions ----*/
|
||||
|
||||
#define S UNICODE_C_SPACE
|
||||
#define D UNICODE_C_DIGIT
|
||||
#define X UNICODE_C_XDIGIT
|
||||
#define U UNICODE_C_UPPER
|
||||
#define L UNICODE_C_LOWER
|
||||
#define _ UNICODE_C_UNDER
|
||||
#define d UNICODE_C_DOLLAR
|
||||
|
||||
uint8_t const lre_ctype_bits[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, S, S, S, S, S, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
S, 0, 0, 0, d, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D,
|
||||
X|D, X|D, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, X|U, X|U, X|U, X|U, X|U, X|U, U,
|
||||
U, U, U, U, U, U, U, U,
|
||||
U, U, U, U, U, U, U, U,
|
||||
U, U, U, 0, 0, 0, 0, _,
|
||||
|
||||
0, X|L, X|L, X|L, X|L, X|L, X|L, L,
|
||||
L, L, L, L, L, L, L, L,
|
||||
L, L, L, L, L, L, L, L,
|
||||
L, L, L, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
S, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
#undef S
|
||||
#undef D
|
||||
#undef X
|
||||
#undef U
|
||||
#undef L
|
||||
#undef _
|
||||
#undef d
|
||||
|
||||
/* code point ranges for Zs,Zl or Zp property */
|
||||
static const uint16_t char_range_s[] = {
|
||||
10,
|
||||
0x0009, 0x000D + 1,
|
||||
0x0020, 0x0020 + 1,
|
||||
0x00A0, 0x00A0 + 1,
|
||||
0x1680, 0x1680 + 1,
|
||||
0x2000, 0x200A + 1,
|
||||
/* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */
|
||||
/* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */
|
||||
0x2028, 0x2029 + 1,
|
||||
0x202F, 0x202F + 1,
|
||||
0x205F, 0x205F + 1,
|
||||
0x3000, 0x3000 + 1,
|
||||
/* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */
|
||||
0xFEFF, 0xFEFF + 1,
|
||||
};
|
||||
|
||||
BOOL lre_is_space_non_ascii(uint32_t c)
|
||||
{
|
||||
size_t i, n;
|
||||
|
||||
n = countof(char_range_s);
|
||||
for(i = 5; i < n; i += 2) {
|
||||
uint32_t low = char_range_s[i];
|
||||
uint32_t high = char_range_s[i + 1];
|
||||
if (c < low)
|
||||
return FALSE;
|
||||
if (c < high)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
103
source/engine/thirdparty/quickjs/libunicode.h
vendored
103
source/engine/thirdparty/quickjs/libunicode.h
vendored
|
@ -24,27 +24,13 @@
|
|||
#ifndef LIBUNICODE_H
|
||||
#define LIBUNICODE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LRE_BOOL int /* for documentation purposes */
|
||||
#include <stdint.h>
|
||||
|
||||
/* define it to include all the unicode tables (40KB larger) */
|
||||
#define CONFIG_ALL_UNICODE
|
||||
|
||||
#define LRE_CC_RES_LEN_MAX 3
|
||||
|
||||
typedef enum {
|
||||
UNICODE_NFC,
|
||||
UNICODE_NFD,
|
||||
UNICODE_NFKC,
|
||||
UNICODE_NFKD,
|
||||
} UnicodeNormalizationEnum;
|
||||
|
||||
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
|
||||
int lre_canonicalize(uint32_t c, LRE_BOOL is_unicode);
|
||||
LRE_BOOL lre_is_cased(uint32_t c);
|
||||
LRE_BOOL lre_is_case_ignorable(uint32_t c);
|
||||
|
||||
/* char ranges */
|
||||
|
||||
typedef struct {
|
||||
|
@ -102,12 +88,14 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
|
|||
|
||||
int cr_invert(CharRange *cr);
|
||||
|
||||
int cr_regexp_canonicalize(CharRange *cr, LRE_BOOL is_unicode);
|
||||
int cr_regexp_canonicalize(CharRange *cr, int is_unicode);
|
||||
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
|
||||
LRE_BOOL lre_is_id_start(uint32_t c);
|
||||
LRE_BOOL lre_is_id_continue(uint32_t c);
|
||||
typedef enum {
|
||||
UNICODE_NFC,
|
||||
UNICODE_NFD,
|
||||
UNICODE_NFKC,
|
||||
UNICODE_NFKD,
|
||||
} UnicodeNormalizationEnum;
|
||||
|
||||
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
|
||||
UnicodeNormalizationEnum n_type,
|
||||
|
@ -115,13 +103,80 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
|
|||
|
||||
/* Unicode character range functions */
|
||||
|
||||
int unicode_script(CharRange *cr,
|
||||
const char *script_name, LRE_BOOL is_ext);
|
||||
int unicode_script(CharRange *cr, const char *script_name, int is_ext);
|
||||
int unicode_general_category(CharRange *cr, const char *gc_name);
|
||||
int unicode_prop(CharRange *cr, const char *prop_name);
|
||||
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
|
||||
int lre_canonicalize(uint32_t c, int is_unicode);
|
||||
|
||||
#undef LRE_BOOL
|
||||
/* Code point type categories */
|
||||
enum {
|
||||
UNICODE_C_SPACE = (1 << 0),
|
||||
UNICODE_C_DIGIT = (1 << 1),
|
||||
UNICODE_C_UPPER = (1 << 2),
|
||||
UNICODE_C_LOWER = (1 << 3),
|
||||
UNICODE_C_UNDER = (1 << 4),
|
||||
UNICODE_C_DOLLAR = (1 << 5),
|
||||
UNICODE_C_XDIGIT = (1 << 6),
|
||||
};
|
||||
extern uint8_t const lre_ctype_bits[256];
|
||||
|
||||
/* zero or non-zero return value */
|
||||
int lre_is_cased(uint32_t c);
|
||||
int lre_is_case_ignorable(uint32_t c);
|
||||
int lre_is_id_start(uint32_t c);
|
||||
int lre_is_id_continue(uint32_t c);
|
||||
|
||||
static inline int lre_is_space_byte(uint8_t c) {
|
||||
return lre_ctype_bits[c] & UNICODE_C_SPACE;
|
||||
}
|
||||
|
||||
static inline int lre_is_id_start_byte(uint8_t c) {
|
||||
return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
|
||||
UNICODE_C_UNDER | UNICODE_C_DOLLAR);
|
||||
}
|
||||
|
||||
static inline int lre_is_id_continue_byte(uint8_t c) {
|
||||
return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
|
||||
UNICODE_C_UNDER | UNICODE_C_DOLLAR |
|
||||
UNICODE_C_DIGIT);
|
||||
}
|
||||
|
||||
int lre_is_space_non_ascii(uint32_t c);
|
||||
|
||||
static inline int lre_is_space(uint32_t c) {
|
||||
if (c < 256)
|
||||
return lre_is_space_byte(c);
|
||||
else
|
||||
return lre_is_space_non_ascii(c);
|
||||
}
|
||||
|
||||
static inline int lre_js_is_ident_first(uint32_t c) {
|
||||
if (c < 128) {
|
||||
return lre_is_id_start_byte(c);
|
||||
} else {
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_start(c);
|
||||
#else
|
||||
return !lre_is_space_non_ascii(c);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline int lre_js_is_ident_next(uint32_t c) {
|
||||
if (c < 128) {
|
||||
return lre_is_id_continue_byte(c);
|
||||
} else {
|
||||
/* ZWNJ and ZWJ are accepted in identifiers */
|
||||
if (c >= 0x200C && c <= 0x200D)
|
||||
return TRUE;
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_continue(c);
|
||||
#else
|
||||
return !lre_is_space_non_ascii(c);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LIBUNICODE_H */
|
||||
|
|
690
source/engine/thirdparty/quickjs/quickjs.c
vendored
690
source/engine/thirdparty/quickjs/quickjs.c
vendored
File diff suppressed because it is too large
Load diff
26
source/engine/thirdparty/quickjs/quickjs.h
vendored
26
source/engine/thirdparty/quickjs/quickjs.h
vendored
|
@ -92,6 +92,7 @@ typedef struct JSRefCountHeader {
|
|||
} JSRefCountHeader;
|
||||
|
||||
void quickjs_set_dumpout(FILE *f);
|
||||
void JS_SetInterruptRate(int count);
|
||||
|
||||
#define JS_FLOAT64_NAN NAN
|
||||
|
||||
|
@ -635,7 +636,9 @@ static inline JS_BOOL JS_IsObject(JSValueConst v)
|
|||
|
||||
JSValue JS_Throw(JSContext *ctx, JSValue obj);
|
||||
JSValue JS_GetException(JSContext *ctx);
|
||||
JS_BOOL JS_HasException(JSContext *ctx);
|
||||
JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val);
|
||||
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, JS_BOOL flag);
|
||||
void JS_ResetUncatchableError(JSContext *ctx);
|
||||
JSValue JS_NewError(JSContext *ctx);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
|
||||
|
@ -684,6 +687,10 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
|
|||
return (JSValue)v;
|
||||
}
|
||||
|
||||
JS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
|
||||
JS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2);
|
||||
JS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
|
||||
|
||||
int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
|
||||
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
|
||||
static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
|
||||
|
@ -726,6 +733,8 @@ JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val)
|
|||
JSValue JS_NewArray(JSContext *ctx);
|
||||
int JS_IsArray(JSContext *ctx, JSValueConst val);
|
||||
|
||||
JSValue JS_NewDate(JSContext *ctx, double epoch_ms);
|
||||
|
||||
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
|
||||
JSAtom prop, JSValueConst receiver,
|
||||
JS_BOOL throw_ref_error);
|
||||
|
@ -824,6 +833,23 @@ JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
|
|||
JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len);
|
||||
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj);
|
||||
uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj);
|
||||
|
||||
typedef enum JSTypedArrayEnum {
|
||||
JS_TYPED_ARRAY_UINT8C = 0,
|
||||
JS_TYPED_ARRAY_INT8,
|
||||
JS_TYPED_ARRAY_UINT8,
|
||||
JS_TYPED_ARRAY_INT16,
|
||||
JS_TYPED_ARRAY_UINT16,
|
||||
JS_TYPED_ARRAY_INT32,
|
||||
JS_TYPED_ARRAY_UINT32,
|
||||
JS_TYPED_ARRAY_BIG_INT64,
|
||||
JS_TYPED_ARRAY_BIG_UINT64,
|
||||
JS_TYPED_ARRAY_FLOAT32,
|
||||
JS_TYPED_ARRAY_FLOAT64,
|
||||
} JSTypedArrayEnum;
|
||||
|
||||
JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
|
||||
JSTypedArrayEnum array_type);
|
||||
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
|
||||
size_t *pbyte_offset,
|
||||
size_t *pbyte_length,
|
||||
|
|
22
source/engine/timer.c
Normal file
22
source/engine/timer.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "timer.h"
|
||||
|
||||
#include "stb_ds.h"
|
||||
|
||||
timer *timers;
|
||||
|
||||
timer *timer_make()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void timer_free(timer *t)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void timer_update(double dt)
|
||||
{
|
||||
for (int i = 0; i < arrlen(timers); i++) {
|
||||
timers[i].remain -= dt;
|
||||
}
|
||||
}
|
13
source/engine/timer.h
Normal file
13
source/engine/timer.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef TIMER_H
|
||||
|
||||
typedef struct timer {
|
||||
double start;
|
||||
double remain;
|
||||
} timer;
|
||||
|
||||
|
||||
timer *timer_make();
|
||||
void timer_free(timer *t);
|
||||
void timer_update(double dt);
|
||||
|
||||
#endif
|
|
@ -5,16 +5,21 @@
|
|||
transform *make_transform()
|
||||
{
|
||||
transform *t = calloc(sizeof(transform),1);
|
||||
|
||||
t->scale = (HMM_Vec3){1,1,1};
|
||||
t->rotation = (HMM_Quat){0,0,0,1};
|
||||
t->dirty = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
void transform_free(transform *t) { free(t); }
|
||||
|
||||
void transform_apply(transform *t) { t->dirty = 1; }
|
||||
|
||||
void transform_move(transform *t, HMM_Vec3 v)
|
||||
{
|
||||
t->pos = HMM_AddV3(t->pos, v);
|
||||
t->dirty = 1;
|
||||
}
|
||||
|
||||
HMM_Vec3 transform_direction(transform *t, HMM_Vec3 dir)
|
||||
|
@ -42,7 +47,6 @@ HMM_Vec2 mat_right(HMM_Mat3 m) { return HMM_NormV2(m.Columns[0].XY); }
|
|||
float vec_angle(HMM_Vec2 a, HMM_Vec2 b) { return acos(HMM_DotV2(a,b)/(HMM_LenV2(a)*HMM_LenV2(b))); }
|
||||
float vec_dirangle(HMM_Vec2 a, HMM_Vec2 b) { return atan2(b.x, b.y) - atan2(a.x, a.y); }
|
||||
|
||||
|
||||
HMM_Vec3 mat3_t_pos(HMM_Mat4 m, HMM_Vec3 pos) { return HMM_MulM4V4(m, (HMM_Vec4){pos.X, pos.Y, pos.Z, 1}).XYZ; }
|
||||
|
||||
HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
|
||||
|
@ -51,8 +55,15 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
|
|||
return mat3_t_pos(m, dir);
|
||||
}
|
||||
|
||||
HMM_Mat4 transform2mat(transform t) {
|
||||
return HMM_M4TRS(t.pos, t.rotation, t.scale);
|
||||
HMM_Mat4 transform2mat(transform *t) {
|
||||
return HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||
|
||||
if (t->dirty) {
|
||||
t->cache = HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||
t->dirty = 0;
|
||||
}
|
||||
|
||||
return t->cache;
|
||||
}
|
||||
|
||||
HMM_Quat angle2rotation(float angle)
|
||||
|
|
|
@ -12,6 +12,7 @@ typedef struct transform {
|
|||
} transform;
|
||||
|
||||
transform *make_transform();
|
||||
void transform_apply(transform *t);
|
||||
void transform_free(transform *t);
|
||||
|
||||
#define VEC2_FMT "[%g,%g]"
|
||||
|
@ -33,7 +34,7 @@ float vec_dirangle(HMM_Vec2 a, HMM_Vec2 b);
|
|||
HMM_Vec3 mat3_t_pos(HMM_Mat4 m, HMM_Vec3 pos);
|
||||
HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir);
|
||||
|
||||
HMM_Mat4 transform2mat(transform t);
|
||||
HMM_Mat4 transform2mat(transform *t);
|
||||
transform mat2transform(HMM_Mat4 m);
|
||||
|
||||
HMM_Quat angle2rotation(float angle);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "resources.h"
|
||||
#include "spline.h"
|
||||
#include <stdio.h>
|
||||
#include "particle.h"
|
||||
#include "simplex.h"
|
||||
#include <wctype.h>
|
||||
|
||||
|
|
Loading…
Reference in a new issue