switch to blobs from arraybuffers
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m29s
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled

This commit is contained in:
2025-05-28 22:33:32 -05:00
parent 53b3f0af9c
commit e86bdf52fe
24 changed files with 287 additions and 433 deletions

View File

@@ -4,6 +4,19 @@ var json = use('json')
var os = use('os')
var draw2d = use('draw2d')
var blob = use('blob')
var myblob = new blob
myblob.write_bit(1)
myblob.write_bit(0)
myblob.__proto__.toString = function() {
return `[${this.length} bit blob]`
}
console.log(myblob.toString())
console.log(myblob)
console.log(myblob.length)
var input = use('input')
input.watch($_)

View File

@@ -238,6 +238,7 @@ globalThis.use = function use(file, ...args) {
globalThis.json = use('json')
var time = use('time')
use('blob')
var DOCPATH = 'scripts/core/doc.js'
var script = io.slurp(DOCPATH)
var fnname = "doc"

View File

@@ -156,6 +156,8 @@ function decode_image(bytes, ext)
function create_image(path){
try{
const bytes = io.slurpbytes(path);
console.log(bytes)
console.log(bytes.length)
let raw = decode_image(bytes, path.ext());
/* ── Case A: static image ─────────────────────────────────── */

View File

@@ -57,6 +57,8 @@ int blob_write_kim(blob *b, int64_t value);
int blob_write_pad(blob *b, int block_size);
int blob_write_text(blob *b, const char *text);
int blob_write_bytes(blob *b, void *data, size_t length);
// Read operations (only work on stone blobs)
int blob_read_bit(const blob *b, size_t pos, int *out_bit);
blob *blob_read_blob(const blob *b, size_t from, size_t to);
@@ -332,7 +334,7 @@ int blob_write_kim(blob *b, int64_t value) {
// Write the kim bytes as bits
for (int i = 0; i < bytes; i++) {
for (int j = 0; j < 8; b++) {
for (int j = 0; j < 8; j++) {
if (blob_write_bit(b, (kim_bytes[i] >> j) & 1) < 0)
return -1;
}

View File

@@ -29,6 +29,7 @@
#include "cgltf.h"
#include "prosperon.h"
#include "qjs_blob.h"
#include "qjs_dmon.h"
#include "qjs_nota.h"
#include "qjs_wota.h"
@@ -262,10 +263,8 @@ JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int el
JSValue tstack[3];
tstack[1] = JS_UNDEFINED;
tstack[2] = JS_UNDEFINED;
if (copy)
tstack[0] = JS_NewArrayBufferCopy(js,data,size);//, make_gpu_buffer, NULL, 1);
else
tstack[0] = JS_NewArrayBuffer(js,data,size,free_gpu_buffer, NULL, 0);
// TODO: always copying; implement "takeover"
tstack[0] = js_new_blob_stoned_copy(js,data,size);//, make_gpu_buffer, NULL, 1);
JSValue ret = JS_NewTypedArray(js, 3, tstack, type);
JS_SetPropertyStr(js,ret,"stride", number2js(js,typed_array_bytes(type)*elements));
JS_SetPropertyStr(js,ret,"elen", number2js(js,typed_array_bytes(type)));
@@ -278,7 +277,7 @@ void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size)
{
size_t o, len, bytes, msize;
JSValue buf = JS_GetTypedArrayBuffer(js, argv, &o, &len, &bytes);
void *data = JS_GetArrayBuffer(js, &msize, buf);
void *data = js_get_blob_data(js, &msize, buf);
JS_FreeValue(js,buf);
if (stride) *stride = js_getnum_str(js, argv, "stride");
if (size) *size = msize;
@@ -755,15 +754,15 @@ JSValue js_util_camera_globals(JSContext *js, JSValue self, int argc, JSValue *a
);
JS_SetPropertyStr(js, data, "world_to_projection",
JS_NewArrayBufferCopy(js, world_to_projection.em,
js_new_blob_stoned_copy(js, world_to_projection.em,
sizeof(float)*16));
JS_SetPropertyStr(js, data, "projection_to_world",
JS_NewArrayBufferCopy(js, projection_to_world.em,
js_new_blob_stoned_copy(js, projection_to_world.em,
sizeof(float)*16));
JS_SetPropertyStr(js, data, "world_to_view",
JS_NewArrayBufferCopy(js, view.em, sizeof(float)*16));
js_new_blob_stoned_copy(js, view.em, sizeof(float)*16));
JS_SetPropertyStr(js, data, "view_to_projection",
JS_NewArrayBufferCopy(js, proj.em, sizeof(float)*16));
js_new_blob_stoned_copy(js, proj.em, sizeof(float)*16));
JS_SetPropertyStr(js, data, "camera_pos_world", vec32js(js, pos));
JS_SetPropertyStr(js, data, "camera_dir_world", vec32js(js, camera_dir_world));
@@ -1003,7 +1002,7 @@ static const JSCFunctionListEntry js_font_funcs[] = {
// input: (encoded image data of jpg, png, bmp, tiff)
JSC_CCALL(os_make_texture,
size_t len;
void *raw = JS_GetArrayBuffer(js, &len, argv[0]);
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;
@@ -1026,7 +1025,7 @@ JSC_CCALL(os_make_texture,
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_NewArrayBufferCopy(js, data, pixels_size));
JS_SetPropertyStr(js, obj, "pixels", js_new_blob_stoned_copy(js, data, pixels_size));
free(data);
ret = obj;
@@ -1036,7 +1035,7 @@ JSC_CCALL(os_make_texture,
// input: (gif image data)
JSC_CCALL(os_make_gif,
size_t rawlen;
void *raw = JS_GetArrayBuffer(js, &rawlen, argv[0]);
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;
@@ -1056,7 +1055,7 @@ JSC_CCALL(os_make_gif,
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));
JS_SetPropertyStr(js, surfData, "pixels", JS_NewArrayBufferCopy(js, pixels, width*height*4));
JS_SetPropertyStr(js, surfData, "pixels", js_new_blob_stoned_copy(js, pixels, width*height*4));
JS_SetPropertyStr(js, gif, "surface", surfData);
return gif;
}
@@ -1075,7 +1074,7 @@ JSC_CCALL(os_make_gif,
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_NewArrayBufferCopy(js, frame_pixels, width*height*4));
JS_SetPropertyStr(js, surfData, "pixels", js_new_blob_stoned_copy(js, frame_pixels, width*height*4));
JS_SetPropertyStr(js, frame, "surface", surfData);
JS_SetPropertyUint32(js, delay_arr, i, frame);
@@ -1098,7 +1097,7 @@ JSValue aseframe2js(JSContext *js, ase_frame_t aframe)
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_NewArrayBufferCopy(js, aframe.pixels, aframe.ase->w*aframe.ase->h*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));
@@ -1108,7 +1107,7 @@ JSValue aseframe2js(JSContext *js, ase_frame_t aframe)
// input: (aseprite data)
JSC_CCALL(os_make_aseprite,
size_t rawlen;
void *raw = JS_GetArrayBuffer(js,&rawlen,argv[0]);
void *raw = js_get_blob_data(js,&rawlen,argv[0]);
ase_t *ase = cute_aseprite_load_from_memory(raw, rawlen, NULL);
@@ -1160,7 +1159,7 @@ JSC_CCALL(os_make_aseprite,
JSC_CCALL(os_make_font,
size_t len;
void *data = JS_GetArrayBuffer(js,&len,argv[0]);
void *data = js_get_blob_data(js,&len,argv[0]);
if (!data) return JS_ThrowReferenceError(js, "could not get array buffer data");
font *f = MakeFont(data, len, js2number(js,argv[1]));
if (!f) return JS_ThrowReferenceError(js, "could not create font");
@@ -1183,7 +1182,7 @@ JSC_CCALL(os_make_font,
}
size_t byte_size = f->surface->pitch * f->surface->h;
JS_SetPropertyStr(js, surfData, "pixels", JS_NewArrayBufferCopy(js, f->surface->pixels, byte_size));
JS_SetPropertyStr(js, surfData, "pixels", js_new_blob_stoned_copy(js, f->surface->pixels, byte_size));
if (locked)
SDL_UnlockSurface(f->surface);
@@ -1256,7 +1255,7 @@ static void render_frame(plm_t *mpeg, plm_frame_t *frame, datastream *ds) {
JS_SetPropertyStr(ds->js, surfData, "height", JS_NewInt32(ds->js, frame->height));
JS_SetPropertyStr(ds->js, surfData, "format", JS_NewString(ds->js, "rgba32"));
JS_SetPropertyStr(ds->js, surfData, "pitch", JS_NewInt32(ds->js, frame->width*4));
JS_SetPropertyStr(ds->js, surfData, "pixels", JS_NewArrayBufferCopy(ds->js, rgb, frame->height*frame->width*4));
JS_SetPropertyStr(ds->js, surfData, "pixels", js_new_blob_stoned_copy(ds->js, rgb, frame->height*frame->width*4));
JSValue s[1];
s[0] = surfData;
@@ -1269,7 +1268,7 @@ static void render_frame(plm_t *mpeg, plm_frame_t *frame, datastream *ds) {
JSC_CCALL(os_make_video,
size_t len;
void *data = JS_GetArrayBuffer(js,&len,argv[0]);
void *data = js_get_blob_data(js,&len,argv[0]);
datastream *ds = ds_openvideo(data, len);
if (!ds) return JS_ThrowReferenceError(js, "Video file was not valid.");
ds->js = js;
@@ -1420,7 +1419,7 @@ JSC_CCALL(graphics_save_png,
JS_ToInt32(js, &h, argv[2]);
JS_ToInt32(js, &pitch, argv[4]);
size_t size;
void *data = JS_GetArrayBuffer(js, &size, argv[3]);
void *data = js_get_blob_data(js, &size, argv[3]);
if (!stbi_write_png(file, w, h, 4, data, pitch))
return JS_ThrowInternalError(js, "Could not write png");
@@ -1435,7 +1434,7 @@ JSC_CCALL(graphics_save_jpg,
JS_ToInt32(js, &quality, argv[5]);
if (!quality) quality = 80;
size_t size;
void *data = JS_GetArrayBuffer(js, &size, argv[3]);
void *data = js_get_blob_data(js, &size, argv[3]);
if (!stbi_write_jpg(file, w, h, 4, data, quality))
return JS_ThrowInternalError(js, "Could not write png");
@@ -1525,7 +1524,6 @@ JSC_CCALL(os_value_id,
#include "qjs_crypto.h"
#include "qjs_time.h"
#include "qjs_blob.h"
#include "qjs_http.h"
//JSValue js_imgui_use(JSContext *js);

View File

@@ -3,6 +3,7 @@
#include <SDL3/SDL.h>
#include "quickjs.h"
#include "qjs_blob.h"
#define STATE_VECTOR_LENGTH 624
#define STATE_VECTOR_M 397

View File

@@ -599,3 +599,30 @@ JSValue js_blob_use(JSContext *js) {
return ctor;
}
JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t bytes)
{
printf("Making blob from %p with %u bytes\n", data, bytes);
blob *b = blob_new(bytes*8);
memcpy(b->data, data, bytes);
blob_make_stone(b);
return blob2js(js, b);
}
void *js_get_blob_data(JSContext *js, size_t *size, JSValue v)
{
blob *b = js2blob(js, v);
if (!b || !b->is_stone)
return NULL;
*size = b->bit_capacity/8;
return b->data;
}
int js_is_blob(JSContext *js, JSValue v)
{
blob *b = js2blob(js,v);
if (b) return 1;
return 0;
}

View File

@@ -5,4 +5,13 @@
JSValue js_blob_use(JSContext *ctx);
// makes a new stone blob from data, copying the data over
JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t bytes);
// returns undefined if the blob is not stone
void *js_get_blob_data(JSContext *js, size_t *size, JSValue v);
int js_is_blob(JSContext *js, JSValue v);
#endif

View File

@@ -151,7 +151,7 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val, int a
// Pass raw data as string or ArrayBuffer
if (event.packet->dataLength > 0) {
JSValue data_val = JS_NewArrayBufferCopy(ctx, event.packet->data, event.packet->dataLength);
JSValue data_val = js_new_blob_stoned_copy(ctx, event.packet->data, event.packet->dataLength);
JS_SetPropertyStr(ctx, event_obj, "data", data_val);
}
enet_packet_destroy(event.packet);
@@ -220,8 +220,8 @@ static JSValue js_enet_host_broadcast(JSContext *ctx, JSValueConst this_val, int
if (JS_IsString(argv[0])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]);
if (!data_str) return JS_EXCEPTION;
} else if (JS_IsArrayBuffer(ctx,argv[0])) {
buf = JS_GetArrayBuffer(ctx, &data_len, argv[0]);
} else if (js_is_blob(ctx,argv[0])) {
buf = js_get_blob_data(ctx, &data_len, argv[0]);
if (!buf) return JS_EXCEPTION;
} else {
return JS_ThrowTypeError(ctx, "broadcast() only accepts a string or ArrayBuffer");
@@ -283,8 +283,8 @@ static JSValue js_enet_peer_send(JSContext *ctx, JSValueConst this_val, int argc
if (JS_IsString(argv[0])) {
data_str = JS_ToCStringLen(ctx, &data_len, argv[0]);
if (!data_str) return JS_EXCEPTION;
} else if (JS_IsArrayBuffer(ctx,argv[0])) {
buf = JS_GetArrayBuffer(ctx, &data_len, argv[0]);
} else if (js_is_blob(ctx,argv[0])) {
buf = js_get_blob_data(ctx, &data_len, argv[0]);
if (!buf) return JS_EXCEPTION;
} else {
return JS_ThrowTypeError(ctx, "send() only accepts a string or ArrayBuffer");

View File

@@ -12,6 +12,7 @@
#include <errno.h>
#include <stdio.h>
#include "wildmatch.h"
#include "prosperon.h"
// File descriptor wrapper structure
typedef struct {
@@ -69,7 +70,7 @@ static ssize_t js_fd_write_helper(JSContext *js, int fd, JSValue val)
wrote = write(fd, data, len);
JS_FreeCString(js, data);
} else {
unsigned char *data = JS_GetArrayBuffer(js, &len, val);
unsigned char *data = js_get_blob_data(js, &len, val);
wrote = write(fd, data, len);
}
return wrote;
@@ -200,7 +201,7 @@ JSC_SCALL(fd_slurpbytes,
goto END;
}
ret = JS_NewArrayBufferCopy(js, data, st.st_size);
ret = js_new_blob_stoned_copy(js, data, st.st_size);
free(data);
END:
@@ -408,7 +409,7 @@ JSC_CCALL(file_read,
return JS_ThrowReferenceError(js, "read failed: %s", strerror(errno));
}
ret = JS_NewArrayBufferCopy(js, buf, bytes_read);
ret = js_new_blob_stoned_copy(js, buf, bytes_read);
free(buf);
return ret;
)

View File

@@ -642,10 +642,10 @@ JSC_CCALL(gpu_make_sprite_queue,
size_t quads = 0;
int needfree = 1;
if (JS_IsArrayBuffer(js, argv[0])) {
if (js_is_blob(js, argv[0])) {
// test for fastest
size_t size;
sprite *sprites = JS_GetArrayBuffer(js, &size, argv[0]);
sprite *sprites = js_get_blob_data(js, &size, argv[0]);
quads = size/sizeof(*sprites);
needfree = 0;
for (int i = 0; i < quads; i++)
@@ -778,7 +778,7 @@ JSC_CCALL(geometry_rect_transform,
rect r = js2rect(js, argv[0]);
// argv[1] = world_to_projection (16 floats)
size_t byte_len;
float *data12 = JS_GetArrayBuffer(js, &byte_len, argv[1]);
float *data12 = js_get_blob_data(js, &byte_len, argv[1]);
HMM_Mat4 wp; memcpy(wp.Elements, data12, sizeof(wp.Elements));
// make our two corners at z=0

View File

@@ -8,6 +8,7 @@
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/error.h>
#include <ctype.h>
#include "prosperon.h"
typedef struct {
char *data;
@@ -647,7 +648,7 @@ static JSValue js_fetch_read_chunk(JSContext *ctx, JSValueConst this_val, int ar
}
// Return chunk as ArrayBuffer
result = JS_NewArrayBufferCopy(ctx, buf, actual_len);
result = js_new_blob_stoned_copy(ctx, buf, actual_len);
js_free(ctx, buf);
return result;
@@ -795,7 +796,7 @@ static JSValue js_fetch(JSContext *ctx, JSValueConst this_val, int argc, JSValue
if (body) {
// Return body as ArrayBuffer
result = JS_NewArrayBufferCopy(ctx, (uint8_t *)body, body_len);
result = js_new_blob_stoned_copy(ctx, (uint8_t *)body, body_len);
} else {
result = JS_ThrowInternalError(ctx, "Failed to parse HTTP response");
}

View File

@@ -202,7 +202,7 @@ JSC_SCALL(imgui_barplot,
JSC_SCALL(imgui_histogramplot,
size_t offset, len, per_e;
JSValue typed = JS_GetTypedArrayBuffer(js, argv[1], &offset, &len, &per_e);
ImPlot::PlotHistogram(str, JS_GetArrayBuffer(js, NULL, typed), JS_ArrayLength(js, argv[1]));
ImPlot::PlotHistogram(str, js_get_blob_data(js, NULL, typed), JS_ArrayLength(js, argv[1]));
JS_FreeValue(js, typed);
)
@@ -312,7 +312,7 @@ JSC_SCALL(imgui_intslider,
JSValue arr = JS_NewTypedArray(js, 1, &argv[1], JS_TYPED_ARRAY_INT32);
size_t len;
JSValue buf = JS_GetTypedArrayBuffer(js, arr, NULL, &len, NULL);
int *data = (int*)JS_GetArrayBuffer(js, NULL, buf);
int *data = (int*)js_get_blob_data(js, NULL, buf);
switch(len) {
case 2:

View File

@@ -30,7 +30,7 @@ static size_t js_physfs_write(JSContext *js, PHYSFS_File *f, JSValue val)
wrote = PHYSFS_writeBytes(f,data,len);
JS_FreeCString(js,data);
} else {
unsigned char *data = JS_GetArrayBuffer(js,&len,val);
unsigned char *data = js_get_blob_data(js,&len,val);
wrote = PHYSFS_writeBytes(f,data,len);
}
@@ -153,7 +153,7 @@ JSC_SCALL(io_slurpbytes,
void *data = malloc(stat.filesize);
PHYSFS_readBytes(f,data,stat.filesize);
PHYSFS_close(f);
ret = JS_NewArrayBufferCopy(js,data,stat.filesize);
ret = js_new_blob_stoned_copy(js,data,stat.filesize);
END:
)

View File

@@ -1,4 +1,5 @@
#include "quickjs.h"
#include "prosperon.h"
#define KIM_IMPLEMENTATION
#define NOTA_IMPLEMENTATION
@@ -67,7 +68,7 @@ char *js_do_nota_decode(JSContext *js, JSValue *tmp, char *nota, JSValue holder,
switch(type) {
case NOTA_BLOB:
nota = nota_read_blob(&n, (char**)&blob, nota);
*tmp = JS_NewArrayBufferCopy(js, blob, n);
*tmp = js_new_blob_stoned_copy(js, blob, n);
free(blob);
break;
case NOTA_TEXT:
@@ -164,9 +165,9 @@ static void nota_encode_value(NotaEncodeContext *enc, JSValueConst val, JSValueC
nota_write_sym(&enc->nb, NOTA_NULL);
break;
case JS_TAG_OBJECT: {
if (JS_IsArrayBuffer(ctx, replaced)) {
if (js_is_blob(ctx, replaced)) {
size_t buf_len;
void *buf_data = JS_GetArrayBuffer(ctx, &buf_len, replaced);
void *buf_data = js_get_blob_data(ctx, &buf_len, replaced);
nota_write_blob(&enc->nb, (unsigned long long)buf_len * 8, (const char*)buf_data);
break;
}
@@ -304,7 +305,7 @@ static JSValue js_nota_encode(JSContext *ctx, JSValueConst this_val, int argc, J
JS_FreeValue(ctx, enc->visitedStack);
size_t total_len = enc->nb.size;
void *data_ptr = enc->nb.data;
JSValue ret = JS_NewArrayBufferCopy(ctx, (uint8_t*)data_ptr, total_len);
JSValue ret = js_new_blob_stoned_copy(ctx, (uint8_t*)data_ptr, total_len);
nota_buffer_free(&enc->nb);
return ret;
@@ -314,7 +315,7 @@ static JSValue js_nota_decode(JSContext *js, JSValueConst self, int argc, JSValu
if (argc < 1) return JS_UNDEFINED;
size_t len;
unsigned char *nota = JS_GetArrayBuffer(js, &len, argv[0]);
unsigned char *nota = js_get_blob_data(js, &len, argv[0]);
if (!nota) return JS_UNDEFINED;
JSValue reviver = (argc > 1 && JS_IsFunction(js, argv[1])) ? argv[1] : JS_UNDEFINED;

View File

@@ -182,7 +182,7 @@ JSC_CCALL(os_buffer2string,
}
size_t len;
uint8_t *buf = JS_GetArrayBuffer(js, &len, argv[0]);
uint8_t *buf = js_get_blob_data(js, &len, argv[0]);
if (!buf) {
return JS_ThrowTypeError(js, "First argument must be an ArrayBuffer");
}
@@ -262,7 +262,7 @@ JSC_CCALL(os_trace_img,
double width, height;
JS_ToFloat64(js,&width,argv[1]);
JS_ToFloat64(js,&height,argv[2]);
___tracy_emit_frame_image(JS_GetArrayBuffer(js, &len, argv[0]), width, height, 0, 0);
___tracy_emit_frame_image(js_get_blob_data(js, &len, argv[0]), width, height, 0, 0);
)
JSC_CCALL(os_trace_message,

View File

@@ -1,6 +1,7 @@
#include "quickjs.h"
#include "quirc.h"
#include "qrencode.h"
#include "prosperon.h"
#include <math.h> // for sqrt
#include <stdlib.h> // for size_t, etc.
@@ -102,7 +103,7 @@ static JSValue js_qr_encode(JSContext *js, JSValueConst this_val, int argc, JSVa
} else {
/* treat everything else as raw bytes */
use_byte_mode = 1;
uint8_t *buf = JS_GetArrayBuffer(js, &data_len, argv[0]);
uint8_t *buf = js_get_blob_data(js, &data_len, argv[0]);
if (!buf) {
return JS_ThrowTypeError(js, "encode expects a string or ArrayBuffer");
}
@@ -160,7 +161,7 @@ static JSValue js_qr_decode(JSContext *js, JSValueConst this_val, int argc, JSVa
size_t data_len;
uint8_t *src;
int w, h, pitch;
src = JS_GetArrayBuffer(js, &data_len, argv[0]);
src = js_get_blob_data(js, &data_len, argv[0]);
if (!src)
return JS_ThrowTypeError(js, "decode expects an ArrayBuffer");
@@ -213,7 +214,7 @@ static JSValue js_qr_decode(JSContext *js, JSValueConst this_val, int argc, JSVa
quirc_extract(qr, i, &code);
int err = quirc_decode(&code, &qdata);
if (err == QUIRC_SUCCESS) {
JSValue item = JS_NewArrayBufferCopy(js, qdata.payload, qdata.payload_len);
JSValue item = js_new_blob_stoned_copy(js, qdata.payload, qdata.payload_len);
JS_SetPropertyUint32(js, result, i, item);
} else {
printf("QR error: %s\n", quirc_strerror(err));
@@ -272,7 +273,7 @@ static JSValue js_qr_rgba(JSContext *js, JSValueConst self, int argc, JSValueCon
}
}
JSValue ab = JS_NewArrayBufferCopy(js, tmp, bytes); /* GC owns copy */
JSValue ab = js_new_blob_stoned_copy(js, tmp, bytes); /* GC owns copy */
js_free(js, tmp);
JS_FreeValue(js, js_bits); /* done with src */

View File

@@ -6,6 +6,8 @@
#include "qjs_actor.h"
#include "qjs_sdl_surface.h"
#include <SDL3/SDL.h>
// SDL Free functions
void SDL_Camera_free(JSRuntime *rt, SDL_Camera *cam)
{
@@ -46,7 +48,15 @@ static JSValue js_keymod(JSContext *js)
}
// INPUT FUNCTIONS
// Thread-safe keyboard functions remain here
JSC_CCALL(input_mouse_lock, SDL_CaptureMouse(JS_ToBool(js,argv[0])))
JSC_CCALL(input_mouse_show,
if (JS_ToBool(js,argv[0]))
SDL_ShowCursor();
else
SDL_HideCursor();
)
JSC_CCALL(input_keyname,
return JS_NewString(js, SDL_GetKeyName(js2number(js,argv[0])));
)
@@ -55,7 +65,30 @@ JSC_CCALL(input_keymod,
return js_keymod(js);
)
JSC_CCALL(input_mousestate,
float x,y;
SDL_MouseButtonFlags flags = SDL_GetMouseState(&x,&y);
JSValue m = JS_NewObject(js);
JS_SetPropertyStr(js,m,"x", number2js(js,x));
JS_SetPropertyStr(js,m,"y", number2js(js,y));
if (flags & SDL_BUTTON_LMASK)
JS_SetPropertyStr(js, m, "left", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_MMASK)
JS_SetPropertyStr(js, m, "middle", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_RMASK)
JS_SetPropertyStr(js, m, "right", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X1MASK)
JS_SetPropertyStr(js, m, "x1", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X2MASK)
JS_SetPropertyStr(js, m, "x2", JS_NewBool(js, 1));
return m;
)
// watch events
extern char **event_watchers;
extern SDL_Mutex *event_watchers_mutex;
JSC_CCALL(input_watch,
/* Use js2actor to get the actor from the JS object */
@@ -106,8 +139,11 @@ JSC_CCALL(input_unwatch,
)
static const JSCFunctionListEntry js_input_funcs[] = {
MIST_FUNC_DEF(input, mouse_show, 1),
MIST_FUNC_DEF(input, mouse_lock, 1),
MIST_FUNC_DEF(input, keyname, 1),
MIST_FUNC_DEF(input, keymod, 0),
MIST_FUNC_DEF(input, mousestate, 0),
MIST_FUNC_DEF(input, watch, 1),
MIST_FUNC_DEF(input, unwatch, 1),
};
@@ -115,6 +151,11 @@ static const JSCFunctionListEntry js_input_funcs[] = {
JSValue js_input_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_input_funcs,countof(js_input_funcs));
// Initialize SDL cursor class (no functions)
JSValue c_types = JS_GetPropertyStr(js, JS_GetGlobalObject(js), "c_types");
JS_FreeValue(js, c_types);
return mod;
}
@@ -254,50 +295,14 @@ SDL_PixelFormat str2pixelformat(const char *str) {
if (!strcmp(str, "nv12")) return SDL_PIXELFORMAT_NV12;
if (!strcmp(str, "nv21")) return SDL_PIXELFORMAT_NV21;
if (!strcmp(str, "p010")) return SDL_PIXELFORMAT_P010;
if (!strcmp(str, "rgba32")) return SDL_PIXELFORMAT_RGBA32;
return SDL_PIXELFORMAT_UNKNOWN;
}
const char *colorspace2str(SDL_Colorspace colorspace) {
switch(colorspace) {
case SDL_COLORSPACE_UNKNOWN: return "unknown";
case SDL_COLORSPACE_SRGB: return "srgb";
case SDL_COLORSPACE_SRGB_LINEAR: return "srgb_linear";
case SDL_COLORSPACE_HDR10: return "hdr10";
case SDL_COLORSPACE_JPEG: return "jpeg";
case SDL_COLORSPACE_BT601_LIMITED: return "bt601_limited";
case SDL_COLORSPACE_BT601_FULL: return "bt601_full";
case SDL_COLORSPACE_BT709_LIMITED: return "bt709_limited";
case SDL_COLORSPACE_BT709_FULL: return "bt709_full";
case SDL_COLORSPACE_BT2020_LIMITED: return "bt2020_limited";
case SDL_COLORSPACE_BT2020_FULL: return "bt2020_full";
default: return "unknown";
}
}
SDL_Colorspace str2colorspace(const char *str) {
if (!str) return SDL_COLORSPACE_UNKNOWN;
if (!strcmp(str, "unknown")) return SDL_COLORSPACE_UNKNOWN;
if (!strcmp(str, "srgb")) return SDL_COLORSPACE_SRGB;
if (!strcmp(str, "srgb_linear")) return SDL_COLORSPACE_SRGB_LINEAR;
if (!strcmp(str, "hdr10")) return SDL_COLORSPACE_HDR10;
if (!strcmp(str, "jpeg")) return SDL_COLORSPACE_JPEG;
if (!strcmp(str, "bt601_limited")) return SDL_COLORSPACE_BT601_LIMITED;
if (!strcmp(str, "bt601_full")) return SDL_COLORSPACE_BT601_FULL;
if (!strcmp(str, "bt709_limited")) return SDL_COLORSPACE_BT709_LIMITED;
if (!strcmp(str, "bt709_full")) return SDL_COLORSPACE_BT709_FULL;
if (!strcmp(str, "bt2020_limited")) return SDL_COLORSPACE_BT2020_LIMITED;
if (!strcmp(str, "bt2020_full")) return SDL_COLORSPACE_BT2020_FULL;
return SDL_COLORSPACE_UNKNOWN;
}
static JSValue cameraspec2js(JSContext *js, const SDL_CameraSpec *spec) {
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "format", JS_NewString(js, pixelformat2str(spec->format)));
JS_SetPropertyStr(js, obj, "colorspace", JS_NewString(js, colorspace2str(spec->colorspace)));
JS_SetPropertyStr(js, obj, "colorspace", JS_NewInt32(js, spec->colorspace));
JS_SetPropertyStr(js, obj, "width", JS_NewInt32(js, spec->width));
JS_SetPropertyStr(js, obj, "height", JS_NewInt32(js, spec->height));
JS_SetPropertyStr(js, obj, "framerate_numerator", JS_NewInt32(js, spec->framerate_numerator));
@@ -320,11 +325,7 @@ static SDL_CameraSpec js2cameraspec(JSContext *js, JSValue obj) {
JS_FreeValue(js, v);
v = JS_GetPropertyStr(js, obj, "colorspace");
if (!JS_IsUndefined(v)) {
const char *s = JS_ToCString(js, v);
spec.colorspace = str2colorspace(s);
JS_FreeCString(js, s);
}
if (!JS_IsUndefined(v)) JS_ToInt32(js, &spec.colorspace, v);
JS_FreeValue(js, v);
v = JS_GetPropertyStr(js, obj, "width");
@@ -437,10 +438,24 @@ JSC_CCALL(camera_capture,
}
// Create a copy of the surface
SDL_Surface *newsurf = SDL_DuplicateSurface(surf);
SDL_Surface *newsurf = SDL_CreateSurface(surf->w, surf->h, surf->format);
if (!newsurf) {
SDL_ReleaseCameraFrame(cam, surf);
return JS_ThrowReferenceError(js, "Could not create surface: %s", SDL_GetError());
}
// Copy the surface data
int result = SDL_BlitSurface(surf, NULL, newsurf, NULL);
// Release the camera frame
SDL_ReleaseCameraFrame(cam, surf);
if (result != 0) {
SDL_DestroySurface(newsurf);
return JS_ThrowReferenceError(js, "Could not blit surface: %s", SDL_GetError());
}
return SDL_Surface2js(js,newsurf);
)
@@ -675,7 +690,7 @@ JSC_CCALL(sdl_audiostream_queued,
JSC_CCALL(sdl_audiostream_put,
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
size_t len;
void *buf = JS_GetArrayBuffer(js, &len, argv[0]);
void *buf = js_get_blob_data(js, &len, argv[0]);
if (!buf)
return JS_ThrowInternalError(js, "Requires array buffer.");
@@ -696,7 +711,7 @@ JSC_CCALL(sdl_audiostream_get,
return JS_ThrowInternalError(js,"%s",SDL_GetError());
}
JSValue ab = JS_NewArrayBufferCopy(js, data, got);
JSValue ab = js_new_blob_stoned_copy(js, data, got);
free(data);
return ab;

View File

@@ -752,7 +752,7 @@ void *gpu_buffer_unpack(JSContext *js, SDL_GPUDevice *device, JSValue buffer, si
{
size_t o, len, bytes, msize;
JSValue buf = JS_GetTypedArrayBuffer(js, buffer, &o, &len, &bytes);
void *data = JS_GetArrayBuffer(js, &msize, buf);
void *data = js_get_blob_data(js, &msize, buf);
JS_FreeValue(js,buf);
if (size) *size = msize;
if (send_gpu) {
@@ -1494,7 +1494,7 @@ static JSValue js_gpu_make_shader(JSContext *js, JSValueConst self, int argc, JS
// code
JSValue code_val = JS_GetPropertyStr(js, obj, "code");
size_t code_size;
void *code_data = JS_GetArrayBuffer(js, &code_size, code_val);
void *code_data = js_get_blob_data(js, &code_size, code_val);
JS_FreeValue(js, code_val);
if (!code_data)
return JS_ThrowTypeError(js, "shader.code must be an ArrayBuffer");
@@ -1709,7 +1709,7 @@ JSC_CCALL(gpu_compute_pipeline,
JSValue shader = JS_GetPropertyStr(js,pipe,"shader");
info.code = JS_GetArrayBuffer(js,&info.code_size, shader);
info.code = js_get_blob_data(js,&info.code_size, shader);
JS_FreeValue(js,shader);
SDL_GPUComputePipeline *pipeline = SDL_CreateGPUComputePipeline(gpu, &info);
@@ -1941,7 +1941,7 @@ JSC_CCALL(cmd_push_vertex_uniform_data,
int slot;
JS_ToInt32(js, &slot, argv[0]);
size_t buf_size;
void *data = JS_GetArrayBuffer(js, &buf_size, argv[1]);
void *data = js_get_blob_data(js, &buf_size, argv[1]);
SDL_PushGPUVertexUniformData(cmds, slot, data, buf_size);
)
@@ -1950,7 +1950,7 @@ JSC_CCALL(cmd_push_fragment_uniform_data,
int slot;
JS_ToInt32(js, &slot, argv[0]);
size_t buf_size;
void *data = JS_GetArrayBuffer(js, &buf_size, argv[1]);
void *data = js_get_blob_data(js, &buf_size, argv[1]);
SDL_PushGPUFragmentUniformData(cmds, slot, data, buf_size);
)
@@ -1959,7 +1959,7 @@ JSC_CCALL(cmd_push_compute_uniform_data,
int slot;
JS_ToInt32(js, &slot, argv[0]);
size_t buf_size;
void *data = JS_GetArrayBuffer(js, &buf_size, argv[1]);
void *data = js_get_blob_data(js, &buf_size, argv[1]);
SDL_PushGPUComputeUniformData(cmds, slot, data, buf_size);
)
@@ -2183,7 +2183,7 @@ JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int el
{
JSValue tstack[2];
if (copy) {
tstack[0] = JS_NewArrayBufferCopy(js,data,size);//, make_gpu_buffer, NULL, 1);
tstack[0] = js_new_blob_stoned_copy(js,data,size);//, make_gpu_buffer, NULL, 1);
} else {
tstack[0] = JS_NewArrayBuffer(js,data,size,free_gpu_buffer, NULL, 0);
}
@@ -2211,7 +2211,7 @@ void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size)
}
JSValue buffer = JS_GetPropertyStr(js,argv,"buffer");
void *data = JS_GetArrayBuffer(js,NULL,buffer);
void *data = js_get_blob_data(js,NULL,buffer);
JS_FreeValue(js,buffer);
JSValue typeval = JS_GetPropertyStr(js,argv,"type");

View File

@@ -1,20 +1,29 @@
#include "qjs_sdl_surface.h"
#include "qjs_macros.h"
#include "jsffi.h"
#include "qjs_common.h"
#include "qjs_sdl.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_surface.h>
#include "prosperon.h"
#include <string.h>
// Helper functions from jsffi.c that need to be declared
extern JSValue number2js(JSContext *js, double g);
extern double js2number(JSContext *js, JSValue v);
extern rect js2rect(JSContext *js, JSValue v);
extern irect js2irect(JSContext *js, JSValue v);
extern colorf js2color(JSContext *js, JSValue v);
extern HMM_Vec2 js2vec2(JSContext *js, JSValue v);
extern SDL_PixelFormat str2pixelformat(const char *str);
extern const char *pixelformat2str(SDL_PixelFormat fmt);
JSValue pixelformat2js(JSContext *js, SDL_PixelFormat fmt)
{
const char *str = pixelformat2str(fmt);
return JS_NewString(js, str);
}
SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v)
static SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v)
{
if (JS_IsUndefined(v)) return SDL_PIXELFORMAT_UNKNOWN;
const char *s = JS_ToCString(js, v);
@@ -25,17 +34,6 @@ SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v)
return fmt;
}
SDL_Colorspace js2colorspace(JSContext *js, JSValue v)
{
if (JS_IsUndefined(v)) return SDL_COLORSPACE_UNKNOWN;
const char *s = JS_ToCString(js, v);
if (!s) return SDL_COLORSPACE_UNKNOWN;
SDL_Colorspace cs = str2colorspace(s);
JS_FreeCString(js,s);
return cs;
}
typedef struct { const char *name; SDL_ScaleMode mode; } scale_entry;
static const scale_entry k_scale_table[] = {
@@ -44,7 +42,7 @@ static const scale_entry k_scale_table[] = {
{ NULL, SDL_SCALEMODE_LINEAR } /* fallback */
};
JSValue SDL_ScaleMode2js(JSContext *js, SDL_ScaleMode mode){
static JSValue scalemode2js(JSContext *js, SDL_ScaleMode mode){
const scale_entry *it;
for(it = k_scale_table; it->name; ++it)
if(it->mode == mode) break;
@@ -142,18 +140,7 @@ JSC_CCALL(surface_rect,
JSC_CCALL(surface_convert,
SDL_Surface *surf = js2SDL_Surface(js,self);
SDL_PixelFormat fmt = js2pixelformat(js, argv[0]);
SDL_Surface *dst;
if (argc > 1 && !JS_IsUndefined(argv[1])) {
// Colorspace provided, use SDL_ConvertSurfaceAndColorspace
SDL_Colorspace colorspace = js2colorspace(js, argv[1]);
SDL_PropertiesID props = 0; // No additional properties needed
dst = SDL_ConvertSurfaceAndColorspace(surf, fmt, NULL, colorspace, props);
} else {
// No colorspace, use regular convert
dst = SDL_ConvertSurface(surf, fmt);
}
SDL_Surface *dst = SDL_ConvertSurface(surf, fmt);
if (!dst) return JS_ThrowInternalError(js, "Convert failed: %s", SDL_GetError());
return SDL_Surface2js(js, dst);
@@ -168,32 +155,25 @@ JSC_CCALL(surface_dup,
return SDL_Surface2js(js,conv);
)
void *surface_pixel_dup(SDL_Surface *surf, size_t *size)
{
int locked = 0;
if (SDL_MUSTLOCK(surf))
if (SDL_LockSurface(surf) < 0)
return NULL;
if (surf->format == SDL_PIXELFORMAT_NV12) {
*size = surf->pitch * (surf->h*3.0/2.0);
} else
*size = (size_t)surf->pitch * surf->h;
void *data = malloc(*size);
memcpy(data, surf->pixels, *size);
if (locked) SDL_UnlockSurface(surf);
return data;
}
JSC_CCALL(surface_pixels,
SDL_Surface *surf = js2SDL_Surface(js, self);
size_t size;
void *data = surface_pixel_dup(surf, &size);
return JS_NewArrayBufferCopy(js, data, size);
int locked = 0;
if (SDL_MUSTLOCK(surf))
if (SDL_LockSurface(surf) < 0)
return JS_ThrowReferenceError(js, "Lock surface failed: %s", SDL_GetError());
size_t byte_size;
if (SDL_ISPIXELFORMAT_FOURCC(surf->format)) {
/* Planar/YUV formats: use BitsPerPixel to compute true size */
printf("FOURCC!!! Bits is %d\n", SDL_BYTESPERPIXEL(surf->format));
byte_size = (size_t)surf->pitch * surf->h * SDL_BYTESPERPIXEL(surf->format);
} else
byte_size = (size_t)surf->pitch * surf->h;
ret = js_new_blob_stoned_copy(js, surf->pixels, byte_size);
if (locked) SDL_UnlockSurface(surf);
)
JSC_CCALL(surface_get_width,
@@ -232,10 +212,25 @@ JSC_CCALL(surface_toJSON,
// Add pitch
JS_SetPropertyStr(js, obj, "pitch", JS_NewInt32(js, surf->pitch));
size_t size;
void *pixels = surface_pixel_dup(surf, &size);
// Lock surface if needed
int locked = 0;
if (SDL_MUSTLOCK(surf)) {
if (SDL_LockSurface(surf) < 0) {
JS_FreeValue(js, obj);
return JS_ThrowInternalError(js, "Lock surface failed: %s", SDL_GetError());
}
locked = 1;
}
// Add pixels as ArrayBuffer
size_t byte_size = surf->pitch * surf->h;
JSValue pixels = js_new_blob_stoned_copy(js, surf->pixels, byte_size);
JS_SetPropertyStr(js, obj, "pixels", pixels);
// Unlock if we locked
if (locked)
SDL_UnlockSurface(surf);
JS_SetPropertyStr(js, obj, "pixels", JS_NewArrayBufferCopy(js, pixels, size));
return obj;
)
@@ -265,7 +260,7 @@ JSC_CCALL(surface_constructor,
if (!JS_IsUndefined(pixels_val)) {
// Create surface from pixel data
size_t len;
void *raw = JS_GetArrayBuffer(js, &len, pixels_val);
void *raw = js_get_blob_data(js, &len, pixels_val);
if (!raw) {
JS_FreeValue(js, pixels_val);
@@ -318,7 +313,7 @@ static const JSCFunctionListEntry js_SDL_Surface_funcs[] = {
MIST_FUNC_DEF(surface, rect,2),
MIST_FUNC_DEF(surface, dup, 0),
MIST_FUNC_DEF(surface, pixels, 0),
MIST_FUNC_DEF(surface, convert, 2),
MIST_FUNC_DEF(surface, convert, 1),
MIST_FUNC_DEF(surface, toJSON, 0),
JS_CGETSET_DEF("width", js_surface_get_width, NULL),
JS_CGETSET_DEF("height", js_surface_get_height, NULL),

View File

@@ -1,9 +1,7 @@
#include "qjs_sdl_video.h"
#include "jsffi.h"
#include "qjs_macros.h"
#include "qjs_common.h"
#include "qjs_sdl_surface.h"
#include "qjs_sdl.h"
#include "qjs_actor.h"
#include "prosperon.h"
#include "sprite.h"
@@ -53,6 +51,31 @@ void SDL_Cursor_free(JSRuntime *rt, SDL_Cursor *c)
QJSCLASS(SDL_Cursor,)
// External function declarations
extern JSValue rect2js(JSContext *js, rect r);
extern rect js2rect(JSContext *js, JSValue v);
extern HMM_Vec2 js2vec2(JSContext *js, JSValue v);
extern JSValue vec22js(JSContext *js, HMM_Vec2 v);
extern colorf js2color(JSContext *js, JSValue v);
extern double js2number(JSContext *js, JSValue v);
extern JSValue number2js(JSContext *js, double n);
extern SDL_Texture *js2SDL_Texture(JSContext *js, JSValue v);
extern JSValue SDL_Texture2js(JSContext *js, SDL_Texture *t);
extern SDL_Window *js2SDL_Window(JSContext *js, JSValue v);
extern JSValue SDL_Window2js(JSContext *js, SDL_Window *w);
extern SDL_Renderer *js2SDL_Renderer(JSContext *js, JSValue v);
extern JSValue SDL_Renderer2js(JSContext *js, SDL_Renderer *r);
extern void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size);
extern double js_getnum_str(JSContext *js, JSValue v, const char *str);
extern sprite *js2sprite(JSContext *js, JSValue v);
extern HMM_Vec3 js2vec3(JSContext *js, JSValue v);
extern JSValue vec32js(JSContext *js, HMM_Vec3 v);
extern HMM_Vec4 js2vec4(JSContext *js, JSValue v);
extern JSValue vec42js(JSContext *js, HMM_Vec4 v);
extern JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int elements, int copy, int index);
extern JSValue make_quad_indices_buffer(JSContext *js, int quads);
extern JSClassID js_SDL_Surface_id;
// Forward declarations for blend mode helpers
static JSValue blendmode2js(JSContext *js, SDL_BlendMode mode);
static SDL_BlendMode js2blendmode(JSContext *js, JSValue v);
@@ -1397,6 +1420,8 @@ static const JSCFunctionListEntry js_SDL_Renderer_funcs[] = {
JS_CGETSET_DEF("safeArea", js_renderer_get_safeArea, NULL),
};
extern SDL_ScaleMode js2SDL_ScaleMode(JSContext *js, JSValue v);
// Blend mode helper
static JSValue blendmode2js(JSContext *js, SDL_BlendMode mode) {
switch(mode) {
@@ -1430,6 +1455,26 @@ static SDL_BlendMode js2blendmode(JSContext *js, JSValue v) {
return mode;
}
// Convert pixel format string to SDL_PixelFormat
static SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v) {
if (JS_IsNumber(v)) {
return js2number(js, v);
}
const char *str = JS_ToCString(js, v);
SDL_PixelFormat fmt = SDL_PIXELFORMAT_RGBA8888;
if (str) {
if (strcmp(str, "rgba8888") == 0) fmt = SDL_PIXELFORMAT_RGBA8888;
else if (strcmp(str, "bgra8888") == 0) fmt = SDL_PIXELFORMAT_BGRA8888;
else if (strcmp(str, "argb8888") == 0) fmt = SDL_PIXELFORMAT_ARGB8888;
else if (strcmp(str, "abgr8888") == 0) fmt = SDL_PIXELFORMAT_ABGR8888;
else if (strcmp(str, "rgba32") == 0) fmt = SDL_PIXELFORMAT_RGBA32;
else if (strcmp(str, "bgra32") == 0) fmt = SDL_PIXELFORMAT_BGRA32;
else if (strcmp(str, "argb32") == 0) fmt = SDL_PIXELFORMAT_ARGB32;
else if (strcmp(str, "abgr32") == 0) fmt = SDL_PIXELFORMAT_ABGR32;
JS_FreeCString(js, str);
}
return fmt;
}
// Texture constructor
static JSValue js_texture_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv)
@@ -1468,7 +1513,7 @@ static JSValue js_texture_constructor(JSContext *js, JSValueConst new_target, in
if (!JS_IsUndefined(pixels_val)) {
// Create surface first, then texture
size_t size;
uint8_t *pixels = JS_GetArrayBuffer(js, &size, pixels_val);
uint8_t *pixels = js_get_blob_data(js, &size, pixels_val);
if (!pixels) {
JS_FreeValue(js, pixels_val);
@@ -1638,7 +1683,7 @@ JSC_CCALL(texture_update,
if (argc >= 2) {
size_t size;
pixels = JS_GetArrayBuffer(js, &size, argv[1]);
pixels = js_get_blob_data(js, &size, argv[1]);
if (!pixels)
return JS_ThrowTypeError(js, "Second argument must be an ArrayBuffer");
}
@@ -1666,17 +1711,6 @@ JSC_CCALL(texture_lock,
(lock_rect.w > 0 && lock_rect.h > 0) ? &lock_rect : NULL,
&pixels, &pitch))
return JS_ThrowReferenceError(js, "Failed to lock texture: %s", SDL_GetError());
// Create ArrayBuffer view of the locked pixels
float w, h;
SDL_GetTextureSize(tex, &w, &h);
int height = lock_rect.h > 0 ? lock_rect.h : (int)h;
size_t buffer_size = pitch * height;
ret = JS_NewObject(js);
JS_SetPropertyStr(js, ret, "pixels", JS_NewArrayBuffer(js, pixels, buffer_size, NULL, NULL, 0));
JS_SetPropertyStr(js, ret, "pitch", number2js(js, pitch));
return ret;
)
// Unlock texture
@@ -1735,245 +1769,6 @@ JSC_CCALL(sdl_createWindowAndRenderer,
return ret;
)
// Mouse functions that must run on main thread
JSC_CCALL(mouse_show,
if (JS_ToBool(js,argv[0]))
SDL_ShowCursor();
else
SDL_HideCursor();
)
JSC_CCALL(mouse_capture,
SDL_CaptureMouse(JS_ToBool(js,argv[0]));
)
JSC_CCALL(mouse_get_state,
float x,y;
SDL_MouseButtonFlags flags = SDL_GetMouseState(&x,&y);
JSValue m = JS_NewObject(js);
JS_SetPropertyStr(js,m,"x", number2js(js,x));
JS_SetPropertyStr(js,m,"y", number2js(js,y));
if (flags & SDL_BUTTON_LMASK)
JS_SetPropertyStr(js, m, "left", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_MMASK)
JS_SetPropertyStr(js, m, "middle", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_RMASK)
JS_SetPropertyStr(js, m, "right", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X1MASK)
JS_SetPropertyStr(js, m, "x1", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X2MASK)
JS_SetPropertyStr(js, m, "x2", JS_NewBool(js, 1));
return m;
)
JSC_CCALL(mouse_get_global_state,
float x,y;
SDL_MouseButtonFlags flags = SDL_GetGlobalMouseState(&x,&y);
JSValue m = JS_NewObject(js);
JS_SetPropertyStr(js,m,"x", number2js(js,x));
JS_SetPropertyStr(js,m,"y", number2js(js,y));
if (flags & SDL_BUTTON_LMASK)
JS_SetPropertyStr(js, m, "left", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_MMASK)
JS_SetPropertyStr(js, m, "middle", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_RMASK)
JS_SetPropertyStr(js, m, "right", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X1MASK)
JS_SetPropertyStr(js, m, "x1", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X2MASK)
JS_SetPropertyStr(js, m, "x2", JS_NewBool(js, 1));
return m;
)
JSC_CCALL(mouse_get_relative_state,
float x,y;
SDL_MouseButtonFlags flags = SDL_GetRelativeMouseState(&x,&y);
JSValue m = JS_NewObject(js);
JS_SetPropertyStr(js,m,"x", number2js(js,x));
JS_SetPropertyStr(js,m,"y", number2js(js,y));
if (flags & SDL_BUTTON_LMASK)
JS_SetPropertyStr(js, m, "left", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_MMASK)
JS_SetPropertyStr(js, m, "middle", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_RMASK)
JS_SetPropertyStr(js, m, "right", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X1MASK)
JS_SetPropertyStr(js, m, "x1", JS_NewBool(js, 1));
if (flags & SDL_BUTTON_X2MASK)
JS_SetPropertyStr(js, m, "x2", JS_NewBool(js, 1));
return m;
)
JSC_CCALL(mouse_warp_global,
HMM_Vec2 pos = js2vec2(js, argv[0]);
SDL_WarpMouseGlobal(pos.x, pos.y);
)
JSC_CCALL(mouse_warp_in_window,
SDL_Window *window = js2SDL_Window(js, argv[0]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
HMM_Vec2 pos = js2vec2(js, argv[1]);
SDL_WarpMouseInWindow(window, pos.x, pos.y);
)
JSC_CCALL(mouse_cursor_visible,
return JS_NewBool(js, SDL_CursorVisible());
)
JSC_CCALL(mouse_get_cursor,
SDL_Cursor *cursor = SDL_GetCursor();
if (!cursor) return JS_NULL;
return SDL_Cursor2js(js, cursor);
)
JSC_CCALL(mouse_get_default_cursor,
SDL_Cursor *cursor = SDL_GetDefaultCursor();
if (!cursor) return JS_NULL;
return SDL_Cursor2js(js, cursor);
)
JSC_CCALL(mouse_create_system_cursor,
int id = js2number(js, argv[0]);
SDL_Cursor *cursor = SDL_CreateSystemCursor(id);
if (!cursor) return JS_ThrowReferenceError(js, "Failed to create system cursor: %s", SDL_GetError());
return SDL_Cursor2js(js, cursor);
)
JSC_CCALL(mouse_get_focus,
SDL_Window *window = SDL_GetMouseFocus();
if (!window) return JS_NULL;
return SDL_Window2js(js, window);
)
static const JSCFunctionListEntry js_mouse_funcs[] = {
MIST_FUNC_DEF(mouse, show, 1),
MIST_FUNC_DEF(mouse, capture, 1),
MIST_FUNC_DEF(mouse, get_state, 0),
MIST_FUNC_DEF(mouse, get_global_state, 0),
MIST_FUNC_DEF(mouse, get_relative_state, 0),
MIST_FUNC_DEF(mouse, warp_global, 1),
MIST_FUNC_DEF(mouse, warp_in_window, 2),
MIST_FUNC_DEF(mouse, cursor_visible, 0),
MIST_FUNC_DEF(mouse, get_cursor, 0),
MIST_FUNC_DEF(mouse, get_default_cursor, 0),
MIST_FUNC_DEF(mouse, create_system_cursor, 1),
MIST_FUNC_DEF(mouse, get_focus, 0),
};
// Keyboard functions that must run on main thread
JSC_CCALL(keyboard_get_state,
int numkeys;
const bool *keystate = SDL_GetKeyboardState(&numkeys);
JSValue arr = JS_NewArray(js);
for (int i = 0; i < numkeys; i++) {
JS_SetPropertyUint32(js, arr, i, JS_NewBool(js, keystate[i]));
}
return arr;
)
JSC_CCALL(keyboard_get_focus,
SDL_Window *window = SDL_GetKeyboardFocus();
if (!window) return JS_NULL;
return SDL_Window2js(js, window);
)
JSC_CCALL(keyboard_start_text_input,
SDL_Window *window = NULL;
if (argc > 0 && !JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0])) {
window = js2SDL_Window(js, argv[0]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
}
SDL_StartTextInput(window);
)
JSC_CCALL(keyboard_stop_text_input,
SDL_Window *window = NULL;
if (argc > 0 && !JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0])) {
window = js2SDL_Window(js, argv[0]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
}
SDL_StopTextInput(window);
)
JSC_CCALL(keyboard_text_input_active,
SDL_Window *window = NULL;
if (argc > 0 && !JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0])) {
window = js2SDL_Window(js, argv[0]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
}
return JS_NewBool(js, SDL_TextInputActive(window));
)
JSC_CCALL(keyboard_get_text_input_area,
SDL_Window *window = NULL;
if (argc > 0 && !JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0])) {
window = js2SDL_Window(js, argv[0]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
}
SDL_Rect rect;
int cursor;
if (!SDL_GetTextInputArea(window, &rect, &cursor))
return JS_ThrowReferenceError(js, "Failed to get text input area: %s", SDL_GetError());
JSValue obj = JS_NewObject(js);
SDL_FRect frect;
SDL_RectToFRect(&rect, &frect);
JS_SetPropertyStr(js, obj, "rect", rect2js(js, frect));
JS_SetPropertyStr(js, obj, "cursor", JS_NewInt32(js, cursor));
return obj;
)
JSC_CCALL(keyboard_set_text_input_area,
SDL_Window *window = NULL;
rect r = js2rect(js, argv[0]);
int cursor = argc > 1 ? js2number(js, argv[1]) : 0;
if (argc > 2 && !JS_IsNull(argv[2]) && !JS_IsUndefined(argv[2])) {
window = js2SDL_Window(js, argv[2]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
}
if (!SDL_SetTextInputArea(window, &r, cursor))
return JS_ThrowReferenceError(js, "Failed to set text input area: %s", SDL_GetError());
)
JSC_CCALL(keyboard_clear_composition,
SDL_Window *window = NULL;
if (argc > 0 && !JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0])) {
window = js2SDL_Window(js, argv[0]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
}
if (!SDL_ClearComposition(window))
return JS_ThrowReferenceError(js, "Failed to clear composition: %s", SDL_GetError());
)
JSC_CCALL(keyboard_screen_keyboard_shown,
SDL_Window *window = js2SDL_Window(js, argv[0]);
if (!window) return JS_ThrowReferenceError(js, "Invalid window");
return JS_NewBool(js, SDL_ScreenKeyboardShown(window));
)
JSC_CCALL(keyboard_reset,
SDL_ResetKeyboard();
)
static const JSCFunctionListEntry js_keyboard_funcs[] = {
MIST_FUNC_DEF(keyboard, get_state, 0),
MIST_FUNC_DEF(keyboard, get_focus, 0),
MIST_FUNC_DEF(keyboard, start_text_input, 1),
MIST_FUNC_DEF(keyboard, stop_text_input, 1),
MIST_FUNC_DEF(keyboard, text_input_active, 1),
MIST_FUNC_DEF(keyboard, get_text_input_area, 1),
MIST_FUNC_DEF(keyboard, set_text_input_area, 3),
MIST_FUNC_DEF(keyboard, clear_composition, 1),
MIST_FUNC_DEF(keyboard, screen_keyboard_shown, 1),
MIST_FUNC_DEF(keyboard, reset, 0),
};
// Hook function to set up endowments for the video actor
static void video_actor_hook(JSContext *js) {
// Get prosperon object
@@ -2021,16 +1816,6 @@ static void video_actor_hook(JSContext *js) {
JS_SetPropertyStr(js, endowments, "setCursor",
JS_NewCFunction(js, js_sdl_set_cursor, "setCursor", 1));
// Create mouse module
JSValue mouse_mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mouse_mod, js_mouse_funcs, countof(js_mouse_funcs));
JS_SetPropertyStr(js, endowments, "mouse", mouse_mod);
// Create keyboard module
JSValue keyboard_mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, keyboard_mod, js_keyboard_funcs, countof(js_keyboard_funcs));
JS_SetPropertyStr(js, endowments, "keyboard", keyboard_mod);
JS_FreeValue(js, endowments);
JS_FreeValue(js, prosperon);
}

View File

@@ -2,6 +2,7 @@
#include "soloud_c.h"
#include "quickjs.h"
#include <stdlib.h>
#include "prosperon.h"
#define countof(x) (sizeof(x)/sizeof((x)[0]))
@@ -97,14 +98,14 @@ static JSValue js_soloud_mix(JSContext *js, JSValue self, int argc, JSValue *arg
JS_ToInt32(js, &req, argv[0]);
float *buf = malloc(2*req*sizeof(float));
Soloud_mix(soloud, buf, req);
return JS_NewArrayBufferCopy(js, buf, 2*req*sizeof(float));
return js_new_blob_stoned_copy(js, buf, 2*req*sizeof(float));
}
// Create a voice from a WAV file
static JSValue js_load_wav_mem(JSContext *js, JSValue self, int argc, JSValue *argv)
{
size_t len;
void *data = JS_GetArrayBuffer(js, &len, argv[0]);
void *data = js_get_blob_data(js, &len, argv[0]);
Wav *wav = Wav_create();
if (Wav_loadMemEx(wav, data, len, 1, 1)) {
Wav_destroy(wav);
@@ -117,7 +118,7 @@ static JSValue js_load_wav_mem(JSContext *js, JSValue self, int argc, JSValue *a
static JSValue js_load_pwm(JSContext *js, JSValue self, int argc, JSValue *argv)
{
size_t len;
void *data = JS_GetArrayBuffer(js, &len, argv[0]);
void *data = js_get_blob_data(js, &len, argv[0]);
Wav *wav = Wav_create();
Wav_loadRawWaveEx(wav, data, len, js2number(js,argv[1]), js2number(js,argv[2]), 1, 1);
return Wav2js(js, wav);

View File

@@ -342,7 +342,7 @@ JSC_CCALL(cloud_write,
}
data = (uint8_t*)str;
} else {
data = JS_GetArrayBuffer(js, &data_len, argv[1]);
data = js_get_blob_data(js, &data_len, argv[1]);
if (!data) {
JS_FreeCString(js, filename);
return JS_ThrowTypeError(js, "Second argument must be string or ArrayBuffer");
@@ -385,7 +385,7 @@ JSC_CCALL(cloud_read,
return JS_UNDEFINED;
}
JSValue result = JS_NewArrayBufferCopy(js, buffer, size);
JSValue result = js_new_blob_stoned_copy(js, buffer, size);
js_free(js, buffer);
return result;
)

View File

@@ -1,6 +1,7 @@
#include "quickjs.h"
#include "wota.h"
#include <stdlib.h>
#include "prosperon.h"
typedef struct WotaEncodeContext {
JSContext *ctx;
@@ -126,9 +127,9 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC
wota_write_sym(&enc->wb, WOTA_NULL);
break;
case JS_TAG_OBJECT: {
if (JS_IsArrayBuffer(ctx, replaced)) {
if (js_is_blob(ctx, replaced)) {
size_t buf_len;
void *buf_data = JS_GetArrayBuffer(ctx, &buf_len, replaced);
void *buf_data = js_get_blob_data(ctx, &buf_len, replaced);
wota_write_blob(&enc->wb, (unsigned long long)buf_len * 8, (const char *)buf_data);
break;
}
@@ -209,7 +210,7 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val,
long long blen;
char *bdata = NULL;
data_ptr = wota_read_blob(&blen, &bdata, data_ptr);
*out_val = bdata ? JS_NewArrayBufferCopy(ctx, (uint8_t *)bdata, (size_t)blen) : JS_NewArrayBufferCopy(ctx, NULL, 0);
*out_val = bdata ? js_new_blob_stoned_copy(ctx, (uint8_t *)bdata, (size_t)blen) : js_new_blob_stoned_copy(ctx, NULL, 0);
if (bdata) free(bdata);
break;
}
@@ -316,7 +317,7 @@ static JSValue js_wota_encode(JSContext *ctx, JSValueConst this_val, int argc, J
}
JS_FreeValue(ctx, enc->visited_stack);
size_t total_bytes = enc->wb.size * sizeof(uint64_t);
JSValue ret = JS_NewArrayBufferCopy(ctx, (uint8_t *)enc->wb.data, total_bytes);
JSValue ret = js_new_blob_stoned_copy(ctx, (uint8_t *)enc->wb.data, total_bytes);
wota_buffer_free(&enc->wb);
return ret;
}
@@ -325,7 +326,7 @@ static JSValue js_wota_decode(JSContext *ctx, JSValueConst this_val, int argc, J
{
if (argc < 1) return JS_UNDEFINED;
size_t len;
uint8_t *buf = JS_GetArrayBuffer(ctx, &len, argv[0]);
uint8_t *buf = js_get_blob_data(ctx, &len, argv[0]);
if (!buf) return JS_UNDEFINED;
JSValue reviver = (argc > 1 && JS_IsFunction(ctx, argv[1])) ? argv[1] : JS_UNDEFINED;
char *data_ptr = (char *)buf;