Fix sprite animation crash; move text/image to render
This commit is contained in:
parent
b17e5d3917
commit
459ef00330
|
@ -315,37 +315,6 @@ time.text = function(num, fmt, zone)
|
||||||
return fmt;
|
return fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
var json = {};
|
|
||||||
json.encode = function(value, space, replacer, whitelist)
|
|
||||||
{
|
|
||||||
return JSON.stringify(value, space, replacer);
|
|
||||||
}
|
|
||||||
|
|
||||||
json.decode = function(text, reviver)
|
|
||||||
{
|
|
||||||
if (!text) return undefined;
|
|
||||||
return JSON.parse(text,reviver);
|
|
||||||
}
|
|
||||||
|
|
||||||
json.readout = function(obj)
|
|
||||||
{
|
|
||||||
var j = {};
|
|
||||||
for (var k in obj)
|
|
||||||
if (typeof obj[k] === 'function')
|
|
||||||
j[k] = 'function ' + obj[k].toString();
|
|
||||||
else
|
|
||||||
j[k] = obj[k];
|
|
||||||
|
|
||||||
return json.encode(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
json.doc = {
|
|
||||||
doc: "json implementation.",
|
|
||||||
encode: "Encode a value to json.",
|
|
||||||
decode: "Decode a json string to a value.",
|
|
||||||
readout: "Encode an object fully, including function definitions."
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.methods = function(o)
|
Object.methods = function(o)
|
||||||
{
|
{
|
||||||
var m = [];
|
var m = [];
|
||||||
|
|
|
@ -5,7 +5,6 @@ this.world2view = function(pos) { return render.world2view(pos); };
|
||||||
this.realzoom = function() { return render.get_zoom(); };
|
this.realzoom = function() { return render.get_zoom(); };
|
||||||
|
|
||||||
this.right = function() { return this.pos.x + (window.rendersize.x/2); }
|
this.right = function() { return this.pos.x + (window.rendersize.x/2); }
|
||||||
|
|
||||||
this.left = function() { return this.pos.x - (window.rendersize.x/2); }
|
this.left = function() { return this.pos.x - (window.rendersize.x/2); }
|
||||||
|
|
||||||
this.zoom = 1;
|
this.zoom = 1;
|
||||||
|
|
|
@ -89,11 +89,14 @@ Object.mixin(os.sprite(true), {
|
||||||
anim:{},
|
anim:{},
|
||||||
playing: 0,
|
playing: 0,
|
||||||
play(str) {
|
play(str) {
|
||||||
|
console.trace();
|
||||||
|
this.del_anim?.();
|
||||||
var sp = this;
|
var sp = this;
|
||||||
this.del_anim = function() {
|
this.del_anim = function() {
|
||||||
sp = undefined;
|
sp = undefined;
|
||||||
advance = undefined;
|
advance = undefined;
|
||||||
this.del_anim = undefined;
|
this.del_anim = undefined;
|
||||||
|
this.anim_done = undefined;
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
str ??= 0;
|
str ??= 0;
|
||||||
|
@ -101,17 +104,19 @@ Object.mixin(os.sprite(true), {
|
||||||
if (!playing) return;
|
if (!playing) return;
|
||||||
var f = 0;
|
var f = 0;
|
||||||
var stop;
|
var stop;
|
||||||
|
sp.path = playing.path;
|
||||||
|
|
||||||
function advance() {
|
function advance() {
|
||||||
if (!sp) this.del_anim();
|
if (!sp) this.del_anim();
|
||||||
if (!sp.gameobject) return;
|
if (!sp.gameobject) return;
|
||||||
sp.path = playing.path;
|
//sp.path = playing.path;
|
||||||
sp.frame = playing.frames[f].rect;
|
sp.frame = playing.frames[f].rect;
|
||||||
f = (f+1)%playing.frames.length;
|
f = (f+1)%playing.frames.length;
|
||||||
if (f === 0) sp.anim_done?.();
|
if (f === 0) sp.anim_done?.();
|
||||||
stop = sp.gameobject.delay(advance, playing.frames[f].time);
|
stop = sp.gameobject.delay(advance, playing.frames[f].time);
|
||||||
}
|
}
|
||||||
|
this.tex(game.texture(playing.path));
|
||||||
|
console.info(`playing anim: ${json.encode(playing)}`);
|
||||||
advance();
|
advance();
|
||||||
},
|
},
|
||||||
stop() {
|
stop() {
|
||||||
|
@ -119,11 +124,13 @@ Object.mixin(os.sprite(true), {
|
||||||
},
|
},
|
||||||
set path(p) {
|
set path(p) {
|
||||||
p = Resources.find_image(p);
|
p = Resources.find_image(p);
|
||||||
if (!p) return;
|
if (!p) {
|
||||||
|
console.warn(`Could not find image ${p}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (p === this.path) return;
|
if (p === this.path) return;
|
||||||
this._p = p;
|
this._p = p;
|
||||||
this.del_anime?.();
|
this.del_anim?.();
|
||||||
this.tex(game.texture(p));
|
|
||||||
this.texture = game.texture(p);
|
this.texture = game.texture(p);
|
||||||
this.tex(this.texture);
|
this.tex(this.texture);
|
||||||
|
|
||||||
|
@ -131,6 +138,8 @@ Object.mixin(os.sprite(true), {
|
||||||
if (!anim) return;
|
if (!anim) return;
|
||||||
this.anim = anim;
|
this.anim = anim;
|
||||||
this.play();
|
this.play();
|
||||||
|
|
||||||
|
this.pos = this.dimensions().scale(this.anchor);
|
||||||
},
|
},
|
||||||
get path() {
|
get path() {
|
||||||
return this._p;
|
return this._p;
|
||||||
|
@ -146,7 +155,7 @@ Object.mixin(os.sprite(true), {
|
||||||
this.scale = this.scale.scale(x);
|
this.scale = this.scale.scale(x);
|
||||||
this.pos = this.pos.scale(x);
|
this.pos = this.pos.scale(x);
|
||||||
},
|
},
|
||||||
|
anchor:[0,0],
|
||||||
sync() { },
|
sync() { },
|
||||||
pick() { return this; },
|
pick() { return this; },
|
||||||
boundingbox() {
|
boundingbox() {
|
||||||
|
@ -184,7 +193,7 @@ sprite.doc = {
|
||||||
pos: "The offset position of the sprite, relative to its entity."
|
pos: "The offset position of the sprite, relative to its entity."
|
||||||
};
|
};
|
||||||
|
|
||||||
sprite.anchor = function(anch) {
|
sprite.setanchor = function(anch) {
|
||||||
var off = [0,0];
|
var off = [0,0];
|
||||||
switch(anch) {
|
switch(anch) {
|
||||||
case "ll": break;
|
case "ll": break;
|
||||||
|
@ -197,19 +206,20 @@ sprite.anchor = function(anch) {
|
||||||
case "um": off = [-0.5,-1]; break;
|
case "um": off = [-0.5,-1]; break;
|
||||||
case "ur": off = [-1,-1]; break;
|
case "ur": off = [-1,-1]; break;
|
||||||
}
|
}
|
||||||
|
this.anchor = off;
|
||||||
this.pos = this.dimensions().scale(off);
|
this.pos = this.dimensions().scale(off);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite.inputs = {};
|
sprite.inputs = {};
|
||||||
sprite.inputs.kp9 = function() { this.anchor("ll"); }
|
sprite.inputs.kp9 = function() { this.setanchor("ll"); }
|
||||||
sprite.inputs.kp8 = function() { this.anchor("lm"); }
|
sprite.inputs.kp8 = function() { this.setanchor("lm"); }
|
||||||
sprite.inputs.kp7 = function() { this.anchor("lr"); }
|
sprite.inputs.kp7 = function() { this.setanchor("lr"); }
|
||||||
sprite.inputs.kp6 = function() { this.anchor("ml"); }
|
sprite.inputs.kp6 = function() { this.setanchor("ml"); }
|
||||||
sprite.inputs.kp5 = function() { this.anchor("mm"); }
|
sprite.inputs.kp5 = function() { this.setanchor("mm"); }
|
||||||
sprite.inputs.kp4 = function() { this.anchor("mr"); }
|
sprite.inputs.kp4 = function() { this.setanchor("mr"); }
|
||||||
sprite.inputs.kp3 = function() { this.anchor("ur"); }
|
sprite.inputs.kp3 = function() { this.setanchor("ur"); }
|
||||||
sprite.inputs.kp2 = function() { this.anchor("um"); }
|
sprite.inputs.kp2 = function() { this.setanchor("um"); }
|
||||||
sprite.inputs.kp1 = function() { this.anchor("ul"); }
|
sprite.inputs.kp1 = function() { this.setanchor("ul"); }
|
||||||
|
|
||||||
Object.seal(sprite);
|
Object.seal(sprite);
|
||||||
|
|
||||||
|
@ -219,14 +229,23 @@ Object.seal(sprite);
|
||||||
time: miliseconds to hold the frame for
|
time: miliseconds to hold the frame for
|
||||||
loop: true if it should be looped
|
loop: true if it should be looped
|
||||||
*/
|
*/
|
||||||
|
var animcache = {};
|
||||||
var SpriteAnim = {
|
var SpriteAnim = {
|
||||||
make(path) {
|
make(path) {
|
||||||
if (path.ext() === 'gif')
|
if (animcache[path]) return animcache[path];
|
||||||
return SpriteAnim.gif(path);
|
var anim;
|
||||||
|
if (io.exists(path.set_ext(".json")))
|
||||||
|
anim = SpriteAnim.aseprite(path.set_ext(".json"));
|
||||||
|
else if (path.ext() === 'gif')
|
||||||
|
anim = SpriteAnim.gif(path);
|
||||||
else if (path.ext() === 'ase')
|
else if (path.ext() === 'ase')
|
||||||
return SpriteAnim.aseprite(path);
|
anim = SpriteAnim.aseprite(path);
|
||||||
else
|
else
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
|
animcache[path] = anim;
|
||||||
|
console.spam(`Created animation like this:\n${json.encode(animcache[path])}`);
|
||||||
|
return animcache[path];
|
||||||
},
|
},
|
||||||
gif(path) {
|
gif(path) {
|
||||||
console.info(`making an anim from ${path}`);
|
console.info(`making an anim from ${path}`);
|
||||||
|
@ -250,7 +269,6 @@ var SpriteAnim = {
|
||||||
anim.frames.push(frame);
|
anim.frames.push(frame);
|
||||||
}
|
}
|
||||||
var times = tex.delays;
|
var times = tex.delays;
|
||||||
console.info(`times are ${times}, num ${times.length}`);
|
|
||||||
for (var i = 0; i < frames; i++)
|
for (var i = 0; i < frames; i++)
|
||||||
anim.frames[i].time = times[i]/1000;
|
anim.frames[i].time = times[i]/1000;
|
||||||
anim.loop = true;
|
anim.loop = true;
|
||||||
|
@ -278,38 +296,37 @@ var SpriteAnim = {
|
||||||
},
|
},
|
||||||
|
|
||||||
aseprite(path) {
|
aseprite(path) {
|
||||||
function aseframeset2anim(frameset, meta) {
|
function aseframeset2anim(frameset, meta) {
|
||||||
var anim = {};
|
var anim = {};
|
||||||
anim.frames = [];
|
anim.frames = [];
|
||||||
anim.path = meta.image;
|
anim.path = path.dir() + "/" + meta.image;
|
||||||
var dim = meta.size;
|
var dim = meta.size;
|
||||||
|
|
||||||
var ase_make_frame = function(ase_frame,i) {
|
var ase_make_frame = function(ase_frame) {
|
||||||
var f = ase_frame.frame;
|
var f = ase_frame.frame;
|
||||||
var frame = {};
|
var frame = {};
|
||||||
frame.rect = {
|
frame.rect = {
|
||||||
x: f.x/dim.w,
|
x: f.x/dim.w,
|
||||||
w: f.w/dim.w,
|
w: f.w/dim.w,
|
||||||
y: f.y/dim.h,
|
y: f.y/dim.h,
|
||||||
h: f.h/dim.h
|
h: f.h/dim.h
|
||||||
|
};
|
||||||
|
frame.time = ase_frame.duration / 1000;
|
||||||
|
anim.frames.push(frame);
|
||||||
};
|
};
|
||||||
frame.time = ase_frame.duration / 1000;
|
|
||||||
anim.frames.push(frame);
|
frameset.forEach(ase_make_frame);
|
||||||
|
anim.dim = frameset[0].sourceSize;
|
||||||
|
anim.loop = true;
|
||||||
|
return anim;
|
||||||
};
|
};
|
||||||
|
|
||||||
frameset.forEach(ase_make_frame);
|
var data = json.decode(io.slurp(path));
|
||||||
anim.dim = [frameset[0].sourceSize.x, frameset[0].sourceSize.y];
|
|
||||||
anim.loop = true;
|
|
||||||
return anim;
|
|
||||||
};
|
|
||||||
|
|
||||||
var json = io.slurp(path);
|
|
||||||
json = JSON.parse(json);
|
|
||||||
var anims = {};
|
var anims = {};
|
||||||
var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames);
|
var frames = Array.isArray(data.frames) ? data.frames : Object.values(data.frames);
|
||||||
var f = 0;
|
var f = 0;
|
||||||
for (var tag of json.meta.frameTags) {
|
for (var tag of data.meta.frameTags) {
|
||||||
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), json.meta);
|
anims[tag.name] = aseframeset2anim(frames.slice(tag.from, tag.to+1), data.meta);
|
||||||
anims[f] = anims[tag.name];
|
anims[f] = anims[tag.name];
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,19 +27,19 @@ debug.draw = function() {
|
||||||
|
|
||||||
if (this.draw_names)
|
if (this.draw_names)
|
||||||
game.all_objects(function(x) {
|
game.all_objects(function(x) {
|
||||||
GUI.text(x, window.world2screen(x.pos).add([0,32]), 1, Color.debug.names);
|
render.text(x, window.world2screen(x.pos).add([0,32]), 1, Color.debug.names);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (debug.gif.rec) {
|
if (debug.gif.rec) {
|
||||||
GUI.text("REC", [0,40], 1);
|
render.text("REC", [0,40], 1);
|
||||||
GUI.text(time.timecode(time.timenow() - debug.gif.start_time, debug.gif.fps), [0,30], 1);
|
render.text(time.timecode(time.timenow() - debug.gif.start_time, debug.gif.fps), [0,30], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sim.paused()) GUI.text("PAUSED", [0,0],1);
|
if (sim.paused()) render.text("PAUSED", [0,0],1);
|
||||||
|
|
||||||
GUI.text(sim.playing() ? "PLAYING"
|
render.text(sim.playing() ? "PLAYING"
|
||||||
: sim.stepping() ?
|
: sim.stepping() ?
|
||||||
"STEP" :
|
"STEP" :
|
||||||
sim.paused() ?
|
sim.paused() ?
|
||||||
|
|
|
@ -343,7 +343,7 @@ var editor = {
|
||||||
root = root ? root + "." : root;
|
root = root ? root + "." : root;
|
||||||
Object.entries(obj.objects).forEach(function(x) {
|
Object.entries(obj.objects).forEach(function(x) {
|
||||||
var p = root + x[0];
|
var p = root + x[0];
|
||||||
GUI.text(p, x[1].screenpos(), 1, editor.color_depths[depth]);
|
render.text(p, x[1].screenpos(), 1, editor.color_depths[depth]);
|
||||||
editor.draw_objects_names(x[1], p, depth+1);
|
editor.draw_objects_names(x[1], p, depth+1);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -393,13 +393,13 @@ var editor = {
|
||||||
gui() {
|
gui() {
|
||||||
/* Clean out killed objects */
|
/* Clean out killed objects */
|
||||||
this.selectlist = this.selectlist.filter(function(x) { return x.alive; });
|
this.selectlist = this.selectlist.filter(function(x) { return x.alive; });
|
||||||
GUI.text([0,0], window.world2screen([0,0]));
|
render.text([0,0], window.world2screen([0,0]));
|
||||||
|
|
||||||
GUI.text("WORKING LAYER: " + this.working_layer, [0,520]);
|
render.text("WORKING LAYER: " + this.working_layer, [0,520]);
|
||||||
GUI.text("MODE: " + this.edit_mode, [0,500]);
|
render.text("MODE: " + this.edit_mode, [0,500]);
|
||||||
|
|
||||||
if (this.comp_info && this.sel_comp)
|
if (this.comp_info && this.sel_comp)
|
||||||
GUI.text(Input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
|
render.text(Input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
|
||||||
|
|
||||||
render.cross(editor.edit_level.screenpos(),3,Color.blue);
|
render.cross(editor.edit_level.screenpos(),3,Color.blue);
|
||||||
|
|
||||||
|
@ -434,24 +434,24 @@ var editor = {
|
||||||
depth = i;
|
depth = i;
|
||||||
var lvlstr = x.namestr();
|
var lvlstr = x.namestr();
|
||||||
if (i === lvlchain.length-1) lvlstr += "[this]";
|
if (i === lvlchain.length-1) lvlstr += "[this]";
|
||||||
GUI.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]);
|
render.text(lvlstr, [0, ypos], 1, editor.color_depths[depth]);
|
||||||
|
|
||||||
GUI.text("^^^^^^", [0,ypos+=5],1);
|
render.text("^^^^^^", [0,ypos+=5],1);
|
||||||
ypos += 15;
|
ypos += 15;
|
||||||
});
|
});
|
||||||
|
|
||||||
depth++;
|
depth++;
|
||||||
GUI.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
||||||
|
|
||||||
this.selectlist.forEach(function(x) {
|
this.selectlist.forEach(function(x) {
|
||||||
GUI.text(x.urstr(), x.screenpos().add([0, 32]), 1, Color.editor.ur);
|
render.text(x.urstr(), 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);
|
render.text(x.worldpos().map(function(x) { return Math.round(x); }), x.screenpos(), 1, Color.white);
|
||||||
render.cross(x.screenpos(), 10, Color.blue);
|
render.cross(x.screenpos(), 10, Color.blue);
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.entries(thiso.objects).forEach(function(x) {
|
Object.entries(thiso.objects).forEach(function(x) {
|
||||||
var p = x[1].namestr();
|
var p = x[1].namestr();
|
||||||
GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]);
|
render.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]);
|
||||||
render.circle(x[1].screenpos(),10,Color.blue.alpha(0.3));
|
render.circle(x[1].screenpos(),10,Color.blue.alpha(0.3));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -459,18 +459,18 @@ var editor = {
|
||||||
|
|
||||||
if (mg) {
|
if (mg) {
|
||||||
var p = mg.path_from(thiso);
|
var p = mg.path_from(thiso);
|
||||||
GUI.text(p, Mouse.screenpos(),1,Color.teal);
|
render.text(p, Mouse.screenpos(),1,Color.teal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rotlist.length === 1)
|
if (this.rotlist.length === 1)
|
||||||
GUI.text(Math.trunc(this.rotlist[0].obj.angle), Mouse.screenpos(), 1, Color.teal);
|
render.text(Math.trunc(this.rotlist[0].obj.angle), Mouse.screenpos(), 1, Color.teal);
|
||||||
|
|
||||||
if (this.selectlist.length === 1) {
|
if (this.selectlist.length === 1) {
|
||||||
var i = 1;
|
var i = 1;
|
||||||
for (var key in this.selectlist[0].components) {
|
for (var key in this.selectlist[0].components) {
|
||||||
var selected = this.sel_comp === this.selectlist[0].components[key];
|
var selected = this.sel_comp === this.selectlist[0].components[key];
|
||||||
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
|
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
|
||||||
GUI.text(str, this.selectlist[0].screenpos().add([0,-16*(i++)]));
|
render.text(str, this.selectlist[0].screenpos().add([0,-16*(i++)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.sel_comp) {
|
if (this.sel_comp) {
|
||||||
|
@ -480,7 +480,7 @@ var editor = {
|
||||||
|
|
||||||
editor.edit_level.objects.forEach(function(obj) {
|
editor.edit_level.objects.forEach(function(obj) {
|
||||||
if (!obj._ed.selectable)
|
if (!obj._ed.selectable)
|
||||||
GUI.text("lock", obj,screenpos());
|
render.text("lock", obj,screenpos());
|
||||||
});
|
});
|
||||||
|
|
||||||
render.grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3));
|
render.grid(1, editor.grid_size, Color.Editor.grid.alpha(0.3));
|
||||||
|
@ -494,12 +494,12 @@ var editor = {
|
||||||
if (h_step === 0) h_step = editor.grid_size;
|
if (h_step === 0) h_step = editor.grid_size;
|
||||||
|
|
||||||
while(startgrid[0] <= endgrid[0]) {
|
while(startgrid[0] <= endgrid[0]) {
|
||||||
GUI.text(startgrid[0], [window.world2screen([startgrid[0], 0])[0],0]);
|
render.text(startgrid[0], [window.world2screen([startgrid[0], 0])[0],0]);
|
||||||
startgrid[0] += w_step;
|
startgrid[0] += w_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(startgrid[1] <= endgrid[1]) {
|
while(startgrid[1] <= endgrid[1]) {
|
||||||
GUI.text(startgrid[1], [0, window.world2screen([0, startgrid[1]])[1]]);
|
render.text(startgrid[1], [0, window.world2screen([0, startgrid[1]])[1]]);
|
||||||
startgrid[1] += h_step;
|
startgrid[1] += h_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,37 @@
|
||||||
"use math";
|
"use math";
|
||||||
|
|
||||||
|
globalThis.json = {};
|
||||||
|
json.encode = function(value, replacer, space, whitelist)
|
||||||
|
{
|
||||||
|
space ??= 1;
|
||||||
|
return JSON.stringify(value, replacer, space);
|
||||||
|
}
|
||||||
|
|
||||||
|
json.decode = function(text, reviver)
|
||||||
|
{
|
||||||
|
if (!text) return undefined;
|
||||||
|
return JSON.parse(text,reviver);
|
||||||
|
}
|
||||||
|
|
||||||
|
json.readout = function(obj)
|
||||||
|
{
|
||||||
|
var j = {};
|
||||||
|
for (var k in obj)
|
||||||
|
if (typeof obj[k] === 'function')
|
||||||
|
j[k] = 'function ' + obj[k].toString();
|
||||||
|
else
|
||||||
|
j[k] = obj[k];
|
||||||
|
|
||||||
|
return json.encode(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
json.doc = {
|
||||||
|
doc: "json implementation.",
|
||||||
|
encode: "Encode a value to json.",
|
||||||
|
decode: "Decode a json string to a value.",
|
||||||
|
readout: "Encode an object fully, including function definitions."
|
||||||
|
};
|
||||||
|
|
||||||
globalThis.Resources = {};
|
globalThis.Resources = {};
|
||||||
Resources.scripts = ["jsoc", "jsc", "jso", "js"];
|
Resources.scripts = ["jsoc", "jsc", "jso", "js"];
|
||||||
Resources.images = ["png", "gif", "jpg", "jpeg"];
|
Resources.images = ["png", "gif", "jpg", "jpeg"];
|
||||||
|
@ -79,6 +111,7 @@ Object.assign(console, {
|
||||||
|
|
||||||
console.stdout_lvl = 1;
|
console.stdout_lvl = 1;
|
||||||
console.log = console.say;
|
console.log = console.say;
|
||||||
|
console.trace = console.stack;
|
||||||
var say = console.say;
|
var say = console.say;
|
||||||
var print = console.print;
|
var print = console.print;
|
||||||
|
|
||||||
|
@ -217,7 +250,6 @@ function process()
|
||||||
render.pass();
|
render.pass();
|
||||||
prosperon.gui();
|
prosperon.gui();
|
||||||
render.flush_hud();
|
render.flush_hud();
|
||||||
|
|
||||||
render.end_pass();
|
render.end_pass();
|
||||||
render.commit();
|
render.commit();
|
||||||
}
|
}
|
||||||
|
@ -242,7 +274,14 @@ game.doc.camera = "Current camera.";
|
||||||
|
|
||||||
game.texture = function(path)
|
game.texture = function(path)
|
||||||
{
|
{
|
||||||
game.texture.cache[path] ??= os.make_texture(path);
|
if (game.texture.cache[path]) return game.texture.cache[path];
|
||||||
|
|
||||||
|
if (!io.exists(path)) {
|
||||||
|
console.warn(`Missing texture: ${path}`);
|
||||||
|
game.texture.cache[path] = game.texture("icons/no_tex.gif");
|
||||||
|
} else
|
||||||
|
game.texture.cache[path] ??= os.make_texture(path);
|
||||||
|
|
||||||
return game.texture.cache[path];
|
return game.texture.cache[path];
|
||||||
}
|
}
|
||||||
game.texture.cache = {};
|
game.texture.cache = {};
|
||||||
|
|
|
@ -184,7 +184,7 @@ var gameobject = {
|
||||||
that.timers.remove(stop);
|
that.timers.remove(stop);
|
||||||
execute = undefined;
|
execute = undefined;
|
||||||
stop = undefined;
|
stop = undefined;
|
||||||
rm();
|
rm?.();
|
||||||
rm = undefined;
|
rm = undefined;
|
||||||
update = undefined;
|
update = undefined;
|
||||||
}
|
}
|
||||||
|
@ -570,7 +570,6 @@ var gameobject = {
|
||||||
this.objects = undefined;
|
this.objects = undefined;
|
||||||
|
|
||||||
if (typeof this.stop === 'function') this.stop();
|
if (typeof this.stop === 'function') this.stop();
|
||||||
if (typeof this.die === 'function') this.die();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
up() { return [0, 1].rotate(this.angle); },
|
up() { return [0, 1].rotate(this.angle); },
|
||||||
|
|
|
@ -5,38 +5,6 @@
|
||||||
gui.scissor_win = function() { gui.scissor(0,0,window.width,window.height); }
|
gui.scissor_win = function() { gui.scissor(0,0,window.width,window.height); }
|
||||||
|
|
||||||
var GUI = {
|
var GUI = {
|
||||||
text(str, pos, size, color, wrap, anchor, cursor) {
|
|
||||||
size ??= 1;
|
|
||||||
color ??= Color.white;
|
|
||||||
wrap ??= -1;
|
|
||||||
anchor ??= [0,1];
|
|
||||||
|
|
||||||
cursor ??= -1;
|
|
||||||
|
|
||||||
var bb = render.text_size(str, size, wrap);
|
|
||||||
var w = bb.r*2;
|
|
||||||
var h = bb.t*2;
|
|
||||||
|
|
||||||
//gui.text draws with an anchor on top left corner
|
|
||||||
var p = pos.slice();
|
|
||||||
p.x -= w * anchor.x;
|
|
||||||
bb.r += (w*anchor.x);
|
|
||||||
bb.l += (w*anchor.x);
|
|
||||||
p.y += h * (1 - anchor.y);
|
|
||||||
bb.t += h*(1-anchor.y);
|
|
||||||
bb.b += h*(1-anchor.y);
|
|
||||||
gui.text(str, p, size, color, wrap, cursor);
|
|
||||||
|
|
||||||
return bb;
|
|
||||||
},
|
|
||||||
|
|
||||||
image(path,pos,color) {
|
|
||||||
color ??= Color.black;
|
|
||||||
var wh = texture.dimensions(64,path);
|
|
||||||
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) {
|
newmg(img) {
|
||||||
var def = {
|
var def = {
|
||||||
path: "",
|
path: "",
|
||||||
|
|
|
@ -89,7 +89,7 @@ render.arrow = function(start, end, color, wingspan, wingangle) {
|
||||||
|
|
||||||
render.coordinate = function(pos, size, color) {
|
render.coordinate = function(pos, size, color) {
|
||||||
color ??= Color.white;
|
color ??= Color.white;
|
||||||
GUI.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color);
|
render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color);
|
||||||
render.point(pos, 2, color);
|
render.point(pos, 2, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,39 @@ render.box = function(pos, wh, color) {
|
||||||
render.rectangle(lower,upper,color);
|
render.rectangle(lower,upper,color);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
render.text = function(str, pos, size, color, wrap, anchor, cursor) {
|
||||||
|
size ??= 1;
|
||||||
|
color ??= Color.white;
|
||||||
|
wrap ??= -1;
|
||||||
|
anchor ??= [0,1];
|
||||||
|
|
||||||
|
cursor ??= -1;
|
||||||
|
|
||||||
|
var bb = render.text_size(str, size, wrap);
|
||||||
|
var w = bb.r*2;
|
||||||
|
var h = bb.t*2;
|
||||||
|
|
||||||
|
//gui.text draws with an anchor on top left corner
|
||||||
|
var p = pos.slice();
|
||||||
|
p.x -= w * anchor.x;
|
||||||
|
bb.r += (w*anchor.x);
|
||||||
|
bb.l += (w*anchor.x);
|
||||||
|
p.y += h * (1 - anchor.y);
|
||||||
|
bb.t += h*(1-anchor.y);
|
||||||
|
bb.b += h*(1-anchor.y);
|
||||||
|
gui.text(str, p, size, color, wrap, cursor);
|
||||||
|
|
||||||
|
return bb;
|
||||||
|
};
|
||||||
|
|
||||||
|
render.image = function(tex, pos, rotation, color) {
|
||||||
|
color ??= Color.black;
|
||||||
|
rotation ??= 0;
|
||||||
|
// var wh = texture.dimensions(64,path);
|
||||||
|
gui.img(tex,pos, [1.0,1.0], 0.0, false, [0.0,0.0], Color.white);
|
||||||
|
// return bbox.fromcwh([0,0], wh);
|
||||||
|
}
|
||||||
|
|
||||||
render.doc = "Draw shapes in screen space.";
|
render.doc = "Draw shapes in screen space.";
|
||||||
render.circle.doc = "Draw a circle at pos, with a given radius and color.";
|
render.circle.doc = "Draw a circle at pos, with a given radius and color.";
|
||||||
render.cross.doc = "Draw a cross centered at pos, with arm length size.";
|
render.cross.doc = "Draw a cross centered at pos, with arm length size.";
|
||||||
|
|
299
source/engine/gif_load.h
Normal file
299
source/engine/gif_load.h
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
#ifndef GIF_LOAD_H
|
||||||
|
#define GIF_LOAD_H
|
||||||
|
|
||||||
|
/** gif_load: A slim, fast and header-only GIF loader written in C.
|
||||||
|
Original author: hidefromkgb (hidefromkgb@gmail.com)
|
||||||
|
_________________________________________________________________________
|
||||||
|
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
_________________________________________________________________________
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include <stdint.h> /** imports uint8_t, uint16_t and uint32_t **/
|
||||||
|
#ifndef GIF_MGET
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define GIF_MGET(m,s,a,c) m = (uint8_t*)realloc((c)? 0 : m, (c)? s : 0UL);
|
||||||
|
#endif
|
||||||
|
#ifndef GIF_BIGE
|
||||||
|
#define GIF_BIGE 0
|
||||||
|
#endif
|
||||||
|
#ifndef GIF_EXTR
|
||||||
|
#define GIF_EXTR static
|
||||||
|
#endif
|
||||||
|
#define _GIF_SWAP(h) ((GIF_BIGE)? ((uint16_t)(h << 8) | (h >> 8)) : h)
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct GIF_WHDR { /** ======== frame writer info: ======== **/
|
||||||
|
long xdim, ydim, clrs, /** global dimensions, palette size **/
|
||||||
|
bkgd, tran, /** background index, transparent index **/
|
||||||
|
intr, mode, /** interlace flag, frame blending mode **/
|
||||||
|
frxd, fryd, frxo, fryo, /** current frame dimensions and offset **/
|
||||||
|
time, ifrm, nfrm; /** delay, frame number, frame count **/
|
||||||
|
uint8_t *bptr; /** frame pixel indices or metadata **/
|
||||||
|
struct { /** [==== GIF RGB palette element: ====] **/
|
||||||
|
uint8_t R, G, B; /** [color values - red, green, blue ] **/
|
||||||
|
} *cpal; /** current palette **/
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
enum {GIF_NONE = 0, GIF_CURR = 1, GIF_BKGD = 2, GIF_PREV = 3};
|
||||||
|
|
||||||
|
/** [ internal function, do not use ] **/
|
||||||
|
static long _GIF_SkipChunk(uint8_t **buff, long size) {
|
||||||
|
long skip;
|
||||||
|
|
||||||
|
for (skip = 2, ++size, ++(*buff); ((size -= skip) > 0) && (skip > 1);
|
||||||
|
*buff += (skip = 1 + **buff));
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** [ internal function, do not use ] **/
|
||||||
|
static long _GIF_LoadHeader(unsigned gflg, uint8_t **buff, void **rpal,
|
||||||
|
unsigned fflg, long *size, long flen) {
|
||||||
|
if (flen && (!(*buff += flen) || ((*size -= flen) <= 0)))
|
||||||
|
return -2; /** v--[ 0x80: "palette is present" flag ]--, **/
|
||||||
|
if (flen && (fflg & 0x80)) { /** local palette has priority | **/
|
||||||
|
*rpal = *buff; /** [ 3L: 3 uint8_t color channels ]--, | **/
|
||||||
|
*buff += (flen = 2 << (fflg & 7)) * 3L; /** <--| | **/
|
||||||
|
return ((*size -= flen * 3L) > 0)? flen : -1; /** <--' | **/
|
||||||
|
} /** no local palette found, checking for the global one | **/
|
||||||
|
return (gflg & 0x80)? (2 << (gflg & 7)) : 0; /** <-----' **/
|
||||||
|
}
|
||||||
|
|
||||||
|
/** [ internal function, do not use ] **/
|
||||||
|
static long _GIF_LoadFrame(uint8_t **buff, long *size,
|
||||||
|
uint8_t *bptr, uint8_t *blen) {
|
||||||
|
typedef uint16_t GIF_H;
|
||||||
|
const long GIF_HLEN = sizeof(GIF_H), /** to rid the scope of sizeof **/
|
||||||
|
GIF_CLEN = 1 << 12; /** code table length: 4096 items **/
|
||||||
|
GIF_H accu, mask; /** bit accumulator / bit mask **/
|
||||||
|
long ctbl, iter, /** last code table index / index string iterator **/
|
||||||
|
prev, curr, /** codes from the stream: previous / current **/
|
||||||
|
ctsz, ccsz, /** code table bit sizes: min LZW / current **/
|
||||||
|
bseq, bszc; /** counters: block sequence / bit size **/
|
||||||
|
uint32_t *code = (uint32_t*)bptr - GIF_CLEN; /** code table pointer **/
|
||||||
|
|
||||||
|
/** preparing initial values **/
|
||||||
|
if ((--(*size) <= GIF_HLEN) || !*++(*buff))
|
||||||
|
return -4; /** unexpected end of the stream: insufficient size **/
|
||||||
|
mask = (GIF_H)((1 << (ccsz = (ctsz = *(*buff - 1)) + 1)) - 1);
|
||||||
|
if ((ctsz < 2) || (ctsz > 8))
|
||||||
|
return -3; /** min LZW size is out of its nominal [2; 8] bounds **/
|
||||||
|
if ((ctbl = (1L << ctsz)) != (mask & _GIF_SWAP(*(GIF_H*)(*buff + 1))))
|
||||||
|
return -2; /** initial code is not equal to min LZW size **/
|
||||||
|
for (curr = ++ctbl; curr; code[--curr] = 0); /** actual color codes **/
|
||||||
|
|
||||||
|
/** getting codes from stream (--size makes up for end-of-stream mark) **/
|
||||||
|
for (--(*size), bszc = -ccsz, prev = curr = 0;
|
||||||
|
((*size -= (bseq = *(*buff)++) + 1) >= 0) && bseq; *buff += bseq)
|
||||||
|
for (; bseq > 0; bseq -= GIF_HLEN, *buff += GIF_HLEN)
|
||||||
|
for (accu = (GIF_H)(_GIF_SWAP(*(GIF_H*)*buff)
|
||||||
|
& ((bseq < GIF_HLEN)? ((1U << (8 * bseq)) - 1U) : ~0U)),
|
||||||
|
curr |= accu << (ccsz + bszc), accu = (GIF_H)(accu >> -bszc),
|
||||||
|
bszc += 8 * ((bseq < GIF_HLEN)? bseq : GIF_HLEN);
|
||||||
|
bszc >= 0; bszc -= ccsz, prev = curr, curr = accu,
|
||||||
|
accu = (GIF_H)(accu >> ccsz))
|
||||||
|
if (((curr &= mask) & ~1L) == (1L << ctsz)) {
|
||||||
|
if (~(ctbl = curr + 1) & 1) /** end-of-data code (ED). **/
|
||||||
|
/** -1: no end-of-stream mark after ED; 1: decoded **/
|
||||||
|
return (*((*buff += bseq + 1) - 1))? -1 : 1;
|
||||||
|
mask = (GIF_H)((1 << (ccsz = ctsz + 1)) - 1);
|
||||||
|
} /** ^- table drop code (TD). TD = 1 << ctsz, ED = TD + 1 **/
|
||||||
|
else { /** single-pixel (SP) or multi-pixel (MP) code. **/
|
||||||
|
if (ctbl < GIF_CLEN) { /** is the code table full? **/
|
||||||
|
if ((ctbl == mask) && (ctbl < GIF_CLEN - 1)) {
|
||||||
|
mask = (GIF_H)(mask + mask + 1);
|
||||||
|
ccsz++; /** yes; extending **/
|
||||||
|
} /** prev = TD? => curr < ctbl = prev **/
|
||||||
|
code[ctbl] = (uint32_t)prev + (code[prev] & 0xFFF000);
|
||||||
|
} /** appending SP / MP decoded pixels to the frame **/
|
||||||
|
prev = (long)code[iter = (ctbl > curr)? curr : prev];
|
||||||
|
if ((bptr += (prev = (prev >> 12) & 0xFFF)) > blen)
|
||||||
|
continue; /** skipping pixels above frame capacity **/
|
||||||
|
for (prev++; (iter &= 0xFFF) >> ctsz;
|
||||||
|
*bptr-- = (uint8_t)((iter = (long)code[iter]) >> 24));
|
||||||
|
(bptr += prev)[-prev] = (uint8_t)iter;
|
||||||
|
if (ctbl < GIF_CLEN) { /** appending the code table **/
|
||||||
|
if (ctbl == curr)
|
||||||
|
*bptr++ = (uint8_t)iter;
|
||||||
|
else if (ctbl < curr)
|
||||||
|
return -5; /** wrong code in the stream **/
|
||||||
|
code[ctbl++] += ((uint32_t)iter << 24) + 0x1000;
|
||||||
|
}
|
||||||
|
} /** 0: no ED before end-of-stream mark; -4: see above **/
|
||||||
|
return (++(*size) >= 0)? 0 : -4; /** ^- N.B.: 0 error is recoverable **/
|
||||||
|
}
|
||||||
|
|
||||||
|
/** _________________________________________________________________________
|
||||||
|
The main loading function. Returns the total number of frames if the data
|
||||||
|
includes proper GIF ending, and otherwise it returns the number of frames
|
||||||
|
loaded per current call, multiplied by -1. So, the data may be incomplete
|
||||||
|
and in this case the function can be called again when more data arrives,
|
||||||
|
just remember to keep SKIP up to date.
|
||||||
|
_________________________________________________________________________
|
||||||
|
DATA: raw data chunk, may be partial
|
||||||
|
SIZE: size of the data chunk that`s currently present
|
||||||
|
GWFR: frame writer function, MANDATORY
|
||||||
|
EAMF: metadata reader function, set to 0 if not needed
|
||||||
|
ANIM: implementation-specific data (e.g. a structure or a pointer to it)
|
||||||
|
SKIP: number of frames to skip before resuming
|
||||||
|
**/
|
||||||
|
GIF_EXTR long GIF_Load(void *data, long size,
|
||||||
|
void (*gwfr)(void*, struct GIF_WHDR*),
|
||||||
|
void (*eamf)(void*, struct GIF_WHDR*),
|
||||||
|
void *anim, long skip) {
|
||||||
|
const long GIF_BLEN = (1 << 12) * sizeof(uint32_t);
|
||||||
|
const uint8_t GIF_EHDM = 0x21, /** extension header mark **/
|
||||||
|
GIF_FHDM = 0x2C, /** frame header mark **/
|
||||||
|
GIF_EOFM = 0x3B, /** end-of-file mark **/
|
||||||
|
GIF_EGCM = 0xF9, /** extension: graphics control mark **/
|
||||||
|
GIF_EAMM = 0xFF; /** extension: app metadata mark **/
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct GIF_GHDR { /** ========== GLOBAL GIF HEADER: ========== **/
|
||||||
|
uint8_t head[6]; /** 'GIF87a' / 'GIF89a' header signature **/
|
||||||
|
uint16_t xdim, ydim; /** total image width, total image height **/
|
||||||
|
uint8_t flgs; /** FLAGS:
|
||||||
|
GlobalPlt bit 7 1: global palette exists
|
||||||
|
0: local in each frame
|
||||||
|
ClrRes bit 6-4 bits/channel = ClrRes+1
|
||||||
|
[reserved] bit 3 0
|
||||||
|
PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits
|
||||||
|
**/
|
||||||
|
uint8_t bkgd, aspr; /** background color index, aspect ratio **/
|
||||||
|
} *ghdr = (struct GIF_GHDR*)data;
|
||||||
|
struct GIF_FHDR { /** ======= GIF FRAME MASTER HEADER: ======= **/
|
||||||
|
uint16_t frxo, fryo; /** offset of this frame in a "full" image **/
|
||||||
|
uint16_t frxd, fryd; /** frame width, frame height **/
|
||||||
|
uint8_t flgs; /** FLAGS:
|
||||||
|
LocalPlt bit 7 1: local palette exists
|
||||||
|
0: global is used
|
||||||
|
Interlaced bit 6 1: interlaced frame
|
||||||
|
0: non-interlaced frame
|
||||||
|
Sorted bit 5 usually 0
|
||||||
|
[reserved] bit 4-3 [undefined]
|
||||||
|
PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits
|
||||||
|
**/
|
||||||
|
} *fhdr;
|
||||||
|
struct GIF_EGCH { /** ==== [EXT] GRAPHICS CONTROL HEADER: ==== **/
|
||||||
|
uint8_t flgs; /** FLAGS:
|
||||||
|
[reserved] bit 7-5 [undefined]
|
||||||
|
BlendMode bit 4-2 000: not set; static GIF
|
||||||
|
001: leave result as is
|
||||||
|
010: restore background
|
||||||
|
011: restore previous
|
||||||
|
1--: [undefined]
|
||||||
|
UserInput bit 1 1: show frame till input
|
||||||
|
0: default; ~99% of GIFs
|
||||||
|
TransColor bit 0 1: got transparent color
|
||||||
|
0: frame is fully opaque
|
||||||
|
**/
|
||||||
|
uint16_t time; /** delay in GIF time units; 1 unit = 10 ms **/
|
||||||
|
uint8_t tran; /** transparent color index **/
|
||||||
|
} *egch = 0;
|
||||||
|
#pragma pack(pop)
|
||||||
|
struct GIF_WHDR wtmp, whdr = {0};
|
||||||
|
long desc, blen;
|
||||||
|
uint8_t *buff;
|
||||||
|
|
||||||
|
/** checking if the stream is not empty and has a 'GIF8[79]a' signature,
|
||||||
|
the data has sufficient size and frameskip value is non-negative **/
|
||||||
|
if (!ghdr || (size <= (long)sizeof(*ghdr)) || (*(buff = ghdr->head) != 71)
|
||||||
|
|| (buff[1] != 73) || (buff[2] != 70) || (buff[3] != 56) || (skip < 0)
|
||||||
|
|| ((buff[4] != 55) && (buff[4] != 57)) || (buff[5] != 97) || !gwfr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
buff = (uint8_t*)(ghdr + 1) /** skipping the global header and palette **/
|
||||||
|
+ _GIF_LoadHeader(ghdr->flgs, 0, 0, 0, 0, 0L) * 3L;
|
||||||
|
if ((size -= buff - (uint8_t*)ghdr) <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
whdr.xdim = _GIF_SWAP(ghdr->xdim);
|
||||||
|
whdr.ydim = _GIF_SWAP(ghdr->ydim);
|
||||||
|
for (whdr.bptr = buff, whdr.bkgd = ghdr->bkgd, blen = --size;
|
||||||
|
(blen >= 0) && ((desc = *whdr.bptr++) != GIF_EOFM); /** sic: '>= 0' **/
|
||||||
|
blen = _GIF_SkipChunk(&whdr.bptr, blen) - 1) /** count all frames **/
|
||||||
|
if (desc == GIF_FHDM) {
|
||||||
|
fhdr = (struct GIF_FHDR*)whdr.bptr;
|
||||||
|
if (_GIF_LoadHeader(ghdr->flgs, &whdr.bptr, (void**)&whdr.cpal,
|
||||||
|
fhdr->flgs, &blen, sizeof(*fhdr)) <= 0)
|
||||||
|
break;
|
||||||
|
whdr.frxd = _GIF_SWAP(fhdr->frxd);
|
||||||
|
whdr.fryd = _GIF_SWAP(fhdr->fryd);
|
||||||
|
whdr.frxo = (whdr.frxd > whdr.frxo)? whdr.frxd : whdr.frxo;
|
||||||
|
whdr.fryo = (whdr.fryd > whdr.fryo)? whdr.fryd : whdr.fryo;
|
||||||
|
whdr.ifrm++;
|
||||||
|
}
|
||||||
|
blen = whdr.frxo * whdr.fryo * (long)sizeof(*whdr.bptr);
|
||||||
|
GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 1)
|
||||||
|
whdr.nfrm = (desc != GIF_EOFM)? -whdr.ifrm : whdr.ifrm;
|
||||||
|
for (whdr.bptr += GIF_BLEN, whdr.ifrm = -1; blen /** load all frames **/
|
||||||
|
&& (skip < ((whdr.nfrm < 0)? -whdr.nfrm : whdr.nfrm)) && (size >= 0);
|
||||||
|
size = (desc != GIF_EOFM)? ((desc != GIF_FHDM) || (skip > whdr.ifrm))?
|
||||||
|
_GIF_SkipChunk(&buff, size) - 1 : size - 1 : -1)
|
||||||
|
if ((desc = *buff++) == GIF_FHDM) { /** found a frame **/
|
||||||
|
whdr.intr = !!((fhdr = (struct GIF_FHDR*)buff)->flgs & 0x40);
|
||||||
|
*(void**)&whdr.cpal = (void*)(ghdr + 1); /** interlaced? -^ **/
|
||||||
|
whdr.clrs = _GIF_LoadHeader(ghdr->flgs, &buff, (void**)&whdr.cpal,
|
||||||
|
fhdr->flgs, &size, sizeof(*fhdr));
|
||||||
|
if ((skip <= ++whdr.ifrm) && ((whdr.clrs <= 0)
|
||||||
|
|| (_GIF_LoadFrame(&buff, &size,
|
||||||
|
whdr.bptr, whdr.bptr + blen) < 0)))
|
||||||
|
size = -(whdr.ifrm--) - 1; /** failed to load the frame **/
|
||||||
|
else if (skip <= whdr.ifrm) {
|
||||||
|
whdr.frxd = _GIF_SWAP(fhdr->frxd);
|
||||||
|
whdr.fryd = _GIF_SWAP(fhdr->fryd);
|
||||||
|
whdr.frxo = _GIF_SWAP(fhdr->frxo);
|
||||||
|
whdr.fryo = _GIF_SWAP(fhdr->fryo);
|
||||||
|
whdr.time = (egch)? _GIF_SWAP(egch->time) : 0;
|
||||||
|
whdr.tran = (egch && (egch->flgs & 0x01))? egch->tran : -1;
|
||||||
|
whdr.time = (egch && (egch->flgs & 0x02))? -whdr.time - 1
|
||||||
|
: whdr.time;
|
||||||
|
whdr.mode = (egch && !(egch->flgs & 0x10))?
|
||||||
|
(egch->flgs & 0x0C) >> 2 : GIF_NONE;
|
||||||
|
egch = 0;
|
||||||
|
wtmp = whdr;
|
||||||
|
gwfr(anim, &wtmp); /** passing the frame to the caller **/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (desc == GIF_EHDM) { /** found an extension **/
|
||||||
|
if (*buff == GIF_EGCM) /** graphics control ext. **/
|
||||||
|
egch = (struct GIF_EGCH*)(buff + 1 + 1);
|
||||||
|
else if ((*buff == GIF_EAMM) && eamf) { /** app metadata ext. **/
|
||||||
|
wtmp = whdr;
|
||||||
|
wtmp.bptr = buff + 1 + 1; /** just passing the raw chunk **/
|
||||||
|
eamf(anim, &wtmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
whdr.bptr -= GIF_BLEN; /** for excess pixel codes ----v (here & above) **/
|
||||||
|
GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 0)
|
||||||
|
return (whdr.nfrm < 0)? (skip - whdr.ifrm - 1) : (whdr.ifrm + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef _GIF_SWAP
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /** GIF_LOAD_H **/
|
|
@ -899,13 +899,11 @@ JSC_CCALL(gui_text,
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(gui_img,
|
JSC_CCALL(gui_img,
|
||||||
const char *img = JS_ToCString(js, argv[0]);
|
|
||||||
transform2d t;
|
transform2d t;
|
||||||
t.pos = js2vec2(argv[1]);
|
t.pos = js2vec2(argv[1]);
|
||||||
t.scale = js2vec2(argv[2]);
|
t.scale = js2vec2(argv[2]);
|
||||||
t.angle = js2number(argv[3]);
|
t.angle = js2number(argv[3]);
|
||||||
gui_draw_img(img, t, js2boolean(argv[4]), js2vec2(argv[5]), 1.0, js2color(argv[6]));
|
gui_draw_img(js2texture(argv[0]), t, js2boolean(argv[4]), js2vec2(argv[5]), 1.0, js2color(argv[6]));
|
||||||
JS_FreeCString(js, img);
|
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_SCALL(gui_font_set, font_set(str))
|
JSC_SCALL(gui_font_set, font_set(str))
|
||||||
|
|
|
@ -111,9 +111,9 @@ void sprite_initialize() {
|
||||||
.layout = {
|
.layout = {
|
||||||
.attrs = {
|
.attrs = {
|
||||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
[2].format = SG_VERTEXFORMAT_UBYTE4N,
|
[2].format = SG_VERTEXFORMAT_UBYTE4N,
|
||||||
[3].format = SG_VERTEXFORMAT_UBYTE4N}},
|
[3].format = SG_VERTEXFORMAT_UBYTE4N}},
|
||||||
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||||
.label = "sprite pipeline",
|
.label = "sprite pipeline",
|
||||||
.colors[0].blend = blend_trans,
|
.colors[0].blend = blend_trans,
|
||||||
|
@ -134,10 +134,10 @@ void sprite_initialize() {
|
||||||
.layout = {
|
.layout = {
|
||||||
.attrs = {
|
.attrs = {
|
||||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
[2].format = SG_VERTEXFORMAT_USHORT4N,
|
[2].format = SG_VERTEXFORMAT_USHORT4N,
|
||||||
[3].format = SG_VERTEXFORMAT_FLOAT2,
|
[3].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
[4].format = SG_VERTEXFORMAT_UBYTE4N
|
[4].format = SG_VERTEXFORMAT_UBYTE4N
|
||||||
}},
|
}},
|
||||||
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||||
});
|
});
|
||||||
|
@ -212,10 +212,8 @@ void sprite_draw(struct sprite *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);
|
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) {
|
void gui_draw_img(texture *tex, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) {
|
||||||
return;
|
//sg_apply_pipeline(pip_sprite);
|
||||||
sg_apply_pipeline(pip_sprite);
|
//sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
||||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
|
|
||||||
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);
|
tex_draw(tex, transform2d2mat(t), ST_UNIT, color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,6 @@ void sprite_draw(struct sprite *sprite);
|
||||||
void sprite_draw_all();
|
void sprite_draw_all();
|
||||||
void sprite_flush();
|
void sprite_flush();
|
||||||
|
|
||||||
void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color);
|
void gui_draw_img(texture *tex, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -117,15 +117,16 @@ struct texture *texture_from_file(const char *path) {
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
tex->data = data;
|
||||||
|
|
||||||
unsigned int nw = next_pow2(tex->width);
|
unsigned int nw = next_pow2(tex->width);
|
||||||
unsigned int nh = next_pow2(tex->height);
|
unsigned int nh = next_pow2(tex->height);
|
||||||
|
|
||||||
tex->data = data;
|
|
||||||
|
|
||||||
int filter = SG_FILTER_NEAREST;
|
int filter = SG_FILTER_NEAREST;
|
||||||
|
|
||||||
sg_image_data sg_img_data;
|
sg_image_data sg_img_data;
|
||||||
|
sg_img_data.subimage[0][0] = (sg_range){.ptr = data, .size=tex->width*tex->height*4};
|
||||||
|
/*
|
||||||
int mips = mip_levels(tex->width, tex->height)+1;
|
int mips = mip_levels(tex->width, tex->height)+1;
|
||||||
|
|
||||||
YughInfo("Has %d mip levels, from wxh %dx%d, pow2 is %ux%u.", mips, tex->width, tex->height,nw,nh);
|
YughInfo("Has %d mip levels, from wxh %dx%d, pow2 is %ux%u.", mips, tex->width, tex->height,nw,nh);
|
||||||
|
@ -141,7 +142,7 @@ struct texture *texture_from_file(const char *path) {
|
||||||
|
|
||||||
for (int i = 1; i < mips; i++) {
|
for (int i = 1; i < mips; i++) {
|
||||||
int w, h, mipw, miph;
|
int w, h, mipw, miph;
|
||||||
mip_wh(tex->width, tex->height, &mipw, &miph, i-1); /* mipw miph are previous iteration */
|
mip_wh(tex->width, tex->height, &mipw, &miph, i-1); // mipw miph are previous iteration
|
||||||
mip_wh(tex->width, tex->height, &w, &h, i);
|
mip_wh(tex->width, tex->height, &w, &h, i);
|
||||||
mipdata[i] = malloc(w * h * 4);
|
mipdata[i] = malloc(w * h * 4);
|
||||||
stbir_resize_uint8_linear(mipdata[i-1], mipw, miph, 0, mipdata[i], w, h, 0, 4);
|
stbir_resize_uint8_linear(mipdata[i-1], mipw, miph, 0, mipdata[i], w, h, 0, 4);
|
||||||
|
@ -150,18 +151,18 @@ struct texture *texture_from_file(const char *path) {
|
||||||
mipw = w;
|
mipw = w;
|
||||||
miph = h;
|
miph = h;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
tex->id = sg_make_image(&(sg_image_desc){
|
tex->id = sg_make_image(&(sg_image_desc){
|
||||||
.type = SG_IMAGETYPE_2D,
|
.type = SG_IMAGETYPE_2D,
|
||||||
.width = tex->width,
|
.width = tex->width,
|
||||||
.height = tex->height,
|
.height = tex->height,
|
||||||
.usage = SG_USAGE_IMMUTABLE,
|
.usage = SG_USAGE_IMMUTABLE,
|
||||||
.num_mipmaps = mips,
|
//.num_mipmaps = mips,
|
||||||
.data = sg_img_data
|
.data = sg_img_data
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int i = 1; i < mips; i++)
|
/*for (int i = 1; i < mips; i++)
|
||||||
free(mipdata[i]);
|
free(mipdata[i]);*/
|
||||||
|
|
||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue