fix qr decoding
This commit is contained in:
@@ -1,12 +1,3 @@
|
||||
/* Sprite façade (JS) ↔ struct sprite (C)
|
||||
* The C side exposes per-field getters/setters plus
|
||||
* `set_affine(m)` which (re)calculates the 2×2 matrix from
|
||||
* scale / skew / rotation.
|
||||
* We mirror every exposed field and make sure the C
|
||||
* matrix is refreshed whenever one of the three factors
|
||||
* changes.
|
||||
*/
|
||||
|
||||
var sprite = {}
|
||||
|
||||
var graphics = use('graphics')
|
||||
@@ -20,6 +11,7 @@ var SCALE = Symbol()
|
||||
var SKEW = Symbol()
|
||||
var CENTER = Symbol()
|
||||
var COLOR = Symbol()
|
||||
var IMAGE = Symbol()
|
||||
|
||||
var ursprite = {
|
||||
get pos() { return this[POS] },
|
||||
@@ -45,7 +37,7 @@ var ursprite = {
|
||||
set scale(v){
|
||||
this[SCALE] = v
|
||||
this[SPRITE].scale = v
|
||||
this[SPRITE].set_affine()
|
||||
this[SPRITE].set_affine()
|
||||
},
|
||||
|
||||
get skew() { return this[SKEW] },
|
||||
@@ -64,36 +56,35 @@ var ursprite = {
|
||||
this[SPRITE].color = v
|
||||
},
|
||||
|
||||
move(mv){
|
||||
this.pos = {x:this.pos.x+mv.x, y:this.pos.y+mv.y}
|
||||
},
|
||||
move(mv) { this[SPRITE].move(mv) },
|
||||
moveto(p){
|
||||
this.pos = p
|
||||
},
|
||||
|
||||
get image() { return this[IMAGE] },
|
||||
set image(img) {
|
||||
this[IMAGE] = img
|
||||
this[SPRITE].set_image(img)
|
||||
}
|
||||
}
|
||||
|
||||
var _sprites = []
|
||||
|
||||
sprite.create = function(image, pos, anchor=[0,0], layer=0, props={}) {
|
||||
var sp = Object.create(ursprite)
|
||||
var raw = graphics.make_sprite()
|
||||
var def_sprite = Object.freeze({
|
||||
pos: [0,0],
|
||||
rotation: 0,
|
||||
scale: [1,1],
|
||||
center: [0,0],
|
||||
color: [1,1,1,1],
|
||||
skew: [0,0],
|
||||
layer: 0,
|
||||
})
|
||||
|
||||
sp[SPRITE] = raw
|
||||
|
||||
sp.pos = pos
|
||||
sp.rotation = 0
|
||||
sp.scale = [1,1]
|
||||
sp.skew = [0,0]
|
||||
sp.center = anchor
|
||||
sp.color = [1,1,1,1]
|
||||
|
||||
var tex = graphics.texture(image)
|
||||
raw.set_image(tex)
|
||||
sp.image = tex
|
||||
|
||||
sp.layer = layer
|
||||
sp.props = props
|
||||
sp.anchor = anchor
|
||||
sprite.create = function(image, info) {
|
||||
info.__proto__ = def_sprite
|
||||
var sp = Object.create(ursprite)
|
||||
sp[SPRITE] = graphics.make_sprite(info)
|
||||
sp.image = graphics.texture(image)
|
||||
|
||||
_sprites.push(sp)
|
||||
return sp
|
||||
@@ -102,6 +93,14 @@ sprite.create = function(image, pos, anchor=[0,0], layer=0, props={}) {
|
||||
sprite.forEach = fn => { for (let s of _sprites) fn(s) }
|
||||
sprite.values = () => _sprites.slice()
|
||||
sprite.geometry= () => graphics.make_sprite_mesh(_sprites)
|
||||
sprite.queue = () => graphics.make_sprite_queue(_sprites)
|
||||
|
||||
var raws = []
|
||||
sprite.queue = function() {
|
||||
if (raws.length != _sprites.length)
|
||||
raws.length = _sprites.length
|
||||
|
||||
for (var i = 0; i < _sprites.length; i++) raws[i] = _sprites[i]
|
||||
return graphics.make_sprite_queue(_sprites.map(x => x[SPRITE]))
|
||||
}
|
||||
|
||||
return sprite
|
||||
|
||||
@@ -53,8 +53,8 @@ var current_color = Color.white
|
||||
|
||||
render.image = function(image, rect, rotation, anchor, shear, info)
|
||||
{
|
||||
rect.width = image.rect_px.width;
|
||||
rect.height = image.rect_px.height;
|
||||
// rect.width = image.rect_px.width;
|
||||
// rect.height = image.rect_px.height;
|
||||
context.texture(image.texture, image.rect_px, rect, rotation, anchor);
|
||||
}
|
||||
|
||||
|
||||
272
source/jsffi.c
272
source/jsffi.c
@@ -3147,8 +3147,10 @@ JSC_CCALL(renderer_sprite,
|
||||
sprite sp = js_getsprite(js, argv[0]);
|
||||
SDL_Texture *tex;
|
||||
JS_GETATOM(js, tex, sp.image, texture, SDL_Texture);
|
||||
rect uv;
|
||||
JS_GETATOM(js, uv, sp.image, rect, rect);
|
||||
|
||||
float w = sp.uv.w, h = sp.uv.h;
|
||||
float w = uv.w, h = uv.h;
|
||||
|
||||
HMM_Vec2 tl_local = { -sp.center.X, -sp.center.Y };
|
||||
HMM_Vec2 tr_local = { -sp.center.X + w, -sp.center.Y };
|
||||
@@ -3162,7 +3164,7 @@ JSC_CCALL(renderer_sprite,
|
||||
SDL_FPoint right = renderer_world_to_screen(ctx, world_tr);
|
||||
SDL_FPoint down = renderer_world_to_screen(ctx, world_bl);
|
||||
|
||||
if (!SDL_RenderTextureAffine(ctx->sdl, tex, &sp.uv, &origin, &right, &down))
|
||||
if (!SDL_RenderTextureAffine(ctx->sdl, tex, &uv, &origin, &right, &down))
|
||||
return JS_ThrowInternalError(js, "Render sprite error: %s", SDL_GetError());
|
||||
)
|
||||
|
||||
@@ -4146,6 +4148,9 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
JS_DupValue(js,sprites[i].image);
|
||||
} else {
|
||||
quads = js_arrlen(js, argv[0]);
|
||||
if (quads == 0)
|
||||
return JS_ThrowReferenceError(js, "Expected an array of sprites with length > 0.");
|
||||
|
||||
arrsetcap(sprites, quads);
|
||||
|
||||
for (int i = 0; i < quads; i++) {
|
||||
@@ -4161,10 +4166,10 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
JS_GETATOM(js, sp.center, sub, center, vec2)
|
||||
JS_GETATOM(js, sp.skew, sub, skew, vec2)
|
||||
JS_GETATOM(js, sp.scale, sub, scale, vec2)
|
||||
JS_GETATOM(js,sp.color,sub,color,color)
|
||||
JS_GETATOM(js,sp.layer,sub,layer,number)
|
||||
JS_GETATOM(js,sp.uv,sub,src,rect)
|
||||
JS_GETATOM(js, sp.color,sub,color,color)
|
||||
JS_GETATOM(js, sp.layer,sub,layer,number)
|
||||
sp.image = JS_GetProperty(js,sub,image);
|
||||
sprite_apply(&sp);
|
||||
arrput(sprites,sp);
|
||||
}
|
||||
JS_FreeValue(js, sub);
|
||||
@@ -4174,28 +4179,50 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
qsort(sprites, quads, sizeof(sprite), sort_sprite);
|
||||
|
||||
struct quad_buffers buffers = quad_buffers_new(quads*4);
|
||||
|
||||
const HMM_Vec2 local[4] = { {0,0}, {1,0}, {0,1}, {1,1} };
|
||||
|
||||
rect uv;
|
||||
rect uv_px;
|
||||
JSValue cur_img = JS_UNDEFINED;
|
||||
|
||||
for (int i = 0; i < quads; i++) {
|
||||
rect pr = {0};
|
||||
rect uv = sprites[i].uv;
|
||||
HMM_Vec4 c = sprites[i].color;
|
||||
|
||||
int idx = i * 4;
|
||||
|
||||
buffers.pos[idx + 0] = (HMM_Vec2){ pr.x, pr.y };
|
||||
buffers.pos[idx + 1] = (HMM_Vec2){ pr.x+pr.w, pr.y };
|
||||
buffers.pos[idx + 2] = (HMM_Vec2){ pr.x, pr.y+pr.h };
|
||||
buffers.pos[idx + 3] = (HMM_Vec2){ pr.x+pr.w, pr.y+pr.h };
|
||||
|
||||
buffers.uv[idx + 0] = (HMM_Vec2){ uv.x, uv.y+uv.h };
|
||||
buffers.uv[idx + 1] = (HMM_Vec2){ uv.x+uv.w, uv.y+uv.h };
|
||||
buffers.uv[idx + 2] = (HMM_Vec2){ uv.x, uv.y };
|
||||
buffers.uv[idx + 3] = (HMM_Vec2){ uv.x+uv.w, uv.y };
|
||||
|
||||
buffers.color[idx + 0] = c;
|
||||
buffers.color[idx + 1] = c;
|
||||
buffers.color[idx + 2] = c;
|
||||
buffers.color[idx + 3] = c;
|
||||
for (size_t i = 0; i < quads; i++) {
|
||||
sprite *s = &sprites[i];
|
||||
if (JS_IsUndefined(cur_img) || !JS_StrictEq(js, s->image, cur_img)) {
|
||||
cur_img = s->image;
|
||||
JS_GETATOM(js, uv, cur_img, rect, rect)
|
||||
JS_GETATOM(js, uv_px, cur_img, rect_px, rect)
|
||||
}
|
||||
|
||||
HMM_Vec2 px_size = {
|
||||
uv_px.w * s->scale.X,
|
||||
uv_px.h * s->scale.Y
|
||||
};
|
||||
|
||||
HMM_Vec2 anchor = {
|
||||
px_size.X * s->center.X,
|
||||
px_size.Y * s->center.Y
|
||||
};
|
||||
|
||||
size_t base = i * 4;
|
||||
|
||||
for (int v = 0; v < 4; v++) {
|
||||
HMM_Vec2 lp = {
|
||||
local[v].X * px_size.X - anchor.X,
|
||||
local[v].Y * px_size.Y - anchor.Y
|
||||
};
|
||||
|
||||
HMM_Vec2 world = HMM_AddV2(s->pos, HMM_MulM2V2(s->affine, lp));
|
||||
|
||||
buffers.pos[base + v] = world;
|
||||
buffers.color[base + v] = s->color;
|
||||
}
|
||||
|
||||
/* UVs are still top-left-origin pixel coords, so keep previous packing */
|
||||
buffers.uv[base + 0] = (HMM_Vec2){ uv.x, uv.y + uv.h };
|
||||
buffers.uv[base + 1] = (HMM_Vec2){ uv.x + uv.w, uv.y + uv.h };
|
||||
buffers.uv[base + 2] = (HMM_Vec2){ uv.x, uv.y };
|
||||
buffers.uv[base + 3] = (HMM_Vec2){ uv.x + uv.w, uv.y };
|
||||
}
|
||||
|
||||
JSValue mesh = quadbuffers_to_mesh(js, buffers);
|
||||
@@ -5407,6 +5434,51 @@ static const JSCFunctionListEntry js_SDL_GPUComputePass_funcs[] = {
|
||||
MIST_FUNC_DEF(compute, storage_textures, 2),
|
||||
};
|
||||
|
||||
typedef struct { const char *name; SDL_PixelFormat fmt; } fmt_entry;
|
||||
|
||||
static const fmt_entry k_fmt_table[] = {
|
||||
{ "rgba32", SDL_PIXELFORMAT_RGBA32 },
|
||||
{ "argb32", SDL_PIXELFORMAT_ARGB32 },
|
||||
{ "bgra32", SDL_PIXELFORMAT_BGRA32 },
|
||||
{ "abgr32", SDL_PIXELFORMAT_ABGR32 },
|
||||
{ "rgb565", SDL_PIXELFORMAT_RGB565 },
|
||||
{ "bgr565", SDL_PIXELFORMAT_BGR565 },
|
||||
{ "rgb24", SDL_PIXELFORMAT_RGB24 },
|
||||
{ "bgr24", SDL_PIXELFORMAT_BGR24 },
|
||||
{ "rgb332", SDL_PIXELFORMAT_RGB332 },
|
||||
{ "rgba64", SDL_PIXELFORMAT_RGBA64 },
|
||||
{ "rgb48", SDL_PIXELFORMAT_RGB48 },
|
||||
{ NULL, SDL_PIXELFORMAT_UNKNOWN }
|
||||
};
|
||||
|
||||
static JSValue pixelformat2js(JSContext *js, SDL_PixelFormat fmt)
|
||||
{
|
||||
fmt_entry *it;
|
||||
for (it = k_fmt_table; it->name; it++)
|
||||
if (it->fmt == fmt)
|
||||
break;
|
||||
|
||||
if (it->name)
|
||||
return JS_NewString(js, it->name);
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v)
|
||||
{
|
||||
if (JS_IsUndefined(v)) return SDL_PIXELFORMAT_UNKNOWN;
|
||||
const char *s = JS_ToCString(js, v);
|
||||
if (!s) return SDL_PIXELFORMAT_UNKNOWN;
|
||||
|
||||
fmt_entry *it;
|
||||
for (it = k_fmt_table; it->name; it++)
|
||||
if (!strcmp(it->name, s))
|
||||
break;
|
||||
|
||||
JS_FreeCString(js,s);
|
||||
return it->fmt;
|
||||
}
|
||||
|
||||
JSC_CCALL(surface_blit,
|
||||
SDL_Surface *dst = js2SDL_Surface(js,self);
|
||||
rect dstrect = js2rect(js,argv[0]);
|
||||
@@ -5461,21 +5533,79 @@ JSC_CCALL(surface_rect,
|
||||
SDL_FillSurfaceRect(dst,&r,SDL_MapRGBA(&pdetails,NULL, color.r*255,color.g*255,color.b*255,color.a*255));
|
||||
)
|
||||
|
||||
JSC_CCALL(surface_convert,
|
||||
SDL_Surface *surf = js2SDL_Surface(js,self);
|
||||
SDL_PixelFormat fmt = js2pixelformat(js, argv[0]);
|
||||
SDL_Surface *dst = SDL_ConvertSurface(surf, fmt);
|
||||
if (!dst) return JS_ThrowInternalError(js, "Convert failed: %s", SDL_GetError());
|
||||
|
||||
return SDL_Surface2js(js, dst);
|
||||
)
|
||||
|
||||
JSC_CCALL(surface_dup,
|
||||
SDL_Surface *surf = js2SDL_Surface(js,self);
|
||||
SDL_Surface *conv = SDL_ConvertSurface(surf, SDL_PIXELFORMAT_RGBA8888);
|
||||
SDL_Surface *conv = SDL_DuplicateSurface(surf);
|
||||
if (!conv)
|
||||
return JS_ThrowReferenceError(js, "could not blit to dup'd surface: %s", SDL_GetError());
|
||||
|
||||
return SDL_Surface2js(js,conv);
|
||||
)
|
||||
|
||||
JSC_CCALL(surface_pixels,
|
||||
SDL_Surface *surf = js2SDL_Surface(js,self);
|
||||
|
||||
/* if (SDL_ISPIXELFORMAT_FOURCC(surf->format->format))
|
||||
return JS_ThrowTypeError(js, "planar or FOURCC formats are not supported - convert first");
|
||||
*/
|
||||
|
||||
int locked = 0;
|
||||
if (SDL_MUSTLOCK(surf)) {
|
||||
if (SDL_LockSurface(surf) < 0)
|
||||
return JS_ThrowInternalError(js, "Lock surface failed: %s", SDL_GetError());
|
||||
|
||||
locked = 1;
|
||||
}
|
||||
|
||||
size_t byte_size = surf->pitch*surf->h;
|
||||
|
||||
ret = JS_NewArrayBufferCopy(js, surf->pixels, byte_size);
|
||||
|
||||
if (locked)
|
||||
SDL_UnlockSurface(surf);
|
||||
)
|
||||
|
||||
JSC_CCALL(surface_width,
|
||||
SDL_Surface *s = js2SDL_Surface(js,self);
|
||||
return JS_NewFloat64(js, s->w);
|
||||
)
|
||||
|
||||
JSC_CCALL(surface_height,
|
||||
SDL_Surface *s = js2SDL_Surface(js,self);
|
||||
return JS_NewFloat64(js, s->h);
|
||||
)
|
||||
|
||||
JSC_CCALL(surface_format,
|
||||
SDL_Surface *s = js2SDL_Surface(js,self);
|
||||
return pixelformat2js(js, s->format);
|
||||
)
|
||||
|
||||
JSC_CCALL(surface_pitch,
|
||||
SDL_Surface *s = js2SDL_Surface(js,self);
|
||||
return JS_NewFloat64(js, s->pitch);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_SDL_Surface_funcs[] = {
|
||||
MIST_FUNC_DEF(surface, blit, 3),
|
||||
MIST_FUNC_DEF(surface, scale, 1),
|
||||
MIST_FUNC_DEF(surface,fill,1),
|
||||
MIST_FUNC_DEF(surface,rect,2),
|
||||
MIST_FUNC_DEF(surface, dup, 0),
|
||||
MIST_FUNC_DEF(surface, pixels, 0),
|
||||
MIST_FUNC_DEF(surface, convert, 1),
|
||||
MIST_FUNC_DEF(surface, width, 0),
|
||||
MIST_FUNC_DEF(surface, height, 0),
|
||||
MIST_FUNC_DEF(surface, format, 0),
|
||||
MIST_FUNC_DEF(surface, pitch, 0),
|
||||
};
|
||||
|
||||
JSC_CCALL(camera_frame,
|
||||
@@ -6419,22 +6549,20 @@ JSC_CCALL(os_make_texture,
|
||||
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, 0);
|
||||
void *data = stbi_load_from_memory(raw, len, &width, &height, &n, 4);
|
||||
|
||||
if (data == NULL)
|
||||
return JS_ThrowReferenceError(js, "no known image type from pixel data");
|
||||
|
||||
int FMT = 0;
|
||||
if (n == 4)
|
||||
FMT = SDL_PIXELFORMAT_RGBA32;
|
||||
else if (n == 3)
|
||||
FMT = SDL_PIXELFORMAT_RGB24;
|
||||
else {
|
||||
free(data);
|
||||
return JS_ThrowReferenceError(js, "unknown pixel format. got %d channels", n);
|
||||
}
|
||||
if (!data)
|
||||
return JS_ThrowReferenceError(js, "no known image type from pixel data: %s", stbi_failure_reason());
|
||||
|
||||
SDL_Surface *surf = SDL_CreateSurfaceFrom(width,height,FMT, data, width*n);
|
||||
if (width <= 0 || height <= 0) {
|
||||
free(data);
|
||||
return JS_ThrowReferenceError(js, "decoded image has invalid size: %dx%d", width, height);
|
||||
}
|
||||
|
||||
int pitch = width*4;
|
||||
int fmt = SDL_PIXELFORMAT_RGBA32;
|
||||
|
||||
SDL_Surface *surf = SDL_CreateSurfaceFrom(width,height,fmt, data, pitch);
|
||||
if (!surf) {
|
||||
free(data);
|
||||
return JS_ThrowReferenceError(js, "Error creating surface from data: %s",SDL_GetError());
|
||||
@@ -6592,7 +6720,18 @@ JSC_CCALL(os_make_transform,
|
||||
// t->self = JS_DupValue(js,ret);
|
||||
t->self = ret;
|
||||
)
|
||||
JSC_CCALL(os_make_sprite, return sprite2js(js,make_sprite()))
|
||||
JSC_CCALL(os_make_sprite,
|
||||
sprite *sp = make_sprite();
|
||||
JS_GETATOM(js, sp->pos, argv[0], pos, vec2)
|
||||
JS_GETATOM(js, sp->center, argv[0], center, vec2)
|
||||
JS_GETATOM(js, sp->skew, argv[0], skew, vec2)
|
||||
JS_GETATOM(js, sp->scale, argv[0], scale, vec2)
|
||||
JS_GETATOM(js, sp->rotation, argv[0], rotation, angle)
|
||||
JS_GETATOM(js, sp->layer, argv[0], layer, number)
|
||||
JS_GETATOM(js, sp->color, argv[0], color, color)
|
||||
sprite_apply(sp);
|
||||
return sprite2js(js,sp);
|
||||
)
|
||||
|
||||
JSC_SCALL(os_system, ret = number2js(js,system(str)); )
|
||||
|
||||
@@ -7139,6 +7278,26 @@ static const JSCFunctionListEntry js_util_funcs[] = {
|
||||
MIST_FUNC_DEF(os, insertion_sort, 2),
|
||||
};
|
||||
|
||||
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});
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_graphics_funcs[] = {
|
||||
MIST_FUNC_DEF(gpu, make_sprite_mesh, 2),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_queue, 4),
|
||||
@@ -7152,8 +7311,9 @@ static const JSCFunctionListEntry js_graphics_funcs[] = {
|
||||
MIST_FUNC_DEF(os, make_surface, 1),
|
||||
MIST_FUNC_DEF(os, make_cursor, 1),
|
||||
MIST_FUNC_DEF(os, make_font, 2),
|
||||
MIST_FUNC_DEF(os, make_sprite, 0),
|
||||
MIST_FUNC_DEF(os, make_sprite, 1),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 5),
|
||||
MIST_FUNC_DEF(graphics, hsl_to_rgb, 3),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_video_funcs[] = {
|
||||
@@ -7362,6 +7522,13 @@ JSC_GETSET(sprite, skew, vec2)
|
||||
JSC_GETSET(sprite, scale, vec2)
|
||||
JSC_GETSET(sprite, rotation, number)
|
||||
|
||||
JSC_CCALL(sprite_move,
|
||||
sprite *sp = js2sprite(js,self);
|
||||
HMM_Vec2 mv = js2vec2(js,argv[0]);
|
||||
sp->pos.x += mv.x;
|
||||
sp->pos.y += mv.y;
|
||||
)
|
||||
|
||||
JSC_CCALL(sprite_set_affine,
|
||||
sprite *sp = js2sprite(js,self);
|
||||
sprite_apply(sp);
|
||||
@@ -7371,21 +7538,20 @@ JSC_CCALL(sprite_set_image,
|
||||
sprite *sp = js2sprite(js,self);
|
||||
if (!JS_IsUndefined(sp->image))
|
||||
JS_FreeValue(js,sp->image);
|
||||
sp->image = JS_DupValue(js,argv[0]);
|
||||
if (JS_IsUndefined(sp->image)) return JS_UNDEFINED;
|
||||
JSValue img = sp->image;
|
||||
JS_GETATOM(js, sp->uv, img, rect, rect)
|
||||
sp->image = JS_DupValue(js, argv[0]);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_sprite_funcs[] = {
|
||||
MIST_FUNC_DEF(sprite, set_affine, 0),
|
||||
MIST_FUNC_DEF(sprite, set_image, 1),
|
||||
CGETSET_ADD(sprite, skew),
|
||||
CGETSET_ADD(sprite, rotation),
|
||||
CGETSET_ADD(sprite, pos),
|
||||
CGETSET_ADD(sprite, center),
|
||||
CGETSET_ADD(sprite, layer),
|
||||
CGETSET_ADD(sprite, color),
|
||||
MIST_FUNC_DEF(sprite, move, 1),
|
||||
JS_CGETSET_DEF("pos", js_sprite_get_pos, js_sprite_set_pos),
|
||||
JS_CGETSET_DEF("scale", js_sprite_get_scale, js_sprite_set_scale),
|
||||
JS_CGETSET_DEF("skew", js_sprite_get_skew, js_sprite_set_skew),
|
||||
JS_CGETSET_DEF("layer", js_sprite_get_layer, js_sprite_set_layer),
|
||||
JS_CGETSET_DEF("color", js_sprite_get_color, js_sprite_set_color),
|
||||
JS_CGETSET_DEF("center", js_sprite_get_center, js_sprite_set_center),
|
||||
JS_CGETSET_DEF("rotation", js_sprite_get_rotation, js_sprite_set_rotation),
|
||||
};
|
||||
|
||||
#define JSSTATIC(NAME, PARENT) \
|
||||
|
||||
@@ -591,6 +591,7 @@ void script_startup(prosperon_rt *prt)
|
||||
JS_AddIntrinsicJSON(js);
|
||||
JS_AddIntrinsicMapSet(js);
|
||||
JS_AddIntrinsicTypedArrays(js);
|
||||
JS_AddIntrinsicWeakRef(js);
|
||||
|
||||
JS_SetContextOpaque(js, prt);
|
||||
prt->context = js;
|
||||
|
||||
112
source/qjs_qr.c
112
source/qjs_qr.c
@@ -125,57 +125,83 @@ static JSValue js_qr_encode(JSContext *js, JSValueConst this_val, int argc, JSVa
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t rgba_to_gray(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return (uint8_t)(( 299 * r + 587 * g + 114 * b + 500) / 1000);
|
||||
}
|
||||
|
||||
// QR decode function (unchanged)
|
||||
static JSValue js_qr_decode(JSContext *js, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
size_t data_len;
|
||||
uint8_t *data;
|
||||
if (argc < 1 || !(data = JS_GetArrayBuffer(js, &data_len, argv[0]))) {
|
||||
return JS_ThrowTypeError(js, "decode expects an ArrayBuffer");
|
||||
}
|
||||
|
||||
struct quirc *qr = quirc_new();
|
||||
if (!qr) {
|
||||
return JS_ThrowInternalError(js, "Failed to initialize QR decoder");
|
||||
}
|
||||
|
||||
int width = (int)sqrt((double)data_len);
|
||||
if (width * width != (int)data_len) {
|
||||
quirc_destroy(qr);
|
||||
return JS_ThrowTypeError(js, "ArrayBuffer must represent a square image");
|
||||
}
|
||||
|
||||
if (quirc_resize(qr, width, width) < 0) {
|
||||
quirc_destroy(qr);
|
||||
return JS_ThrowInternalError(js, "Failed to resize QR decoder");
|
||||
}
|
||||
|
||||
int h;
|
||||
uint8_t *image = quirc_begin(qr, &width, &h);
|
||||
memcpy(image, data, data_len);
|
||||
quirc_end(qr);
|
||||
|
||||
int count = quirc_count(qr);
|
||||
JSValue result = JS_NewArray(js);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct quirc_code code;
|
||||
struct quirc_data qdata;
|
||||
|
||||
quirc_extract(qr, i, &code);
|
||||
if (quirc_decode(&code, &qdata) == QUIRC_SUCCESS) {
|
||||
JSValue item = JS_NewStringLen(js, (const char *)qdata.payload, qdata.payload_len);
|
||||
JS_SetPropertyUint32(js, result, i, item);
|
||||
}
|
||||
}
|
||||
|
||||
size_t data_len;
|
||||
uint8_t *src;
|
||||
int w, h, pitch;
|
||||
src = JS_GetArrayBuffer(js, &data_len, argv[0]);
|
||||
|
||||
if (!src)
|
||||
return JS_ThrowTypeError(js, "decode expects an ArrayBuffer");
|
||||
|
||||
JS_ToInt32(js, &w, argv[1]);
|
||||
JS_ToInt32(js, &h, argv[2]);
|
||||
JS_ToInt32(js, &pitch, argv[3]);
|
||||
|
||||
if (w <= 0 || h <= 0)
|
||||
return JS_ThrowInternalError(js, "Bad width or height: %dx%d", w, h);
|
||||
|
||||
struct quirc *qr = quirc_new();
|
||||
if (!qr)
|
||||
return JS_ThrowInternalError(js, "Failed to initialize QR decoder");
|
||||
|
||||
if (quirc_resize(qr, w, h) < 0) {
|
||||
quirc_destroy(qr);
|
||||
return result;
|
||||
return JS_ThrowInternalError(js, "quirc_resize failed");
|
||||
}
|
||||
|
||||
uint8_t *dst = quirc_begin(qr, NULL, NULL);
|
||||
|
||||
printf("decoding image size %dx%d, pitch %d and size %d\n", w, h, pitch, data_len);
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
uint8_t *row = src + y * pitch;
|
||||
uint8_t *out = dst + y * w;
|
||||
for (int x = 0; x < w; ++x) {
|
||||
uint8_t a = row[x*4 + 3]; /* alpha */
|
||||
if (a < 128) { /* mostly transparent */
|
||||
out[x] = 255;
|
||||
} else {
|
||||
uint8_t r = row[x*4+0];
|
||||
uint8_t g = row[x*4+1];
|
||||
uint8_t b = row[x*4+2];
|
||||
out[x] = rgba_to_gray(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quirc_end(qr);
|
||||
|
||||
int count = quirc_count(qr);
|
||||
JSValue result = JS_NewArray(js);
|
||||
|
||||
printf("found %d codes\n", count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct quirc_code code;
|
||||
struct quirc_data qdata;
|
||||
|
||||
quirc_extract(qr, i, &code);
|
||||
printf("code is %p\n", code.size);
|
||||
if (quirc_decode(&code, &qdata) == QUIRC_SUCCESS) {
|
||||
JSValue item = JS_NewStringLen(js, (const char *)qdata.payload, qdata.payload_len);
|
||||
JS_SetPropertyUint32(js, result, i, item);
|
||||
}
|
||||
}
|
||||
|
||||
quirc_destroy(qr);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Exported functions for the module
|
||||
static const JSCFunctionListEntry js_qr_funcs[] = {
|
||||
JS_CFUNC_DEF("encode", 2, js_qr_encode), // Updated to expect 2 args
|
||||
JS_CFUNC_DEF("decode", 1, js_qr_decode),
|
||||
JS_CFUNC_DEF("decode", 4, js_qr_decode),
|
||||
};
|
||||
|
||||
// Helper to return the default export object
|
||||
|
||||
@@ -15,18 +15,15 @@ void sprite_free(JSRuntime *rt, sprite *sprite)
|
||||
|
||||
void sprite_apply(sprite *sp)
|
||||
{
|
||||
float rot = sp->rotation;
|
||||
HMM_Vec2 k = sp->skew;
|
||||
HMM_Vec2 s = sp->scale;
|
||||
/* -------- rotation + skew → 2×2 affine matrix -------- */
|
||||
float rot = sp->rotation;
|
||||
HMM_Vec2 k = sp->skew;
|
||||
|
||||
float c = cosf(rot), si = sinf(rot);
|
||||
float c = cosf(rot), s = sinf(rot);
|
||||
|
||||
sp->affine.Columns[0] = (HMM_Vec2){
|
||||
.x = (c + k.x * si) * s.x,
|
||||
.y = (k.y * c + si) * s.x
|
||||
};
|
||||
sp->affine.Columns[1] = (HMM_Vec2){
|
||||
.x = (-si + k.x * c) * s.y,
|
||||
.y = (-k.y * si + c) * s.y
|
||||
};
|
||||
sp->affine.Columns[0] = (HMM_Vec2){ .x = c + k.x * s,
|
||||
.y = k.y * c + s };
|
||||
sp->affine.Columns[1] = (HMM_Vec2){ .x = -s + k.x * c,
|
||||
.y = -k.y * s + c };
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ struct sprite{
|
||||
HMM_Vec2 scale;
|
||||
float rotation;
|
||||
HMM_Mat2 affine;
|
||||
JSValue image; // the actual texture resource - perhaps SDL_GPUTexture, or SDL_Texture, or something else ...
|
||||
rect uv; // pixel coordinates of the sprite on its image
|
||||
JSValue image; // the JS image
|
||||
int layer; // layer this sprite draws onto
|
||||
HMM_Vec4 color; // color in 0-1f
|
||||
};
|
||||
|
||||
@@ -53,16 +53,13 @@ var bunny_count = 2000
|
||||
|
||||
for (var i = 0; i < bunny_count; i++) {
|
||||
var pct = i/bunny_count
|
||||
var sp = sprite.create(bunny, [Math.random()*dim.x*pct, Math.random()*dim.y*pct], center)
|
||||
var hue = 270 * i / bunny_count
|
||||
var sp = sprite.create(bunny, {
|
||||
pos: [Math.random()*dim.x*pct, Math.random()*dim.y*pct],
|
||||
center,
|
||||
color: hsl_to_rgb(hue, 0.5, 0.5)
|
||||
})
|
||||
sp.dir = [Math.random()*vel, Math.random()*vel]
|
||||
var hue = 270 * i / bunny_count
|
||||
sp.color = hsl_to_rgb(hue, 0.5, 0.5)
|
||||
}
|
||||
|
||||
function movendraw(sp)
|
||||
{
|
||||
sp.move([sp.dir[0]*dt, sp.dir[1]*dt])
|
||||
// sp.draw()
|
||||
}
|
||||
|
||||
var dt = 0
|
||||
@@ -76,11 +73,15 @@ function loop()
|
||||
render.clear([22/255,120/255,194/255,255/255])
|
||||
render.camera(camera)
|
||||
|
||||
// sprite.forEach(movendraw)
|
||||
sprite.forEach(x => x.move(x.dir.scale(dt)))
|
||||
var queue = sprite.queue()
|
||||
|
||||
for (var q of queue)
|
||||
//console.log(json.encode(queue))
|
||||
|
||||
for (var q of queue) {
|
||||
if (!q.image) continue
|
||||
render.geometry(q.image.texture, q.mesh)
|
||||
}
|
||||
|
||||
render.present()
|
||||
dt = os.now() - now
|
||||
|
||||
76
tests/qr_drag.js
Normal file
76
tests/qr_drag.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// bunnymark
|
||||
var render = use('render')
|
||||
var os = use('os')
|
||||
var dim = [500,500]
|
||||
render.initialize({
|
||||
width:dim.x,
|
||||
height:dim.y,
|
||||
resolution_x:dim.x,
|
||||
resolution_y:dim.y,
|
||||
mode:"letterboxed",
|
||||
refresh: 60,
|
||||
})
|
||||
|
||||
var camera = {
|
||||
size: [500,500],
|
||||
transform: os.make_transform(),
|
||||
fov:50,
|
||||
near_z: 0,
|
||||
far_z: 1000,
|
||||
surface: undefined,
|
||||
viewport: {x:0,y:0,width:1,height:1},
|
||||
ortho:true,
|
||||
anchor:[0,0],
|
||||
}
|
||||
|
||||
var draw = use('draw2d')
|
||||
var sprite = use('lcdsprite')
|
||||
var graphics = use('graphics')
|
||||
|
||||
var dt = 0
|
||||
var img = undefined
|
||||
|
||||
var ioguy = {
|
||||
__ACTORDATA__: { id: os.ioactor() }
|
||||
}
|
||||
|
||||
var io = use('io')
|
||||
io.mount('/')
|
||||
|
||||
var qr = use('qr')
|
||||
|
||||
$_.send(ioguy, {
|
||||
type: "subscribe",
|
||||
actor: $_
|
||||
})
|
||||
|
||||
$_.receiver(e => {
|
||||
if (e.type === 'quit')
|
||||
os.exit()
|
||||
|
||||
switch(e.type) {
|
||||
case "drop_file":
|
||||
console.log(`got ${e.data} dropped`)
|
||||
img = e.data
|
||||
var image = graphics.texture(e.data)
|
||||
console.log(json.encode(qr.decode(image.surface.pixels(), image.surface.width(), image.surface.height(), image.surface.pitch())))
|
||||
}
|
||||
})
|
||||
|
||||
function loop()
|
||||
{
|
||||
var now = os.now()
|
||||
render.clear([22/255,120/255,194/255,255/255])
|
||||
render.camera(camera)
|
||||
|
||||
if (img)
|
||||
draw.image(img, {x:0,y:0,width:300,height:300})
|
||||
|
||||
render.present()
|
||||
|
||||
dt = os.now() - now
|
||||
var delay = (1/60) - dt
|
||||
$_.delay(loop, delay)
|
||||
}
|
||||
|
||||
loop()
|
||||
Reference in New Issue
Block a user