Sprites are now defined in C; gameobject getsets
This commit is contained in:
parent
3e8bbdbeb2
commit
bb24fd2bc0
|
@ -19,25 +19,22 @@ var component = {
|
|||
return (typeof component[c.toString()] === 'object');
|
||||
},
|
||||
|
||||
hides: ['gameobject', 'id'],
|
||||
|
||||
make(go) {
|
||||
var nc = Object.create(this);
|
||||
nc.gameobject = go;
|
||||
Object.assign(nc, this._enghook(go.body));
|
||||
Object.mixin(nc, this._enghook(go.body));
|
||||
assign_impl(nc,this.impl);
|
||||
Object.hide(nc, ...this.hides);
|
||||
Object.hide(nc, ['gameobject', 'id']);
|
||||
nc.post();
|
||||
return nc;
|
||||
},
|
||||
|
||||
kill() { console.info("Kill not created for this component yet"); },
|
||||
sync() {},
|
||||
sync(){},
|
||||
post(){},
|
||||
gui() { },
|
||||
gizmo() { },
|
||||
gui(){},
|
||||
gizmo(){},
|
||||
|
||||
prepare_center() {},
|
||||
finish_center() {},
|
||||
extend(spec) { return Object.copy(this, spec); },
|
||||
};
|
||||
|
@ -68,126 +65,95 @@ var assign_impl = function(obj, impl)
|
|||
obj[key] = tmp[key];
|
||||
}
|
||||
|
||||
component.sprite = Object.copy(component, {
|
||||
pos:[0,0],
|
||||
color:[1,1,1,1],
|
||||
layer:0,
|
||||
enabled:true,
|
||||
path: "",
|
||||
rect: {s0:0, s1: 1, t0: 0, t1: 1},
|
||||
toString() { return "sprite"; },
|
||||
_enghook: make_sprite,
|
||||
});
|
||||
function json_from_whitelist(whitelist)
|
||||
{
|
||||
return function() {
|
||||
var o = {};
|
||||
for (var p of whitelist)
|
||||
o[p] = this[p];
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
component.sprite.mode = {
|
||||
simple: 0,
|
||||
tile: 1
|
||||
};
|
||||
|
||||
component.sprite.impl = {
|
||||
toJSON() {
|
||||
var j = {};
|
||||
Object.keys(this).forEach(k => j[k] = this[k]);
|
||||
delete j.rect;
|
||||
return j;
|
||||
Object.mixin(cmd(268,true), {
|
||||
toJSON:json_from_whitelist([
|
||||
"path",
|
||||
"pos",
|
||||
"scale",
|
||||
"angle",
|
||||
"color",
|
||||
"emissive",
|
||||
"parallax",
|
||||
"frame"
|
||||
]),
|
||||
anim:{},
|
||||
playing: 0,
|
||||
play(str) {
|
||||
var sp = this;
|
||||
str ??= 0;
|
||||
var playing = this.anim[str];
|
||||
if (!playing) return; //TODO: ERROR
|
||||
var f = 0;
|
||||
|
||||
function advance() {
|
||||
sp.path = playing.path;
|
||||
sp.frame = playing.frames[f].rect;
|
||||
f = (f+1)%playing.frames.length;
|
||||
if (f === 0)
|
||||
sp.anim_done?.();
|
||||
sp.gameobject?.delay(advance, playing.frames[f].time);
|
||||
}
|
||||
advance();
|
||||
},
|
||||
|
||||
set path(x) {
|
||||
if (this.cancel) {
|
||||
this.cancel();
|
||||
this.cancel = undefined;
|
||||
}
|
||||
|
||||
if (!Resources.is_animation(x)) {
|
||||
this.rect = component.sprite.rect;
|
||||
cmd(12,this.id,x,this.rect);
|
||||
}
|
||||
else {
|
||||
this.anims = SpriteAnim.make(x);
|
||||
Object.hide(this, 'anims');
|
||||
var anim = this.anims[0];
|
||||
this.rect = anim.frames[0].rect;
|
||||
cmd(12,this.id,anim.path,this.rect);
|
||||
}
|
||||
stop() {},
|
||||
set path(p) {
|
||||
p = Resources.find_image(p);
|
||||
if (!p) return;
|
||||
if (p === this.path) return;
|
||||
this.tex = cmd(269,p);
|
||||
var anim = SpriteAnim.make(p);
|
||||
if (!anim) return;
|
||||
this.anim = anim;
|
||||
this.play();
|
||||
},
|
||||
get path() {
|
||||
var s = cmd(116,this.id);
|
||||
if (s === "icons/no_tex.gif") return undefined;
|
||||
return s;
|
||||
return this.tex.path();
|
||||
},
|
||||
|
||||
play(name) {
|
||||
if (!this.anims) return;
|
||||
if (this.cancel) this.cancel();
|
||||
name ??= 0;
|
||||
var frame = 0;
|
||||
var anim = this.anims[name];
|
||||
var advance = function() {
|
||||
frame = (frame+1)%anim.frames.length;
|
||||
this.rect = anim.frames[frame].rect;
|
||||
cmd(12,this.id,anim.path,this.rect);
|
||||
this.cancel = this.gameobject.delay(advance.bind(this), anim.frames[frame].time);
|
||||
}
|
||||
advance.call(this);
|
||||
},
|
||||
|
||||
stop() {
|
||||
if (!this.cancel) return;
|
||||
this.cancel();
|
||||
this.cancel = undefined;
|
||||
},
|
||||
setframe(f) {
|
||||
if (!this.anims) return;
|
||||
this.stop();
|
||||
var anim = this.anims[0];
|
||||
this.rect = anim.frames[f].rect;
|
||||
cmd(12,this.id,anim.path,this.rect);
|
||||
},
|
||||
|
||||
toString() { return "sprite"; },
|
||||
hide() { this.enabled = false; },
|
||||
show() { this.enabled = true; },
|
||||
asset(str) { this.path = str; },
|
||||
get enabled() { return cmd(114,this.id); },
|
||||
set enabled(x) { cmd(20,this.id,x); },
|
||||
set color(x) { cmd(96,this.id,x); },
|
||||
get color() {return cmd(148,this.id);},
|
||||
get pos() { return cmd(111, this.id); },
|
||||
set pos(x) { cmd(37,this.id,x); },
|
||||
get parallax() { return cmd(232, this.id); },
|
||||
set parallax(x) { cmd(233,this.id,x); },
|
||||
get angle() { return cmd(217,this.id); },
|
||||
set angle(x) { cmd(218,this.id,x); },
|
||||
get scale() { return cmd(215, this.id); },
|
||||
set scale(x) { cmd(216, this.id, x); },
|
||||
move(d) { this.pos = this.pos.add(d); },
|
||||
grow(x) {
|
||||
this.scale = this.scale.scale(x);
|
||||
this.pos = this.pos.scale(x);
|
||||
},
|
||||
get drawmode() { return cmd(220,this.id); },
|
||||
set drawmode(x) { cmd(219,this.id,x); },
|
||||
emissive(x) { cmd(170, this.id, x); },
|
||||
|
||||
sync() { },
|
||||
pickm() { return this; },
|
||||
move(d) { this.pos = this.pos.add(d); },
|
||||
|
||||
pick() { return this; },
|
||||
boundingbox() {
|
||||
var dim = this.dimensions();
|
||||
dim = dim.scale(this.gameobject.gscale());
|
||||
var realpos = dim.scale(0.5).add(this.pos);
|
||||
return bbox.fromcwh(realpos,dim);
|
||||
},
|
||||
|
||||
kill() { cmd(9,this.id); },
|
||||
|
||||
dimensions() {
|
||||
var dim = Resources.texture.dimensions(this.path);
|
||||
dim.x *= (this.rect.s1-this.rect.s0);
|
||||
dim.y *= (this.rect.t1-this.rect.t0);
|
||||
var dim = [this.tex.width(), this.tex.height()];
|
||||
dim.x *= this.frame.w;
|
||||
dim.y *= this.frame.h;
|
||||
return dim;
|
||||
},
|
||||
width() { return this.dimensions().x; },
|
||||
height() { return this.dimensions().y; },
|
||||
};
|
||||
});
|
||||
|
||||
cmd(268,true).make = function(go)
|
||||
{
|
||||
var sp = cmd(268);
|
||||
sp.go = go.body;
|
||||
sp.gameobject = go;
|
||||
return sp;
|
||||
}
|
||||
|
||||
component.sprite = cmd(268,true);
|
||||
|
||||
Object.freeze(sprite);
|
||||
|
||||
|
@ -195,6 +161,7 @@ component.model = Object.copy(component, {
|
|||
path:"",
|
||||
_enghook: make_model,
|
||||
});
|
||||
|
||||
component.model.impl = {
|
||||
set path(x) { cmd(149, this.id, x); },
|
||||
draw() { cmd(150, this.id); },
|
||||
|
@ -245,10 +212,10 @@ var SpriteAnim = {
|
|||
for (var f = 0; f < frames; f++) {
|
||||
var frame = {};
|
||||
frame.rect = {
|
||||
s0: 0,
|
||||
s1: 1,
|
||||
t0: yslice*f,
|
||||
t1: yslice*(f+1)
|
||||
x: 0,
|
||||
w: 1,
|
||||
y: yslice*f,
|
||||
h: yslice
|
||||
};
|
||||
frame.time = 0.05;
|
||||
anim.frames.push(frame);
|
||||
|
@ -290,10 +257,10 @@ var SpriteAnim = {
|
|||
var f = ase_frame.frame;
|
||||
var frame = {};
|
||||
frame.rect = {
|
||||
s0: f.x/dim.w,
|
||||
s1: (f.x+f.w)/dim.w,
|
||||
t0: f.y/dim.h,
|
||||
t1: (f.y+f.h)/dim.h
|
||||
x: f.x/dim.w,
|
||||
w: f.w/dim.w,
|
||||
y: f.y/dim.h,
|
||||
h: f.h/dim.h
|
||||
};
|
||||
frame.time = ase_frame.duration / 1000;
|
||||
anim.frames.push(frame);
|
||||
|
@ -365,6 +332,10 @@ collider2d.inputs['M-t'] = function() { this.enabled = !this.enabled; }
|
|||
collider2d.inputs['M-t'].doc = "Toggle if this collider is enabled.";
|
||||
|
||||
component.polygon2d = Object.copy(collider2d, {
|
||||
toJSON:json_from_whitelist([
|
||||
'points',
|
||||
'sensor'
|
||||
]),
|
||||
toString() { return "polygon2d"; },
|
||||
flipx: false,
|
||||
flipy: false,
|
||||
|
@ -463,6 +434,13 @@ polygon2d.inputs['C-b'] = function() {
|
|||
polygon2d.inputs['C-b'].doc = "Freeze mirroring in place.";
|
||||
|
||||
component.edge2d = Object.copy(collider2d, {
|
||||
toJSON:json_from_whitelist([
|
||||
'sensor',
|
||||
'thickness',
|
||||
'points',
|
||||
'hollow',
|
||||
'hollowt',
|
||||
]),
|
||||
dimensions:2,
|
||||
thickness:0,
|
||||
/* if type === -1, point to point */
|
||||
|
@ -821,6 +799,11 @@ component.circle2d = Object.copy(collider2d, {
|
|||
});
|
||||
|
||||
component.circle2d.impl = Object.mix({
|
||||
toJSON:json_from_whitelist([
|
||||
"pos",
|
||||
"radius",
|
||||
]),
|
||||
|
||||
set radius(x) { cmd_circle2d(0,this.id,x); },
|
||||
get radius() { return cmd_circle2d(2,this.id); },
|
||||
|
||||
|
@ -840,4 +823,4 @@ component.circle2d.impl = Object.mix({
|
|||
|
||||
}, collider2d.impl);
|
||||
|
||||
return {component};
|
||||
return {component, SpriteAnim};
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
function obj_unique_name(name, obj)
|
||||
{
|
||||
function obj_unique_name(name, obj) {
|
||||
name = name.replaceAll('.', '_');
|
||||
if (!(name in obj)) return name;
|
||||
var t = 1;
|
||||
var n = name + t;
|
||||
while (n in obj) {
|
||||
t++;
|
||||
n = name+t;
|
||||
n = name + t;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
var gameobject_impl = {
|
||||
get pos() {
|
||||
assert(this.master, `Entity ${this.toString()} has no master.`);
|
||||
|
@ -27,7 +25,7 @@ var gameobject_impl = {
|
|||
assert(this.master, `No master set on ${this.toString()}`);
|
||||
return this.worldangle() - this.master.worldangle();
|
||||
},
|
||||
|
||||
|
||||
set angle(x) {
|
||||
var diff = x - this.angle;
|
||||
|
||||
|
@ -36,64 +34,64 @@ var gameobject_impl = {
|
|||
x.pos = Vector.rotate(x.pos, diff);
|
||||
});
|
||||
|
||||
this.sworldangle(x-this.master.worldangle());
|
||||
this.sworldangle(x - this.master.worldangle());
|
||||
},
|
||||
|
||||
get scale() {
|
||||
assert(this.master, `No master set on ${this.toString()}`);
|
||||
var pscale = [1,1,1];
|
||||
return this.gscale().map((x,i) => x/(this.master.gscale()[i]*pscale[i]));
|
||||
var pscale = [1, 1, 1];
|
||||
return this.gscale().map((x, i) => x / (this.master.gscale()[i] * pscale[i]));
|
||||
},
|
||||
|
||||
set scale(x) {
|
||||
if (typeof x === 'number')
|
||||
x = [x,x];
|
||||
x = [x, x];
|
||||
|
||||
var pct = this.scale.map((s,i) => x[i]/s);
|
||||
var pct = this.scale.map((s, i) => x[i] / s);
|
||||
this.grow(pct);
|
||||
|
||||
|
||||
/* TRANSLATE ALL SUB OBJECTS */
|
||||
this.objects.forEach(obj => {
|
||||
obj.grow(pct);
|
||||
obj.pos = obj.pos.map((x,i)=>x*pct[i]);
|
||||
obj.pos = obj.pos.map((x, i) => x * pct[i]);
|
||||
});
|
||||
},
|
||||
|
||||
get draw_layer() { return cmd(171, this.body); },
|
||||
set draw_layer(x) { cmd(172, this.body, x); },
|
||||
set layer(x) { cmd(75,this.body,x); },
|
||||
get layer() { return cmd(77,this.body); },
|
||||
set warp_layer(x) { cmd(251, this.body,x); },
|
||||
get warp_layer() { return cmd(252, this.body); },
|
||||
get draw_layer() { return this.body.drawlayer; },
|
||||
set draw_layer(x) { this.body.drawlayer = x; },
|
||||
set layer(x) { this.body.layer = x; },
|
||||
get layer() { return this.body.layer; },
|
||||
set warp_layer(x) { this.body.warp_filter = x; },
|
||||
get warp_layer() { return this.body.warp_filter; },
|
||||
|
||||
set mass(x) { set_body(7,this.body,x); },
|
||||
set mass(x) { set_body(7, this.body, x); },
|
||||
get mass() {
|
||||
if (!(this.phys === physics.dynamic))
|
||||
return undefined;
|
||||
|
||||
return q_body(5, this.body);
|
||||
},
|
||||
get elasticity() { return cmd(107,this.body); },
|
||||
set elasticity(x) { cmd(106,this.body,x); },
|
||||
get friction() { return cmd(109,this.body); },
|
||||
set friction(x) { cmd(108,this.body,x); },
|
||||
set timescale(x) { cmd(168,this.body,x); },
|
||||
get timescale() { return cmd(169,this.body); },
|
||||
get elasticity() { return this.body.e; },
|
||||
set elasticity(x) { this.body.e = x; },
|
||||
get friction() { return this.body.f; },
|
||||
set friction(x) { this.body.f = x; },
|
||||
set timescale(x) { this.body.timescale = x; },
|
||||
get timescale() { return this.body.timescale; },
|
||||
set phys(x) { set_body(1, this.body, x); },
|
||||
get phys() { return q_body(0,this.body); },
|
||||
get phys() { return q_body(0, this.body); },
|
||||
get velocity() { return q_body(3, this.body); },
|
||||
set velocity(x) { set_body(9, this.body, x); },
|
||||
get damping() { return cmd(157,this.body); },
|
||||
set damping(x) { cmd(156, this.body, x); },
|
||||
get angularvelocity() { return Math.rad2turn(q_body(4,this.body)); },
|
||||
get damping() { return this.body.damping; },
|
||||
set damping(x) { this.body.damping = x },
|
||||
get angularvelocity() { return Math.rad2turn(q_body(4, this.body)); },
|
||||
set angularvelocity(x) { set_body(8, this.body, Math.turn2rad(x)); },
|
||||
get max_velocity() { return cmd(152, this.body); },
|
||||
set max_velocity(x) { cmd(151, this.body, x); },
|
||||
get max_angularvelocity() { return cmd(155,this.body); },
|
||||
set max_angularvelocity(x) { cmd(154,this.body,x); },
|
||||
get max_velocity() { return this.body.maxvelocity; },
|
||||
set max_velocity(x) { this.body.maxvelocity = x; },
|
||||
get max_angularvelocity() { return this.body.maxangularvelocity; },
|
||||
set max_angularvelocity(x) { this.body.maxangularvelocity = x; },
|
||||
get_moi() { return q_body(6, this.body); },
|
||||
set_moi(x) {
|
||||
if(x <= 0) {
|
||||
if (x <= 0) {
|
||||
console.error("Cannot set moment of inertia to 0 or less.");
|
||||
return;
|
||||
}
|
||||
|
@ -117,7 +115,7 @@ var gameobject = {
|
|||
var lur = ur[this.master.ur];
|
||||
if (!lur) return;
|
||||
var lur = lur.objects[this.toString()];
|
||||
var d = ediff(this._ed.urdiff,lur);
|
||||
var d = ediff(this._ed.urdiff, lur);
|
||||
if (!d || Object.empty(d))
|
||||
this._ed.inst = true;
|
||||
else
|
||||
|
@ -127,7 +125,7 @@ var gameobject = {
|
|||
selectable: false,
|
||||
dirty: false
|
||||
},
|
||||
|
||||
|
||||
namestr() {
|
||||
var s = this.toString();
|
||||
if (this._ed.dirty)
|
||||
|
@ -137,41 +135,41 @@ var gameobject = {
|
|||
},
|
||||
|
||||
urstr() {
|
||||
if (this._ed.dirty) return "*"+this.ur;
|
||||
if (this._ed.dirty) return "*" + this.ur;
|
||||
return this.ur;
|
||||
},
|
||||
|
||||
|
||||
full_path() {
|
||||
return this.path_from(world);
|
||||
},
|
||||
/* pin this object to the to object */
|
||||
pin(to) {
|
||||
var p = cmd(222,this.body, to.body);
|
||||
var p = cmd(222, this.body, to.body);
|
||||
},
|
||||
slide(to, a, b, min, max) {
|
||||
a ??= [0,0];
|
||||
b ??= [0,0];
|
||||
a ??= [0, 0];
|
||||
b ??= [0, 0];
|
||||
min ??= 0;
|
||||
max ??= 50;
|
||||
var p = cmd(229,this.body,to.body,a,b,min,max);
|
||||
var p = cmd(229, this.body, to.body, a, b, min, max);
|
||||
p.max_force = 500;
|
||||
p.break();
|
||||
},
|
||||
pivot(to, piv) {
|
||||
piv ??= this.worldpos();
|
||||
var p = cmd(221,this.body,to.body,piv);
|
||||
var p = cmd(221, this.body, to.body, piv);
|
||||
},
|
||||
/* groove is on to, from local points a and b, anchored to this at local anchor */
|
||||
groove(to, a, b, anchor) {
|
||||
anchor ??= [0,0];
|
||||
anchor ??= [0, 0];
|
||||
var p = cmd(228, to.body, this.body, a, b, anchor);
|
||||
},
|
||||
damped_spring(to, length, stiffness, damping) {
|
||||
length ??= Vector.length(this.worldpos(), to.worldpos());
|
||||
stiffness ??= 1;
|
||||
damping ??= 1;
|
||||
var dc = 2*Math.sqrt(stiffness*this.mass);
|
||||
var p = cmd(227, this.body, to.body, [0,0], [0,0], stiffness, damping*dc);
|
||||
var dc = 2 * Math.sqrt(stiffness * this.mass);
|
||||
var p = cmd(227, this.body, to.body, [0, 0], [0, 0], stiffness, damping * dc);
|
||||
},
|
||||
damped_rotary_spring(to, angle, stiffness, damping) {
|
||||
angle ??= 0;
|
||||
|
@ -179,14 +177,14 @@ var gameobject = {
|
|||
damping ??= 1;
|
||||
/* calculate actual damping value from the damping ratio */
|
||||
/* damping = 1 is critical */
|
||||
var dc = 2*Math.sqrt(stiffness*this.get_moi()); /* critical damping number */
|
||||
var dc = 2 * Math.sqrt(stiffness * this.get_moi()); /* critical damping number */
|
||||
/* zeta = actual/critical */
|
||||
var p = cmd(226,this.body,to.body,angle,stiffness,damping*dc);
|
||||
var p = cmd(226, this.body, to.body, angle, stiffness, damping * dc);
|
||||
},
|
||||
rotary_limit(to, min, max) {
|
||||
var p = cmd(225,this.body,to.body, Math.turn2rad(min),Math.turn2rad(max));
|
||||
var p = cmd(225, this.body, to.body, Math.turn2rad(min), Math.turn2rad(max));
|
||||
},
|
||||
ratchet(to,ratch) {
|
||||
ratchet(to, ratch) {
|
||||
var phase = this.angle - to.angle;
|
||||
var p = cmd(230, this.body, to.body, phase, Math.turn2rad(ratch));
|
||||
},
|
||||
|
@ -194,183 +192,187 @@ var gameobject = {
|
|||
phase ??= 1;
|
||||
ratio ??= 1;
|
||||
var phase = this.angle - to.angle;
|
||||
var p = cmd(223,this.body,to.body,phase,ratio);
|
||||
var p = cmd(223, this.body, to.body, phase, ratio);
|
||||
},
|
||||
motor(to, rate) {
|
||||
var p = cmd(231, this.body, to.body, rate);
|
||||
},
|
||||
|
||||
path_from(o) {
|
||||
var p = this.toString();
|
||||
var c = this.master;
|
||||
while (c && c !== o && c !== world) {
|
||||
p = c.toString() + "." + p;
|
||||
c = c.master;
|
||||
}
|
||||
if (c === world) p = "world." + p;
|
||||
return p;
|
||||
},
|
||||
|
||||
clear() {
|
||||
for (var k in this.objects) {
|
||||
this.objects[k].kill();
|
||||
};
|
||||
this.objects = {};
|
||||
},
|
||||
|
||||
delay(fn, seconds) {
|
||||
var t = timer.delay(fn.bind(this), seconds);
|
||||
this.timers.push(t);
|
||||
return t;
|
||||
},
|
||||
|
||||
tween(prop, values, def){
|
||||
var t = Tween.make(this, prop, values, def);
|
||||
t.play();
|
||||
|
||||
var k = function() { t.pause(); }
|
||||
this.timers.push(k);
|
||||
return k;
|
||||
},
|
||||
path_from(o) {
|
||||
var p = this.toString();
|
||||
var c = this.master;
|
||||
while (c && c !== o && c !== world) {
|
||||
p = c.toString() + "." + p;
|
||||
c = c.master;
|
||||
}
|
||||
if (c === world) p = "world." + p;
|
||||
return p;
|
||||
},
|
||||
|
||||
cry(file) {
|
||||
return;
|
||||
this.crying = audio.sound.play(file, audio.sound.bus.sfx);
|
||||
var killfn = () => {this.crying = undefined; console.warn("killed"); }
|
||||
this.crying.hook = killfn;
|
||||
return killfn;
|
||||
},
|
||||
clear() {
|
||||
for (var k in this.objects) {
|
||||
this.objects[k].kill();
|
||||
};
|
||||
this.objects = {};
|
||||
},
|
||||
|
||||
set torque(x) { if (!(x >= 0 && x <= Infinity)) return; cmd(153, this.body, x); },
|
||||
gscale() { return cmd(103,this.body); },
|
||||
sgscale(x) {
|
||||
if (typeof x === 'number')
|
||||
x = [x,x];
|
||||
cmd(36,this.body,x)
|
||||
},
|
||||
|
||||
phys_material() {
|
||||
var mat = {};
|
||||
mat.elasticity = this.elasticity;
|
||||
mat.friction = this.friction;
|
||||
return mat;
|
||||
},
|
||||
delay(fn, seconds) {
|
||||
var t = timer.delay(fn.bind(this), seconds);
|
||||
this.timers.push(t);
|
||||
return t;
|
||||
},
|
||||
|
||||
worldpos() { return q_body(1,this.body); },
|
||||
set_worldpos(x) {
|
||||
var poses = this.objects.map(x => x.pos);
|
||||
set_body(2,this.body,x);
|
||||
this.objects.forEach((o,i) => o.set_worldpos(this.this2world(poses[i])));
|
||||
},
|
||||
screenpos() { return Window.world2screen(this.worldpos()); },
|
||||
tween(prop, values, def) {
|
||||
var t = Tween.make(this, prop, values, def);
|
||||
t.play();
|
||||
|
||||
worldangle() { return Math.rad2turn(q_body(2,this.body)); },
|
||||
sworldangle(x) { set_body(0,this.body,Math.turn2rad(x)); },
|
||||
var k = function() { t.pause(); }
|
||||
this.timers.push(k);
|
||||
return k;
|
||||
},
|
||||
|
||||
get_ur() {
|
||||
// if (this.ur === 'empty') return undefined;
|
||||
return Object.access(ur,this.ur);
|
||||
},
|
||||
cry(file) {
|
||||
return;
|
||||
this.crying = audio.sound.play(file, audio.sound.bus.sfx);
|
||||
var killfn = () => { this.crying = undefined;
|
||||
console.warn("killed"); }
|
||||
this.crying.hook = killfn;
|
||||
return killfn;
|
||||
},
|
||||
|
||||
/* spawn an entity
|
||||
set torque(x) { if (!(x >= 0 && x <= Infinity)) return;
|
||||
cmd(153, this.body, x); },
|
||||
gscale() { return cmd(103, this.body); },
|
||||
sgscale(x) {
|
||||
if (typeof x === 'number')
|
||||
x = [x, x];
|
||||
cmd(36, this.body, x)
|
||||
},
|
||||
|
||||
phys_material() {
|
||||
var mat = {};
|
||||
mat.elasticity = this.elasticity;
|
||||
mat.friction = this.friction;
|
||||
return mat;
|
||||
},
|
||||
|
||||
worldpos() { return q_body(1, this.body); },
|
||||
set_worldpos(x) {
|
||||
var poses = this.objects.map(x => x.pos);
|
||||
set_body(2, this.body, x);
|
||||
this.objects.forEach((o, i) => o.set_worldpos(this.this2world(poses[i])));
|
||||
},
|
||||
screenpos() { return Window.world2screen(this.worldpos()); },
|
||||
|
||||
worldangle() { return Math.rad2turn(q_body(2, this.body)); },
|
||||
sworldangle(x) { set_body(0, this.body, Math.turn2rad(x)); },
|
||||
|
||||
get_ur() {
|
||||
// if (this.ur === 'empty') return undefined;
|
||||
return Object.access(ur, this.ur);
|
||||
},
|
||||
|
||||
/* spawn an entity
|
||||
text can be:
|
||||
the file path of a script
|
||||
an ur object
|
||||
nothing
|
||||
the file path of a script
|
||||
an ur object
|
||||
nothing
|
||||
*/
|
||||
spawn(text) {
|
||||
var ent = Object.create(gameobject);
|
||||
|
||||
if (typeof text === 'object')
|
||||
text = text.name;
|
||||
spawn(text) {
|
||||
var ent = Object.create(gameobject);
|
||||
|
||||
if (typeof text === 'undefined')
|
||||
ent.ur = "empty";
|
||||
else if (typeof text !== 'string') {
|
||||
console.error(`Must pass in an ur type or a string to make an entity.`);
|
||||
return;
|
||||
} else {
|
||||
if (Object.access(ur,text))
|
||||
ent.ur = text;
|
||||
else if (io.exists(text))
|
||||
ent.ur = "script";
|
||||
else {
|
||||
console.warn(`Cannot make an entity from '${text}'. Not a valid ur.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Object.mixin(ent,gameobject_impl);
|
||||
ent.body = make_gameobject();
|
||||
ent.warp_layer = [true];
|
||||
ent.phys = 2;
|
||||
ent.components = {};
|
||||
ent.objects = {};
|
||||
ent.timers = [];
|
||||
|
||||
ent.reparent(this);
|
||||
if (typeof text === 'object')
|
||||
text = text.name;
|
||||
|
||||
ent._ed = {
|
||||
selectable: true,
|
||||
dirty: false,
|
||||
inst: false,
|
||||
urdiff: {},
|
||||
};
|
||||
if (typeof text === 'undefined')
|
||||
ent.ur = "empty";
|
||||
else if (typeof text !== 'string') {
|
||||
console.error(`Must pass in an ur type or a string to make an entity.`);
|
||||
return;
|
||||
} else {
|
||||
if (Object.access(ur, text))
|
||||
ent.ur = text;
|
||||
else if (io.exists(text))
|
||||
ent.ur = "script";
|
||||
else {
|
||||
console.warn(`Cannot make an entity from '${text}'. Not a valid ur.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cmd(113, ent.body, ent); // set the internal obj reference to this obj
|
||||
Object.mixin(ent, gameobject_impl);
|
||||
ent.body = make_gameobject();
|
||||
ent.warp_layer = [true];
|
||||
ent.phys = 2;
|
||||
ent.components = {};
|
||||
ent.objects = {};
|
||||
ent.timers = [];
|
||||
|
||||
Object.hide(ent, 'ur', 'body', 'components', 'objects', '_ed', 'timers', 'master');
|
||||
if (ent.ur === 'empty') {
|
||||
if (!ur.empty.proto) ur.empty.proto = json.decode(json.encode(ent));
|
||||
return ent;
|
||||
}
|
||||
ent.reparent(this);
|
||||
|
||||
if (ent.ur === 'script')
|
||||
eval_env(io.slurp(text), ent, ent.ur);
|
||||
else
|
||||
apply_ur(ent.ur, ent);
|
||||
ent._ed = {
|
||||
selectable: true,
|
||||
dirty: false,
|
||||
inst: false,
|
||||
urdiff: {},
|
||||
};
|
||||
|
||||
for (var [prop,p] of Object.entries(ent)) {
|
||||
if (!p) continue;
|
||||
if (typeof p !== 'object') continue;
|
||||
if (component.isComponent(p)) continue;
|
||||
if (!p.comp) continue;
|
||||
ent[prop] = component[p.comp].make(ent);
|
||||
Object.merge(ent[prop], p);
|
||||
ent.components[prop] = ent[prop];
|
||||
};
|
||||
cmd(113, ent.body, ent); // set the internal obj reference to this obj
|
||||
|
||||
check_registers(ent);
|
||||
ent.components.forEach(function(x) {
|
||||
if (typeof x.collide === 'function')
|
||||
register_collide(1, x.collide.bind(x), ent.body, x.shape);
|
||||
});
|
||||
|
||||
|
||||
if (typeof ent.load === 'function') ent.load();
|
||||
if (Game.playing())
|
||||
if (typeof ent.start === 'function') ent.start();
|
||||
|
||||
var mur = ent.get_ur();
|
||||
if (mur && !mur.proto)
|
||||
mur.proto = json.decode(json.encode(ent));
|
||||
|
||||
ent.sync();
|
||||
|
||||
if (!Object.empty(ent.objects)) {
|
||||
var o = ent.objects;
|
||||
delete ent.objects;
|
||||
for (var i in o) {
|
||||
say(`MAKING ${i}`);
|
||||
var n = ent.spawn(ur[o[i].ur]);
|
||||
ent.rename_obj(n.toString(), i);
|
||||
delete o[i].ur;
|
||||
Object.assign(n, o[i]);
|
||||
}
|
||||
}
|
||||
Object.hide(ent, 'ur', 'body', 'components', 'objects', '_ed', 'timers', 'master');
|
||||
if (ent.ur === 'empty') {
|
||||
if (!ur.empty.proto) ur.empty.proto = json.decode(json.encode(ent));
|
||||
return ent;
|
||||
}
|
||||
|
||||
return ent;
|
||||
},
|
||||
if (ent.ur === 'script')
|
||||
eval_env(io.slurp(text), ent, ent.ur);
|
||||
else
|
||||
apply_ur(ent.ur, ent);
|
||||
|
||||
for (var [prop, p] of Object.entries(ent)) {
|
||||
if (!p) continue;
|
||||
if (typeof p !== 'object') continue;
|
||||
if (component.isComponent(p)) continue;
|
||||
if (!p.comp) continue;
|
||||
ent[prop] = component[p.comp].make(ent);
|
||||
Object.merge(ent[prop], p);
|
||||
ent.components[prop] = ent[prop];
|
||||
};
|
||||
|
||||
check_registers(ent);
|
||||
ent.components.forEach(function(x) {
|
||||
if (typeof x.collide === 'function')
|
||||
register_collide(1, x.collide.bind(x), ent.body, x.shape);
|
||||
});
|
||||
|
||||
|
||||
if (typeof ent.load === 'function') ent.load();
|
||||
if (Game.playing())
|
||||
if (typeof ent.start === 'function') ent.start();
|
||||
|
||||
var mur = ent.get_ur();
|
||||
if (mur && !mur.proto)
|
||||
mur.proto = json.decode(json.encode(ent));
|
||||
|
||||
ent.sync();
|
||||
|
||||
if (!Object.empty(ent.objects)) {
|
||||
var o = ent.objects;
|
||||
delete ent.objects;
|
||||
for (var i in o) {
|
||||
say(`MAKING ${i}`);
|
||||
var n = ent.spawn(ur[o[i].ur]);
|
||||
ent.rename_obj(n.toString(), i);
|
||||
delete o[i].ur;
|
||||
Object.assign(n, o[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.body.phys = this.body.phys; // simple way to sync
|
||||
|
||||
return ent;
|
||||
},
|
||||
|
||||
/* Reparent 'this' to be 'parent's child */
|
||||
reparent(parent) {
|
||||
|
@ -382,9 +384,9 @@ var gameobject = {
|
|||
}
|
||||
|
||||
this.master?.remove_obj(this);
|
||||
|
||||
|
||||
this.master = parent;
|
||||
|
||||
|
||||
function unique_name(list, name) {
|
||||
name ??= "new_object";
|
||||
var str = name.replaceAll('.', '_');
|
||||
|
@ -392,7 +394,7 @@ var gameobject = {
|
|||
var t = str;
|
||||
while (list.indexOf(t) !== -1) {
|
||||
t = str + n;
|
||||
n++;
|
||||
n++;
|
||||
}
|
||||
return t;
|
||||
};
|
||||
|
@ -403,34 +405,36 @@ var gameobject = {
|
|||
parent[name] = this;
|
||||
this.toString = function() { return name; };
|
||||
},
|
||||
|
||||
remove_obj(obj) {
|
||||
if (this[obj.toString()] === this.objects[obj.toString()])
|
||||
delete this[obj.toString()];
|
||||
|
||||
delete this.objects[obj.toString()];
|
||||
delete this[obj.toString()];
|
||||
},
|
||||
|
||||
remove_obj(obj) {
|
||||
if (this[obj.toString()] === this.objects[obj.toString()])
|
||||
delete this[obj.toString()];
|
||||
|
||||
delete this.objects[obj.toString()];
|
||||
delete this[obj.toString()];
|
||||
},
|
||||
|
||||
components: {},
|
||||
objects: {},
|
||||
master: undefined,
|
||||
|
||||
pulse(vec) { set_body(4, this.body, vec);},
|
||||
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); },
|
||||
this2screen(pos) { return Window.world2screen(this.this2world(pos)); },
|
||||
screen2this(pos) { return this.world2this(Window.screen2world(pos)); },
|
||||
dir_world2this(dir) { return cmd(160, this.body, dir); },
|
||||
dir_this2world(dir) { return cmd(161, this.body, dir); },
|
||||
|
||||
alive() { return this.body >= 0; },
|
||||
in_air() { return q_body(7, this.body);},
|
||||
|
||||
hide() { this.components.forEach(x=>x.hide?.()); this.objects.forEach(x=>x.hide?.());},
|
||||
show() { this.components.forEach(function(x) { x.show?.(); }); this.objects.forEach(function(x) { x.show?.(); }); },
|
||||
pulse(vec) { set_body(4, this.body, vec); },
|
||||
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); },
|
||||
this2screen(pos) { return Window.world2screen(this.this2world(pos)); },
|
||||
screen2this(pos) { return this.world2this(Window.screen2world(pos)); },
|
||||
dir_world2this(dir) { return cmd(160, this.body, dir); },
|
||||
dir_this2world(dir) { return cmd(161, this.body, dir); },
|
||||
|
||||
alive() { return this.body >= 0; },
|
||||
in_air() { return q_body(7, this.body); },
|
||||
|
||||
hide() { this.components.forEach(x => x.hide?.());
|
||||
this.objects.forEach(x => x.hide?.()); },
|
||||
show() { this.components.forEach(function(x) { x.show?.(); });
|
||||
this.objects.forEach(function(x) { x.show?.(); }); },
|
||||
|
||||
width() {
|
||||
var bb = this.boundingbox();
|
||||
|
@ -439,13 +443,13 @@ var gameobject = {
|
|||
|
||||
height() {
|
||||
var bb = this.boundingbox();
|
||||
return bb.t-bb.b;
|
||||
return bb.t - bb.b;
|
||||
},
|
||||
|
||||
/* Moving, rotating, scaling functions, world relative */
|
||||
move(vec) { this.set_worldpos(this.worldpos().add(vec)); },
|
||||
rotate(x) { this.sworldangle(this.worldangle()+x); },
|
||||
grow(vec) { this.sgscale(this.gscale().map((x,i)=>x*vec[i])); },
|
||||
rotate(x) { this.sworldangle(this.worldangle() + x); },
|
||||
grow(vec) { this.sgscale(this.gscale().map((x, i) => x * vec[i])); },
|
||||
|
||||
/* Make a unique object the same as its prototype */
|
||||
revert() {
|
||||
|
@ -462,155 +466,155 @@ var gameobject = {
|
|||
},
|
||||
|
||||
toString() { return "new_object"; },
|
||||
|
||||
|
||||
flipx() { return this.scale.x < 0; },
|
||||
flipy() { return this.scale.y < 0; },
|
||||
|
||||
|
||||
mirror(plane) {
|
||||
this.scale = Vector.reflect(this.scale, plane);
|
||||
},
|
||||
|
||||
save:true,
|
||||
selectable:true,
|
||||
ed_locked:false,
|
||||
|
||||
disable() { this.components.forEach(function(x) { x.disable(); });},
|
||||
enable() { this.components.forEach(function(x) { x.enable(); });},
|
||||
sync() {
|
||||
this.components.forEach(function(x) { x.sync?.(); });
|
||||
this.objects.forEach(function(x) { x.sync?.(); });
|
||||
},
|
||||
|
||||
/* Bounding box of the object in world dimensions */
|
||||
boundingbox() {
|
||||
var boxes = [];
|
||||
boxes.push({
|
||||
t:0,
|
||||
r:0,
|
||||
b:0,
|
||||
l:0
|
||||
});
|
||||
save: true,
|
||||
selectable: true,
|
||||
ed_locked: false,
|
||||
|
||||
for (var key in this.components) {
|
||||
if ('boundingbox' in this.components[key])
|
||||
boxes.push(this.components[key].boundingbox());
|
||||
}
|
||||
for (var key in this.objects)
|
||||
boxes.push(this.objects[key].boundingbox());
|
||||
disable() { this.components.forEach(function(x) { x.disable(); }); },
|
||||
enable() { this.components.forEach(function(x) { x.enable(); }); },
|
||||
sync() {
|
||||
this.components.forEach(function(x) { x.sync?.(); });
|
||||
this.objects.forEach(function(x) { x.sync?.(); });
|
||||
},
|
||||
|
||||
var bb = boxes.shift();
|
||||
/* Bounding box of the object in world dimensions */
|
||||
boundingbox() {
|
||||
var boxes = [];
|
||||
boxes.push({
|
||||
t: 0,
|
||||
r: 0,
|
||||
b: 0,
|
||||
l: 0
|
||||
});
|
||||
|
||||
boxes.forEach(function(x) { bb = bbox.expand(bb, x); });
|
||||
|
||||
bb = bbox.move(bb, this.pos);
|
||||
for (var key in this.components) {
|
||||
if ('boundingbox' in this.components[key])
|
||||
boxes.push(this.components[key].boundingbox());
|
||||
}
|
||||
for (var key in this.objects)
|
||||
boxes.push(this.objects[key].boundingbox());
|
||||
|
||||
return bb ? bb : bbox.fromcwh([0,0], [0,0]);
|
||||
},
|
||||
var bb = boxes.shift();
|
||||
|
||||
/* The unique components of this object. Its diff. */
|
||||
json_obj() {
|
||||
var u = this.get_ur();
|
||||
if (!u) return {};
|
||||
var proto = u.proto;
|
||||
var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components.
|
||||
|
||||
var d = ediff(thiso,proto);
|
||||
|
||||
d ??= {};
|
||||
|
||||
var objects = {};
|
||||
proto.objects ??= {};
|
||||
var curobjs = {};
|
||||
for (var o in this.objects)
|
||||
curobjs[o] = this.objects[o].instance_obj();
|
||||
boxes.forEach(function(x) { bb = bbox.expand(bb, x); });
|
||||
|
||||
var odiff = ediff(curobjs, proto.objects);
|
||||
if (odiff)
|
||||
d.objects = curobjs;
|
||||
bb = bbox.move(bb, this.pos);
|
||||
|
||||
delete d.pos;
|
||||
delete d.angle;
|
||||
delete d.scale;
|
||||
delete d.velocity;
|
||||
delete d.angularvelocity;
|
||||
return d;
|
||||
},
|
||||
return bb ? bb : bbox.fromcwh([0, 0], [0, 0]);
|
||||
},
|
||||
|
||||
/* The object needed to store an object as an instance of a master */
|
||||
instance_obj() {
|
||||
var t = this.transform();
|
||||
t.ur = this.ur;
|
||||
return t;
|
||||
},
|
||||
/* The unique components of this object. Its diff. */
|
||||
json_obj() {
|
||||
var u = this.get_ur();
|
||||
if (!u) return {};
|
||||
var proto = u.proto;
|
||||
var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components.
|
||||
|
||||
proto() {
|
||||
var u = this.get_ur();
|
||||
if (!u) return {};
|
||||
return u.proto;
|
||||
},
|
||||
var d = ediff(thiso, proto);
|
||||
|
||||
transform() {
|
||||
var t = {};
|
||||
t.pos = this.pos;
|
||||
if (t.pos.every(x=>x===0)) delete t.pos;
|
||||
t.angle = Math.places(this.angle,4);
|
||||
if (t.angle === 0) delete t.angle;
|
||||
t.scale = this.scale;
|
||||
t.scale = t.scale.map((x,i) => x/this.proto().scale[i]);
|
||||
t.scale = t.scale.map(x => Math.places(x,3));
|
||||
if (t.scale.every(x=>x===1)) delete t.scale;
|
||||
return t;
|
||||
},
|
||||
d ??= {};
|
||||
|
||||
/* Velocity and angular velocity of the object */
|
||||
phys_obj() {
|
||||
var phys = {};
|
||||
phys.velocity = this.velocity;
|
||||
phys.angularvelocity = this.angularvelocity;
|
||||
return phys;
|
||||
},
|
||||
var objects = {};
|
||||
proto.objects ??= {};
|
||||
var curobjs = {};
|
||||
for (var o in this.objects)
|
||||
curobjs[o] = this.objects[o].instance_obj();
|
||||
|
||||
dup(diff) {
|
||||
var n = this.master.spawn(this.__proto__);
|
||||
Object.totalmerge(n, this.instance_obj());
|
||||
return n;
|
||||
},
|
||||
var odiff = ediff(curobjs, proto.objects);
|
||||
if (odiff)
|
||||
d.objects = curobjs;
|
||||
|
||||
delete d.pos;
|
||||
delete d.angle;
|
||||
delete d.scale;
|
||||
delete d.velocity;
|
||||
delete d.angularvelocity;
|
||||
return d;
|
||||
},
|
||||
|
||||
/* The object needed to store an object as an instance of a master */
|
||||
instance_obj() {
|
||||
var t = this.transform();
|
||||
t.ur = this.ur;
|
||||
return t;
|
||||
},
|
||||
|
||||
proto() {
|
||||
var u = this.get_ur();
|
||||
if (!u) return {};
|
||||
return u.proto;
|
||||
},
|
||||
|
||||
transform() {
|
||||
var t = {};
|
||||
t.pos = this.pos;
|
||||
if (t.pos.every(x => x === 0)) delete t.pos;
|
||||
t.angle = Math.places(this.angle, 4);
|
||||
if (t.angle === 0) delete t.angle;
|
||||
t.scale = this.scale;
|
||||
t.scale = t.scale.map((x, i) => x / this.proto().scale[i]);
|
||||
t.scale = t.scale.map(x => Math.places(x, 3));
|
||||
if (t.scale.every(x => x === 1)) delete t.scale;
|
||||
return t;
|
||||
},
|
||||
|
||||
/* Velocity and angular velocity of the object */
|
||||
phys_obj() {
|
||||
var phys = {};
|
||||
phys.velocity = this.velocity;
|
||||
phys.angularvelocity = this.angularvelocity;
|
||||
return phys;
|
||||
},
|
||||
|
||||
dup(diff) {
|
||||
var n = this.master.spawn(this.__proto__);
|
||||
Object.totalmerge(n, this.instance_obj());
|
||||
return n;
|
||||
},
|
||||
|
||||
kill() {
|
||||
if (this.__kill) return;
|
||||
this.__kill = true;
|
||||
|
||||
|
||||
this.timers.forEach(t => t());
|
||||
this.timers = [];
|
||||
Event.rm_obj(this);
|
||||
Player.do_uncontrol(this);
|
||||
register_collide(2, undefined, this.body);
|
||||
|
||||
|
||||
if (this.master) {
|
||||
this.master.remove_obj(this);
|
||||
this.master = undefined;
|
||||
}
|
||||
|
||||
|
||||
if (this.__proto__.instances)
|
||||
delete this.__proto__.instances[this.toString()];
|
||||
|
||||
for (var key in this.components) {
|
||||
this.components[key].kill();
|
||||
this.components[key].kill?.();
|
||||
this.components[key].gameobject = undefined;
|
||||
delete this.components[key];
|
||||
}
|
||||
|
||||
this.clear();
|
||||
this.objects = undefined;
|
||||
|
||||
|
||||
if (typeof this.stop === 'function') this.stop();
|
||||
if (typeof this.die === 'function') this.die();
|
||||
},
|
||||
|
||||
up() { return [0,1].rotate(this.angle);},
|
||||
down() { return [0,-1].rotate(this.angle);},
|
||||
right() { return [1,0].rotate(this.angle);},
|
||||
left() { return [-1,0].rotate(this.angle); },
|
||||
up() { return [0, 1].rotate(this.angle); },
|
||||
down() { return [0, -1].rotate(this.angle); },
|
||||
right() { return [1, 0].rotate(this.angle); },
|
||||
left() { return [-1, 0].rotate(this.angle); },
|
||||
|
||||
make_objs(objs) {
|
||||
for (var prop in objs) {
|
||||
|
@ -659,7 +663,7 @@ var gameobject = {
|
|||
this.objects[o].obj_descend(fn);
|
||||
},
|
||||
}
|
||||
Object.mixin(gameobject,gameobject_impl);
|
||||
Object.mixin(gameobject, gameobject_impl);
|
||||
|
||||
gameobject.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`;
|
||||
|
||||
|
@ -737,14 +741,13 @@ ur {
|
|||
|
||||
/* Apply an ur u to an entity e */
|
||||
/* u is given as */
|
||||
function apply_ur(u, e)
|
||||
{
|
||||
function apply_ur(u, e) {
|
||||
console.log(`applying ur ${u}`);
|
||||
if (typeof u !== 'string') {
|
||||
console.warn("Must give u as a string.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var urs = u.split('.');
|
||||
var config = {};
|
||||
var topur = ur;
|
||||
|
@ -759,7 +762,7 @@ function apply_ur(u, e)
|
|||
var script = Resources.replstrs(topur.text);
|
||||
eval_env(script, e, topur.text);
|
||||
}
|
||||
|
||||
|
||||
if (topur.data) {
|
||||
var jss = Resources.replstrs(topur.data);
|
||||
Object.merge(config, json.decode(jss));
|
||||
|
@ -769,28 +772,27 @@ function apply_ur(u, e)
|
|||
Object.merge(e, config);
|
||||
}
|
||||
|
||||
function file2fqn(file)
|
||||
{
|
||||
function file2fqn(file) {
|
||||
var fqn = file.strip_ext();
|
||||
if (fqn.folder_same_name())
|
||||
fqn = fqn.up_path();
|
||||
|
||||
fqn = fqn.replace('/','.');
|
||||
fqn = fqn.replace('/', '.');
|
||||
var topur;
|
||||
if (topur = Object.access(ur,fqn)) return topur;
|
||||
if (topur = Object.access(ur, fqn)) return topur;
|
||||
|
||||
var fqnlast = fqn.split('.').last();
|
||||
|
||||
if (topur = Object.access(ur,fqn.tolast('.'))) {
|
||||
if (topur = Object.access(ur, fqn.tolast('.'))) {
|
||||
topur[fqnlast] = {
|
||||
name: fqn
|
||||
};
|
||||
ur._list.push(fqn);
|
||||
return Object.access(ur,fqn);
|
||||
return Object.access(ur, fqn);
|
||||
}
|
||||
|
||||
|
||||
fqn = fqnlast;
|
||||
|
||||
|
||||
ur[fqn] = {
|
||||
name: fqn
|
||||
};
|
||||
|
@ -821,4 +823,4 @@ Game.loadurs = function() {
|
|||
|
||||
return {
|
||||
gameobject
|
||||
}
|
||||
}
|
|
@ -40,6 +40,27 @@ var GUI = {
|
|||
gui_img(path,pos, [1.0,1.0], 0.0, false, [0.0,0.0], Color.white);
|
||||
return bbox.fromcwh([0,0], wh);
|
||||
},
|
||||
|
||||
newmg(img) {
|
||||
var def = {
|
||||
path: "",
|
||||
pos: [0,0],
|
||||
size:[0,0],
|
||||
frame: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 1,
|
||||
h: 1
|
||||
},
|
||||
angle: 0,
|
||||
anchor: [0,0],
|
||||
color: Color.white,
|
||||
}
|
||||
for (var i in def)
|
||||
img[i] ??= def[i];
|
||||
|
||||
gui_newmg
|
||||
},
|
||||
|
||||
input_lmouse_pressed() {
|
||||
if (GUI.selected)
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
var audio = {};
|
||||
|
||||
var sound_pref = ['wav', 'flac', 'mp3', 'qoa'];
|
||||
|
||||
audio.sound = {
|
||||
bus: {},
|
||||
samplerate() { return cmd(198); },
|
||||
sounds: [], /* array of loaded sound files */
|
||||
play(file, bus) {
|
||||
if (!io.exists(file)) {
|
||||
file = Resources.find_sound(file);
|
||||
if (!file) {
|
||||
console.error(`Cannot play sound ${file}: does not exist.`);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -41,14 +41,27 @@ os.prefpath = function() {
|
|||
var projectfile = ".prosperon/project.json";
|
||||
|
||||
var Resources = {};
|
||||
Resources.images = ["png", "jpg", "jpeg", "gif"];
|
||||
Resources.sounds = ["wav", "mp3", "flac", "qoa"];
|
||||
Resources.images = ["png", "gif", "jpg", "jpeg"];
|
||||
Resources.sounds = ["wav", 'flac', 'mp3', "qoa"];
|
||||
Resources.scripts = "js";
|
||||
Resources.is_image = function(path) {
|
||||
var ext = path.ext();
|
||||
return Resources.images.any(x => x === ext);
|
||||
}
|
||||
|
||||
function find_ext(file, ext)
|
||||
{
|
||||
if (io.exists(file)) return file;
|
||||
for (var e of ext) {
|
||||
var nf = `${file}.${e}`;
|
||||
if (io.exists(nf)) return nf;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Resources.find_image = function(file) { return find_ext(file,Resources.images); }
|
||||
Resources.find_sound = function(file) { return find_ext(file,Resources.sounds); }
|
||||
|
||||
Resources.is_sound = function(path) {
|
||||
var ext = path.ext();
|
||||
return Resources.sounds.any(x => x === ext);
|
||||
|
|
|
@ -21,6 +21,7 @@ cpSpace *space = NULL;
|
|||
|
||||
struct rgba color_white = {255,255,255,255};
|
||||
struct rgba color_black = {0,0,0,255};
|
||||
struct rgba color_clear = {0,0,0,0};
|
||||
|
||||
struct rgba disabled_color = {148,148,148,255};
|
||||
struct rgba sleep_color = {255,140,228,255};
|
||||
|
@ -624,13 +625,13 @@ JSValue arb2js(cpArbiter *arb)
|
|||
norm.cp = cpArbiterGetNormal(arb);
|
||||
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "normal", vec2js(norm));
|
||||
JS_SetPropertyStr(js, obj, "normal", vec22js(norm));
|
||||
JS_SetPropertyStr(js, obj, "obj", JS_DupValue(js,go2->ref));
|
||||
JS_SetPropertyStr(js, obj, "sensor", JS_NewBool(js, cpShapeGetSensor(shape2)));
|
||||
|
||||
HMM_Vec2 srfv;
|
||||
srfv.cp = cpArbiterGetSurfaceVelocity(arb);
|
||||
JS_SetPropertyStr(js, obj, "velocity", vec2js(srfv));
|
||||
JS_SetPropertyStr(js, obj, "velocity", vec22js(srfv));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -143,19 +143,19 @@ void mesh_add_material(mesh *mesh, cgltf_material *mat)
|
|||
mesh->bind.fs.images[0] = texture_fromdata(buf->buffer->data, buf->size)->id;
|
||||
} else {
|
||||
// char *imp = seprint("%s/%s", dirname(mesh->model->path), img->uri);
|
||||
// mesh->bind.fs.images[0] = texture_pullfromfile(imp)->id;
|
||||
// mesh->bind.fs.images[0] = texture_from_file(imp)->id;
|
||||
// free(imp);
|
||||
}
|
||||
} else
|
||||
mesh->bind.fs.images[0] = texture_pullfromfile("k")->id;
|
||||
mesh->bind.fs.images[0] = texture_from_file("k")->id;
|
||||
|
||||
mesh->bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||
/*
|
||||
cgltf_texture *tex;
|
||||
if (tex = mat->normal_texture.texture)
|
||||
mesh->bind.fs.images[1] = texture_pullfromfile(tex->image->uri)->id;
|
||||
mesh->bind.fs.images[1] = texture_from_file(tex->image->uri)->id;
|
||||
else
|
||||
mesh->bind.fs.images[1] = texture_pullfromfile("k")->id;*/
|
||||
mesh->bind.fs.images[1] = texture_from_file("k")->id;*/
|
||||
}
|
||||
|
||||
sg_buffer texcoord_floats(float *f, int verts, int comp)
|
||||
|
|
|
@ -19,11 +19,11 @@ struct datastream {
|
|||
soundbyte *ring;
|
||||
};
|
||||
|
||||
struct Texture;
|
||||
struct texture;
|
||||
|
||||
void MakeDatastream();
|
||||
struct datastream *ds_openvideo(const char *path);
|
||||
struct Texture *ds_maketexture(struct datastream *);
|
||||
struct texture *ds_maketexture(struct datastream *);
|
||||
void ds_advance(struct datastream *ds, double);
|
||||
void ds_seek(struct datastream *ds, double);
|
||||
void ds_advanceframes(struct datastream *ds, int frames);
|
||||
|
|
|
@ -180,11 +180,11 @@ struct sFont *MakeFont(const char *fontfile, int height) {
|
|||
for (unsigned char c = 32; c < 127; c++) {
|
||||
stbtt_packedchar glyph = glyphs[c - 32];
|
||||
|
||||
struct glrect r;
|
||||
r.s0 = (glyph.x0) / (float)packsize;
|
||||
r.s1 = (glyph.x1) / (float)packsize;
|
||||
r.t0 = (glyph.y0) / (float)packsize;
|
||||
r.t1 = (glyph.y1) / (float)packsize;
|
||||
struct rect r;
|
||||
r.x = (glyph.x0) / (float)packsize;
|
||||
r.w = (glyph.x1-glyph.x0) / (float)packsize;
|
||||
r.y = (glyph.y0) / (float)packsize;
|
||||
r.h = (glyph.y1-glyph.y0) / (float)packsize;
|
||||
|
||||
stbtt_GetCodepointHMetrics(&fontinfo, c, &newfont->Characters[c].Advance, &newfont->Characters[c].leftbearing);
|
||||
newfont->Characters[c].leftbearing *= newfont->emscale;
|
||||
|
@ -260,10 +260,10 @@ void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgb
|
|||
|
||||
// if (vert.pos.x > frame.l || vert.pos.y > frame.t || (vert.pos.y + vert.wh.y) < frame.b || (vert.pos.x + vert.wh.x) < frame.l) return;
|
||||
|
||||
vert.uv.u = c.rect.s0*USHRT_MAX;
|
||||
vert.uv.v = c.rect.t0*USHRT_MAX;
|
||||
vert.st.u = (c.rect.s1-c.rect.s0)*USHRT_MAX;
|
||||
vert.st.v = (c.rect.t1-c.rect.t0)*USHRT_MAX;
|
||||
vert.uv.u = c.rect.x*USHRT_MAX;
|
||||
vert.uv.v = c.rect.y*USHRT_MAX;
|
||||
vert.st.u = c.rect.w*USHRT_MAX;
|
||||
vert.st.v = c.rect.h*USHRT_MAX;
|
||||
vert.color = color;
|
||||
|
||||
memcpy(text_buffer + curchar, &vert, sizeof(struct text_vert));
|
||||
|
|
|
@ -14,7 +14,7 @@ struct Character {
|
|||
float Bearing[2]; // Offset from baseline to left/top of glyph
|
||||
int Advance; // Horizontal offset to advance to next glyph
|
||||
int leftbearing;
|
||||
struct glrect rect;
|
||||
struct rect rect;
|
||||
};
|
||||
|
||||
struct sFont {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define FREELIST_H
|
||||
|
||||
/* Given a pointer to a struct, create a free list
|
||||
Struct must have a 'next' field
|
||||
Struct must have an 'unsigned int next' field
|
||||
*/
|
||||
|
||||
struct freelistheader
|
||||
|
@ -32,7 +32,7 @@ static inline unsigned int freelist_check(struct freelistheader *h, void *data,
|
|||
#define freelist_size(p,l) do{p = freelist_make(sizeof(*p),l); for(int i = 0; i < l; i++) { p[i].next = i+1; }}while(0)
|
||||
#define freelist_len(p) (freelist_header(p)->len)
|
||||
#define freelist_first(p) (freelist_header(p)->first)
|
||||
#define freelist_grab(i,p) do{i=freelist_header(p)->first; freelist_header(p)->first = p[i].next; p[i].next = -1;freelist_header(p)->count++;}while(0)
|
||||
#define freelist_grab(p,i) do{i=freelist_header(p)->first; freelist_header(p)->first = p[i].next; p[i].next = -1;freelist_header(p)->count++;}while(0)
|
||||
#define freelist_kill(p,i) do{p[i].next = freelist_first(p);freelist_first(p)=i;freelist_header(p)->count--;}while(0)
|
||||
#define freelist_free(p) (free(freelist_header(p)))
|
||||
#define freelist_count(p) (freelist_header(p)->count)
|
||||
|
|
|
@ -67,10 +67,11 @@ static JSValue TYPE##2js(TYPE *n) { \
|
|||
JS_SetOpaque(j,n);\
|
||||
return j; }\
|
||||
|
||||
|
||||
QJSCLASS(gameobject)
|
||||
QJSCLASS(emitter)
|
||||
QJSCLASS(dsp_node)
|
||||
QJSCLASS(texture)
|
||||
QJSCLASS(sprite)
|
||||
QJSCLASS(warp_gravity)
|
||||
QJSCLASS(warp_damp)
|
||||
QJSCLASS(material)
|
||||
|
@ -107,6 +108,7 @@ JS_SetPropertyStr(js, globalThis, #NAME, NAME); \
|
|||
JS_NewClassID(&js_##TYPE##_id);\
|
||||
JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\
|
||||
|
||||
/* Defines a class and uses its function list as its prototype */
|
||||
#define QJSCLASSPREP_FUNCS(TYPE) \
|
||||
QJSCLASSPREP(TYPE); \
|
||||
JSValue TYPE##_proto = JS_NewObject(js); \
|
||||
|
@ -215,7 +217,6 @@ void *js2ptr(JSValue v) { return JS_GetOpaque(v,js_ptr_id); }
|
|||
JSValue number2js(double g) {
|
||||
return JS_NewFloat64(js,g);
|
||||
}
|
||||
struct sprite *js2sprite(JSValue v) { return id2sprite(js2int(v)); }
|
||||
|
||||
JSValue ptr2js(void *ptr) {
|
||||
JSValue obj = JS_NewObjectClass(js, js_ptr_id);
|
||||
|
@ -231,15 +232,6 @@ double js_get_prop_number(JSValue v, const char *p) {
|
|||
return num;
|
||||
}
|
||||
|
||||
struct glrect js2glrect(JSValue v) {
|
||||
struct glrect rect;
|
||||
rect.s0 = js_get_prop_number(v, "s0");
|
||||
rect.s1 = js_get_prop_number(v, "s1");
|
||||
rect.t0 = js_get_prop_number(v, "t0");
|
||||
rect.t1 = js_get_prop_number(v, "t1");
|
||||
return rect;
|
||||
}
|
||||
|
||||
JSValue js_arridx(JSValue v, int idx) { return js_getpropidx(v, idx); }
|
||||
|
||||
int js_arrlen(JSValue v) {
|
||||
|
@ -406,6 +398,14 @@ HMM_Vec2 js2vec2(JSValue v)
|
|||
return v2;
|
||||
}
|
||||
|
||||
JSValue vec22js(HMM_Vec2 v)
|
||||
{
|
||||
JSValue array = JS_NewArray(js);
|
||||
js_setprop_num(array,0,number2js(v.x));
|
||||
js_setprop_num(array,1,number2js(v.y));
|
||||
return array;
|
||||
}
|
||||
|
||||
HMM_Vec3 js2vec3(JSValue v)
|
||||
{
|
||||
HMM_Vec3 v3;
|
||||
|
@ -474,17 +474,10 @@ void vec2float(HMM_Vec2 v, float *f) {
|
|||
f[1] = v.y;
|
||||
}
|
||||
|
||||
JSValue vec2js(HMM_Vec2 v) {
|
||||
JSValue array = JS_NewArray(js);
|
||||
js_setprop_num(array,0,number2js(v.x));
|
||||
js_setprop_num(array,1,number2js(v.y));
|
||||
return array;
|
||||
}
|
||||
|
||||
JSValue vecarr2js(HMM_Vec2 *points, int n) {
|
||||
JSValue array = JS_NewArray(js);
|
||||
for (int i = 0; i < n; i++)
|
||||
js_setprop_num(array,i,vec2js(points[i]));
|
||||
js_setprop_num(array,i,vec22js(points[i]));
|
||||
|
||||
return array;
|
||||
}
|
||||
|
@ -695,11 +688,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
ret = JS_NewInt64(js, script_dofile(str));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
YughWarn("Do not set pawns here anymore; Do it entirely in script.");
|
||||
// set_pawn(js2ptrduk_get_heapptr(duk, 1));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
set_timescale(js2number(argv[1]));
|
||||
break;
|
||||
|
@ -715,34 +703,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
case 7:
|
||||
physMS = js2number(argv[1]);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
phys2d_set_gravity(js2vec2(argv[1]));
|
||||
break;
|
||||
|
||||
case 9:
|
||||
sprite_delete(js2int(argv[1]));
|
||||
break;
|
||||
|
||||
case 10:
|
||||
YughWarn("Pawns are handled in script only now.");
|
||||
break;
|
||||
|
||||
case 11:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
ret = JS_NewInt64(js, file_mod_secs(str));
|
||||
break;
|
||||
|
||||
case 12:
|
||||
str = JS_ToCString(js, argv[2]);
|
||||
sprite_loadtex(id2sprite(js2int(argv[1])), str, js2glrect(argv[3]));
|
||||
break;
|
||||
|
||||
case 13:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
str2 = JS_ToCString(js, argv[2]);
|
||||
play_song(str, str2);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
gameobject_draw_debug(js2gameobject(argv[1]));
|
||||
break;
|
||||
|
@ -760,10 +721,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
shape_set_sensor(js2ptr(argv[1]), JS_ToBool(js, argv[2]));
|
||||
break;
|
||||
|
||||
case 20:
|
||||
sprite_enabled(js2int(argv[1]), JS_ToBool(js, argv[2]));
|
||||
break;
|
||||
|
||||
case 21:
|
||||
ret = JS_NewBool(js, shape_get_sensor(js2ptr(argv[1])));
|
||||
break;
|
||||
|
@ -776,79 +733,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
ret = JS_NewBool(js, shape_is_enabled(js2ptr(argv[1])));
|
||||
break;
|
||||
|
||||
case 24:
|
||||
timer_pause(js2timer(argv[1]));
|
||||
break;
|
||||
|
||||
case 25:
|
||||
timer_stop(js2timer(argv[1]));
|
||||
break;
|
||||
|
||||
case 26:
|
||||
timer_start(js2timer(argv[1]));
|
||||
break;
|
||||
|
||||
case 27:
|
||||
timer_remove(js2int(argv[1]));
|
||||
break;
|
||||
|
||||
case 28:
|
||||
timerr_settime(js2timer(argv[1]), js2number(argv[2]));
|
||||
break;
|
||||
|
||||
case 29:
|
||||
ret = JS_NewFloat64(js, js2timer(argv[1])->interval);
|
||||
break;
|
||||
|
||||
case 31:
|
||||
free(js2ptr(argv[1]));
|
||||
break;
|
||||
|
||||
case 32:
|
||||
ret = JS_NewFloat64(js, js2timer(argv[1])->remain_time);
|
||||
break;
|
||||
|
||||
case 33:
|
||||
ret = JS_NewBool(js, js2timer(argv[1])->on);
|
||||
break;
|
||||
|
||||
case 34:
|
||||
ret = JS_NewBool(js, js2timer(argv[1])->repeat);
|
||||
break;
|
||||
|
||||
case 35:
|
||||
js2timer(argv[1])->repeat = JS_ToBool(js, argv[2]);
|
||||
break;
|
||||
|
||||
case 36:
|
||||
js2gameobject(argv[1])->scale.XY = js2vec2(argv[2]);
|
||||
gameobject_apply(js2gameobject(argv[1]));
|
||||
cpSpaceReindexShapesForBody(space, js2gameobject(argv[1])->body);
|
||||
break;
|
||||
|
||||
case 37:
|
||||
if (!id2sprite(js2int(argv[1]))) break;
|
||||
id2sprite(js2int(argv[1]))->t.pos = js2vec2(argv[2]);
|
||||
break;
|
||||
|
||||
case 40:
|
||||
js2gameobject(argv[1])->filter.categories = js2bitmask(argv[2]);
|
||||
gameobject_apply(js2gameobject(argv[1]));
|
||||
break;
|
||||
|
||||
case 41:
|
||||
js2gameobject(argv[1])->filter.mask = js2bitmask(argv[2]);
|
||||
gameobject_apply(js2gameobject(argv[1]));
|
||||
break;
|
||||
|
||||
case 42:
|
||||
ret = bitmask2js(js2gameobject(argv[1])->filter.categories);
|
||||
break;
|
||||
|
||||
case 43:
|
||||
ret = bitmask2js(js2gameobject(argv[1])->filter.mask);
|
||||
break;
|
||||
|
||||
case 44:
|
||||
go = pos2gameobject(js2vec2(argv[1]), js2number(argv[2]));
|
||||
ret = go ? JS_DupValue(js,go->ref) : JS_UNDEFINED;
|
||||
|
@ -884,10 +774,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
draw_box(js2vec2(argv[1]), js2vec2(argv[2]), js2color(argv[3]));
|
||||
break;
|
||||
|
||||
case 54:
|
||||
gameobject_apply(js2gameobject(argv[1]));
|
||||
break;
|
||||
|
||||
case 59:
|
||||
v1 = js2cpvec2arr(argv[2]);
|
||||
ret = JS_NewInt64(js, point2segindex(js2vec2(argv[1]), v1, js2number(argv[3])));
|
||||
|
@ -901,17 +787,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
add_zoom(js2number(argv[1]));
|
||||
break;
|
||||
|
||||
case 63:
|
||||
set_cam_body(NULL);
|
||||
break;
|
||||
|
||||
case 64:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
ret = vec2js(tex_get_dimensions(texture_pullfromfile(str)));
|
||||
break;
|
||||
|
||||
case 66:
|
||||
ret = strarr2js(ls(","));
|
||||
ret = vec22js(tex_get_dimensions(texture_from_file(str)));
|
||||
break;
|
||||
|
||||
case 67:
|
||||
|
@ -923,37 +801,17 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 70:
|
||||
ret = vec2js(world2go(js2gameobject(argv[1]), js2vec2(argv[2])));
|
||||
ret = vec22js(world2go(js2gameobject(argv[1]), js2vec2(argv[2])));
|
||||
break;
|
||||
|
||||
case 71:
|
||||
ret = vec2js(go2world(js2gameobject(argv[1]), js2vec2(argv[2])));
|
||||
break;
|
||||
|
||||
case 72:
|
||||
ret = vec2js((HMM_Vec2)cpSpaceGetGravity(space));
|
||||
break;
|
||||
|
||||
case 73:
|
||||
cpSpaceSetDamping(space, js2number(argv[1]));
|
||||
break;
|
||||
|
||||
case 74:
|
||||
ret = JS_NewFloat64(js, cpSpaceGetDamping(space));
|
||||
break;
|
||||
|
||||
case 75:
|
||||
js2gameobject(argv[1])->layer = js2int(argv[2]);
|
||||
ret = vec22js(go2world(js2gameobject(argv[1]), js2vec2(argv[2])));
|
||||
break;
|
||||
|
||||
case 76:
|
||||
set_cat_mask(js2int(argv[1]), js2bitmask(argv[2]));
|
||||
break;
|
||||
|
||||
case 77:
|
||||
ret = int2js(js2gameobject(argv[1])->layer);
|
||||
break;
|
||||
|
||||
case 79:
|
||||
ret = JS_NewBool(js, phys_stepping());
|
||||
break;
|
||||
|
@ -978,7 +836,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 85:
|
||||
ret = vec2js(HMM_ProjV2(js2vec2(argv[1]), js2vec2(argv[2])));
|
||||
ret = vec22js(HMM_ProjV2(js2vec2(argv[1]), js2vec2(argv[2])));
|
||||
break;
|
||||
|
||||
case 86:
|
||||
|
@ -1010,36 +868,13 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
ret = int2js(logLevel);
|
||||
break;
|
||||
|
||||
case 96:
|
||||
id2sprite(js2int(argv[1]))->color = js2color(argv[2]);
|
||||
break;
|
||||
|
||||
case 97:
|
||||
str = js2str(argv[1]);
|
||||
cursor_img(str);
|
||||
break;
|
||||
case 103:
|
||||
ret = vec2js(js2gameobject(argv[1])->scale.XY);
|
||||
ret = vec22js(js2gameobject(argv[1])->scale.XY);
|
||||
break;
|
||||
case 106:
|
||||
js2gameobject(argv[1])->e = js2number(argv[2]);
|
||||
break;
|
||||
case 107:
|
||||
ret = number2js(js2gameobject(argv[1])->e);
|
||||
break;
|
||||
case 108:
|
||||
js2gameobject(argv[1])->f = js2number(argv[2]);
|
||||
break;
|
||||
case 109:
|
||||
ret = number2js(js2gameobject(argv[1])->f);
|
||||
break;
|
||||
case 110:
|
||||
ret = number2js(js2gameobject(argv[1])->e);
|
||||
break;
|
||||
|
||||
case 111:
|
||||
ret = vec2js(js2sprite(argv[1])->t.pos);
|
||||
break;
|
||||
|
||||
case 112:
|
||||
ret = number2js(((struct phys2d_edge*)js2ptr(argv[1]))->thickness);
|
||||
|
@ -1049,18 +884,10 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
js2gameobject(argv[1])->ref = argv[2];
|
||||
break;
|
||||
|
||||
case 114:
|
||||
ret = bool2js(js2sprite(argv[1])->enabled);
|
||||
break;
|
||||
|
||||
case 115:
|
||||
draw_circle(js2vec2(argv[1]), js2number(argv[2]), js2number(argv[2]), js2color(argv[3]), -1);
|
||||
break;
|
||||
|
||||
case 116:
|
||||
ret = str2js(tex_get_path(js2sprite(argv[1])->tex));
|
||||
break;
|
||||
|
||||
case 117:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
ret = script_runfile(str);
|
||||
|
@ -1141,16 +968,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
|
||||
case 136:
|
||||
ret = vec2js(world2screen(js2vec2(argv[1])));
|
||||
ret = vec22js(world2screen(js2vec2(argv[1])));
|
||||
break;
|
||||
|
||||
case 137:
|
||||
ret = vec2js(screen2world(js2vec2(argv[1])));
|
||||
break;
|
||||
|
||||
case 138:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
ret = JS_NewInt64(js, jso_file(str));
|
||||
ret = vec22js(screen2world(js2vec2(argv[1])));
|
||||
break;
|
||||
|
||||
case 139:
|
||||
|
@ -1171,13 +993,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
console_print(str);
|
||||
break;
|
||||
|
||||
case 143:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
if (!getenv(str)) ret = JS_UNDEFINED;
|
||||
else
|
||||
ret = str2js(getenv(str));
|
||||
break;
|
||||
|
||||
case 145:
|
||||
if (js2bool(argv[1])) window_makefullscreen(&mainwin);
|
||||
else window_unfullscreen(&mainwin);
|
||||
|
@ -1186,12 +1001,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
log_clear();
|
||||
break;
|
||||
|
||||
case 147:
|
||||
exit(js2int(argv[1]));
|
||||
break;
|
||||
case 148:
|
||||
ret = color2js(id2sprite(js2int(argv[1]))->color);
|
||||
break;
|
||||
case 149:
|
||||
((struct drawmodel *)js2ptr(argv[1]))->model = GetExistingModel(js2str(argv[2]));
|
||||
break;
|
||||
|
@ -1200,58 +1009,18 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
draw_drawmodel(js2ptr(argv[1]));
|
||||
break;
|
||||
|
||||
case 151:
|
||||
js2gameobject(argv[1])->maxvelocity = js2number(argv[2]);
|
||||
break;
|
||||
case 152:
|
||||
ret = number2js(js2gameobject(argv[1])->maxvelocity);
|
||||
break;
|
||||
case 153:
|
||||
cpBodySetTorque(js2gameobject(argv[1])->body, js2number(argv[2]));
|
||||
break;
|
||||
case 154:
|
||||
js2gameobject(argv[1])->maxangularvelocity = js2number(argv[2]);
|
||||
break;
|
||||
case 155:
|
||||
ret = number2js(js2gameobject(argv[1])->maxangularvelocity);
|
||||
break;
|
||||
|
||||
case 156:
|
||||
js2gameobject(argv[1])->damping = js2number(argv[2]);
|
||||
break;
|
||||
case 157:
|
||||
ret = number2js(js2gameobject(argv[1])->damping);
|
||||
break;
|
||||
|
||||
case 160:
|
||||
ret = vec2js(mat_t_dir(t_world2go(js2gameobject(argv[1])), js2vec2(argv[2])));
|
||||
ret = vec22js(mat_t_dir(t_world2go(js2gameobject(argv[1])), js2vec2(argv[2])));
|
||||
break;
|
||||
case 161:
|
||||
ret = vec2js(mat_t_dir(t_go2world(js2gameobject(argv[1])), js2vec2(argv[2])));
|
||||
break;
|
||||
case 162:
|
||||
str = JS_ToCString(js, argv[1]);
|
||||
ret = int2js(remove(str));
|
||||
ret = vec22js(mat_t_dir(t_go2world(js2gameobject(argv[1])), js2vec2(argv[2])));
|
||||
break;
|
||||
|
||||
case 164:
|
||||
unplug_node(js2ptr(argv[1]));
|
||||
break;
|
||||
|
||||
case 168:
|
||||
js2gameobject(argv[1])->timescale = js2number(argv[2]);
|
||||
break;
|
||||
case 169:
|
||||
ret = number2js(js2gameobject(argv[1])->timescale);
|
||||
break;
|
||||
case 170:
|
||||
id2sprite(js2int(argv[1]))->emissive = js2color(argv[2]);
|
||||
break;
|
||||
case 171:
|
||||
ret = number2js(js2gameobject(argv[1])->drawlayer);
|
||||
break;
|
||||
case 172:
|
||||
js2gameobject(argv[1])->drawlayer = js2number(argv[2]);
|
||||
break;
|
||||
case 173:
|
||||
str = js2str(argv[1]);
|
||||
capture_screen(js2number(argv[2]), js2number(argv[3]), js2number(argv[4]), js2number(argv[5]), str);
|
||||
|
@ -1340,24 +1109,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
case 214:
|
||||
ret = int2js(go_count());
|
||||
break;
|
||||
case 215:
|
||||
ret = vec2js(js2sprite(argv[1])->t.scale);
|
||||
break;
|
||||
case 216:
|
||||
js2sprite(argv[1])->t.scale = js2vec2(argv[2]);
|
||||
break;
|
||||
case 217:
|
||||
ret = number2js(js2sprite(argv[1])->t.angle);
|
||||
break;
|
||||
case 218:
|
||||
js2sprite(argv[1])->t.angle = js2number(argv[2]);
|
||||
break;
|
||||
case 219:
|
||||
js2sprite(argv[1])->drawmode = js2number(argv[2]);
|
||||
break;
|
||||
case 220:
|
||||
ret = number2js(js2sprite(argv[1])->drawmode);
|
||||
break;
|
||||
|
||||
case 221:
|
||||
ret = constraint2js(constraint_make(cpPivotJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body,js2vec2(argv[3]).cp)));
|
||||
break;
|
||||
|
@ -1392,12 +1144,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
case 231:
|
||||
ret = constraint2js(constraint_make(cpSimpleMotorNew(js2body(argv[1]), js2body(argv[2]), js2number(argv[3]))));
|
||||
break;
|
||||
case 232:
|
||||
ret = number2js(js2sprite(argv[1])->parallax);
|
||||
break;
|
||||
case 233:
|
||||
js2sprite(argv[1])->parallax = js2number(argv[2]);
|
||||
break;
|
||||
|
||||
case 234:
|
||||
ret = emitter2js(make_emitter());
|
||||
break;
|
||||
|
@ -1406,17 +1153,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
break;
|
||||
case 249:
|
||||
str = JS_ToCString(js,argv[2]);
|
||||
js2emitter(argv[1])->texture = texture_pullfromfile(str);
|
||||
js2emitter(argv[1])->texture = texture_from_file(str);
|
||||
break;
|
||||
case 250:
|
||||
sapp_show_keyboard(js2bool(argv[1]));
|
||||
break;
|
||||
case 251:
|
||||
js2gameobject(argv[1])->warp_filter = js2bitmask(argv[2]);
|
||||
break;
|
||||
case 252:
|
||||
ret = bitmask2js(js2gameobject(argv[1])->warp_filter);
|
||||
break;
|
||||
|
||||
case 253:
|
||||
ret = warp_gravity2js(warp_gravity_make());
|
||||
break;
|
||||
|
@ -1460,7 +1202,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
aspect_mode = js2int(argv[1]);
|
||||
break;
|
||||
case 265:
|
||||
ret = vec2js((HMM_Vec2){mainwin.width, mainwin.height});
|
||||
ret = vec22js((HMM_Vec2){mainwin.width, mainwin.height});
|
||||
break;
|
||||
case 266:
|
||||
mainwin.width = js2number(argv[1]);
|
||||
|
@ -1468,6 +1210,16 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
case 267:
|
||||
mainwin.height = js2number(argv[1]);
|
||||
break;
|
||||
case 268:
|
||||
if (js2bool(argv[1]))
|
||||
ret = JS_GetClassProto(js, js_sprite_id);
|
||||
else
|
||||
ret = sprite2js(sprite_make());
|
||||
break;
|
||||
case 269:
|
||||
str = js2str(argv[1]);
|
||||
ret = texture2js(texture_from_file(str));
|
||||
break;
|
||||
}
|
||||
|
||||
if (str) JS_FreeCString(js, str);
|
||||
|
@ -1526,10 +1278,6 @@ JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
|
|||
cpSpaceReindexStatic(space);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
sim_pause();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
sim_pause();
|
||||
break;
|
||||
|
@ -1613,14 +1361,6 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a
|
|||
cpBodySetVelocity(go->body, js2vec2(argv[2]).cp);
|
||||
return JS_UNDEFINED;
|
||||
|
||||
case 10:
|
||||
go->e = fmax(js2number(argv[2]), 0);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
go->f = fmax(js2number(argv[2]), 0);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
cpBodyApplyForceAtWorldPoint(go->body, js2vec2(argv[2]).cp, cpBodyGetPosition(go->body));
|
||||
return JS_UNDEFINED;
|
||||
|
@ -1649,13 +1389,13 @@ JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *arg
|
|||
return JS_NewInt64(js, cpBodyGetType(go->body));
|
||||
|
||||
case 1:
|
||||
return vec2js((HMM_Vec2)cpBodyGetPosition(go->body));
|
||||
return vec22js((HMM_Vec2)cpBodyGetPosition(go->body));
|
||||
|
||||
case 2:
|
||||
return JS_NewFloat64(js, cpBodyGetAngle(go->body));
|
||||
|
||||
case 3:
|
||||
return vec2js((HMM_Vec2)cpBodyGetVelocity(go->body));
|
||||
return vec22js((HMM_Vec2)cpBodyGetVelocity(go->body));
|
||||
|
||||
case 4:
|
||||
return JS_NewFloat64(js, cpBodyGetAngularVelocity(go->body));
|
||||
|
@ -1668,21 +1408,11 @@ JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *arg
|
|||
|
||||
case 7:
|
||||
return JS_NewBool(js, phys2d_in_air(go->body));
|
||||
|
||||
case 8:
|
||||
gameobject_free(go);
|
||||
break;
|
||||
}
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
JSValue duk_make_sprite(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
|
||||
JSValue sprite = JS_NewObject(js);
|
||||
js_setprop_str(sprite,"id",JS_NewInt64(js, make_sprite(js2gameobject(argv[0]))));
|
||||
return sprite;
|
||||
}
|
||||
|
||||
JSValue duk_make_circle2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
|
||||
gameobject *go = js2gameobject(argv[0]);
|
||||
|
||||
|
@ -1722,7 +1452,7 @@ JSValue duk_cmd_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCons
|
|||
return number2js(circle->radius);
|
||||
|
||||
case 3:
|
||||
return vec2js(circle->offset);
|
||||
return vec22js(circle->offset);
|
||||
}
|
||||
phys2d_shape_apply(&circle->shape);
|
||||
|
||||
|
@ -2085,6 +1815,85 @@ static const JSCFunctionListEntry js_sound_funcs[] = {
|
|||
CGETSET_ADD(sound, hook)
|
||||
};
|
||||
|
||||
#define GETSET_PAIR_BODY(ID, ENTRY, TYPE) \
|
||||
JSValue ID##_set_##ENTRY (JSContext *js, JSValue this, JSValue val) { \
|
||||
js2##ID (this)->ENTRY = js2##TYPE (val); \
|
||||
ID##_apply(js2##ID (this)); \
|
||||
return JS_UNDEFINED; \
|
||||
} \
|
||||
\
|
||||
JSValue ID##_get_##ENTRY (JSContext *js, JSValue this) { \
|
||||
return TYPE##2js(js2##ID (this)->ENTRY); \
|
||||
} \
|
||||
|
||||
GETSET_PAIR_BODY(gameobject, f, number)
|
||||
GETSET_PAIR_BODY(gameobject, e, number)
|
||||
GETSET_PAIR_BODY(gameobject, mass, number)
|
||||
GETSET_PAIR(gameobject, damping, number)
|
||||
GETSET_PAIR(gameobject, timescale, number)
|
||||
GETSET_PAIR(gameobject, maxvelocity, number)
|
||||
GETSET_PAIR(gameobject, maxangularvelocity, number)
|
||||
GETSET_PAIR_BODY(gameobject, layer, number)
|
||||
GETSET_PAIR(gameobject, warp_filter, bitmask)
|
||||
GETSET_PAIR(gameobject, scale, vec3)
|
||||
GETSET_PAIR(gameobject, drawlayer, number)
|
||||
|
||||
static const JSCFunctionListEntry js_gameobject_funcs[] = {
|
||||
CGETSET_ADD(gameobject, f),
|
||||
CGETSET_ADD(gameobject, e),
|
||||
CGETSET_ADD(gameobject,mass),
|
||||
CGETSET_ADD(gameobject,damping),
|
||||
CGETSET_ADD(gameobject,timescale),
|
||||
CGETSET_ADD(gameobject,maxvelocity),
|
||||
CGETSET_ADD(gameobject,maxangularvelocity),
|
||||
CGETSET_ADD(gameobject,layer),
|
||||
CGETSET_ADD(gameobject,warp_filter),
|
||||
|
||||
CGETSET_ADD(gameobject,scale),
|
||||
CGETSET_ADD(gameobject,drawlayer)
|
||||
};
|
||||
|
||||
GETSET_PAIR(sprite, color, color)
|
||||
GETSET_PAIR(sprite, emissive, color)
|
||||
GETSET_PAIR(sprite, enabled, bool)
|
||||
GETSET_PAIR(sprite, parallax, number)
|
||||
GETSET_PAIR(sprite, tex, texture)
|
||||
GETSET_PAIR(sprite, pos, vec2)
|
||||
GETSET_PAIR(sprite, scale, vec2)
|
||||
GETSET_PAIR(sprite, angle, number)
|
||||
GETSET_PAIR(sprite, frame, rect)
|
||||
GETSET_PAIR(sprite,go,gameobject)
|
||||
|
||||
static const JSCFunctionListEntry js_sprite_funcs[] = {
|
||||
CGETSET_ADD(sprite,pos),
|
||||
CGETSET_ADD(sprite,scale),
|
||||
CGETSET_ADD(sprite,angle),
|
||||
CGETSET_ADD(sprite,tex),
|
||||
CGETSET_ADD(sprite,color),
|
||||
CGETSET_ADD(sprite,emissive),
|
||||
CGETSET_ADD(sprite,enabled),
|
||||
CGETSET_ADD(sprite,parallax),
|
||||
CGETSET_ADD(sprite,frame),
|
||||
CGETSET_ADD(sprite,go)
|
||||
};
|
||||
|
||||
#define GETFN(ID, ENTRY, TYPE) \
|
||||
JSValue ID##_get_##ENTRY (JSContext *js, JSValue this, JSValue val) {\
|
||||
return TYPE##2js(js2##ID (this)->ENTRY); \
|
||||
} \
|
||||
|
||||
GETFN(texture,width,number)
|
||||
GETFN(texture,height,number)
|
||||
JSValue texture_get_path(JSContext *js, JSValue this, JSValue val)
|
||||
{
|
||||
return str2js(tex_get_path(js2texture(this)));
|
||||
}
|
||||
static const JSCFunctionListEntry js_texture_funcs[] = {
|
||||
MIST_CFUNC_DEF("width", 0, texture_get_width),
|
||||
MIST_CFUNC_DEF("height", 0, texture_get_height),
|
||||
MIST_CFUNC_DEF("path", 0, texture_get_path)
|
||||
};
|
||||
|
||||
JSValue constraint_set_max_force (JSContext *js, JSValue this, JSValue val) {
|
||||
cpConstraintSetMaxForce(js2constraint(this)->c, js2number(val));
|
||||
return JS_UNDEFINED;
|
||||
|
@ -2165,11 +1974,6 @@ JSValue duk_cmd_points(JSContext *js, JSValueConst this, int argc, JSValueConst
|
|||
|
||||
const char *STRTEST = "TEST STRING";
|
||||
|
||||
JSValue duk_performance_js2num(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
JSValue duk_performance(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||
{
|
||||
int cmd = js2int(argv[0]);
|
||||
|
@ -2242,7 +2046,6 @@ void ffi_load() {
|
|||
DUK_FUNC(set_body, 3)
|
||||
DUK_FUNC(q_body, 2)
|
||||
DUK_FUNC(sys_cmd, 1)
|
||||
DUK_FUNC(make_sprite, 1)
|
||||
DUK_FUNC(spline_cmd, 6)
|
||||
DUK_FUNC(make_circle2d, 1)
|
||||
DUK_FUNC(cmd_circle2d, 6)
|
||||
|
@ -2265,7 +2068,7 @@ void ffi_load() {
|
|||
JS_FreeValue(js,globalThis);
|
||||
|
||||
QJSCLASSPREP(ptr);
|
||||
QJSCLASSPREP(gameobject);
|
||||
QJSCLASSPREP_FUNCS(gameobject);
|
||||
QJSCLASSPREP_FUNCS(dsp_node);
|
||||
|
||||
sound_proto = JS_NewObject(js);
|
||||
|
@ -2275,7 +2078,8 @@ void ffi_load() {
|
|||
QJSCLASSPREP_FUNCS(emitter);
|
||||
QJSCLASSPREP_FUNCS(warp_gravity);
|
||||
QJSCLASSPREP_FUNCS(warp_damp);
|
||||
|
||||
QJSCLASSPREP_FUNCS(sprite);
|
||||
QJSCLASSPREP_FUNCS(texture);
|
||||
QJSCLASSPREP_FUNCS(constraint);
|
||||
|
||||
QJSGLOBALCLASS(os);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
void ffi_load();
|
||||
void ffi_stop();
|
||||
|
||||
JSValue vec2js(HMM_Vec2 v);
|
||||
JSValue vec22js(HMM_Vec2 v);
|
||||
HMM_Vec2 js2vec2(JSValue v);
|
||||
|
||||
JSValue bitmask2js(cpBitmask mask);
|
||||
|
|
|
@ -99,7 +99,7 @@ emitter *make_emitter() {
|
|||
sampler_add(&e->color, 0, (HMM_Vec4){1,1,1,1});
|
||||
e->scale = 1;
|
||||
e->speed = 20;
|
||||
e->texture = texture_pullfromfile("glass_chunk2.gif");
|
||||
e->texture = texture_from_file("glass_chunk2.gif");
|
||||
arrpush(emitters,e);
|
||||
return e;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
extern struct rgba color_white;
|
||||
extern struct rgba color_black;
|
||||
extern struct rgba color_clear;
|
||||
|
||||
extern int renderMode;
|
||||
|
||||
|
@ -105,16 +106,9 @@ struct boundingbox {
|
|||
};
|
||||
|
||||
struct rect {
|
||||
float h, w, x, y;
|
||||
};
|
||||
|
||||
/* Normalized S,T coordinates for rendering */
|
||||
struct glrect {
|
||||
float s0;
|
||||
float s1;
|
||||
float t0;
|
||||
float t1;
|
||||
float x,y,w,h;
|
||||
};
|
||||
typedef struct rect rect;
|
||||
|
||||
struct boundingbox cwh2bb(HMM_Vec2 c, HMM_Vec2 wh);
|
||||
float *rgba2floats(float *r, struct rgba c);
|
||||
|
|
|
@ -295,7 +295,7 @@ void callee_int(struct callee c, int i) {
|
|||
}
|
||||
|
||||
void callee_vec2(struct callee c, HMM_Vec2 vec) {
|
||||
JSValue v = vec2js(vec);
|
||||
JSValue v = vec22js(vec);
|
||||
js_callee_exec(&c, 1, &v);
|
||||
JS_FreeValue(js, v);
|
||||
}
|
||||
|
|
|
@ -1,25 +1,17 @@
|
|||
#include "sprite.h"
|
||||
|
||||
#include "datastream.h"
|
||||
#include "font.h"
|
||||
#include "gameobject.h"
|
||||
#include "log.h"
|
||||
#include "render.h"
|
||||
#include "stb_ds.h"
|
||||
#include "texture.h"
|
||||
#include "timer.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include "HandmadeMath.h"
|
||||
#include "freelist.h"
|
||||
|
||||
#include "sprite.sglsl.h"
|
||||
#include "9slice.sglsl.h"
|
||||
|
||||
struct TextureOptions TEX_SPRITE = {1};
|
||||
|
||||
static struct sprite *sprites = NULL;
|
||||
static sprite **sprites = NULL;
|
||||
|
||||
static sg_shader shader_sprite;
|
||||
static sg_pipeline pip_sprite;
|
||||
|
@ -51,89 +43,70 @@ struct slice9_vert {
|
|||
struct rgba color;
|
||||
};
|
||||
|
||||
int make_sprite(gameobject *go) {
|
||||
struct sprite sprite = {
|
||||
.t = t2d_unit,
|
||||
.color = color_white,
|
||||
.emissive = {0,0,0,0},
|
||||
.tex = texture_pullfromfile(NULL),
|
||||
.go = go,
|
||||
.next = -1,
|
||||
.enabled = 1,
|
||||
.drawmode = DRAW_SIMPLE,
|
||||
.parallax = 1
|
||||
};
|
||||
int id;
|
||||
freelist_grab(id, sprites);
|
||||
sprites[id] = sprite;
|
||||
return id;
|
||||
}
|
||||
|
||||
void sprite_delete(int id) {
|
||||
struct sprite *sp = id2sprite(id);
|
||||
sprite *sprite_make()
|
||||
{
|
||||
sprite *sp = calloc(sizeof(*sp), 1);
|
||||
sp->pos = (HMM_Vec2){0,0};
|
||||
sp->scale = (HMM_Vec2){1,1};
|
||||
sp->angle = 0;
|
||||
sp->color = color_white;
|
||||
sp->emissive = color_clear;
|
||||
sp->go = NULL;
|
||||
sp->enabled = 0;
|
||||
freelist_kill(sprites,id);
|
||||
sp->tex = texture_from_file(NULL);
|
||||
sp->frame = ST_UNIT;
|
||||
sp->drawmode = DRAW_SIMPLE;
|
||||
sp->enabled = 1;
|
||||
sp->parallax = 1;
|
||||
|
||||
arrpush(sprites,sp);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
void sprite_enabled(int id, int e) { sprites[id].enabled = e; }
|
||||
|
||||
struct sprite *id2sprite(int id) {
|
||||
if (id < 0) return NULL;
|
||||
return &sprites[id];
|
||||
void sprite_free(sprite *sprite)
|
||||
{
|
||||
YughWarn("Freeing sprite %p.", sprite);
|
||||
|
||||
free(sprite);
|
||||
for (int i = arrlen(sprites)-1; i >= 0; i--)
|
||||
if (sprites[i] == sprite) {
|
||||
arrdelswap(sprites,i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int sprite_count = 0;
|
||||
|
||||
void sprite_flush() { sprite_count = 0; }
|
||||
|
||||
int sprite_sort(int *a, int *b)
|
||||
int sprite_sort(sprite **sa, sprite **sb)
|
||||
{
|
||||
struct gameobject *goa = sprites[*a].go;
|
||||
struct gameobject *gob = sprites[*b].go;
|
||||
sprite *a = *sa;
|
||||
sprite *b = *sb;
|
||||
struct gameobject *goa = a->go;
|
||||
struct gameobject *gob= b->go;
|
||||
if (!goa && !gob) return 0;
|
||||
if (!goa) return -1;
|
||||
if (!gob) return 1;
|
||||
if (goa->drawlayer == gob->drawlayer) return 0;
|
||||
if (goa->drawlayer > gob->drawlayer) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sprite_draw_all() {
|
||||
if (arrlen(sprites) == 0) return;
|
||||
|
||||
sg_apply_pipeline(pip_sprite);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
|
||||
int *layers = NULL;
|
||||
if (layers) arrfree(layers);
|
||||
|
||||
for (int i = 0; i < freelist_len(sprites); i++)
|
||||
if (sprites[i].next == -1 && sprites[i].go != NULL && sprites[i].enabled)
|
||||
arrpush(layers, i);
|
||||
qsort(sprites, arrlen(sprites), sizeof(*sprites), sprite_sort);
|
||||
|
||||
if (!layers || arrlen(layers) == 0) return;
|
||||
if (arrlen(layers) > 1)
|
||||
qsort(layers, arrlen(layers), sizeof(*layers), sprite_sort);
|
||||
|
||||
for (int i = 0; i < arrlen(layers); i++)
|
||||
sprite_draw(&sprites[layers[i]]);
|
||||
|
||||
arrfree(layers);
|
||||
}
|
||||
|
||||
|
||||
void sprite_loadtex(struct sprite *sprite, const char *path, struct glrect frame) {
|
||||
if (!sprite) {
|
||||
YughWarn("NO SPRITE!");
|
||||
return;
|
||||
}
|
||||
sprite->tex = texture_pullfromfile(path);
|
||||
sprite_setframe(sprite, &frame);
|
||||
}
|
||||
|
||||
void sprite_settex(struct sprite *sprite, struct Texture *tex) {
|
||||
sprite->tex = tex;
|
||||
sprite_setframe(sprite, &ST_UNIT);
|
||||
for (int i = 0; i < arrlen(sprites); i++)
|
||||
sprite_draw(sprites[i]);
|
||||
}
|
||||
|
||||
void sprite_initialize() {
|
||||
freelist_size(sprites, 500);
|
||||
|
||||
|
||||
shader_sprite = sg_make_shader(sprite_shader_desc(sg_query_backend()));
|
||||
|
||||
pip_sprite = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
|
@ -179,15 +152,15 @@ void sprite_initialize() {
|
|||
});
|
||||
}
|
||||
|
||||
void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, HMM_Vec2 wrapscale, struct rgba emissive, float parallax) {
|
||||
void tex_draw(struct texture *tex, HMM_Mat3 m, struct rect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, HMM_Vec2 wrapscale, struct rgba emissive, float parallax) {
|
||||
struct sprite_vert verts[4];
|
||||
float w = tex->width*st_s_w(r);
|
||||
float h = tex->height*st_s_h(r);
|
||||
float w = tex->width*r.w;
|
||||
float h = tex->height*r.h;
|
||||
|
||||
HMM_Vec2 sposes[4] = {
|
||||
{0.0,0.0},
|
||||
{w,0.0},
|
||||
{0.0,h},
|
||||
{0,0},
|
||||
{w,0},
|
||||
{0,h},
|
||||
{w,h}
|
||||
};
|
||||
|
||||
|
@ -198,18 +171,18 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo
|
|||
}
|
||||
|
||||
if (wrap) {
|
||||
r.s1 *= wrapscale.x;
|
||||
r.t1 *= wrapscale.y;
|
||||
r.w *= wrapscale.x;
|
||||
r.h *= wrapscale.y;
|
||||
}
|
||||
|
||||
verts[0].uv.X = r.s0;
|
||||
verts[0].uv.Y = r.t1;
|
||||
verts[1].uv.X = r.s1;
|
||||
verts[1].uv.Y = r.t1;
|
||||
verts[2].uv.X = r.s0;
|
||||
verts[2].uv.Y = r.t0;
|
||||
verts[3].uv.X = r.s1;
|
||||
verts[3].uv.Y = r.t0;
|
||||
verts[0].uv.X = r.x;
|
||||
verts[0].uv.Y = r.y+r.h;
|
||||
verts[1].uv.X = r.x+r.w;
|
||||
verts[1].uv.Y = r.y+r.h;
|
||||
verts[2].uv.X = r.x;
|
||||
verts[2].uv.Y = r.y;
|
||||
verts[3].uv.X = r.x+r.w;
|
||||
verts[3].uv.Y = r.y;
|
||||
|
||||
bind_sprite.fs.images[0] = tex->id;
|
||||
|
||||
|
@ -220,64 +193,31 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo
|
|||
sprite_count++;
|
||||
}
|
||||
|
||||
transform2d sprite2t(sprite *s)
|
||||
{
|
||||
return (transform2d){
|
||||
.pos = s->pos,
|
||||
.scale = s->scale,
|
||||
.angle = s->angle
|
||||
};
|
||||
}
|
||||
|
||||
void sprite_draw(struct sprite *sprite) {
|
||||
if (!sprite->tex) return;
|
||||
transform2d t = go2t(sprite->go);
|
||||
transform2d t;
|
||||
if (!sprite->go) t = t2d_unit;
|
||||
else t = go2t(sprite->go);
|
||||
|
||||
t.pos.x += (cam_pos().x - (cam_pos().x/sprite->parallax));
|
||||
t.pos.y += (cam_pos().y - (cam_pos().y/sprite->parallax));
|
||||
HMM_Mat3 m = transform2d2mat(t);
|
||||
HMM_Mat3 sm = transform2d2mat(sprite->t);
|
||||
|
||||
tex_draw(sprite->tex, HMM_MulM3(m, sm), sprite->frame, sprite->color, sprite->drawmode, (HMM_Vec2){0,0}, sprite->t.scale, sprite->emissive, sprite->parallax);
|
||||
HMM_Mat3 sm = transform2d2mat(sprite2t(sprite));
|
||||
tex_draw(sprite->tex, HMM_MulM3(m,sm), sprite->frame, sprite->color, sprite->drawmode, (HMM_Vec2){0,0}, sprite->scale, sprite->emissive, sprite->parallax);
|
||||
}
|
||||
|
||||
void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) {
|
||||
sg_apply_pipeline(pip_sprite);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
||||
struct Texture *tex = texture_pullfromfile(img);
|
||||
struct texture *tex = texture_from_file(img);
|
||||
tex_draw(tex, transform2d2mat(t), ST_UNIT, color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}, 0);
|
||||
}
|
||||
|
||||
void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba color)
|
||||
{
|
||||
sg_apply_pipeline(slice9_pipe);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
||||
struct Texture *tex = texture_pullfromfile(img);
|
||||
|
||||
struct glrect r = ST_UNIT;
|
||||
|
||||
struct slice9_vert verts[4];
|
||||
|
||||
HMM_Vec2 sposes[4] = {
|
||||
{0.0,0.0},
|
||||
{1.0,0.0},
|
||||
{0.0,1.0},
|
||||
{1.0,1.0},
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
verts[i].pos = HMM_MulV2(sposes[i], dimensions);
|
||||
//verts[i].uv =z sposes[i];
|
||||
verts[i].color = color;
|
||||
}
|
||||
|
||||
verts[0].uv.u = r.s0 * USHRT_MAX;
|
||||
verts[0].uv.v = r.t1 * USHRT_MAX;
|
||||
verts[1].uv.u = r.s1 * USHRT_MAX;
|
||||
verts[1].uv.v = r.t1 * USHRT_MAX;
|
||||
verts[2].uv.u = r.s0 * USHRT_MAX;
|
||||
verts[2].uv.v = r.t0 * USHRT_MAX;
|
||||
verts[3].uv.u = r.s1 * USHRT_MAX;
|
||||
verts[3].uv.v = r.t0 * USHRT_MAX;
|
||||
|
||||
bind_sprite.fs.images[0] = tex->id;
|
||||
sg_append_buffer(bind_sprite.vertex_buffers[0], SG_RANGE_REF(verts));
|
||||
sg_apply_bindings(&bind_sprite);
|
||||
|
||||
sg_draw(sprite_count * 4, 4, 1);
|
||||
sprite_count++;
|
||||
}
|
||||
|
||||
void sprite_setframe(struct sprite *sprite, struct glrect *frame) {
|
||||
sprite->frame = *frame;
|
||||
}
|
||||
|
|
|
@ -11,29 +11,29 @@
|
|||
#define DRAW_TILE 1
|
||||
|
||||
struct sprite {
|
||||
transform2d t;
|
||||
HMM_Vec2 pos;
|
||||
HMM_Vec2 scale;
|
||||
float angle;
|
||||
struct rgba color;
|
||||
struct rgba emissive;
|
||||
gameobject *go;
|
||||
struct Texture *tex;
|
||||
struct glrect frame;
|
||||
texture *tex;
|
||||
struct rect frame;
|
||||
int enabled;
|
||||
int next;
|
||||
int drawmode;
|
||||
float parallax;
|
||||
unsigned int next;
|
||||
};
|
||||
|
||||
typedef struct sprite sprite;
|
||||
|
||||
sprite *sprite_make();
|
||||
int make_sprite(gameobject *go);
|
||||
struct sprite *id2sprite(int id);
|
||||
void sprite_free(sprite *sprite);
|
||||
void sprite_delete(int id);
|
||||
void sprite_enabled(int id, int e);
|
||||
void sprite_loadtex(struct sprite *sprite, const char *path, struct glrect rect);
|
||||
void sprite_settex(struct sprite *sprite, struct Texture *tex);
|
||||
void sprite_setframe(struct sprite *sprite, struct glrect *frame);
|
||||
void sprite_initialize();
|
||||
void sprite_draw(struct sprite *sprite);
|
||||
void sprite_draw_all();
|
||||
unsigned int incrementAnimFrame(unsigned int interval, struct sprite *sprite);
|
||||
void sprite_flush();
|
||||
|
||||
void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color);
|
||||
|
|
|
@ -21,15 +21,15 @@
|
|||
#include "nanosvgrast.h"
|
||||
#endif
|
||||
|
||||
struct glrect ST_UNIT = {0.f, 1.f, 0.f, 1.f};
|
||||
struct rect ST_UNIT = {0.f, 0.f, 1.f, 1.f};
|
||||
|
||||
static struct {
|
||||
char *key;
|
||||
struct Texture *value;
|
||||
struct texture *value;
|
||||
} *texhash = NULL;
|
||||
|
||||
struct Texture *tex_default;
|
||||
struct Texture *texture_notex() { return texture_pullfromfile("icons/no_tex.gif"); }
|
||||
struct texture *tex_default;
|
||||
struct texture *texture_notex() { return texture_from_file("icons/no_tex.gif"); }
|
||||
|
||||
unsigned int next_pow2(unsigned int v)
|
||||
{
|
||||
|
@ -72,18 +72,18 @@ int mip_wh(int w, int h, int *mw, int *mh, int lvl)
|
|||
|
||||
int gif_nframes(const char *path)
|
||||
{
|
||||
struct Texture *t = texture_pullfromfile(path);
|
||||
struct texture *t = texture_from_file(path);
|
||||
return t->frames;
|
||||
}
|
||||
|
||||
int *gif_delays(const char *path)
|
||||
{
|
||||
struct Texture *t = texture_pullfromfile(path);
|
||||
struct texture *t = texture_from_file(path);
|
||||
return t->delays;
|
||||
}
|
||||
|
||||
/* If an empty string or null is put for path, loads default texture */
|
||||
struct Texture *texture_pullfromfile(const char *path) {
|
||||
struct texture *texture_from_file(const char *path) {
|
||||
if (!path) return texture_notex();
|
||||
if (shlen(texhash) == 0) sh_new_arena(texhash);
|
||||
|
||||
|
@ -98,8 +98,7 @@ struct Texture *texture_pullfromfile(const char *path) {
|
|||
|
||||
unsigned char *data;
|
||||
|
||||
struct Texture *tex = calloc(1, sizeof(*tex));
|
||||
tex->opts.sprite = 1;
|
||||
struct texture *tex = calloc(1, sizeof(*tex));
|
||||
|
||||
int n;
|
||||
|
||||
|
@ -152,12 +151,7 @@ struct Texture *texture_pullfromfile(const char *path) {
|
|||
|
||||
tex->data = data;
|
||||
|
||||
int filter;
|
||||
if (tex->opts.sprite) {
|
||||
filter = SG_FILTER_NEAREST;
|
||||
} else {
|
||||
filter = SG_FILTER_LINEAR;
|
||||
}
|
||||
int filter = SG_FILTER_NEAREST;
|
||||
|
||||
sg_image_data sg_img_data;
|
||||
|
||||
|
@ -199,13 +193,18 @@ struct Texture *texture_pullfromfile(const char *path) {
|
|||
|
||||
for (int i = 1; i < mips; i++)
|
||||
free(mipdata[i]);
|
||||
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void texture_sync(const char *path) { YughWarn("Need to implement texture sync."); }
|
||||
|
||||
char *tex_get_path(struct Texture *tex) {
|
||||
void texture_free(texture *tex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
char *tex_get_path(struct texture *tex) {
|
||||
for (int i = 0; i < shlen(texhash); i++) {
|
||||
if (tex == texhash[i].value) {
|
||||
YughInfo("Found key %s", texhash[i].key);
|
||||
|
@ -216,10 +215,9 @@ char *tex_get_path(struct Texture *tex) {
|
|||
return "";
|
||||
}
|
||||
|
||||
struct Texture *texture_fromdata(void *raw, long size)
|
||||
struct texture *texture_fromdata(void *raw, long size)
|
||||
{
|
||||
struct Texture *tex = calloc(1, sizeof(*tex));
|
||||
tex->opts.sprite = 1;
|
||||
struct texture *tex = calloc(1, sizeof(*tex));
|
||||
|
||||
int n;
|
||||
void *data = stbi_load_from_memory(raw, size, &tex->width, &tex->height, &n, 4);
|
||||
|
@ -234,12 +232,7 @@ struct Texture *texture_fromdata(void *raw, long size)
|
|||
|
||||
tex->data = data;
|
||||
|
||||
int filter;
|
||||
if (tex->opts.sprite) {
|
||||
filter = SG_FILTER_NEAREST;
|
||||
} else {
|
||||
filter = SG_FILTER_LINEAR;
|
||||
}
|
||||
int filter = SG_FILTER_NEAREST;
|
||||
|
||||
sg_image_data sg_img_data;
|
||||
|
||||
|
@ -283,9 +276,7 @@ struct Texture *texture_fromdata(void *raw, long size)
|
|||
return tex;
|
||||
}
|
||||
|
||||
struct Texture *texture_loadfromfile(const char *path) { return texture_pullfromfile(path); }
|
||||
|
||||
HMM_Vec2 tex_get_dimensions(struct Texture *tex) {
|
||||
HMM_Vec2 tex_get_dimensions(struct texture *tex) {
|
||||
if (!tex) return (HMM_Vec2){0,0};
|
||||
HMM_Vec2 d;
|
||||
d.x = tex->width;
|
||||
|
@ -293,10 +284,6 @@ HMM_Vec2 tex_get_dimensions(struct Texture *tex) {
|
|||
return d;
|
||||
}
|
||||
|
||||
float st_s_w(struct glrect st) { return (st.s1 - st.s0); }
|
||||
|
||||
float st_s_h(struct glrect st) { return (st.t1 - st.t0); }
|
||||
|
||||
static double fade (double t) { return t*t*t*(t*(t*6-15)+10); }
|
||||
double grad (int hash, double x, double y, double z)
|
||||
{
|
||||
|
|
|
@ -14,26 +14,20 @@
|
|||
#define FILTER_NONE SG_FILTER_NONE
|
||||
#define FILTER_LINEAR SG_FILTER_LINEAR
|
||||
|
||||
float st_s_w(struct glrect st);
|
||||
float st_s_h(struct glrect st);
|
||||
|
||||
extern struct glrect ST_UNIT;
|
||||
|
||||
struct TextureOptions {
|
||||
int sprite;
|
||||
};
|
||||
extern struct rect ST_UNIT;
|
||||
|
||||
/* Represents an actual texture on the GPU */
|
||||
struct Texture {
|
||||
struct texture {
|
||||
sg_image id; /* ID reference for the GPU memory location of the texture */
|
||||
int width;
|
||||
int height;
|
||||
unsigned char *data;
|
||||
struct TextureOptions opts;
|
||||
int frames;
|
||||
int *delays;
|
||||
};
|
||||
|
||||
typedef struct texture texture;
|
||||
|
||||
typedef struct img_sampler{
|
||||
int wrap_u;
|
||||
int wrap_v;
|
||||
|
@ -43,21 +37,21 @@ typedef struct img_sampler{
|
|||
int mip_filter;
|
||||
} img_sampler;
|
||||
|
||||
typedef struct Texture texture;
|
||||
struct texture *texture_from_file(const char *path); // Create texture from image
|
||||
struct texture *texture_fromdata(void *raw, long size);
|
||||
|
||||
struct Texture *texture_pullfromfile(const char *path); // Create texture from image
|
||||
struct Texture *texture_fromdata(void *raw, long size);
|
||||
void texture_free(texture *tex);
|
||||
|
||||
/* Hot reloads a texture, if needed */
|
||||
void texture_sync(const char *path);
|
||||
|
||||
char * tex_get_path(struct Texture *tex); // Get image path for texture
|
||||
char * tex_get_path(struct texture *tex); // Get image path for texture
|
||||
|
||||
int gif_nframes(const char *path);
|
||||
int *gif_delays(const char *path);
|
||||
|
||||
struct glrect tex_get_rect(struct Texture *tex);
|
||||
HMM_Vec2 tex_get_dimensions(struct Texture *tex);
|
||||
struct glrect tex_get_rect(struct texture *tex);
|
||||
HMM_Vec2 tex_get_dimensions(struct texture *tex);
|
||||
|
||||
double perlin(double x, double y, double z);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ struct window mainwin;
|
|||
|
||||
static struct window *windows = NULL;
|
||||
|
||||
struct Texture *icon = NULL;
|
||||
struct texture *icon = NULL;
|
||||
|
||||
void window_resize(int width, int height)
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ void window_suspended(int s)
|
|||
}
|
||||
|
||||
void window_set_icon(const char *png) {
|
||||
icon = texture_pullfromfile(png);
|
||||
icon = texture_from_file(png);
|
||||
window_seticon(&mainwin, icon);
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ void window_togglefullscreen(struct window *w) {
|
|||
mainwin.fullscreen = sapp_is_fullscreen();
|
||||
}
|
||||
|
||||
void window_seticon(struct window *w, struct Texture *tex)
|
||||
void window_seticon(struct window *w, struct texture *tex)
|
||||
{
|
||||
struct isize {
|
||||
int size;
|
||||
|
|
|
@ -16,7 +16,7 @@ struct window {
|
|||
int focus;
|
||||
int shown;
|
||||
};
|
||||
struct Texture;
|
||||
struct texture;
|
||||
extern struct window mainwin;
|
||||
|
||||
void window_resize(int width, int height);
|
||||
|
@ -29,7 +29,7 @@ void window_togglefullscreen(struct window *w);
|
|||
void window_unfullscreen(struct window *w);
|
||||
|
||||
void window_set_icon(const char *png);
|
||||
void window_seticon(struct window *w, struct Texture *icon);
|
||||
void window_seticon(struct window *w, struct texture *icon);
|
||||
|
||||
void window_render(struct window *w);
|
||||
|
||||
|
|
Loading…
Reference in a new issue