automatically use spritesheets
This commit is contained in:
parent
a8ce3106e1
commit
f928f3e8a2
|
@ -12,15 +12,14 @@ var make_point_obj = function (o, p) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var fullrect = [0, 0, 1, 1];
|
|
||||||
|
|
||||||
var sprite_addbucket = function (sprite) {
|
var sprite_addbucket = function (sprite) {
|
||||||
|
if (!sprite.image) return;
|
||||||
var layer = 1000000 + sprite.gameobject.drawlayer * 1000 - sprite.gameobject.pos.y;
|
var layer = 1000000 + sprite.gameobject.drawlayer * 1000 - sprite.gameobject.pos.y;
|
||||||
sprite_buckets[layer] ??= {};
|
sprite_buckets[layer] ??= {};
|
||||||
sprite_buckets[layer][sprite.path] ??= [];
|
sprite_buckets[layer][sprite.image.texture.path] ??= [];
|
||||||
sprite_buckets[layer][sprite.path].push(sprite);
|
sprite_buckets[layer][sprite.image.texture.path].push(sprite);
|
||||||
sprite._oldlayer = layer;
|
sprite._oldlayer = layer;
|
||||||
sprite._oldpath = sprite.path;
|
sprite._oldpath = sprite.image.texture.path;
|
||||||
};
|
};
|
||||||
|
|
||||||
var sprite_rmbucket = function (sprite) {
|
var sprite_rmbucket = function (sprite) {
|
||||||
|
@ -28,87 +27,100 @@ var sprite_rmbucket = function (sprite) {
|
||||||
else for (var layer of Object.values(sprite_buckets)) for (var path of Object.values(layer)) path.remove(sprite);
|
else for (var layer of Object.values(sprite_buckets)) for (var path of Object.values(layer)) path.remove(sprite);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* an anim is simply an array of images */
|
||||||
|
/* an anim set is like this
|
||||||
|
frog = {
|
||||||
|
walk: [],
|
||||||
|
hop: [],
|
||||||
|
...etc
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
var sprite = {
|
var sprite = {
|
||||||
loop: true,
|
image: undefined,
|
||||||
rect: fullrect,
|
get diffuse() { return this.image.texture; },
|
||||||
anim: {},
|
set diffuse(x) {},
|
||||||
playing: 0,
|
|
||||||
anim_speed: 1,
|
anim_speed: 1,
|
||||||
play(str = 0, fn, loop = true, reverse = false) {
|
play(str, loop = true, reverse = false) {
|
||||||
|
str ??= this.anim;
|
||||||
|
if (!str) return;
|
||||||
|
|
||||||
|
if (typeof str === 'string')
|
||||||
|
str = this.animset[str];
|
||||||
|
|
||||||
|
var playing = str;
|
||||||
|
|
||||||
this.del_anim?.();
|
this.del_anim?.();
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var stop;
|
var stop;
|
||||||
|
|
||||||
self.del_anim = function () {
|
self.del_anim = function () {
|
||||||
self.del_anim = undefined;
|
self.del_anim = undefined;
|
||||||
self = undefined;
|
self = undefined;
|
||||||
advance = undefined;
|
advance = undefined;
|
||||||
stop?.();
|
stop?.();
|
||||||
};
|
};
|
||||||
var playing = self.anim[str];
|
|
||||||
if (!playing) return;
|
|
||||||
var f = 0;
|
|
||||||
if (reverse) f = playing.frames.length - 1;
|
|
||||||
|
|
||||||
self.path = playing.path;
|
var f = 0;
|
||||||
|
if (reverse) f = playing.length - 1;
|
||||||
|
|
||||||
function advance(time) {
|
function advance(time) {
|
||||||
if (!self) return;
|
if (!self) return;
|
||||||
if (!self.gameobject) return;
|
if (!self.gameobject) return;
|
||||||
self.frame = playing.frames[f].rect;
|
|
||||||
self.rect = [self.frame.x, self.frame.y, self.frame.w, self.frame.h];
|
|
||||||
self.update_dimensions();
|
|
||||||
var done = false;
|
var done = false;
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
f = (((f - 1) % playing.frames.length) + playing.frames.length) % playing.frames.length;
|
f = (((f - 1) % playing.length) + playing.length) % playing.length;
|
||||||
if (f === playing.frames.length - 1) done = true;
|
if (f === playing.length - 1) done = true;
|
||||||
} else {
|
} else {
|
||||||
f = (f + 1) % playing.frames.length;
|
f = (f + 1) % playing.length;
|
||||||
if (f === 0) done = true;
|
if (f === 0) done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.image = playing[f];
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
fn?.();
|
self.anim_done?.();
|
||||||
if (!loop) {
|
if (!loop) {
|
||||||
self?.stop();
|
self?.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return playing.frames[f].time/self.anim_speed;
|
return playing[f].time/self.anim_speed;
|
||||||
}
|
}
|
||||||
stop = self.gameobject.delay(advance, playing.frames[f].time/self.anim_speed);
|
stop = self.gameobject.delay(advance, playing[f].time/self.anim_speed);
|
||||||
advance();
|
advance();
|
||||||
},
|
},
|
||||||
tex_sync() {
|
tex_sync() {
|
||||||
if (this.anim) this.stop();
|
if (this.anim) this.stop();
|
||||||
this.rect = fullrect;
|
|
||||||
var anim = SpriteAnim.make(this.path);
|
|
||||||
this.update_dimensions();
|
|
||||||
this.sync();
|
this.sync();
|
||||||
|
|
||||||
if (!anim) return;
|
|
||||||
this.anim = anim;
|
|
||||||
this.play();
|
this.play();
|
||||||
|
|
||||||
this.pos = this.dimensions().scale(this.anchor);
|
|
||||||
},
|
},
|
||||||
stop() {
|
stop() {
|
||||||
this.del_anim?.();
|
this.del_anim?.();
|
||||||
},
|
},
|
||||||
set path(p) {
|
set path(p) {
|
||||||
p = Resources.find_image(p, this.gameobject._root);
|
var image = game.texture(p);
|
||||||
if (!p) {
|
if (!image) {
|
||||||
console.warn(`Could not find image ${p}.`);
|
console.warn(`Could not find image ${p}.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (p === this.path) return;
|
|
||||||
|
|
||||||
this._p = p;
|
this._p = p;
|
||||||
|
|
||||||
this.del_anim?.();
|
this.del_anim?.();
|
||||||
this.texture = game.texture(p);
|
this.image = image;
|
||||||
|
if (Array.isArray(image)) {
|
||||||
this.diffuse = this.texture;
|
this.anim = image;
|
||||||
|
this.image = image[0];
|
||||||
|
}
|
||||||
|
if (Object.values(image)[0][0]) {
|
||||||
|
// it is an anims set
|
||||||
|
this.animset = image;
|
||||||
|
this.image = Object.values(image)[0][0];
|
||||||
|
}
|
||||||
|
|
||||||
this.tex_sync();
|
this.tex_sync();
|
||||||
},
|
},
|
||||||
|
@ -147,21 +159,6 @@ var sprite = {
|
||||||
var realpos = dim.scale(0.5).add(this.pos);
|
var realpos = dim.scale(0.5).add(this.pos);
|
||||||
return bbox.fromcwh(realpos, dim);
|
return bbox.fromcwh(realpos, dim);
|
||||||
},
|
},
|
||||||
|
|
||||||
update_dimensions() {
|
|
||||||
this._dimensions = [this.texture.width * this.rect[2], this.texture.height * this.rect[3]];
|
|
||||||
component.sprite_dim_hook?.(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
dimensions() {
|
|
||||||
return this._dimensions;
|
|
||||||
},
|
|
||||||
width() {
|
|
||||||
return this.dimensions().x;
|
|
||||||
},
|
|
||||||
height() {
|
|
||||||
return this.dimensions().y;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
globalThis.allsprites = [];
|
globalThis.allsprites = [];
|
||||||
var sprite_buckets = [];
|
var sprite_buckets = [];
|
||||||
|
@ -247,7 +244,6 @@ component.sprite = function (obj) {
|
||||||
sp.transform = obj.transform;
|
sp.transform = obj.transform;
|
||||||
sp.guid = prosperon.guid();
|
sp.guid = prosperon.guid();
|
||||||
allsprites.push(sp);
|
allsprites.push(sp);
|
||||||
if (component.sprite.make_hook) component.sprite.make_hook(sp);
|
|
||||||
sprite_addbucket(sp);
|
sprite_addbucket(sp);
|
||||||
return sp;
|
return sp;
|
||||||
};
|
};
|
||||||
|
@ -271,37 +267,38 @@ var SpriteAnim = {};
|
||||||
SpriteAnim.hotreload = function(path) {
|
SpriteAnim.hotreload = function(path) {
|
||||||
delete animcache[path];
|
delete animcache[path];
|
||||||
}
|
}
|
||||||
SpriteAnim.make = function (path) {
|
SpriteAnim.make = function (path, tex) {
|
||||||
var anim;
|
var anim;
|
||||||
if (animcache[path]) return animcache[path];
|
if (animcache[path]) return animcache[path];
|
||||||
|
|
||||||
|
if (!tex) return;
|
||||||
|
|
||||||
profile.report(`animation_${path}`);
|
profile.report(`animation_${path}`);
|
||||||
if (io.exists(path.set_ext(".ase"))) anim = SpriteAnim.aseprite(path.set_ext(".ase"));
|
if (io.exists(path.set_ext(".ase"))) anim = SpriteAnim.aseprite(path.set_ext(".ase"), tex);
|
||||||
else if (io.exists(path.set_ext(".json"))) anim = SpriteAnim.aseprite(path.set_ext(".json"));
|
else if (io.exists(path.set_ext(".json"))) anim = SpriteAnim.aseprite(path.set_ext(".json"), tex);
|
||||||
else if (path.ext() === "ase") anim = SpriteAnim.aseprite(path);
|
else if (path.ext() === "ase") anim = SpriteAnim.aseprite(path, tex);
|
||||||
else if (path.ext() === "gif") anim = SpriteAnim.gif(path);
|
else if (path.ext() === "gif") anim = SpriteAnim.gif(path, tex);
|
||||||
else anim = undefined;
|
else anim = undefined;
|
||||||
|
|
||||||
profile.endreport(`animation_${path}`);
|
profile.endreport(`animation_${path}`);
|
||||||
animcache[path] = anim;
|
animcache[path] = anim;
|
||||||
return animcache[path];
|
return animcache[path];
|
||||||
};
|
};
|
||||||
SpriteAnim.gif = function (path) {
|
SpriteAnim.gif = function (path, tex) {
|
||||||
var anim = {};
|
var anim = {};
|
||||||
anim.frames = [];
|
anim.frames = [];
|
||||||
anim.path = path;
|
anim.path = path;
|
||||||
var tex = game.texture(path).texture;
|
|
||||||
var frames = tex.frames;
|
var frames = tex.frames;
|
||||||
if (frames === 1) return undefined;
|
if (frames === 1) return undefined;
|
||||||
var yslice = 1 / frames;
|
var yslice = 1 / frames;
|
||||||
for (var f = 0; f < frames; f++) {
|
for (var f = 0; f < frames; f++) {
|
||||||
var frame = {};
|
var frame = {};
|
||||||
frame.rect = {
|
frame.rect = [
|
||||||
x: 0,
|
0,
|
||||||
w: 1,
|
yslice * f,
|
||||||
y: yslice * f,
|
1,
|
||||||
h: yslice,
|
yslice,
|
||||||
};
|
];
|
||||||
frame.time = 0.05;
|
frame.time = 0.05;
|
||||||
anim.frames.push(frame);
|
anim.frames.push(frame);
|
||||||
}
|
}
|
||||||
|
@ -340,12 +337,12 @@ SpriteAnim.aseprite = function (path) {
|
||||||
var ase_make_frame = function (ase_frame) {
|
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,
|
f.x / dim.w,
|
||||||
w: f.w / dim.w,
|
f.y / dim.h,
|
||||||
y: f.y / dim.h,
|
f.w / dim.w,
|
||||||
h: f.h / dim.h,
|
f.h / dim.h,
|
||||||
};
|
];
|
||||||
frame.time = ase_frame.duration / 1000;
|
frame.time = ase_frame.duration / 1000;
|
||||||
anim.frames.push(frame);
|
anim.frames.push(frame);
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,6 @@ mum.base = {
|
||||||
font_size: 16,
|
font_size: 16,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
inset: null,
|
|
||||||
anchor: [0, 1], // where to draw the item from, relative to the cursor. [0,1] is from the top left corner. [1,0] is from the bottom right
|
anchor: [0, 1], // where to draw the item from, relative to the cursor. [0,1] is from the top left corner. [1,0] is from the bottom right
|
||||||
background_image: null,
|
background_image: null,
|
||||||
slice: null, // pass to slice an image as a 9 slice. see render.slice9 for its format
|
slice: null, // pass to slice an image as a 9 slice. see render.slice9 for its format
|
||||||
|
@ -47,7 +46,10 @@ mum.base = {
|
||||||
image_repeat_offset: [0, 0],
|
image_repeat_offset: [0, 0],
|
||||||
debug: false /* set to true to draw debug boxes */,
|
debug: false /* set to true to draw debug boxes */,
|
||||||
hide: false,
|
hide: false,
|
||||||
|
child_gap: 0,
|
||||||
|
child_layout: 'top2bottom', /* top2bottom, left2right */
|
||||||
tooltip: null,
|
tooltip: null,
|
||||||
|
children: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
// data is passed into each function, and various stats are generated
|
// data is passed into each function, and various stats are generated
|
||||||
|
@ -64,9 +66,46 @@ var context = mum.base;
|
||||||
var context_stack = [];
|
var context_stack = [];
|
||||||
var cursor = [0,0];
|
var cursor = [0,0];
|
||||||
|
|
||||||
|
function computeContainerSize(context)
|
||||||
|
{
|
||||||
|
var sizing = context.sizing.value;
|
||||||
|
var content_dim = [0,0];
|
||||||
|
var max_child_dim = [0,0];
|
||||||
|
|
||||||
|
if (context.layout === 'left2right') {
|
||||||
|
for (var child of context.children) {
|
||||||
|
content_dim.x += child.size.x + context.child_gap;
|
||||||
|
if (child.size.y > max_child_dim.y)
|
||||||
|
max_child_dim.y = child.size.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
content_dim.width -= context.child_gap; // remove extra gap after last child
|
||||||
|
content_dim.y = max_child_dim.y;
|
||||||
|
} else {
|
||||||
|
for (var child of context.children) {
|
||||||
|
content_dim.y += child.size.y + context.child_gap;
|
||||||
|
if (child.size.x > max_child_dim.x)
|
||||||
|
max_child_dim.x = child.size.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
content_dim.y -= child_gap;
|
||||||
|
content_dim.x = max_child_dim.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
content_dim = content_dim.add(context.padding.scale(2));
|
||||||
|
|
||||||
|
var container_size = [0,0];
|
||||||
|
if (context.sizing.x.type === 'fit')
|
||||||
|
container_size.x = content_dim.x;
|
||||||
|
else if (container.sizing.x.type === 'grow') {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
mum.container = function(data, cb) {
|
mum.container = function(data, cb) {
|
||||||
context_stack.push(context);
|
context_stack.push(context);
|
||||||
data.__proto__ = mum.base;
|
data.__proto__ = mum.base;
|
||||||
|
data.children = [];
|
||||||
var container_context = {
|
var container_context = {
|
||||||
pos:cursor.slice(),
|
pos:cursor.slice(),
|
||||||
size:[0,0],
|
size:[0,0],
|
||||||
|
@ -194,8 +233,9 @@ mum.label = function (str, data = {}) {
|
||||||
mum.image = function (path, data = {}) {
|
mum.image = function (path, data = {}) {
|
||||||
if (pre(data)) return;
|
if (pre(data)) return;
|
||||||
path ??= data.background_image;
|
path ??= data.background_image;
|
||||||
var tex = path;
|
|
||||||
if (typeof path === "string") tex = game.texture(path);
|
var image = game.texture(path);
|
||||||
|
var tex = image.texture;
|
||||||
|
|
||||||
if (!data.height)
|
if (!data.height)
|
||||||
if (data.width) data.height = tex.height * (data.width / tex.width);
|
if (data.width) data.height = tex.height * (data.width / tex.width);
|
||||||
|
@ -212,12 +252,12 @@ mum.image = function (path, data = {}) {
|
||||||
data.drawpos = data.drawpos.add(aa.scale([data.width, data.height]));
|
data.drawpos = data.drawpos.add(aa.scale([data.width, data.height]));
|
||||||
|
|
||||||
if (data.slice) render.slice9(tex, data.drawpos, data.slice, [data.width, data.height]);
|
if (data.slice) render.slice9(tex, data.drawpos, data.slice, [data.width, data.height]);
|
||||||
else data.bb = render.image(tex, data.drawpos, [data.width, data.height]);
|
else data.bb = render.image(image, data.drawpos, [data.width, data.height]);
|
||||||
|
|
||||||
end(data);
|
end(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
mum.rectangle = function (data = {}) {
|
mum.rectangle = function (data = {}, cb) {
|
||||||
if (pre(data)) return;
|
if (pre(data)) return;
|
||||||
var aa = [0, 0].sub(data.anchor);
|
var aa = [0, 0].sub(data.anchor);
|
||||||
data.drawpos = data.drawpos.add(aa.scale([data.width, data.height]));
|
data.drawpos = data.drawpos.add(aa.scale([data.width, data.height]));
|
||||||
|
|
|
@ -101,6 +101,7 @@ function update_emitters(dt) {
|
||||||
|
|
||||||
var arr = [];
|
var arr = [];
|
||||||
function draw_emitters() {
|
function draw_emitters() {
|
||||||
|
return;
|
||||||
ssbo ??= render.make_textssbo();
|
ssbo ??= render.make_textssbo();
|
||||||
render.use_shader("shaders/baseparticle.cg");
|
render.use_shader("shaders/baseparticle.cg");
|
||||||
var buckets = {};
|
var buckets = {};
|
||||||
|
|
|
@ -61,7 +61,7 @@ game.engine_start = function (s) {
|
||||||
function () {
|
function () {
|
||||||
global.mixin("scripts/sound.js");
|
global.mixin("scripts/sound.js");
|
||||||
world_start();
|
world_start();
|
||||||
window.set_icon(game.texture("moon"));
|
window.set_icon(game.texture("moon").texture);
|
||||||
Object.readonly(window.__proto__, "vsync");
|
Object.readonly(window.__proto__, "vsync");
|
||||||
Object.readonly(window.__proto__, "enable_dragndrop");
|
Object.readonly(window.__proto__, "enable_dragndrop");
|
||||||
Object.readonly(window.__proto__, "enable_clipboard");
|
Object.readonly(window.__proto__, "enable_clipboard");
|
||||||
|
@ -225,6 +225,65 @@ game.tex_hotreload = function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var image = {};
|
||||||
|
image.dimensions = function()
|
||||||
|
{
|
||||||
|
return [this.texture.width, this.texture.height].scale([this.rect[2], this.rect[3]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_proto.copy = function(src, pos, rect)
|
||||||
|
{
|
||||||
|
var pixel_rect = {
|
||||||
|
x: rect[0]*src.width,
|
||||||
|
y: rect[1]*src.height,
|
||||||
|
w: rect[2]*src.width,
|
||||||
|
h: rect[3]*src.height
|
||||||
|
};
|
||||||
|
|
||||||
|
this.blit(src, {
|
||||||
|
x: pos[0],
|
||||||
|
y: pos[1],
|
||||||
|
w: rect[2]*src.width,
|
||||||
|
h: rect[3]*src.height
|
||||||
|
}, pixel_rect, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var spritesheet;
|
||||||
|
var sheet_frames = [];
|
||||||
|
var sheetsize = 1024;
|
||||||
|
|
||||||
|
function pack_into_sheet(images)
|
||||||
|
{
|
||||||
|
if (!Array.isArray(images)) images = [images];
|
||||||
|
if (images[0].texture.width > 300 && images[0].texture.height > 300) return;
|
||||||
|
sheet_frames = sheet_frames.concat(images);
|
||||||
|
var sizes = sheet_frames.map(x => [x.rect[2]*x.texture.width, x.rect[3]*x.texture.height]);
|
||||||
|
var pos = os.rectpack(sheetsize, sheetsize, sizes);
|
||||||
|
if (!pos) {
|
||||||
|
console.error(`did not make spritesheet properly from images ${images}`);
|
||||||
|
console.info(sizes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newsheet = os.make_tex_data(sheetsize,sheetsize);
|
||||||
|
|
||||||
|
for (var i = 0; i < pos.length; i++) {
|
||||||
|
// Copy the texture to the new sheet
|
||||||
|
newsheet.copy(sheet_frames[i].texture, pos[i], sheet_frames[i].rect);
|
||||||
|
|
||||||
|
// Update the frame's rect to the new position in normalized coordinates
|
||||||
|
sheet_frames[i].rect[0] = pos[i][0] / newsheet.width;
|
||||||
|
sheet_frames[i].rect[1] = pos[i][1] / newsheet.height;
|
||||||
|
sheet_frames[i].rect[2] = sizes[i][0] / newsheet.width;
|
||||||
|
sheet_frames[i].rect[3] = sizes[i][1] / newsheet.height;
|
||||||
|
sheet_frames[i].texture = newsheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
newsheet.load_gpu();
|
||||||
|
spritesheet = newsheet;
|
||||||
|
return spritesheet;
|
||||||
|
}
|
||||||
|
|
||||||
game.texture = function (path) {
|
game.texture = function (path) {
|
||||||
if (!path) return game.texture("icons/no_tex.gif");
|
if (!path) return game.texture("icons/no_tex.gif");
|
||||||
path = Resources.find_image(path);
|
path = Resources.find_image(path);
|
||||||
|
@ -236,8 +295,40 @@ game.texture = function (path) {
|
||||||
return game.texture.cache[path];
|
return game.texture.cache[path];
|
||||||
}
|
}
|
||||||
if (game.texture.cache[path]) return game.texture.cache[path];
|
if (game.texture.cache[path]) return game.texture.cache[path];
|
||||||
game.texture.cache[path] = os.make_texture(path);
|
var tex = os.make_texture(path);
|
||||||
|
|
||||||
|
var image;
|
||||||
|
|
||||||
|
var anim = SpriteAnim.make(path, tex);
|
||||||
|
if (!anim) {
|
||||||
|
image = {
|
||||||
|
texture: tex,
|
||||||
|
rect:[0,0,1,1]
|
||||||
|
};
|
||||||
|
if (pack_into_sheet([image]))
|
||||||
|
tex = spritesheet;
|
||||||
|
} else if (Object.keys(anim).length === 1) {
|
||||||
|
image = Object.values(anim)[0].frames;
|
||||||
|
image.forEach(x => x.texture = tex);
|
||||||
|
if (pack_into_sheet(image))
|
||||||
|
tex = spritesheet;
|
||||||
|
} else {
|
||||||
|
image = {};
|
||||||
|
var packs = [];
|
||||||
|
for (var a in anim) {
|
||||||
|
image[a] = anim[a].frames.slice();
|
||||||
|
image[a].forEach(x => x.texture = tex);
|
||||||
|
packs = packs.concat(image[a]);
|
||||||
|
}
|
||||||
|
if (pack_into_sheet(packs))
|
||||||
|
tex = spritesheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
game.texture.cache[path] = image;
|
||||||
game.texture.time_cache[path] = io.mod(path);
|
game.texture.time_cache[path] = io.mod(path);
|
||||||
|
|
||||||
|
tex.load_gpu();
|
||||||
|
|
||||||
return game.texture.cache[path];
|
return game.texture.cache[path];
|
||||||
};
|
};
|
||||||
game.texture.cache = {};
|
game.texture.cache = {};
|
||||||
|
@ -246,14 +337,14 @@ game.texture.time_cache = {};
|
||||||
game.texture.total_size = function()
|
game.texture.total_size = function()
|
||||||
{
|
{
|
||||||
var size = 0;
|
var size = 0;
|
||||||
Object.values(game.texture.cache).forEach(x => size += x.inram() ? x.width*x.height*4 : 0);
|
// Object.values(game.texture.cache).forEach(x => size += x.texture.inram() ? x..texture.width*x.texture.height*4 : 0);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
game.texture.total_vram = function()
|
game.texture.total_vram = function()
|
||||||
{
|
{
|
||||||
var vram = 0;
|
var vram = 0;
|
||||||
Object.values(game.texture.cache).forEach(x => vram += x.vram);
|
// Object.values(game.texture.cache).forEach(x => vram += x.vram);
|
||||||
return vram;
|
return vram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,46 @@
|
||||||
|
/*
|
||||||
|
Anatomy of rendering an image
|
||||||
|
render.image(path)
|
||||||
|
Path can be a file like "toad"
|
||||||
|
If this is a gif, this would display the entire range of the animation
|
||||||
|
It can be a frame of animation, like "frog.0"
|
||||||
|
If it's an aseprite, it can have multiple animations, like "frog.walk.0"
|
||||||
|
file^ frame^ idx
|
||||||
|
|
||||||
|
render.image("frog.walk.0",
|
||||||
|
game.image("frog.walk.0") ==> retrieve
|
||||||
|
|
||||||
|
image = {
|
||||||
|
texture: "spritesheet.png",
|
||||||
|
rect: [x,y,w,h],
|
||||||
|
time: 100
|
||||||
|
},
|
||||||
|
|
||||||
|
frames: {
|
||||||
|
toad: {
|
||||||
|
x: 4,
|
||||||
|
y: 5,
|
||||||
|
w: 10,
|
||||||
|
h: 10
|
||||||
|
},
|
||||||
|
frog: {
|
||||||
|
|
||||||
|
walk: [
|
||||||
|
{ texture: spritesheet.png, x: 10, y:10, w:6,h:6, time: 100 },
|
||||||
|
{ texture: spritesheet.png, x:16,y:10,w:6,h:6,time:100} <--- two frame walk animation
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
texture frog {
|
||||||
|
texture: {"frog.png"}, <--- this is the actual thing to send to the gpu
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
w:10,
|
||||||
|
h:10
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
render.doc = {
|
render.doc = {
|
||||||
doc: "Functions for rendering modes.",
|
doc: "Functions for rendering modes.",
|
||||||
normal: "Final render with all lighting.",
|
normal: "Final render with all lighting.",
|
||||||
|
@ -886,7 +929,6 @@ function img_e() {
|
||||||
var e = {
|
var e = {
|
||||||
transform: os.make_transform(),
|
transform: os.make_transform(),
|
||||||
shade: Color.white,
|
shade: Color.white,
|
||||||
rect: [0, 0, 1, 1],
|
|
||||||
};
|
};
|
||||||
img_cache.push(e);
|
img_cache.push(e);
|
||||||
return e;
|
return e;
|
||||||
|
@ -954,7 +996,9 @@ render.invertmask = function()
|
||||||
|
|
||||||
render.mask = function mask(tex, pos, scale, rotation = 0, ref = 1)
|
render.mask = function mask(tex, pos, scale, rotation = 0, ref = 1)
|
||||||
{
|
{
|
||||||
if (typeof tex === 'string') tex = game.texture(tex);
|
if (typeof tex === 'string')
|
||||||
|
tex = game.texture(tex);
|
||||||
|
|
||||||
var pipe = stencil_writer(ref);
|
var pipe = stencil_writer(ref);
|
||||||
render.use_shader('shaders/sprite.cg', pipe);
|
render.use_shader('shaders/sprite.cg', pipe);
|
||||||
var t = os.make_transform();
|
var t = os.make_transform();
|
||||||
|
@ -962,16 +1006,18 @@ render.mask = function mask(tex, pos, scale, rotation = 0, ref = 1)
|
||||||
t.scale = scale.div(tex.dimensions);
|
t.scale = scale.div(tex.dimensions);
|
||||||
set_model(t);
|
set_model(t);
|
||||||
render.use_mat({
|
render.use_mat({
|
||||||
diffuse:tex,
|
diffuse:tex.texture,
|
||||||
rect: [0,0,1,1],
|
rect: tex.rect,
|
||||||
shade: Color.white
|
shade: Color.white
|
||||||
});
|
});
|
||||||
render.draw(shape.quad);
|
render.draw(shape.quad);
|
||||||
}
|
}
|
||||||
|
|
||||||
render.image = function image(tex, pos, scale, rotation = 0, color = Color.white) {
|
render.image = function image(image, pos, scale, rotation = 0, color = Color.white) {
|
||||||
if (typeof tex === "string")
|
if (typeof image === "string")
|
||||||
tex = game.texture(tex);
|
image = game.texture(image);
|
||||||
|
|
||||||
|
var tex = image.texture;
|
||||||
|
|
||||||
if (scale)
|
if (scale)
|
||||||
scale = scale.div([tex.width, tex.height]);
|
scale = scale.div([tex.width, tex.height]);
|
||||||
|
@ -992,8 +1038,8 @@ render.image = function image(tex, pos, scale, rotation = 0, color = Color.white
|
||||||
|
|
||||||
var e = img_e();
|
var e = img_e();
|
||||||
e.transform.trs(pos, undefined, scale);
|
e.transform.trs(pos, undefined, scale);
|
||||||
|
e.image = image;
|
||||||
e.shade = color;
|
e.shade = color;
|
||||||
e.texture = tex;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
var bb = {};
|
var bb = {};
|
||||||
|
|
|
@ -273,7 +273,7 @@ Cmdline.register_order(
|
||||||
if (io.exists("game.js")) global.app = actor.spawn("game.js");
|
if (io.exists("game.js")) global.app = actor.spawn("game.js");
|
||||||
else global.app = actor.spawn("scripts/nogame.js");
|
else global.app = actor.spawn("scripts/nogame.js");
|
||||||
|
|
||||||
if (project.icon) window.set_icon(game.texture(project.icon));
|
if (project.icon) window.set_icon(game.texture(project.icon).texture);
|
||||||
game.camera = world.spawn("scripts/camera2d");
|
game.camera = world.spawn("scripts/camera2d");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
1358
source/engine/cute_aseprite.h
Normal file
1358
source/engine/cute_aseprite.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1174,7 +1174,8 @@ JSC_CCALL(render_make_sprite_ssbo,
|
||||||
JSValue sub = js_getpropidx(array,i);
|
JSValue sub = js_getpropidx(array,i);
|
||||||
|
|
||||||
transform *tr = js2transform(js_getpropstr(sub, "transform"));
|
transform *tr = js2transform(js_getpropstr(sub, "transform"));
|
||||||
texture *t = js2texture(js_getpropstr(sub, "texture"));
|
JSValue image = js_getpropstr(sub, "image");
|
||||||
|
texture *t = js2texture(js_getpropstr(image, "texture"));
|
||||||
HMM_Vec3 tscale;
|
HMM_Vec3 tscale;
|
||||||
|
|
||||||
if (t) {
|
if (t) {
|
||||||
|
@ -1185,7 +1186,7 @@ JSC_CCALL(render_make_sprite_ssbo,
|
||||||
}
|
}
|
||||||
|
|
||||||
ms[i].model = transform2mat(tr);
|
ms[i].model = transform2mat(tr);
|
||||||
ms[i].rect = js2vec4(js_getpropstr(sub,"rect"));
|
ms[i].rect = js2vec4(js_getpropstr(image,"rect"));
|
||||||
ms[i].shade = js2vec4(js_getpropstr(sub,"shade"));
|
ms[i].shade = js2vec4(js_getpropstr(sub,"shade"));
|
||||||
|
|
||||||
if (t)
|
if (t)
|
||||||
|
@ -3274,6 +3275,10 @@ JSC_SCALL(os_make_texture,
|
||||||
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
|
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
|
||||||
)
|
)
|
||||||
|
|
||||||
|
JSC_SCALL(os_make_aseprite,
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
JSC_SCALL(os_texture_swap,
|
JSC_SCALL(os_texture_swap,
|
||||||
texture *old = js2texture(argv[1]);
|
texture *old = js2texture(argv[1]);
|
||||||
texture *tex = texture_from_file(str);
|
texture *tex = texture_from_file(str);
|
||||||
|
@ -3510,8 +3515,9 @@ JSC_CCALL(os_rectpack,
|
||||||
stbrp_init_target(ctx, width, height, nodes, width);
|
stbrp_init_target(ctx, width, height, nodes, width);
|
||||||
int packed = stbrp_pack_rects(ctx, rects, num);
|
int packed = stbrp_pack_rects(ctx, rects, num);
|
||||||
|
|
||||||
if (!packed)
|
if (!packed) {
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
ret = JS_NewArray(js);
|
ret = JS_NewArray(js);
|
||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
|
|
||||||
#include "qoi.h"
|
#include "qoi.h"
|
||||||
|
|
||||||
|
#define CUTE_ASEPRITE_IMPLEMENTATION
|
||||||
|
#include "cute_aseprite.h"
|
||||||
|
|
||||||
#ifndef NSVG
|
#ifndef NSVG
|
||||||
#include "nanosvgrast.h"
|
#include "nanosvgrast.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -178,7 +181,31 @@ struct texture *texture_from_file(const char *path) {
|
||||||
|
|
||||||
char *ext = strrchr(path, '.');
|
char *ext = strrchr(path, '.');
|
||||||
|
|
||||||
if (!strcmp(ext, ".qoi")) {
|
if (!strcmp(ext, ".ase")) {
|
||||||
|
ase_t *ase = cute_aseprite_load_from_memory(raw, rawlen, NULL);
|
||||||
|
// frame is ase->w, ase->h
|
||||||
|
/* sprite anim is
|
||||||
|
anim = {
|
||||||
|
frames: [
|
||||||
|
rect: { <---- gathered after rect packing
|
||||||
|
x:
|
||||||
|
y:
|
||||||
|
w:
|
||||||
|
h:
|
||||||
|
},
|
||||||
|
time: ase->duration_milliseconds / 1000 (so it's in seconds)
|
||||||
|
],
|
||||||
|
path: path,
|
||||||
|
};
|
||||||
|
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < ase->frame_count; i++) {
|
||||||
|
ase_frame_t *frame = ase->frames+i;
|
||||||
|
// add to thing with frame->pixels
|
||||||
|
}
|
||||||
|
|
||||||
|
cute_aseprite_free(ase);
|
||||||
|
} else if (!strcmp(ext, ".qoi")) {
|
||||||
qoi_desc qoi;
|
qoi_desc qoi;
|
||||||
data = qoi_decode(raw, rawlen, &qoi, 4);
|
data = qoi_decode(raw, rawlen, &qoi, 4);
|
||||||
tex->width = qoi.width;
|
tex->width = qoi.width;
|
||||||
|
@ -221,8 +248,6 @@ struct texture *texture_from_file(const char *path) {
|
||||||
|
|
||||||
tex->data = data;
|
tex->data = data;
|
||||||
|
|
||||||
texture_load_gpu(tex);
|
|
||||||
|
|
||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,9 +257,9 @@ void texture_free(texture *tex)
|
||||||
if (tex->data)
|
if (tex->data)
|
||||||
free(tex->data);
|
free(tex->data);
|
||||||
if (tex->delays) arrfree(tex->delays);
|
if (tex->delays) arrfree(tex->delays);
|
||||||
sg_destroy_image(tex->id);
|
|
||||||
if (tex->simgui.id)
|
if (tex->simgui.id)
|
||||||
simgui_destroy_image(tex->simgui);
|
simgui_destroy_image(tex->simgui);
|
||||||
|
|
||||||
free(tex);
|
free(tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,9 +535,9 @@ void texture_load_gpu(texture *tex)
|
||||||
.num_mipmaps = 1,
|
.num_mipmaps = 1,
|
||||||
.data = img_data
|
.data = img_data
|
||||||
});
|
});
|
||||||
} else {
|
} //else {
|
||||||
// Simple update
|
// Simple update
|
||||||
sg_image_data img_data = tex_img_data(tex,0);
|
// sg_image_data img_data = tex_img_data(tex,0);
|
||||||
sg_update_image(tex->id, &img_data);
|
// sg_update_image(tex->id, &img_data);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
|
||||||
|
#include "stb_rect_pack.h";
|
||||||
|
|
||||||
#include "sokol_app.h"
|
#include "sokol_app.h"
|
||||||
#include "sokol/util/sokol_imgui.h"
|
#include "sokol/util/sokol_imgui.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue