add many source files
This commit is contained in:
287
graphics.c
Normal file
287
graphics.c
Normal file
@@ -0,0 +1,287 @@
|
||||
#include "cell.h"
|
||||
#include "jsffi.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include "datastream.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_FAILURE_USERMSG
|
||||
#define STBI_NO_STDIO
|
||||
#include "stb_image.h"
|
||||
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#include "stb_rect_pack.h"
|
||||
|
||||
#define CUTE_ASEPRITE_IMPLEMENTATION
|
||||
#include "cute_aseprite.h"
|
||||
|
||||
// input: (encoded image data of jpg, png, bmp, tiff)
|
||||
JSC_CCALL(os_image_decode,
|
||||
size_t len;
|
||||
void *raw = js_get_blob_data(js, &len, argv[0]);
|
||||
if (!raw) return JS_ThrowReferenceError(js, "could not load texture with array buffer");
|
||||
|
||||
int n, width, height;
|
||||
void *data = stbi_load_from_memory(raw, len, &width, &height, &n, 4);
|
||||
|
||||
if (!data)
|
||||
return JS_ThrowReferenceError(js, "no known image type from pixel data: %s", stbi_failure_reason());
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
free(data);
|
||||
return JS_ThrowReferenceError(js, "decoded image has invalid size: %dx%d", width, height);
|
||||
}
|
||||
|
||||
int pitch = width*4;
|
||||
size_t pixels_size = pitch * height;
|
||||
|
||||
// Create JS object with surface data
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "width", JS_NewInt32(js, width));
|
||||
JS_SetPropertyStr(js, obj, "height", JS_NewInt32(js, height));
|
||||
JS_SetPropertyStr(js, obj, "format", JS_NewString(js, "rgba32"));
|
||||
JS_SetPropertyStr(js, obj, "pitch", JS_NewInt32(js, pitch));
|
||||
JS_SetPropertyStr(js, obj, "pixels", js_new_blob_stoned_copy(js, data, pixels_size));
|
||||
JS_SetPropertyStr(js, obj, "depth", JS_NewInt32(js, 8));
|
||||
JS_SetPropertyStr(js, obj, "hdr", JS_NewBool(js,0));
|
||||
|
||||
free(data);
|
||||
ret = obj;
|
||||
)
|
||||
|
||||
JSC_CCALL(graphics_hsl_to_rgb,
|
||||
float h, s, l;
|
||||
JS_ToFloat64(js, &h, argv[0]);
|
||||
JS_ToFloat64(js, &s, argv[1]);
|
||||
JS_ToFloat64(js, &l, argv[2]);
|
||||
float c = (1 - abs(2 * l - 1)) * s;
|
||||
float x = c * (1 - abs(fmod((h/60),2) - 1));
|
||||
float m = l - c / 2;
|
||||
float r = 0, g = 0, b = 0;
|
||||
|
||||
if (h < 60) { r = c; g = x; }
|
||||
else if (h < 120) { r = x; g = c; }
|
||||
else if (h < 180) { g = c; b = x; }
|
||||
else if (h < 240) { g = x; b = c; }
|
||||
else if (h < 300) { r = x; b = c; }
|
||||
else { r = c; b = x; }
|
||||
|
||||
return color2js(js, (colorf){r+m, g+m, b+m, 1});
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_line_prim,
|
||||
return JS_NULL;
|
||||
/*
|
||||
JSValue prim = JS_NewObject(js);
|
||||
HMM_Vec2 *v = js2cpvec2arr(js,argv[0]);
|
||||
|
||||
parsl_context *par_ctx = parsl_create_context((parsl_config){
|
||||
.thickness = js2number(js,argv[1]),
|
||||
.flags= PARSL_FLAG_ANNOTATIONS,
|
||||
.u_mode = js2number(js,argv[2])
|
||||
});
|
||||
|
||||
uint16_t spine_lens[] = {arrlen(v)};
|
||||
|
||||
parsl_mesh *m = parsl_mesh_from_lines(par_ctx, (parsl_spine_list){
|
||||
.num_vertices = arrlen(v),
|
||||
.num_spines = 1,
|
||||
.vertices = v,
|
||||
.spine_lengths = spine_lens,
|
||||
.closed = JS_ToBool(js,argv[3])
|
||||
});
|
||||
|
||||
JS_SetPropertyStr(js, prim, "pos", make_gpu_buffer(js,m->positions,sizeof(*m->positions)*m->num_vertices, 0, 2,1,0));
|
||||
|
||||
JS_SetPropertyStr(js, prim, "indices", make_gpu_buffer(js,m->triangle_indices,sizeof(*m->triangle_indices)*m->num_triangles*3, JS_TYPED_ARRAY_UINT32, 1,1,1));
|
||||
|
||||
float uv[m->num_vertices*2];
|
||||
for (int i = 0; i < m->num_vertices; i++) {
|
||||
uv[i*2] = m->annotations[i].u_along_curve;
|
||||
uv[i*2+1] = m->annotations[i].v_across_curve;
|
||||
}
|
||||
|
||||
JS_SetPropertyStr(js, prim, "uv", make_gpu_buffer(js, uv, sizeof(uv), 0,2,1,0));
|
||||
JS_SetPropertyStr(js,prim,"vertices", number2js(js,m->num_vertices));
|
||||
JS_SetPropertyStr(js,prim,"num_indices", number2js(js,m->num_triangles*3));
|
||||
JS_SetPropertyStr(js,prim,"first_index", number2js(js,0));
|
||||
|
||||
parsl_destroy_context(par_ctx);
|
||||
|
||||
return prim;
|
||||
*/
|
||||
)
|
||||
|
||||
JSC_CCALL(os_rectpack,
|
||||
int width = js2number(js,argv[0]);
|
||||
int height = js2number(js,argv[1]);
|
||||
int num = JS_ArrayLength(js,argv[2]);
|
||||
stbrp_context ctx[1];
|
||||
stbrp_rect rects[num];
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
HMM_Vec2 wh = js2vec2(js,JS_GetPropertyUint32(js, argv[2], i));
|
||||
rects[i].w = wh.x;
|
||||
rects[i].h = wh.y;
|
||||
rects[i].id = i;
|
||||
}
|
||||
|
||||
stbrp_node nodes[width];
|
||||
stbrp_init_target(ctx, width, height, nodes, width);
|
||||
int packed = stbrp_pack_rects(ctx, rects, num);
|
||||
|
||||
if (!packed) {
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
ret = JS_NewArray(js);
|
||||
for (int i = 0; i < num; i++) {
|
||||
HMM_Vec2 pos;
|
||||
pos.x = rects[i].x;
|
||||
pos.y = rects[i].y;
|
||||
JS_SetPropertyUint32(js, ret, i, vec22js(js,pos));
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
// input: (gif image data)
|
||||
JSC_CCALL(os_make_gif,
|
||||
size_t rawlen;
|
||||
void *raw = js_get_blob_data(js, &rawlen, argv[0]);
|
||||
if (!raw) return JS_ThrowReferenceError(js, "could not load gif from supplied array buffer");
|
||||
|
||||
int n;
|
||||
int frames;
|
||||
int *delays;
|
||||
int width;
|
||||
int height;
|
||||
void *pixels = stbi_load_gif_from_memory(raw, rawlen, &delays, &width, &height, &frames, &n, 4);
|
||||
|
||||
if (!pixels) {
|
||||
return JS_ThrowReferenceError(js, "1decode GIF: %s", stbi_failure_reason());
|
||||
}
|
||||
|
||||
// Always return an array of surfaces, even for single frame
|
||||
JSValue surface_array = JS_NewArray(js);
|
||||
ret = surface_array;
|
||||
|
||||
for (int i = 0; i < frames; i++) {
|
||||
// Create surface data object
|
||||
JSValue surfData = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, surfData, "width", JS_NewInt32(js, width));
|
||||
JS_SetPropertyStr(js, surfData, "height", JS_NewInt32(js, height));
|
||||
JS_SetPropertyStr(js, surfData, "format", JS_NewString(js, "rgba32"));
|
||||
JS_SetPropertyStr(js, surfData, "pitch", JS_NewInt32(js, width*4));
|
||||
|
||||
void *frame_pixels = (unsigned char*)pixels+(width*height*4*i);
|
||||
JS_SetPropertyStr(js, surfData, "pixels", js_new_blob_stoned_copy(js, frame_pixels, width*height*4));
|
||||
|
||||
// Add time property for animation frames
|
||||
if (frames > 1 && delays) {
|
||||
JS_SetPropertyStr(js, surfData, "time", number2js(js,(float)delays[i]/1000.0));
|
||||
}
|
||||
|
||||
JS_SetPropertyUint32(js, surface_array, i, surfData);
|
||||
}
|
||||
|
||||
CLEANUP:
|
||||
if (delays) free(delays);
|
||||
if (pixels) free(pixels);
|
||||
)
|
||||
|
||||
JSValue aseframe2js(JSContext *js, ase_frame_t aframe)
|
||||
{
|
||||
JSValue frame = JS_NewObject(js);
|
||||
|
||||
// Create surface data object instead of SDL_Surface
|
||||
JSValue surfData = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, surfData, "width", JS_NewInt32(js, aframe.ase->w));
|
||||
JS_SetPropertyStr(js, surfData, "height", JS_NewInt32(js, aframe.ase->h));
|
||||
JS_SetPropertyStr(js, surfData, "format", JS_NewString(js, "rgba32"));
|
||||
JS_SetPropertyStr(js, surfData, "pitch", JS_NewInt32(js, aframe.ase->w*4));
|
||||
JS_SetPropertyStr(js, surfData, "pixels", js_new_blob_stoned_copy(js, aframe.pixels, aframe.ase->w*aframe.ase->h*4));
|
||||
|
||||
JS_SetPropertyStr(js, frame, "surface", surfData);
|
||||
JS_SetPropertyStr(js, frame, "time", number2js(js,(float)aframe.duration_milliseconds/1000.0));
|
||||
return frame;
|
||||
}
|
||||
|
||||
// input: (aseprite data)
|
||||
JSC_CCALL(os_make_aseprite,
|
||||
size_t rawlen;
|
||||
void *raw = js_get_blob_data(js,&rawlen,argv[0]);
|
||||
|
||||
ase_t *ase = cute_aseprite_load_from_memory(raw, rawlen, NULL);
|
||||
|
||||
if (!ase)
|
||||
return JS_ThrowReferenceError(js, "could not load aseprite from supplied array buffer: %s", aseprite_GetError());
|
||||
|
||||
if (ase->tag_count == 0) {
|
||||
// we're dealing with a single frame image, or single animation
|
||||
if (ase->frame_count == 1) {
|
||||
JSValue obj = aseframe2js(js,ase->frames[0]);
|
||||
cute_aseprite_free(ase);
|
||||
return obj;
|
||||
} else {
|
||||
// Multiple frames but no tags - create a simple animation
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JSValue frames = JS_NewArray(js);
|
||||
for (int f = 0; f < ase->frame_count; f++) {
|
||||
JSValue frame = aseframe2js(js,ase->frames[f]);
|
||||
JS_SetPropertyUint32(js, frames, f, frame);
|
||||
}
|
||||
JS_SetPropertyStr(js, obj, "frames", frames);
|
||||
JS_SetPropertyStr(js, obj, "loop", JS_NewBool(js, true));
|
||||
ret = obj;
|
||||
cute_aseprite_free(ase);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
JSValue obj = JS_NewObject(js);
|
||||
|
||||
for (int t = 0; t < ase->tag_count; t++) {
|
||||
ase_tag_t tag = ase->tags[t];
|
||||
JSValue anim = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, anim, "repeat", number2js(js,tag.repeat));
|
||||
switch(tag.loop_animation_direction) {
|
||||
case ASE_ANIMATION_DIRECTION_FORWARDS:
|
||||
JS_SetPropertyStr(js, anim, "loop", JS_NewString(js,"forward"));
|
||||
break;
|
||||
case ASE_ANIMATION_DIRECTION_BACKWORDS:
|
||||
JS_SetPropertyStr(js, anim, "loop", JS_NewString(js,"backward"));
|
||||
break;
|
||||
case ASE_ANIMATION_DIRECTION_PINGPONG:
|
||||
JS_SetPropertyStr(js, anim, "loop", JS_NewString(js,"pingpong"));
|
||||
break;
|
||||
}
|
||||
|
||||
int _frame = 0;
|
||||
JSValue frames = JS_NewArray(js);
|
||||
for (int f = tag.from_frame; f <= tag.to_frame; f++) {
|
||||
JSValue frame = aseframe2js(js,ase->frames[f]);
|
||||
JS_SetPropertyUint32(js, frames, _frame, frame);
|
||||
_frame++;
|
||||
}
|
||||
JS_SetPropertyStr(js, anim, "frames", frames);
|
||||
JS_SetPropertyStr(js, obj, tag.name, anim);
|
||||
}
|
||||
|
||||
ret = obj;
|
||||
|
||||
cute_aseprite_free(ase);
|
||||
)
|
||||
|
||||
const JSCFunctionListEntry js_graphics_funcs[] = {
|
||||
MIST_FUNC_DEF(os, rectpack, 3),
|
||||
MIST_FUNC_DEF(os, image_decode, 1),
|
||||
MIST_FUNC_DEF(os, make_gif, 1),
|
||||
MIST_FUNC_DEF(os, make_aseprite, 1),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 5),
|
||||
MIST_FUNC_DEF(graphics, hsl_to_rgb, 3),
|
||||
};
|
||||
|
||||
JSValue js_graphics_use(JSContext *js) {
|
||||
JSValue mod = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js,mod,js_graphics_funcs,countof(js_graphics_funcs));
|
||||
return mod;
|
||||
}
|
||||
Reference in New Issue
Block a user