From 693087afaecee75f530ddc32f6d3e69c18fc99c9 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 22 May 2025 15:42:45 -0500 Subject: [PATCH] move rtree to its own module --- meson.build | 2 +- scripts/modules/graphics.js | 5 - source/jsffi.c | 185 +-------------------------------- source/qjs_macros.h | 2 +- source/qjs_rtree.c | 201 ++++++++++++++++++++++++++++++++++++ source/qjs_rtree.h | 8 ++ 6 files changed, 213 insertions(+), 190 deletions(-) create mode 100644 source/qjs_rtree.c create mode 100644 source/qjs_rtree.h diff --git a/meson.build b/meson.build index cdd643e3..29f7f6c1 100644 --- a/meson.build +++ b/meson.build @@ -148,7 +148,7 @@ src += [ 'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c', 'render.c','simplex.c','spline.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_os.c', - 'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c' + 'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c' ] # quirc src src += [ diff --git a/scripts/modules/graphics.js b/scripts/modules/graphics.js index 463473db..021401d3 100644 --- a/scripts/modules/graphics.js +++ b/scripts/modules/graphics.js @@ -377,11 +377,6 @@ graphics.rectpack[prosperon.DOC] = ` Perform a rectangle packing using the stbrp library. Return positions for each rect. ` -graphics.make_rtree[prosperon.DOC] = ` -:return: An R-Tree object for quickly querying many rectangles or sprite bounds. -Create a new R-Tree for geometry queries. -` - graphics.make_texture[prosperon.DOC] = ` :param data: Raw image bytes (PNG, JPG, etc.) as an ArrayBuffer. :return: An SDL_Surface object representing the decoded image in RAM, for use with GPU or software rendering. diff --git a/source/jsffi.c b/source/jsffi.c index efd1d428..57415f0d 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -44,6 +44,7 @@ #include "qjs_io.h" #include "qjs_sdl_gpu.h" #include "qjs_os.h" +#include "qjs_rtree.h" SDL_Window *global_window; @@ -67,10 +68,6 @@ void gui_input(SDL_Event *e); #include "sprite.h" -#include "rtree.h" - -typedef struct rtree rtree; - #include #include #include @@ -439,12 +436,6 @@ QJSCLASS(SDL_Surface, JS_SetProperty(js,j,height_atom,number2js(js,n->h)); ) -void rtree_free(JSRuntime *rt, rtree *tree) -{ - rtree_destroy(tree); -} - -QJSCLASS(rtree,) JSValue angle2js(JSContext *js,double g) { return number2js(js,g*HMM_RadToTurn); @@ -1958,8 +1949,6 @@ static const JSCFunctionListEntry js_console_funcs[] = { MIST_FUNC_DEF(console,print,1), }; - - JSC_CCALL(debug_stack_depth, return number2js(js,js_debugger_stack_depth(js))) JSC_CCALL(debug_build_backtrace, return js_debugger_build_backtrace(js,NULL)) JSC_CCALL(debug_closure_vars, return js_debugger_closure_variables(js,argv[0])) @@ -2469,11 +2458,6 @@ JSC_CCALL(os_cull_sprites, } ) -JSC_CCALL(os_make_rtree, - struct rtree *tree = rtree_new(); - if (!tree) return JS_ThrowOutOfMemory(js); - return rtree2js(js,tree); -) JSC_CCALL(os_on, prosperon_rt *rt = JS_GetContextOpaque(js); @@ -3198,7 +3182,6 @@ static const JSCFunctionListEntry js_graphics_funcs[] = { MIST_FUNC_DEF(gpu, make_sprite_queue, 4), MIST_FUNC_DEF(os, make_text_buffer, 6), MIST_FUNC_DEF(os, rectpack, 3), - MIST_FUNC_DEF(os, make_rtree, 0), MIST_FUNC_DEF(os, make_texture, 1), MIST_FUNC_DEF(os, make_gif, 1), MIST_FUNC_DEF(os, make_aseprite, 1), @@ -3248,170 +3231,6 @@ JSC_SCALL(os_use_dyn, SDL_UnloadObject(ptr); ) -JSC_CCALL(rtree_add, - rtree *tree = js2rtree(js,self); - JSValue v = argv[0]; - rect r; - JS_GETATOM(js,r,v,rect,rect) - NUMTYPE min[3]; - NUMTYPE max[3]; - min[0] = r.x; - min[1] = r.y; - min[2] = 0; - max[0] = r.x+r.w; - max[1] = r.y+r.h; - max[2] = 0; - JSValue *ins = malloc(sizeof(*ins)); - *ins = JS_DupValue(js,v); - if (!rtree_insert(tree, min, max, ins)) { - JS_FreeValue(js,*ins); - return JS_ThrowOutOfMemory(js); - } -) - -int rtree_cmp(const JSValue *a, const JSValue *b, JSContext *js) -{ - int same = JS_SameValue(js, *a, *b); - if (same) - JS_FreeValue(js,*a); - - return !same; -} - -JSC_CCALL(rtree_delete, - rtree *tree = js2rtree(js,self); - JSValue v = argv[0]; - rect r; - JS_GETATOM(js,r,v,rect,rect) - NUMTYPE min[3]; - NUMTYPE max[3]; - min[0] = r.x; - min[1] = r.y; - min[2] = 0; - max[0] = r.x+r.w; - max[1] = r.y+r.h; - max[2] = 0; - - if (!rtree_delete_with_comparator(tree, min, max, &v, rtree_cmp, js)) - return JS_ThrowOutOfMemory(js); -) - -struct rtree_iter_data { - JSContext *js; - JSValue arr; - int n; -}; - -bool rtree_iter(const NUMTYPE *min, const NUMTYPE *max, const JSValue *data, struct rtree_iter_data *ctx) -{ - JS_SetPropertyUint32(ctx->js,ctx->arr,ctx->n, JS_DupValue(ctx->js,*data)); - ctx->n++; - return 1; -} - -JSC_CCALL(rtree_query, - rtree *tree = js2rtree(js,self); - rect r = js2rect(js,argv[0]); - NUMTYPE min[3]; - NUMTYPE max[3]; - min[0] = r.x; - min[1] = r.y; - min[2] = 0; - max[0] = r.x+r.w; - max[1] = r.y+r.h; - max[2] = 0; - - struct rtree_iter_data data = {0}; - data.js = js; - data.arr = JS_NewArray(js); - data.n = 0; - rtree_search(tree, min, max, rtree_iter, &data); - ret = data.arr; -) - -struct rtree_each -{ - JSValue fn; - JSContext *js; -}; - -int rtree_foreach(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, struct rtree_each *each) -{ - JSValue ret = JS_Call(each->js, each->fn, JS_UNDEFINED, 0, NULL); - uncaught_exception(each->js, ret); - return 1; -} - -JSC_CCALL(rtree_forEach, - rtree *tree = js2rtree(js,self); - struct rtree_each each; - each.fn = JS_DupValue(js,argv[0]); - each.js = js; - - rtree_scan(tree, rtree_foreach, &each); - JS_FreeValue(js,each.fn); -) - -typedef struct { - JSContext *js; - JSValue v; - int has; -} rtree_has; - -int rtree_hasfn(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, rtree_has *has) -{ - if (JS_SameValue(has->js, has->v, *value)) { - has->has = 1; - return 0; - } - return 1; -} - -JSC_CCALL(rtree_has, - rtree *tree = js2rtree(js,self); - rtree_has has; - has.js = js; - has.v = JS_DupValue(js,argv[0]); - has.has = 0; - rtree_scan(tree, rtree_hasfn, &has); - JS_FreeValue(js,argv[0]); - return JS_NewBool(js,has.has); -) - -JSValue js_rtree_get_size(JSContext *js, JSValue self, int magic) -{ - rtree *tree = js2rtree(js,self); - return number2js(js,rtree_count(tree)); -} - -int rtree_valuefn(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, struct rtree_iter_data *data) -{ - JS_SetPropertyUint32(data->js, data->arr, data->n, JS_DupValue(data->js, *value)); - data->n++; - return 1; -} - -JSC_CCALL(rtree_values, - rtree *tree = js2rtree(js,self); - struct rtree_iter_data data = {0}; - data.js = js; - data.arr = JS_NewArray(js); - data.n = 0; - rtree_scan(tree, rtree_valuefn, &data); - - ret = data.arr; -) - -static const JSCFunctionListEntry js_rtree_funcs[] = { - MIST_FUNC_DEF(rtree, add, 1), - MIST_FUNC_DEF(rtree, delete, 1), - MIST_FUNC_DEF(rtree, query, 1), - JS_CGETSET_DEF("size", js_rtree_get_size,NULL), - MIST_FUNC_DEF(rtree, forEach, 1), - MIST_FUNC_DEF(rtree, has, 1), - MIST_FUNC_DEF(rtree,values,0), -}; - #define JSSTATIC(NAME, PARENT) \ js_##NAME = JS_NewObject(js); \ @@ -3514,6 +3333,7 @@ void ffi_load(JSContext *js) arrput(rt->module_registry, MISTLINE(http)); arrput(rt->module_registry, ((ModuleEntry){"sdl_audio", js_sdl_audio_use})); arrput(rt->module_registry, MISTLINE(console)); + arrput(rt->module_registry, MISTLINE(rtree)); #ifdef TRACY_ENABLE arrput(rt->module_registry, MISTLINE(tracy)); @@ -3526,7 +3346,6 @@ void ffi_load(JSContext *js) JSValue c_types = JS_NewObject(js); JS_SetPropertyStr(js,prosp, "c_types", c_types); - QJSCLASSPREP_FUNCS(rtree) QJSCLASSPREP_FUNCS(SDL_Window) QJSCLASSPREP_FUNCS(SDL_Surface) QJSCLASSPREP_FUNCS(SDL_Texture) diff --git a/source/qjs_macros.h b/source/qjs_macros.h index a56dd958..e60302e2 100644 --- a/source/qjs_macros.h +++ b/source/qjs_macros.h @@ -180,7 +180,7 @@ JS_NewClassID(&js_##TYPE##_id);\ JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\ JSValue TYPE##_proto = JS_NewObject(js); \ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ -JS_SetPropertyStr(js, c_types, #TYPE, JS_DupValue(js,TYPE##_proto)); \ +//JS_SetPropertyStr(js, c_types, #TYPE, JS_DupValue(js,TYPE##_proto)); \ #define countof(x) (sizeof(x)/sizeof((x)[0])) diff --git a/source/qjs_rtree.c b/source/qjs_rtree.c new file mode 100644 index 00000000..3eafc4b4 --- /dev/null +++ b/source/qjs_rtree.c @@ -0,0 +1,201 @@ +#include "qjs_rtree.h" +#include "qjs_macros.h" +#include "jsffi.h" +#include "rtree.h" +#include "prosperon.h" +#include +#include + +// External declarations +typedef struct rtree rtree; + +void rtree_free(JSRuntime *rt, rtree *tree) +{ + rtree_destroy(tree); +} + +QJSCLASS(rtree,) + +JSC_CCALL(rtree_add, + rtree *tree = js2rtree(js,self); + JSValue v = argv[0]; + rect r; + JS_GETATOM(js,r,v,rect,rect) + NUMTYPE min[3]; + NUMTYPE max[3]; + min[0] = r.x; + min[1] = r.y; + min[2] = 0; + max[0] = r.x+r.w; + max[1] = r.y+r.h; + max[2] = 0; + JSValue *ins = malloc(sizeof(*ins)); + *ins = JS_DupValue(js,v); + if (!rtree_insert(tree, min, max, ins)) { + JS_FreeValue(js,*ins); + return JS_ThrowOutOfMemory(js); + } +) + +int rtree_cmp(const JSValue *a, const JSValue *b, JSContext *js) +{ + int same = JS_SameValue(js, *a, *b); + if (same) + JS_FreeValue(js,*a); + + return !same; +} + +JSC_CCALL(rtree_delete, + rtree *tree = js2rtree(js,self); + JSValue v = argv[0]; + rect r; + JS_GETATOM(js,r,v,rect,rect) + NUMTYPE min[3]; + NUMTYPE max[3]; + min[0] = r.x; + min[1] = r.y; + min[2] = 0; + max[0] = r.x+r.w; + max[1] = r.y+r.h; + max[2] = 0; + + if (!rtree_delete_with_comparator(tree, min, max, &v, rtree_cmp, js)) + return JS_ThrowOutOfMemory(js); +) + +struct rtree_iter_data { + JSContext *js; + JSValue arr; + int n; +}; + +bool rtree_iter(const NUMTYPE *min, const NUMTYPE *max, const JSValue *data, struct rtree_iter_data *ctx) +{ + JS_SetPropertyUint32(ctx->js,ctx->arr,ctx->n, JS_DupValue(ctx->js,*data)); + ctx->n++; + return 1; +} + +JSC_CCALL(rtree_query, + rtree *tree = js2rtree(js,self); + rect r = js2rect(js,argv[0]); + NUMTYPE min[3]; + NUMTYPE max[3]; + min[0] = r.x; + min[1] = r.y; + min[2] = 0; + max[0] = r.x+r.w; + max[1] = r.y+r.h; + max[2] = 0; + + struct rtree_iter_data data = {0}; + data.js = js; + data.arr = JS_NewArray(js); + data.n = 0; + rtree_search(tree, min, max, rtree_iter, &data); + ret = data.arr; +) + +struct rtree_each +{ + JSValue fn; + JSContext *js; +}; + +int rtree_foreach(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, struct rtree_each *each) +{ + JSValue ret = JS_Call(each->js, each->fn, JS_UNDEFINED, 0, NULL); + uncaught_exception(each->js, ret); + return 1; +} + +JSC_CCALL(rtree_forEach, + rtree *tree = js2rtree(js,self); + struct rtree_each each; + each.fn = JS_DupValue(js,argv[0]); + each.js = js; + + rtree_scan(tree, rtree_foreach, &each); + JS_FreeValue(js,each.fn); +) + +typedef struct { + JSContext *js; + JSValue v; + int has; +} rtree_has; + +int rtree_hasfn(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, rtree_has *has) +{ + if (JS_SameValue(has->js, has->v, *value)) { + has->has = 1; + return 0; + } + return 1; +} + +JSC_CCALL(rtree_has, + rtree *tree = js2rtree(js,self); + rtree_has has; + has.js = js; + has.v = JS_DupValue(js,argv[0]); + has.has = 0; + rtree_scan(tree, rtree_hasfn, &has); + JS_FreeValue(js,argv[0]); + return JS_NewBool(js,has.has); +) + +JSValue js_rtree_get_size(JSContext *js, JSValue self, int magic) +{ + rtree *tree = js2rtree(js,self); + return number2js(js,rtree_count(tree)); +} + +int rtree_valuefn(const NUMTYPE *min, const NUMTYPE *max, const JSValue *value, struct rtree_iter_data *data) +{ + JS_SetPropertyUint32(data->js, data->arr, data->n, JS_DupValue(data->js, *value)); + data->n++; + return 1; +} + +JSC_CCALL(rtree_values, + rtree *tree = js2rtree(js,self); + struct rtree_iter_data data = {0}; + data.js = js; + data.arr = JS_NewArray(js); + data.n = 0; + rtree_scan(tree, rtree_valuefn, &data); + + ret = data.arr; +) + +JSC_CCALL(os_make_rtree, + struct rtree *tree = rtree_new(); + if (!tree) return JS_ThrowOutOfMemory(js); + return rtree2js(js,tree); +) + +static const JSCFunctionListEntry js_rtree_funcs[] = { + MIST_FUNC_DEF(rtree, add, 1), + MIST_FUNC_DEF(rtree, delete, 1), + MIST_FUNC_DEF(rtree, query, 1), + JS_CGETSET_DEF("size", js_rtree_get_size,NULL), + MIST_FUNC_DEF(rtree, forEach, 1), + MIST_FUNC_DEF(rtree, has, 1), + MIST_FUNC_DEF(rtree,values,0), +}; + +static const JSCFunctionListEntry js_rtree_module_funcs[] = { + MIST_FUNC_DEF(os, make_rtree, 0), +}; + +JSValue js_rtree_use(JSContext *js) { + // Register the rtree class + QJSCLASSPREP_FUNCS(rtree); + + // Create and return the module object + JSValue mod = JS_NewObject(js); + JS_SetPropertyFunctionList(js, mod, js_rtree_module_funcs, countof(js_rtree_module_funcs)); + return mod; +} \ No newline at end of file diff --git a/source/qjs_rtree.h b/source/qjs_rtree.h new file mode 100644 index 00000000..3e7ece55 --- /dev/null +++ b/source/qjs_rtree.h @@ -0,0 +1,8 @@ +#ifndef QJS_RTREE_H +#define QJS_RTREE_H + +#include + +JSValue js_rtree_use(JSContext *ctx); + +#endif