bezier spline controls

This commit is contained in:
John Alanbrook 2023-12-18 12:45:27 +00:00
parent b732d12bed
commit 444fb98125
12 changed files with 309 additions and 172 deletions

View file

@ -3,16 +3,16 @@
Register functions with built-in drawing callbacks to have code execute at particular points in time. Some drawing functions take world coordinates, while others take screen coordinates.
gui
Called before nk_gui. Screen space.
Called every frame.
draw
Called every frame. World space.
Called every frame.
debug
Called if drawing physics. World space.
Called if drawing physics.
gizmo
Called usually for editor purposes. World space.
Called on an object if it is selected in the editor.
# Mum

View file

@ -110,6 +110,7 @@
/* test the GC by forcing it before each object allocation */
//#define FORCE_GC_AT_MALLOC
#ifdef CONFIG_ATOMICS
#include <pthread.h>
#include <stdatomic.h>

View file

@ -1,5 +1,3 @@
/* Removing crud I don't like */
/* Functions that lead to bloated error prone javascript */
/* It is EMCA6 but without a lot of builtin objects and various functions. There are no:
* Promises and so on (Generators, async)
* WeakMaps and so on (weakset, weakref)
@ -10,7 +8,7 @@
In addition to the removal of a bunch of stuff as seen here.
Access prototypes through __proto__ instead of the long-winded Object.getProtoTypeOf.
*/
/*
Object.getPrototypeOf = undefined;
Object.setPrototypeOf = undefined;
Reflect = undefined;
@ -22,6 +20,7 @@ WeakMap = undefined;
Promise = undefined;
Set = undefined;
WeakSet = undefined;
*/
var fmt = {};
@ -1127,7 +1126,7 @@ Object.defineProperty(Array.prototype, 'find', {
}});
Object.defineProperty(Array.prototype, 'last', {
get: function() { return this[this.length-1]; },
value: function() { return this[this.length-1]; },
});
Object.defineProperty(Array.prototype, 'at', {

View file

@ -487,7 +487,7 @@ component.polygon2d = Object.copy(collider2d, {
gizmo() {
this.spoints.forEach(function(x) {
Debug.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
Shape.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
}, this);
this.points.forEach(function(x, i) {
@ -499,7 +499,8 @@ component.polygon2d = Object.copy(collider2d, {
if (!Object.hasOwn(this,'points'))
this.points = deep_copy(this.__proto__.points);
var p = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
var i = Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
var p = this.points[i];
if (p)
return make_point_obj(this, p);
@ -553,6 +554,7 @@ component.edge2d = Object.copy(collider2d, {
thickness:0,
/* if type === -1, point to point */
type: Spline.type.catmull,
C: 1, /* when in bezier, continuity required. 0, 1 or 2. */
looped: false,
angle: 3, /* maximum angle between two segments */
@ -612,30 +614,18 @@ component.edge2d = Object.copy(collider2d, {
}
if (this.type === Spline.type.catmull) {
if (this.looped) {
spoints.unshift(spoints[spoints.length-1]);
spoints.push(spoints[1]);
spoints.push(spoints[2]);
} else {
spoints.unshift(spoints[0].sub(spoints[1]).add(spoints[0]));
spoints.push(spoints[spoints.length-1].sub(spoints[spoints.length-2]).add(spoints[spoints.length-1]));
}
if (this.looped)
spoints = Spline.catmull_loop(spoints);
else
spoints = Spline.catmull_caps(spoints);
return Spline.sample_angle(this.type, spoints,this.angle);
}
var tp = [];
for (var i = 0; i < spoints.length-1; i++)
tp.push([spoints[i+1].sub(spoints[i]), spoints[i+1].sub(spoints[i])]);
spoints = spoints.map((p,i) => p.concat(tp[i]));
spoints = spoints.flat();
return Spline.sample_angle(this.type, spoints, this.angle);
},
boundingbox() {
return points2bb(this.points.map(x => x.scale(this.gameobject.scale)));
},
boundingbox() { return points2bb(this.points.map(x => x.scale(this.gameobject.scale))); },
hides: ['gameobject', 'id', 'shape'],
_enghook: make_edge2d,
@ -643,27 +633,50 @@ component.edge2d = Object.copy(collider2d, {
/* EDITOR */
gizmo() {
if (this.type === Spline.type.catmull) {
this.spoints().forEach(x => Debug.point(this.gameobject.this2world(x), 3, Color.teal));
this.cpoints.forEach((x,i) => Debug.numbered_point(this.gameobject.this2world(x), i));
this.spoints().forEach(x => Shape.point(this.gameobject.this2screen(x), 3, Color.teal));
this.cpoints.forEach((x,i) => Debug.numbered_point(this.gameobject.this2screen(x), i));
} else {
for (var i = 1; i < this.cpoints.length; i+=2) {
Debug.point(this.gameobject.this2world(this.cpoints[i]), 3, Color.green);
Debug.line([this.gameobject.this2world(this.cpoints[i-1]), this.gameobject.this2world(this.cpoints[i])], Color.yellow);
}
// for (var i = 0; i < this.cpoints.length; i+=3)
// Debug.numbered_point(this.gameobject.this2world(this.cpoints[
}
for (var i = 0; i < this.cpoints.length; i += 3)
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i]), i, Color.teal);
for (var i = 1; i < this.cpoints.length; i+=3) {
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i]), i, Color.green);
Debug.numbered_point(this.gameobject.this2screen(this.cpoints[i+1]), i+1, Color.green);
Shape.line([this.gameobject.this2screen(this.cpoints[i-1]), this.gameobject.this2screen(this.cpoints[i])], Color.yellow);
Shape.line([this.gameobject.this2screen(this.cpoints[i+1]), this.gameobject.this2screen(this.cpoints[i+2])], Color.yellow);
}
}
},
finish_center(change) {
this.cpoints = this.cpoints.map(function(x) { return x.sub(change); });
},
finish_center(change) { this.cpoints = this.cpoints.map(function(x) { return x.sub(change); }); },
pick(pos) {
var p = Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints);
if (p)
return make_point_obj(this, p);
var i = Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints);
var p = this.cpoints[i];
var that = this.gameobject;
var me = this;
if (p) {
var o = {
pos: p,
sync: me.sync.bind(me)
};
if (Spline.bezier_is_handle(this.cpoints,i))
o.move = function(d) {
d = that.dir_world2this(d);
p.x += d.x;
p.y += d.y;
Spline.bezier_cp_mirror(me.cpoints,i);
};
else
o.move = function(d) {
d = that.dir_world2this(d);
p.x += d.x;
p.y += d.y;
var pp = Spline.bezier_point_handles(me.cpoints,i);
pp.forEach(ph => me.cpoints[ph] = me.cpoints[ph].add(d));
}
return o;
}
return undefined;
},
@ -741,10 +754,25 @@ bucket.inputs['C-r'].doc = "Reverse the order of the spline's points.";
bucket.inputs['C-l'] = function() { this.looped = !this.looped};
bucket.inputs['C-l'].doc = "Toggle spline being looped.";
bucket.inputs['C-c'] = function() { this.type = Spline.type.catmull; };
bucket.inputs['C-c'] = function() {
switch(this.type) {
case Spline.type.bezier:
this.cpoints = Spline.bezier2catmull(this.cpoints);
break;
}
this.type = Spline.type.catmull;
};
bucket.inputs['C-c'].doc = "Set type of spline to catmull-rom.";
bucket.inputs['C-b'] = function() { this.type = Spline.type.bezier; };
bucket.inputs['C-b'] = function() {
switch(this.type) {
case Spline.type.catmull:
this.cpoints = Spline.catmull2bezier(Spline.catmull_caps(this.cpoints));
break;
}
this.type = Spline.type.bezier;
};
bucket.inputs['C-o'] = function() { this.type = -1; };
bucket.inputs['C-o'].doc = "Set spline to linear.";
@ -760,10 +788,10 @@ bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline.
bucket.inputs['C-lm'] = function() {
var idx = 0;
if (this.cpoints.length >= 2) {
idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 1000);
if (idx === -1) return;
}
if (this.cpoints.length >= 2)
idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 400);
console.say("new point");
if (idx === this.cpoints.length)
this.cpoints.push(this.gameobject.world2this(screen2world(Mouse.pos)));
@ -836,30 +864,10 @@ component.circle2d.impl = Object.mix({
/* ASSETS */
var Texture = {
mipmaps(path, x) {
cmd(94, path, x);
},
mipmaps(path, x) { cmd(94, path, x); },
sprite(path, x) {
cmd(95, path, x);
},
sprite(path, x) { cmd(95, path, x); },
};
var Resources = {
load(path) {
if (path in this)
return this[path];
var src = {};
this[path] = src;
src.path = path;
if (!IO.exists(`${path}.asset`))
return this[path];
var data = JSON.parse(IO.slurp(`${path}.asset`));
Object.assign(src,data);
return this[path];
},
};
Texture.mipmaps.doc = "Return true if the texture has mipmaps.";
Texture.sprite.do = "Return true if the texture is treated as a sprite.";

View file

@ -1,13 +1,35 @@
var Gizmos = {
pick_gameobject_points(worldpos, gameobject, points) {
var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
if (idx === -1) return undefined;
return points[idx];
},
};
/* All draw in screen space */
var Shape = {
circle(pos, radius, color) { cmd(115, pos, radius, color); },
point(pos,size,color) {
color ??= Color.blue;
Shape.circle(pos,size,color);
},
arrow(start, end, color, capsize) {
color ??= Color.red;
capsize ??= 4;
cmd(81, start, end, color, capsize);
},
poly(points, color) { cmd_points(0,points,color); },
box(pos, wh, color) {
color ??= Color.white;
cmd(53, pos, wh, color);
},
line(points, color, type, thickness) {
thickness ??= 1;
type ??= 0;
color ??= Color.white;
switch (type) {
case 0:
cmd(83, points, color, thickness);
}
},
};
var Debug = {
@ -27,38 +49,17 @@ var Debug = {
cmd(47, width, span, color);
},
point(pos, size, color) {
color = color ? color : Color.blue;
Shape.circle(pos, size, color);
// cmd(51, pos, size,color);
},
coordinate(pos, size, color) { GUI.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); },
arrow(start, end, color, capsize) {
color = color ? color : Color.red;
if (!capsize)
capsize = 4;
cmd(81, start, end, color, capsize);
},
poly(points, color) {
cmd_points(0,points,color);
},
boundingbox(bb, color) {
color ??= Color.white;
cmd_points(0, bb2points(bb), color);
},
box(pos, wh, color) {
numbered_point(pos, n, color) {
color ??= Color.white;
cmd(53, pos, wh, color);
},
numbered_point(pos, n) {
Debug.point(pos, 3);
GUI.text(n, pos.add([0,4]), 1);
Shape.point(pos, 3, color);
GUI.text(n, pos.add([0,4]), 1, color);
},
phys_drawing: false,
@ -75,22 +76,7 @@ var Debug = {
Register.debug.register(fn,obj);
},
gameobject(go) {
},
line(points, color, type, thickness) {
thickness ??= 1;
type ??= 0;
if (!color)
color = Color.white;
switch (type) {
case 0:
cmd(83, points, color, thickness);
}
},
gameobject(go) { cmd(15, go.body); },
draw_bb: false,
draw_gizmos: false,
@ -136,8 +122,8 @@ Debug.Options.Color = {
var Gizmos = {
pick_gameobject_points(worldpos, gameobject, points) {
var idx = Math.grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
if (idx === -1) return null;
return points[idx];
if (idx === -1) return undefined;
return idx;
},
};
@ -146,19 +132,51 @@ var Profile = {
ns(ticks) { return cmd(128, ticks); },
us(ticks) { return cmd(129, ticks); },
ms(ticks) { return cmd(130, ticks); },
best_t(ns) {
var e = ns;
var qq = 'ns';
if (e > 1000) {
e /= 1000;
qq = 'us';
if (e > 1000) {
e /= 1000;
qq = 'ms';
}
}
return {
time: e,
unit: qq
};
},
cpu(fn, times, q) {
times ??= 1;
q ??= "ns";
q ??= "unnamed";
var start = Profile.tick_now();
for (var i = 0; i < times; i++)
fn();
var elapsed = Profile.tick_now() - start;
Log.say(`Profiled in ${Profile[q](elapsed)/times} avg ${q}.`);
var avgt = Profile.best_t(elapsed/times);
var totalt = Profile.best_t(elapsed);
console.say(`Profile [${q}]: ${avgt.time.toFixed(3)} ${avgt.unit} average [${totalt.time.toFixed(3)} ${totalt.unit} for ${times} loops]`);
},
get fps() { return sys_cmd(8); },
};
Profile.test = {
barecall() { profile(0); },
unpack_num(n) { profile(1,n); },
unpack_array(n) { profile(2,n); },
pack_num() { profile(3); },
pack_string() { profile(6); },
unpack_string(s) { profile(4,s); },
unpack_32farr(a) { profile(5,a); },
};
Profile.cpu.doc = `Output the time it takes to do a given function n number of times. Provide 'q' as "ns", "us", or "ms" to output the time taken in the requested resolution.`;
/* These controls are available during editing, and during play of debug builds */

View file

@ -270,7 +270,7 @@ var editor = {
if (!dif) return;
if (this.snapshots.length !== 0) {
var ddif = ediff(dif, this.snapshots.last);
var ddif = ediff(dif, this.snapshots.last());
if (!ddif) return;
dif = ddif;
}
@ -344,7 +344,7 @@ var editor = {
root = root ? root + "." : root;
Object.entries(obj.objects).forEach(function(x) {
var p = root + x[0];
GUI.text(p, world2screen(x[1].worldpos()), 1, editor.color_depths[depth]);
GUI.text(p, x[1].screenpos(), 1, editor.color_depths[depth]);
editor.draw_objects_names(x[1], p, depth+1);
});
},
@ -367,14 +367,14 @@ var editor = {
color_depths: [],
draw() {
Debug.point(world2screen(this.cursor), 2, Color.green);
Shape.point(world2screen(this.cursor), 2, Color.green);
this.selectlist.forEach(x => {
if ('gizmo' in x && typeof x['gizmo'] === 'function' )
x.gizmo();
});
Debug.line(bb2points(cwh2bb([0,0],[Game.native.x,Game.native.y])).wrapped(1), Color.yellow);
Shape.line(bb2points(cwh2bb([0,0],[Game.native.x,Game.native.y])).wrapped(1), Color.yellow);
/* Draw selection box */
if (this.sel_start) {
@ -389,7 +389,7 @@ var editor = {
wh[1] = Math.abs(endpos[1] - this.sel_start[1]);
var bb = cwh2bb(c,wh);
Debug.boundingbox(bb, Color.Editor.select.alpha(0.1));
Debug.line(bb2points(bb).wrapped(1), Color.white);
Shape.line(bb2points(bb).wrapped(1), Color.white);
}
Debug.coordinate([0,0]);
@ -405,9 +405,7 @@ var editor = {
if (this.comp_info && this.sel_comp)
GUI.text(Input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
// GUI.text(editor.edit_level.worldpos().map(x => Math.round(x)), world2screen(editor.edit_level.worldpos()), 1, Color.red);
GUI.text("+", world2screen(editor.edit_level.worldpos()), 1, Color.blue);
GUI.text("+", editor.edit_level.screenpos(), 1, Color.blue);
var thiso = editor.get_this();
var clvl = thiso;
@ -454,21 +452,20 @@ var editor = {
x._ed.check_dirty();
if (x._ed.dirty) sname += "*";
GUI.text(sname, world2screen(x.worldpos()).add([0, 32]), 1, Color.editor.ur);
GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), world2screen(x.worldpos()), 1, Color.white);
// Debug.arrow(world2screen(x.worldpos()), world2screen(x.worldpos().add(x.up().scale(40))), Color.yellow, 1);
GUI.text(sname, x.screenpos().add([0, 32]), 1, Color.editor.ur);
GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white);
});
Object.entries(thiso.objects).forEach(function(x) {
var p = x[1]._ed.namestr();
GUI.text(p, world2screen(x[1].worldpos().add([0,16])),1,editor.color_depths[depth]);
GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]);
});
var mg = physics.pos_query(Mouse.worldpos);
if (mg) {
var p = mg.path_from(thiso);
GUI.text(p, world2screen(Mouse.worldpos),1,Color.teal);
GUI.text(p, Mouse.screenpos(),1,Color.teal);
}
if (this.selectlist.length === 1) {
@ -476,7 +473,7 @@ var editor = {
for (var key in this.selectlist[0].components) {
var selected = this.sel_comp === this.selectlist[0].components[key];
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
GUI.text(str, world2screen(this.selectlist[0].worldpos()).add([0,-16*(i++)]));
GUI.text(str, this.selectlist[0].screenpos().add([0,-16*(i++)]));
}
if (this.sel_comp) {
@ -486,7 +483,7 @@ var editor = {
editor.edit_level.objects.forEach(function(obj) {
if (!obj._ed.selectable)
GUI.image("icons/icons8-lock-16.png", world2screen(obj.worldpos()));
GUI.image("icons/icons8-lock-16.png", obj.screenpos());
});
Debug.draw_grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3));
@ -1684,7 +1681,7 @@ var objectexplorer = Object.copy(inputpanel, {
}
if (!this.previous.empty)
items.push(Mum.text({str:"prev: " + this.previous.last, action: this.prev_obj}));
items.push(Mum.text({str:"prev: " + this.previous.last(), action: this.prev_obj}));
Object.getOwnPropertyNames(this.obj).forEach(key => {
var descriptor = Object.getOwnPropertyDescriptor(this.obj, key);

View file

@ -95,12 +95,11 @@ var timer = {
load("scripts/animation.js");
var Render = {
normal() {
cmd(67);
},
normal() { cmd(67);},
wireframe() { cmd(68); },
pass() {
wireframe() {
cmd(68);
},
};
@ -125,7 +124,7 @@ function world2screen(worldpos) { return Game.camera.world2view(worldpos); }
var Register = {
kbm_input(mode, btn, state, ...args) {
if (state === 'released') {
btn = btn.split('-').last;
btn = btn.split('-').last();
}
switch(mode) {
@ -338,6 +337,45 @@ Spline.sample_angle = function(type, points, angle) {
return spline_cmd(0, type, points[0].length, points, angle);
}
Spline.bezier2catmull = function(b)
{
var c = [];
for (var i = 0; i < b.length; i += 3)
c.push(b[i]);
return c;
}
Spline.catmull2bezier = function(c)
{
var b = [];
for (var i = 1; i < c.length-2; i++) {
b.push(c[i].slice());
b.push(c[i+1].sub(c[i-1]).scale(0.25).add(c[i]));
b.push(c[i].sub(c[i+2]).scale(0.25).add(c[i+1]));
}
b.push(c[c.length-2]);
return b;
}
Spline.catmull_loop = function(cp)
{
cp = cp.slice();
cp.unshift(cp.last());
cp.push(cp[1]);
cp.push(cp[2]);
return cp;
}
Spline.catmull_caps = function(cp)
{
cp = cp.slice();
cp.unshift(cp[0].sub(cp[1]).add(cp[0]));
cp.push(cp.last().sub(cp.at(-2).add(cp.last())));
return cp;
}
Spline.catmull2bezier.doc = "Given a set of control points C for a camtull-rom type curve, return a set of cubic bezier points to give the same curve."
Spline.type = {
catmull: 0,
bezier: 1,
@ -345,6 +383,40 @@ Spline.type = {
cubichermite: 3
};
Spline.bezier_tan_partner = function(points, i)
{
if (i%3 === 0) return undefined;
var partner_i = (i%3) === 2 ? i-1 : i+1;
return points[i];
}
Spline.bezier_cp_mirror = function(points, i)
{
if (i%3 === 0) return undefined;
var partner_i = (i%3) === 2 ? i+2 : i-2;
var node_i = (i%3) === 2 ? i+1 : i-1;
if (partner_i >= points.length || node_i >= points.length) return;
points[partner_i] = points[node_i].sub(points[i]).add(points[node_i]);
}
Spline.bezier_point_handles = function(points, i)
{
if (!Spline.bezier_is_node(points,i)) return [];
var a = i-1;
var b = i+1;
var c = []
if (a > 0)
c.push(a);
if (b < points.length)
c.push(b);
return c;
}
Spline.bezier_is_node = function(points, i) { return i%3 === 0; }
Spline.bezier_is_handle = function(points, i) { return !Spline.bezier_is_node(points,i); }
load("scripts/components.js");
var Game = {

View file

@ -181,6 +181,7 @@ var gameobject = {
set_body(2,this.body,x);
this.objects.forEach((o,i) => o.set_worldpos(this.this2world(poses[i])));
},
screenpos() { return world2screen(this.worldpos()); },
worldangle() { return Math.rad2deg(q_body(2,this.body))%360; },
sworldangle(x) { set_body(0,this.body,Math.deg2rad(x)); },
@ -280,7 +281,8 @@ var gameobject = {
shove(vec) { set_body(12,this.body,vec);},
shove_at(vec, at) { set_body(14,this.body,vec,at); },
world2this(pos) { return cmd(70, this.body, pos); },
this2world(pos) { return cmd(71, this.body,pos); },
this2world(pos) { return cmd(71, this.body, pos); },
this2screen(pos) { return world2screen(this.this2world(pos)); },
dir_world2this(dir) { return cmd(160, this.body, dir); },
dir_this2world(dir) { return cmd(161, this.body, dir); },

View file

@ -1,3 +1,7 @@
/*
GUI functions take screen space coordinates
*/
var GUI = {
text(str, pos, size, color, wrap, anchor, cursor) {
size ??= 1;
@ -271,7 +275,7 @@ GUI.window = function(pos, wh, color)
var p = pos.slice();
p.x += wh.x/2;
p.y += wh.y/2;
Debug.box(p,wh,color);
Shape.box(p,wh,color);
}
GUI.flush = function() { cmd(141); };

View file

@ -4,9 +4,9 @@ var Input = {
};
var Mouse = {
get pos() {
return cmd(45);
},
get pos() { return cmd(45); },
screenpos() { return cmd(45); },
get worldpos() {
return screen2world(cmd(45));

View file

@ -69,10 +69,7 @@ JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\
(byte & 0x02 ? '1' : '0'), \
(byte & 0x01 ? '1' : '0')
void js_setprop_str(JSValue obj, const char *prop, JSValue v)
{
JS_SetPropertyStr(js, obj, prop, v);
}
void js_setprop_str(JSValue obj, const char *prop, JSValue v) { JS_SetPropertyStr(js, obj, prop, v); }
JSValue jstzone()
{
@ -140,18 +137,10 @@ int js2int(JSValue v) {
return i;
}
JSValue int2js(int i) {
return JS_NewInt64(js, i);
}
JSValue int2js(int i) { return JS_NewInt64(js, i); }
JSValue str2js(const char *c) {
return JS_NewString(js, c);
}
const char *js2str(JSValue v)
{
return JS_ToCString(js, v);
}
JSValue str2js(const char *c) { return JS_NewString(js, c); }
const char *js2str(JSValue v) { return JS_ToCString(js, v); }
JSValue strarr2js(const char **c)
{
@ -197,7 +186,7 @@ struct glrect js2glrect(JSValue v) {
return rect;
}
JSValue js_arridx(JSValue v, int idx) { return js_getpropidx( v, idx); }
JSValue js_arridx(JSValue v, int idx) { return js_getpropidx(v, idx); }
int js_arrlen(JSValue v) {
int len;
@ -270,9 +259,23 @@ cpBitmask js2bitmask(JSValue v) {
HMM_Vec2 *js2cpvec2arr(JSValue v) {
HMM_Vec2 *arr = NULL;
int n = js_arrlen(v);
for (int i = 0; i < n; i++)
arrput(arr, js2vec2(js_getpropidx( v, i)));
arrsetlen(arr,n);
for (int i = 0; i < n; i++)
arr[i] = js2vec2(js_getpropidx( v, i));
return arr;
}
HMM_Vec2 *jsfloat2vec(JSValue v)
{
size_t s;
void *buf = JS_GetArrayBuffer(js, &s, v);
HMM_Vec2 *arr = NULL;
int n = s/2;
n /= sizeof(float);
// arrsetcap(arr,n);
// memcpy(arr,buf,s);
return arr;
}
@ -401,6 +404,8 @@ JSValue duk_spline_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst
break;
}
arrfree(points);
if (!samples)
@ -573,7 +578,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 15:
// music_stop();
gameobject_draw_debug(js2gameobject(argv[1]));
break;
case 16:
@ -1054,7 +1059,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 128:
YughWarn("%g",stm_ms(9737310));
ret = JS_NewFloat64(js, stm_ns(js2uint64(argv[1])));
break;
@ -1842,6 +1846,34 @@ JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst
return JS_UNDEFINED;
}
const char *STRTEST = "TEST STRING";
JSValue duk_profile(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
{
int cmd = js2int(argv[0]);
switch(cmd) {
case 0:
break;
case 1:
js2number(argv[1]);
break;
case 2:
js2cpvec2arr(argv[1]);
break;
case 3:
return num2js(1.0);
case 4:
js2str(argv[1]);
break;
case 5:
jsfloat2vec(argv[1]);
break;
case 6:
return JS_NewStringLen(js, STRTEST, sizeof(*STRTEST));
}
return JS_UNDEFINED;
}
#define DUK_FUNC(NAME, ARGS) JS_SetPropertyStr(js, globalThis, #NAME, JS_NewCFunction(js, duk_##NAME, #NAME, ARGS));
void ffi_load() {
@ -1880,6 +1912,8 @@ void ffi_load() {
DUK_FUNC(inflate_cpv, 3)
DUK_FUNC(profile, 2)
JS_FreeValue(js,globalThis);
JS_NewClassID(&js_ptr_id);

View file

@ -2,6 +2,8 @@
#define RESOURCES_H
#include <stdio.h>
#include "stb_ds.h"
#include "string.h"
extern char *DATA_PATH;