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) {
|
||||
if (!sprite.image) return;
|
||||
var layer = 1000000 + sprite.gameobject.drawlayer * 1000 - sprite.gameobject.pos.y;
|
||||
sprite_buckets[layer] ??= {};
|
||||
sprite_buckets[layer][sprite.path] ??= [];
|
||||
sprite_buckets[layer][sprite.path].push(sprite);
|
||||
sprite_buckets[layer][sprite.image.texture.path] ??= [];
|
||||
sprite_buckets[layer][sprite.image.texture.path].push(sprite);
|
||||
sprite._oldlayer = layer;
|
||||
sprite._oldpath = sprite.path;
|
||||
sprite._oldpath = sprite.image.texture.path;
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
/* an anim is simply an array of images */
|
||||
/* an anim set is like this
|
||||
frog = {
|
||||
walk: [],
|
||||
hop: [],
|
||||
...etc
|
||||
}
|
||||
*/
|
||||
|
||||
var sprite = {
|
||||
loop: true,
|
||||
rect: fullrect,
|
||||
anim: {},
|
||||
playing: 0,
|
||||
image: undefined,
|
||||
get diffuse() { return this.image.texture; },
|
||||
set diffuse(x) {},
|
||||
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?.();
|
||||
|
||||
var self = this;
|
||||
var stop;
|
||||
|
||||
self.del_anim = function () {
|
||||
self.del_anim = undefined;
|
||||
self = undefined;
|
||||
advance = undefined;
|
||||
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) {
|
||||
if (!self) 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;
|
||||
if (reverse) {
|
||||
f = (((f - 1) % playing.frames.length) + playing.frames.length) % playing.frames.length;
|
||||
if (f === playing.frames.length - 1) done = true;
|
||||
f = (((f - 1) % playing.length) + playing.length) % playing.length;
|
||||
if (f === playing.length - 1) done = true;
|
||||
} else {
|
||||
f = (f + 1) % playing.frames.length;
|
||||
f = (f + 1) % playing.length;
|
||||
if (f === 0) done = true;
|
||||
}
|
||||
|
||||
self.image = playing[f];
|
||||
|
||||
if (done) {
|
||||
fn?.();
|
||||
self.anim_done?.();
|
||||
if (!loop) {
|
||||
self?.stop();
|
||||
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();
|
||||
},
|
||||
tex_sync() {
|
||||
if (this.anim) this.stop();
|
||||
this.rect = fullrect;
|
||||
var anim = SpriteAnim.make(this.path);
|
||||
this.update_dimensions();
|
||||
this.sync();
|
||||
|
||||
if (!anim) return;
|
||||
this.anim = anim;
|
||||
this.play();
|
||||
|
||||
this.pos = this.dimensions().scale(this.anchor);
|
||||
},
|
||||
stop() {
|
||||
this.del_anim?.();
|
||||
},
|
||||
set path(p) {
|
||||
p = Resources.find_image(p, this.gameobject._root);
|
||||
if (!p) {
|
||||
var image = game.texture(p);
|
||||
if (!image) {
|
||||
console.warn(`Could not find image ${p}.`);
|
||||
return;
|
||||
}
|
||||
if (p === this.path) return;
|
||||
|
||||
this._p = p;
|
||||
|
||||
this.del_anim?.();
|
||||
this.texture = game.texture(p);
|
||||
|
||||
this.diffuse = this.texture;
|
||||
this.image = image;
|
||||
if (Array.isArray(image)) {
|
||||
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();
|
||||
},
|
||||
|
@ -147,21 +159,6 @@ var sprite = {
|
|||
var realpos = dim.scale(0.5).add(this.pos);
|
||||
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 = [];
|
||||
var sprite_buckets = [];
|
||||
|
@ -247,7 +244,6 @@ component.sprite = function (obj) {
|
|||
sp.transform = obj.transform;
|
||||
sp.guid = prosperon.guid();
|
||||
allsprites.push(sp);
|
||||
if (component.sprite.make_hook) component.sprite.make_hook(sp);
|
||||
sprite_addbucket(sp);
|
||||
return sp;
|
||||
};
|
||||
|
@ -271,37 +267,38 @@ var SpriteAnim = {};
|
|||
SpriteAnim.hotreload = function(path) {
|
||||
delete animcache[path];
|
||||
}
|
||||
SpriteAnim.make = function (path) {
|
||||
SpriteAnim.make = function (path, tex) {
|
||||
var anim;
|
||||
if (animcache[path]) return animcache[path];
|
||||
|
||||
if (!tex) return;
|
||||
|
||||
profile.report(`animation_${path}`);
|
||||
if (io.exists(path.set_ext(".ase"))) anim = SpriteAnim.aseprite(path.set_ext(".ase"));
|
||||
else if (io.exists(path.set_ext(".json"))) anim = SpriteAnim.aseprite(path.set_ext(".json"));
|
||||
else if (path.ext() === "ase") anim = SpriteAnim.aseprite(path);
|
||||
else if (path.ext() === "gif") anim = SpriteAnim.gif(path);
|
||||
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"), tex);
|
||||
else if (path.ext() === "ase") anim = SpriteAnim.aseprite(path, tex);
|
||||
else if (path.ext() === "gif") anim = SpriteAnim.gif(path, tex);
|
||||
else anim = undefined;
|
||||
|
||||
profile.endreport(`animation_${path}`);
|
||||
animcache[path] = anim;
|
||||
return animcache[path];
|
||||
};
|
||||
SpriteAnim.gif = function (path) {
|
||||
SpriteAnim.gif = function (path, tex) {
|
||||
var anim = {};
|
||||
anim.frames = [];
|
||||
anim.path = path;
|
||||
var tex = game.texture(path).texture;
|
||||
var frames = tex.frames;
|
||||
if (frames === 1) return undefined;
|
||||
var yslice = 1 / frames;
|
||||
for (var f = 0; f < frames; f++) {
|
||||
var frame = {};
|
||||
frame.rect = {
|
||||
x: 0,
|
||||
w: 1,
|
||||
y: yslice * f,
|
||||
h: yslice,
|
||||
};
|
||||
frame.rect = [
|
||||
0,
|
||||
yslice * f,
|
||||
1,
|
||||
yslice,
|
||||
];
|
||||
frame.time = 0.05;
|
||||
anim.frames.push(frame);
|
||||
}
|
||||
|
@ -340,12 +337,12 @@ SpriteAnim.aseprite = function (path) {
|
|||
var ase_make_frame = function (ase_frame) {
|
||||
var f = ase_frame.frame;
|
||||
var frame = {};
|
||||
frame.rect = {
|
||||
x: f.x / dim.w,
|
||||
w: f.w / dim.w,
|
||||
y: f.y / dim.h,
|
||||
h: f.h / dim.h,
|
||||
};
|
||||
frame.rect = [
|
||||
f.x / dim.w,
|
||||
f.y / dim.h,
|
||||
f.w / dim.w,
|
||||
f.h / dim.h,
|
||||
];
|
||||
frame.time = ase_frame.duration / 1000;
|
||||
anim.frames.push(frame);
|
||||
};
|
||||
|
|
|
@ -21,7 +21,6 @@ mum.base = {
|
|||
font_size: 16,
|
||||
scale: 1,
|
||||
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
|
||||
background_image: null,
|
||||
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],
|
||||
debug: false /* set to true to draw debug boxes */,
|
||||
hide: false,
|
||||
child_gap: 0,
|
||||
child_layout: 'top2bottom', /* top2bottom, left2right */
|
||||
tooltip: null,
|
||||
children: [],
|
||||
};
|
||||
|
||||
// data is passed into each function, and various stats are generated
|
||||
|
@ -64,9 +66,46 @@ var context = mum.base;
|
|||
var context_stack = [];
|
||||
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) {
|
||||
context_stack.push(context);
|
||||
data.__proto__ = mum.base;
|
||||
data.children = [];
|
||||
var container_context = {
|
||||
pos:cursor.slice(),
|
||||
size:[0,0],
|
||||
|
@ -194,8 +233,9 @@ mum.label = function (str, data = {}) {
|
|||
mum.image = function (path, data = {}) {
|
||||
if (pre(data)) return;
|
||||
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.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]));
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
mum.rectangle = function (data = {}) {
|
||||
mum.rectangle = function (data = {}, cb) {
|
||||
if (pre(data)) return;
|
||||
var aa = [0, 0].sub(data.anchor);
|
||||
data.drawpos = data.drawpos.add(aa.scale([data.width, data.height]));
|
||||
|
|
|
@ -101,6 +101,7 @@ function update_emitters(dt) {
|
|||
|
||||
var arr = [];
|
||||
function draw_emitters() {
|
||||
return;
|
||||
ssbo ??= render.make_textssbo();
|
||||
render.use_shader("shaders/baseparticle.cg");
|
||||
var buckets = {};
|
||||
|
|
|
@ -61,7 +61,7 @@ game.engine_start = function (s) {
|
|||
function () {
|
||||
global.mixin("scripts/sound.js");
|
||||
world_start();
|
||||
window.set_icon(game.texture("moon"));
|
||||
window.set_icon(game.texture("moon").texture);
|
||||
Object.readonly(window.__proto__, "vsync");
|
||||
Object.readonly(window.__proto__, "enable_dragndrop");
|
||||
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) {
|
||||
if (!path) return game.texture("icons/no_tex.gif");
|
||||
path = Resources.find_image(path);
|
||||
|
@ -236,8 +295,40 @@ game.texture = function (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);
|
||||
|
||||
tex.load_gpu();
|
||||
|
||||
return game.texture.cache[path];
|
||||
};
|
||||
game.texture.cache = {};
|
||||
|
@ -246,14 +337,14 @@ game.texture.time_cache = {};
|
|||
game.texture.total_size = function()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
game.texture.total_vram = function()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
doc: "Functions for rendering modes.",
|
||||
normal: "Final render with all lighting.",
|
||||
|
@ -886,7 +929,6 @@ function img_e() {
|
|||
var e = {
|
||||
transform: os.make_transform(),
|
||||
shade: Color.white,
|
||||
rect: [0, 0, 1, 1],
|
||||
};
|
||||
img_cache.push(e);
|
||||
return e;
|
||||
|
@ -954,7 +996,9 @@ render.invertmask = function()
|
|||
|
||||
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);
|
||||
render.use_shader('shaders/sprite.cg', pipe);
|
||||
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);
|
||||
set_model(t);
|
||||
render.use_mat({
|
||||
diffuse:tex,
|
||||
rect: [0,0,1,1],
|
||||
diffuse:tex.texture,
|
||||
rect: tex.rect,
|
||||
shade: Color.white
|
||||
});
|
||||
render.draw(shape.quad);
|
||||
}
|
||||
|
||||
render.image = function image(tex, pos, scale, rotation = 0, color = Color.white) {
|
||||
if (typeof tex === "string")
|
||||
tex = game.texture(tex);
|
||||
render.image = function image(image, pos, scale, rotation = 0, color = Color.white) {
|
||||
if (typeof image === "string")
|
||||
image = game.texture(image);
|
||||
|
||||
var tex = image.texture;
|
||||
|
||||
if (scale)
|
||||
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();
|
||||
e.transform.trs(pos, undefined, scale);
|
||||
e.image = image;
|
||||
e.shade = color;
|
||||
e.texture = tex;
|
||||
|
||||
return;
|
||||
var bb = {};
|
||||
|
|
|
@ -273,7 +273,7 @@ Cmdline.register_order(
|
|||
if (io.exists("game.js")) global.app = actor.spawn("game.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");
|
||||
});
|
||||
},
|
||||
|
|
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);
|
||||
|
||||
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;
|
||||
|
||||
if (t) {
|
||||
|
@ -1185,7 +1186,7 @@ JSC_CCALL(render_make_sprite_ssbo,
|
|||
}
|
||||
|
||||
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"));
|
||||
|
||||
if (t)
|
||||
|
@ -3274,6 +3275,10 @@ JSC_SCALL(os_make_texture,
|
|||
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
|
||||
)
|
||||
|
||||
JSC_SCALL(os_make_aseprite,
|
||||
|
||||
)
|
||||
|
||||
JSC_SCALL(os_texture_swap,
|
||||
texture *old = js2texture(argv[1]);
|
||||
texture *tex = texture_from_file(str);
|
||||
|
@ -3510,8 +3515,9 @@ JSC_CCALL(os_rectpack,
|
|||
stbrp_init_target(ctx, width, height, nodes, width);
|
||||
int packed = stbrp_pack_rects(ctx, rects, num);
|
||||
|
||||
if (!packed)
|
||||
if (!packed) {
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
ret = JS_NewArray(js);
|
||||
for (int i = 0; i < num; i++) {
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
#include "qoi.h"
|
||||
|
||||
#define CUTE_ASEPRITE_IMPLEMENTATION
|
||||
#include "cute_aseprite.h"
|
||||
|
||||
#ifndef NSVG
|
||||
#include "nanosvgrast.h"
|
||||
#endif
|
||||
|
@ -178,7 +181,31 @@ struct texture *texture_from_file(const char *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;
|
||||
data = qoi_decode(raw, rawlen, &qoi, 4);
|
||||
tex->width = qoi.width;
|
||||
|
@ -221,8 +248,6 @@ struct texture *texture_from_file(const char *path) {
|
|||
|
||||
tex->data = data;
|
||||
|
||||
texture_load_gpu(tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
|
@ -232,9 +257,9 @@ void texture_free(texture *tex)
|
|||
if (tex->data)
|
||||
free(tex->data);
|
||||
if (tex->delays) arrfree(tex->delays);
|
||||
sg_destroy_image(tex->id);
|
||||
if (tex->simgui.id)
|
||||
simgui_destroy_image(tex->simgui);
|
||||
|
||||
free(tex);
|
||||
}
|
||||
|
||||
|
@ -510,9 +535,9 @@ void texture_load_gpu(texture *tex)
|
|||
.num_mipmaps = 1,
|
||||
.data = img_data
|
||||
});
|
||||
} else {
|
||||
} //else {
|
||||
// Simple update
|
||||
sg_image_data img_data = tex_img_data(tex,0);
|
||||
sg_update_image(tex->id, &img_data);
|
||||
}
|
||||
// sg_image_data img_data = tex_img_data(tex,0);
|
||||
// sg_update_image(tex->id, &img_data);
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "HandmadeMath.h"
|
||||
#include "render.h"
|
||||
|
||||
#include "stb_rect_pack.h";
|
||||
|
||||
#include "sokol_app.h"
|
||||
#include "sokol/util/sokol_imgui.h"
|
||||
|
||||
|
|
Loading…
Reference in a new issue