add aseprite support
This commit is contained in:
parent
12bb5e084a
commit
27d7c5ab02
|
@ -88,10 +88,10 @@ game.engine_start = function (s) {
|
|||
1, 1, 0], 0),
|
||||
verts: 4,
|
||||
uv: os.make_buffer([
|
||||
0, 0,
|
||||
0, 1,
|
||||
1, 0,
|
||||
1, 1], 2),
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 0], 2),
|
||||
index: os.make_buffer([0, 1, 2, 2, 1, 3], 1),
|
||||
count: 6,
|
||||
};
|
||||
|
@ -112,10 +112,10 @@ game.engine_start = function (s) {
|
|||
0.5, 0.5, -0.5], 0),
|
||||
verts: 4,
|
||||
uv: os.make_buffer([
|
||||
0, 0,
|
||||
0, 1,
|
||||
1, 0,
|
||||
1, 1], 2),
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 0], 2),
|
||||
index: os.make_buffer([0, 1, 2, 2, 1, 3], 1),
|
||||
count: 6,
|
||||
};
|
||||
|
@ -255,7 +255,9 @@ function pack_into_sheet(images)
|
|||
|
||||
game.texture = function (path) {
|
||||
if (!path) return game.texture("icons/no_tex.gif");
|
||||
path = Resources.find_image(path);
|
||||
|
||||
var parts = path.split(':');
|
||||
path = Resources.find_image(parts[0]);
|
||||
|
||||
if (!io.exists(path)) {
|
||||
console.error(`Missing texture: ${path}`);
|
||||
|
@ -263,12 +265,38 @@ game.texture = function (path) {
|
|||
game.texture.time_cache[path] = io.mod(path);
|
||||
return game.texture.cache[path];
|
||||
}
|
||||
if (game.texture.cache[path]) return game.texture.cache[path];
|
||||
var tex = os.make_texture(path);
|
||||
|
||||
var cachestr = path;
|
||||
if (parts[1])
|
||||
cachestr += parts[1];
|
||||
|
||||
var frame;
|
||||
var anim_str;
|
||||
if (parts.length > 1) {
|
||||
// it's an animation
|
||||
path = parts[0];
|
||||
parts = parts[1].split('_'); // For a gif, it might be 'water.gif:3', but for an ase it might be 'water.ase:run_3', meaning the third frame of the 'run' animation
|
||||
if (parts.length === 1)
|
||||
frame = Number(parts[0]);
|
||||
else {
|
||||
anim_str = parts[0];
|
||||
frame = Number(parts[1]);
|
||||
}
|
||||
} else
|
||||
parts = undefined;
|
||||
|
||||
if (game.texture.cache[cachestr]) return game.texture.cache[path];
|
||||
|
||||
var tex = os.make_texture(path.split(':')[0]);
|
||||
if (!tex) return;
|
||||
|
||||
var image;
|
||||
|
||||
var anim = SpriteAnim.make(path, tex);
|
||||
var ext = path.ext();
|
||||
var anim;
|
||||
if (ext === 'ase' || ext === 'aseprite') {
|
||||
anim = os.make_aseprite(path);
|
||||
}
|
||||
if (!anim) {
|
||||
image = {
|
||||
texture: tex,
|
||||
|
@ -293,12 +321,12 @@ game.texture = function (path) {
|
|||
tex = spritesheet;
|
||||
}
|
||||
|
||||
game.texture.cache[path] = image;
|
||||
game.texture.cache[cachestr] = image;
|
||||
game.texture.time_cache[path] = io.mod(path);
|
||||
|
||||
tex.load_gpu();
|
||||
|
||||
return game.texture.cache[path];
|
||||
return game.texture.cache[cachestr];
|
||||
};
|
||||
game.texture.cache = {};
|
||||
game.texture.time_cache = {};
|
||||
|
|
|
@ -1012,7 +1012,9 @@ render.image = function image(image, rect = [0,0], rotation = 0, color = Color.w
|
|||
var tex = image.texture;
|
||||
if (!tex) return;
|
||||
|
||||
var size = [rect.width ? rect.width : tex.width, rect.height ? rect.height : tex.height];
|
||||
var image_size = [image.rect.width*tex.width, image.rect.height*tex.height];
|
||||
|
||||
var size = [rect.width ? rect.width : image_size.x, rect.height ? rect.height : image_size.y];
|
||||
|
||||
if (!lasttex) {
|
||||
check_flush(flush_img);
|
||||
|
@ -1026,7 +1028,7 @@ render.image = function image(image, rect = [0,0], rotation = 0, color = Color.w
|
|||
|
||||
var e = img_e();
|
||||
var pos = [rect.x,rect.y].sub(size.scale([rect.anchor_x, rect.anchor_y]));
|
||||
e.transform.trs(pos, undefined, size.div([tex.width,tex.height]));
|
||||
e.transform.trs(pos, undefined, size.div(image_size));
|
||||
e.image = image;
|
||||
e.shade = color;
|
||||
|
||||
|
|
|
@ -7,8 +7,12 @@
|
|||
#include "sokol/sokol_args.h"
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include "sokol/sokol_app.h"
|
||||
#include "sokol/sokol_fetch.h"
|
||||
#include "sokol/util/sokol_gl.h"
|
||||
|
||||
#define CUTE_ASEPRITE_IMPLEMENTATION
|
||||
#include "cute_aseprite.h"
|
||||
|
||||
#define LAY_FLOAT 1
|
||||
#define LAY_IMPLEMENTATION
|
||||
#include "layout.h"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "datastream.h"
|
||||
#include "sound.h"
|
||||
#include "stb_ds.h"
|
||||
#include "stb_image.h"
|
||||
#include "stb_rect_pack.h"
|
||||
#include "string.h"
|
||||
#include "window.h"
|
||||
|
@ -40,6 +41,8 @@
|
|||
#include "gui.h"
|
||||
#include "timer.h"
|
||||
|
||||
#include "cute_aseprite.h"
|
||||
|
||||
#define LAY_FLOAT 1
|
||||
#include "layout.h"
|
||||
|
||||
|
@ -627,8 +630,8 @@ JSValue rect2js(struct rect rect) {
|
|||
JSValue obj = JS_NewObject(js);
|
||||
js_setprop_str(obj, "x", number2js(rect.x));
|
||||
js_setprop_str(obj, "y", number2js(rect.y));
|
||||
js_setprop_str(obj, "w", number2js(rect.w));
|
||||
js_setprop_str(obj, "h", number2js(rect.h));
|
||||
js_setprop_str(obj, "width", number2js(rect.w));
|
||||
js_setprop_str(obj, "height", number2js(rect.h));
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -2758,8 +2761,6 @@ static const JSCFunctionListEntry js_datastream_funcs[] = {
|
|||
|
||||
JSC_GET(texture, width, number)
|
||||
JSC_GET(texture, height, number)
|
||||
JSC_GET(texture, frames, number)
|
||||
JSC_GET(texture, delays, ints)
|
||||
JSC_GET(texture, vram, number)
|
||||
|
||||
JSC_SCALL(texture_save, texture_save(js2texture(self), str));
|
||||
|
@ -2811,8 +2812,6 @@ JSC_CCALL(texture_offload,
|
|||
static const JSCFunctionListEntry js_texture_funcs[] = {
|
||||
MIST_GET(texture, width),
|
||||
MIST_GET(texture, height),
|
||||
MIST_GET(texture, frames),
|
||||
MIST_GET(texture, delays),
|
||||
MIST_GET(texture, vram),
|
||||
MIST_FUNC_DEF(texture, save, 1),
|
||||
MIST_FUNC_DEF(texture, write_pixel, 2),
|
||||
|
@ -3377,12 +3376,101 @@ JSC_SCALL(os_make_texture,
|
|||
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
|
||||
)
|
||||
|
||||
JSC_SCALL(os_make_pcm,
|
||||
ret = pcm2js(make_pcm(str));
|
||||
JSC_SCALL(os_make_gif,
|
||||
size_t rawlen;
|
||||
unsigned char *raw = slurp_file(str, &rawlen);
|
||||
if (!raw) goto ENDEND;
|
||||
int n;
|
||||
texture *tex = calloc(1,sizeof(*tex));
|
||||
int frames;
|
||||
int *delays;
|
||||
tex->data = stbi_load_gif_from_memory(raw, rawlen, &delays, &tex->width, &tex->height, &frames, &n, 4);
|
||||
|
||||
JSValue gif = JS_NewObject(js);
|
||||
js_setpropstr(gif, "texture", texture2js(tex));
|
||||
|
||||
JSValue delay_arr = JS_NewArray(js);
|
||||
float yslice = 1.0/frames;
|
||||
for (int i = 0; i < frames; i++) {
|
||||
JSValue frame = JS_NewObject(js);
|
||||
js_setpropstr(frame, "time", number2js((float)delays[i]/1000.0));
|
||||
js_setpropstr(frame, "rect", rect2js((rect){
|
||||
.x = 0,
|
||||
.y = yslice*i,
|
||||
.w = 1,
|
||||
.h = yslice
|
||||
}));
|
||||
js_setprop_num(delay_arr, i, frame);
|
||||
}
|
||||
|
||||
js_setpropstr(gif, "delays", delay_arr);
|
||||
|
||||
free(delays);
|
||||
|
||||
ret = gif;
|
||||
|
||||
END:
|
||||
free(raw);
|
||||
|
||||
ENDEND:
|
||||
)
|
||||
|
||||
JSC_SCALL(os_make_aseprite,
|
||||
size_t rawlen;
|
||||
unsigned char *raw = slurp_file(str, &rawlen);
|
||||
ase_t *ase = cute_aseprite_load_from_memory(raw, rawlen, NULL);
|
||||
|
||||
JSValue obj = JS_NewObject(js);
|
||||
|
||||
int w = ase->w;
|
||||
int h = ase->h;
|
||||
|
||||
int pixels = w*h;
|
||||
|
||||
for (int t = 0; t < ase->tag_count; t++) {
|
||||
ase_tag_t tag = ase->tags[t];
|
||||
JSValue anim = JS_NewObject(js);
|
||||
js_setpropstr(anim, "repeat", number2js(tag.repeat));
|
||||
switch(tag.loop_animation_direction) {
|
||||
case ASE_ANIMATION_DIRECTION_FORWARDS:
|
||||
js_setpropstr(anim, "loop", str2js("forward"));
|
||||
break;
|
||||
case ASE_ANIMATION_DIRECTION_BACKWORDS:
|
||||
js_setpropstr(anim, "loop", str2js("backward"));
|
||||
break;
|
||||
case ASE_ANIMATION_DIRECTION_PINGPONG:
|
||||
js_setpropstr(anim, "loop", str2js("pingpong"));
|
||||
break;
|
||||
}
|
||||
|
||||
int _frame = 0;
|
||||
JSValue frames = JS_NewArray(js);
|
||||
for (int f = tag.from_frame; f <= tag.to_frame; f++) {
|
||||
ase_frame_t aframe = ase->frames[f];
|
||||
JSValue frame = JS_NewObject(js);
|
||||
|
||||
texture *tex = calloc(1,sizeof(*tex));
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->data = malloc(w*h*4);
|
||||
memcpy(tex->data, aframe.pixels, w*h*4);
|
||||
js_setpropstr(frame, "texture", texture2js(tex));
|
||||
js_setpropstr(frame, "rect", rect2js((rect){.x=0,.y=0,.w=1,.h=1}));
|
||||
js_setpropstr(frame, "time", number2js((float)aframe.duration_milliseconds/1000.0));
|
||||
js_setprop_num(frames, _frame, frame);
|
||||
_frame++;
|
||||
}
|
||||
js_setpropstr(anim, "frames", frames);
|
||||
js_setpropstr(obj, tag.name, anim);
|
||||
}
|
||||
|
||||
ret = obj;
|
||||
|
||||
cute_aseprite_free(ase);
|
||||
)
|
||||
|
||||
JSC_SCALL(os_make_pcm,
|
||||
ret = pcm2js(make_pcm(str));
|
||||
)
|
||||
|
||||
JSC_SCALL(os_texture_swap,
|
||||
|
@ -3678,6 +3766,8 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||
MIST_FUNC_DEF(os, make_poly2d, 2),
|
||||
MIST_FUNC_DEF(os, make_seg2d, 1),
|
||||
MIST_FUNC_DEF(os, make_texture, 1),
|
||||
MIST_FUNC_DEF(os, make_gif, 1),
|
||||
MIST_FUNC_DEF(os, make_aseprite, 1),
|
||||
MIST_FUNC_DEF(os, make_pcm, 1),
|
||||
MIST_FUNC_DEF(os, texture_swap, 2),
|
||||
MIST_FUNC_DEF(os, make_tex_data, 3),
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
#include <ftw.h>
|
||||
#endif
|
||||
|
||||
#define SOKOL_FETCH_IMPL
|
||||
#include "sokol/sokol_fetch.h"
|
||||
|
||||
#include "stb_ds.h"
|
||||
|
||||
#include "core.cdb.h"
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
|
||||
#include "qoi.h"
|
||||
|
||||
#define CUTE_ASEPRITE_IMPLEMENTATION
|
||||
#include "cute_aseprite.h"
|
||||
|
||||
#ifndef NSVG
|
||||
#include "nanosvgrast.h"
|
||||
#endif
|
||||
|
@ -175,50 +172,16 @@ struct texture *texture_from_file(const char *path) {
|
|||
|
||||
struct texture *tex = calloc(1, sizeof(*tex));
|
||||
|
||||
stbi_set_flip_vertically_on_load(1);
|
||||
|
||||
int n;
|
||||
|
||||
char *ext = strrchr(path, '.');
|
||||
|
||||
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")) {
|
||||
if (!strcmp(ext, ".qoi")) {
|
||||
qoi_desc qoi;
|
||||
data = qoi_decode(raw, rawlen, &qoi, 4);
|
||||
tex->width = qoi.width;
|
||||
tex->height = qoi.height;
|
||||
n = qoi.channels;
|
||||
} else if (!strcmp(ext, ".gif")) {
|
||||
data = stbi_load_gif_from_memory(raw, rawlen, &tex->delays, &tex->width, &tex->height, &tex->frames, &n, 4);
|
||||
int *dd = tex->delays;
|
||||
tex->delays = NULL;
|
||||
arrsetlen(tex->delays, tex->frames);
|
||||
for (int i = 0; i < tex->frames; i++) tex->delays[i] = dd[i];
|
||||
free(dd);
|
||||
tex->height *= tex->frames;
|
||||
} else if (!strcmp(ext, ".svg")) {
|
||||
#ifndef NSVG
|
||||
NSVGimage *svg = nsvgParse(raw, "px", 96);
|
||||
|
@ -256,7 +219,6 @@ void texture_free(texture *tex)
|
|||
if (!tex) return;
|
||||
if (tex->data)
|
||||
free(tex->data);
|
||||
if (tex->delays) arrfree(tex->delays);
|
||||
if (tex->simgui.id)
|
||||
simgui_destroy_image(tex->simgui);
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@ struct texture {
|
|||
int height;
|
||||
HMM_Vec3 dimensions;
|
||||
unsigned char *data;
|
||||
int frames;
|
||||
int *delays;
|
||||
int vram;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue