From ede899e9a30637cb4ffd6968c0cedc0a756f942c Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 3 Feb 2025 17:08:07 -0600 Subject: [PATCH] fix camera ortho set to true; fix module loading; remove loop function to loop.js --- README.md | 18 ++-- scripts/cmd.js | 3 +- scripts/engine.js | 3 +- scripts/loop.js | 61 +++++++++++++ scripts/modules/camera.js | 2 + scripts/modules/{layout.js => clay.js} | 34 ++++---- scripts/render.js | 67 ++++----------- scripts/sound.js | 2 +- source/jsffi.c | 114 +++++++++++++++---------- source/qjs_imgui.cpp | 41 ++------- source/qjs_macros.h | 10 +++ 11 files changed, 203 insertions(+), 152 deletions(-) create mode 100644 scripts/loop.js rename scripts/modules/{layout.js => clay.js} (90%) diff --git a/README.md b/README.md index e03f65d4..a88a88b9 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ -![alt text](doc/prosperon_orb_horizontal.gif) +git![alt text](doc/prosperon_orb_horizontal.gif) The easily moddable, programming minded, 2D-first game engine. The aim is to make the fastest way to make games. -Using ... -* Sokol for rendering -* Chipmunk2D for physics -* imgui for easy editor UI -* Clay for game UI +It implements a good amount of ES6, but is NOT terribly compatible with the larger javascript ecosystem. Instead, the goal is to make it trivial to use C libraries in your programs, and to even write C code directly in your javascript. -Includes an implementation for Nota, and Kim. +Everything is text based, which makes integrating with AI trivial. -*Prosperon is useful, but is a work in progress. Breaking changes are frequent.* +## What's different from ES6? + +Prosperon does not use the module system. Instead, there is a 'use' statement. Modules return a single javascript object. It can be a number, a function, or an object with a list of them. Modules are ran once, cached, and frozen before returned. It is wise to keep scripts short and generously import modules. + +Programs are separated into modules and scripts. Modules end in a return statement; scripts do not. + +Javascript promises do not work. await does not work. async does not work. It's all handled via callbacks, and parseq wrapper functions. This is a lot more intuitive for computer game AI. \ No newline at end of file diff --git a/scripts/cmd.js b/scripts/cmd.js index 0a97bdbc..14d2d943 100644 --- a/scripts/cmd.js +++ b/scripts/cmd.js @@ -1,5 +1,6 @@ var io = use('io') var util = use('util') +var loop = use('loop') var dumpfolder = ".prosperon"; @@ -86,7 +87,7 @@ Cmdline.register_order( var ren = use('render') - while(1) ren.process(); + while(1) loop.step(); }, "Play the game present in this folder.", ); diff --git a/scripts/engine.js b/scripts/engine.js index 5468992c..477f92e8 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -54,6 +54,7 @@ Object.defineProperty(Function.prototype, "hashify", { }); var io = use_embed('io') +var tracy = use_embed('tracy') var canonical = io.realdir('scripts/resources.js') + 'resources.js' var content = io.slurp('scripts/resources.js') @@ -424,7 +425,6 @@ Register.add_cb("hud"); Register.add_cb("draw"); Register.add_cb("imgui"); Register.add_cb("app"); -Register.add_cb("prerender"); function cant_kill() { @@ -551,3 +551,4 @@ actor[UNDERLINGS] = new Set() globalThis.mixin("color"); use('cmd')(prosperon.argv) + diff --git a/scripts/loop.js b/scripts/loop.js new file mode 100644 index 00000000..ef554ce4 --- /dev/null +++ b/scripts/loop.js @@ -0,0 +1,61 @@ +// loop.js +var render = use('render') // The refactored file above +var layout = use('clay') +var input = use('input') +var emitter = use('emitter') +var os = use('os') +var event = use('event') +var imgui = use('imgui') + +var waittime = 1/240 +var last_frame_time = 0 +var frame_t = 0 +var fpses = [] +var timescale = 1 + +// This was originally your 'imgui_fn' in render.js +function imgui_fn() { + imgui.newframe() + // ... your debug menus, etc. ... + prosperon.imgui() +} + +// Pull your old 'render.process' logic here: +function step() { + var now = os.now() + var dt = now - last_frame_time + if (dt < waittime) os.sleep(waittime - dt) + last_frame_time = os.now() + + dt = last_frame_time - frame_t + frame_t = last_frame_time + + // Input & events + event.engine_input(e => prosperon.dispatch(e.type, e)) + layout.newframe() + + // Game logic + prosperon.appupdate(dt) + input.procdown() + emitter.update(dt * timescale) + os.update_timers(dt * timescale) + prosperon.update(dt * timescale) + + // Scenes or “draw” hooks + // We point to whichever queue we want + render.setup_draw() + render.setup_hud() + + // Show your UI or debug + imgui_fn() + + // Now do the GPU present (calls gpupresent in render.js) + render._main.present() + + tracy.end_frame() +} + +// Return or export them so you can call from a main script +return { + step +} diff --git a/scripts/modules/camera.js b/scripts/modules/camera.js index 8300d6e8..dacd19ba 100644 --- a/scripts/modules/camera.js +++ b/scripts/modules/camera.js @@ -89,12 +89,14 @@ cam.make = function() { var c = Object.create(basecam) c.transform = os.make_transform() + c.transform.unit() c.zoom = 1 c.size = [640,360] c.mode = 'keep' c.viewport = {x:0,y:0,width:1,height:1} c.fov = 45 c.type = 'ortho' + c.ortho = true c.aspect = 16/9 return c } diff --git a/scripts/modules/layout.js b/scripts/modules/clay.js similarity index 90% rename from scripts/modules/layout.js rename to scripts/modules/clay.js index 44abf75b..7291979b 100644 --- a/scripts/modules/layout.js +++ b/scripts/modules/clay.js @@ -1,6 +1,7 @@ // Layout code // Contain is for how it will treat its children. If they should be laid out as a row, or column, or in a flex style, etc. +var layout = use('layout') var geometry = use('geometry') var draw = use('draw2d') var graphics = use('graphics') @@ -28,7 +29,10 @@ var root_config; var boxes = []; var clay = {} -layout.draw = function draw(size, fn, config = {}) +clay.behave = layout.behave; +clay.contain = layout.contain; + +clay.draw = function draw(size, fn, config = {}) { lay_ctx.reset(); boxes = []; @@ -93,15 +97,15 @@ function create_view_fn(base_config) } } -layout.vstack = create_view_fn({ +clay.vstack = create_view_fn({ contain: layout.contain.column | layout.contain.start, }); -layout.hstack = create_view_fn({ +clay.hstack = create_view_fn({ contain: layout.contain.row | layout.contain.start, }); -layout.spacer = create_view_fn({ +clay.spacer = create_view_fn({ behave: layout.behave.hfill | layout.behave.vfill }); @@ -169,7 +173,7 @@ function rectify_configs(config_array) return cleanobj; } -layout.image = function image(path, ...configs) +clay.image = function image(path, ...configs) { var config = rectify_configs(configs); var image = graphics.texture(path); @@ -178,7 +182,7 @@ layout.image = function image(path, ...configs) add_item(config); } -layout.text = function text(str, ...configs) +clay.text = function text(str, ...configs) { var config = rectify_configs(configs); config.size ??= [0,0]; @@ -201,7 +205,7 @@ var button_base = Object.assign(Object.create(clay_base), { hovered:{ } }); -layout.button = function button(str, action, config = {}) +clay.button = function button(str, action, config = {}) { config.__proto__ = button_base; config.font = graphics.get_font(config.font) @@ -212,10 +216,10 @@ layout.button = function button(str, action, config = {}) } var hovered = undefined; -layout.newframe = function() { hovered = undefined; } +clay.newframe = function() { hovered = undefined; } // mousepos given in hud coordinates -layout.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = prosperon.camera.screen2hud(input.mouse.screenpos())) +clay.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = prosperon.camera.screen2hud(input.mouse.screenpos())) { for (var cmd of cmds) { var config = cmd.config; @@ -244,11 +248,11 @@ layout.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = pros } var dbg_colors = {}; -layout.debug_colors = dbg_colors; +clay.debug_colors = dbg_colors; dbg_colors.content = [1,0,0,0.1]; dbg_colors.boundingbox = [0,1,0,0,0.1]; dbg_colors.margin = [0,0,1,0.1]; -layout.draw_debug = function draw_debug(cmds, pos = [0,0]) +clay.draw_debug = function draw_debug(cmds, pos = [0,0]) { for (var i = 0; i < cmds.length; i++) { var cmd = cmds[i]; @@ -260,11 +264,11 @@ layout.draw_debug = function draw_debug(cmds, pos = [0,0]) } } -layout.inputs = {}; -layout.inputs.mouse = {} -layout.inputs.mouse.left = function() +clay.inputs = {}; +clay.inputs.mouse = {} +clay.inputs.mouse.left = function() { if (hovered && hovered.action) hovered.action(); } -return layout +return clay diff --git a/scripts/render.js b/scripts/render.js index 0860c582..4ddf6ce0 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -1,5 +1,5 @@ var render = {} -var config = use('config.js') + var math = use('math') var io = use('io') var os = use('os') @@ -7,10 +7,14 @@ var util = use('util') var emitter = use('emitter') var controller = use('controller') var event = use('event') - +var imgui = use('imgui') var sprite = use('sprite') var graphics = use('graphics') +var config = use('config.js') +prosperon.camera = use('camera').make() +prosperon.camera.size = [config.width,config.height] + var base_pipeline = { vertex: "sprite.vert", fragment: "sprite.frag", @@ -527,7 +531,6 @@ function render_camera(cmds, camera) full_upload(buffers) var pass = cmds.render_pass(camera.target); - var camera = prosperon.camera; var pipeline = sprite_pipeline; bind_pipeline(pass,pipeline); @@ -590,16 +593,11 @@ function render_camera(cmds, camera) hud_queue = []; } - -prosperon.camera = use('camera').make() - var swaps = []; function gpupresent() { os.clean_transforms(); - prosperon.prerender(); var cmds = render._main.acquire_cmd_buffer(); - render_queue = sprite.to_queue().concat(render_queue); render_camera(cmds, prosperon.camera); var swapchain_tex = cmds.acquire_swapchain(); if (!swapchain_tex) @@ -616,13 +614,13 @@ function gpupresent() }); // imgui -/* cmds.push_debug_group("imgui") + cmds.push_debug_group("imgui") imgui.prepend(cmds); var pass = cmds.render_pass({ color_targets:[{texture:swapchain_tex}]}); imgui.endframe(cmds,pass); pass.end(); - cmds.pop_debug_group()*/ + cmds.pop_debug_group() } cmds.submit() } @@ -734,7 +732,6 @@ var observed_tex = undefined; var debug = {} debug.console = false var imgui_fn = function imgui_fn() { - return imgui.newframe(); if (debug.console) debug.console = imgui.window("console", _ => { @@ -807,45 +804,7 @@ var imgui_fn = function imgui_fn() { }); */ prosperon.imgui(); -// imgui.endframe(render._main); -}; - -var waittime = 1/240; -var last_frame_time = 0; -var frame_t = 0; -// Ran once per frame -var fpses = []; -var timescale = 1 -render.process = function process() { - var now = os.now(); - var dt = now - last_frame_time; - if (dt < waittime) os.sleep(waittime-dt); - last_frame_time = os.now(); - - var dt = last_frame_time - frame_t; - frame_t = last_frame_time; - - event.engine_input(e => { - prosperon.dispatch(e.type, e); - }); - - layout.newframe(); - - prosperon.appupdate(dt) - input.procdown() - - emitter.update(dt * timescale) - os.update_timers(dt * timescale) - prosperon.update(dt*timescale) - - current_queue = render_queue; - prosperon.draw() - current_queue = hud_queue; - prosperon.hud() - imgui_fn() - render._main.present(); - - tracy.end_frame(); + imgui.endframe(render._main); }; // Some initialization @@ -866,7 +825,13 @@ tracy.gpu_init() render.queue = function(cmd) { - current_queue.push(cmd) + if (Array.isArray(cmd)) + for (var i of cmd) current_queue.push(i) + else + current_queue.push(cmd) } +render.setup_draw = function() { current_queue = render_queue; prosperon.draw() } +render.setup_hud = function() { current_queue = hud_queue; prosperon.hud() } + return render diff --git a/scripts/sound.js b/scripts/sound.js index 962cf942..6871afc3 100644 --- a/scripts/sound.js +++ b/scripts/sound.js @@ -1,4 +1,4 @@ -//var soloud = use('soloud') +var soloud = use('soloud') var tween = use('tween') var io = use('io') var res = use('resources') diff --git a/source/jsffi.c b/source/jsffi.c index ba92b771..4a247bfa 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -472,14 +472,14 @@ static int rets_SDL_GPUSwapchainComposition[] = { SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR, SDL_GPU_SWAPCHAINCOMPOSITION_HDR_EXTENDED_LINEAR, - SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2084 +// SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2084 }; static const char *vals_SDL_GPUSwapchainComposition[] = { "sdr", "linear", "hdr", - "hdr10" +// "hdr10" }; JS2ENUM(SDL_GPUSwapchainComposition, rets_SDL_GPUSwapchainComposition, vals_SDL_GPUSwapchainComposition) @@ -4252,7 +4252,7 @@ JSC_CCALL(gpu_make_sprite_queue, } if (sort) qsort(sprites, quads, sizeof(sprite), sort_sprite); - else qsort(sprites, quads, sizeof(sprite), sort_sprite_texture); +// else qsort(sprites, quads, sizeof(sprite), sort_sprite_texture); struct quad_buffers buffers = quad_buffers_new(quads*4); @@ -6977,12 +6977,6 @@ JSC_CCALL(os_clean_transforms, clean_all(); ) -typedef struct { - const char *name; - const JSCFunctionListEntry *fn; - size_t fn_count; -} ModuleEntry; - JSC_CCALL(os_totalmem, return number2js(js, SDL_GetSystemRAM())) JSC_CCALL(os_platform, return JS_NewString(js,SDL_GetPlatform())) JSC_CCALL(os_hostname, @@ -7195,29 +7189,19 @@ static const JSCFunctionListEntry js_event_funcs[] = { MIST_FUNC_DEF(os, engine_input, 1), }; -#define MISTLINE(NAME) { #NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs) } +typedef JSValue (*MODULEFN)(JSContext *js); -static ModuleEntry module_registry[] = { - MISTLINE(io), - MISTLINE(os), - MISTLINE(input), - MISTLINE(time), - MISTLINE(math), - MISTLINE(spline), - MISTLINE(geometry), - MISTLINE(graphics), - MISTLINE(js), - MISTLINE(util), - MISTLINE(video), - MISTLINE(event), -}; +typedef struct { + const char *name; + MODULEFN fn; +} ModuleEntry; + +static ModuleEntry *module_registry = NULL; JSC_SCALL(os_use_embed, - for (int i = 0; i < sizeof(module_registry)/sizeof(module_registry[0]); i++) { + for (int i = 0; i < arrlen(module_registry); i++) { if (strcmp(str,module_registry[i].name) == 0) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js,mod,module_registry[i].fn, module_registry[i].fn_count); - ret = mod; + ret = module_registry[i].fn(js); break; } } @@ -7392,6 +7376,24 @@ JSValue js_rtree_get_size(JSContext *js, JSValue self, int magic) 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), @@ -7399,6 +7401,7 @@ static const JSCFunctionListEntry js_rtree_funcs[] = { 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), }; JSC_GETSET(sprite, layer, number) @@ -7447,10 +7450,6 @@ JSValue js_soloud_use(JSContext *js); JSValue js_tracy_use(JSContext *js); #endif -#ifndef NEDITOR -JSValue js_imgui(JSContext *js); -#endif - static void signal_handler(int sig) { const char *str = NULL; switch(sig) { @@ -7483,7 +7482,47 @@ static void exit_handler() script_stop(); } +MISTUSE(io) +MISTUSE(os) +MISTUSE(input) +MISTUSE(time) +MISTUSE(math) +MISTUSE(spline) +MISTUSE(geometry) +MISTUSE(js) +MISTUSE(graphics) +MISTUSE(util) +MISTUSE(video) +MISTUSE(event) +#ifndef NEDITOR +JSValue js_imgui_use(JSContext *js); +#endif + +#define MISTLINE(NAME) (ModuleEntry){#NAME, js_##NAME##_use} + void ffi_load(JSContext *js, int argc, char **argv) { + arrput(module_registry, MISTLINE(io)); + arrput(module_registry, MISTLINE(os)); + arrput(module_registry, MISTLINE(input)); + arrput(module_registry, MISTLINE(time)); + arrput(module_registry, MISTLINE(math)); + arrput(module_registry, MISTLINE(spline)); + arrput(module_registry, MISTLINE(geometry)); + arrput(module_registry, MISTLINE(graphics)); + arrput(module_registry, MISTLINE(js)); + arrput(module_registry, MISTLINE(util)); + arrput(module_registry, MISTLINE(video)); + arrput(module_registry, MISTLINE(event)); + arrput(module_registry, MISTLINE(soloud)); + arrput(module_registry,MISTLINE(layout)); +#ifndef NEDITOR + arrput(module_registry, MISTLINE(imgui)); +#endif + +#ifdef TRACY_ENABLE + arrput(module_registry, MISTLINE(tracy)); +#endif + JSValue globalThis = JS_GetGlobalObject(js); QJSCLASSPREP_FUNCS(rtree) @@ -7540,17 +7579,6 @@ void ffi_load(JSContext *js, int argc, char **argv) { JS_FreeValue(js,jsnumber); JS_FreeValue(js,number_proto); - JS_SetPropertyStr(js, globalThis, "layout", js_layout_use(js)); - JS_SetPropertyStr(js, globalThis, "soloud", js_soloud_use(js)); - -#ifdef TRACY_ENABLE - JS_SetPropertyStr(js, globalThis, "tracy", js_tracy_use(js)); -#endif - -#ifndef NEDITOR - JS_SetPropertyStr(js, globalThis, "imgui", js_imgui(js)); -#endif - x_atom = JS_NewAtom(js,"x"); y_atom = JS_NewAtom(js,"y"); width_atom = JS_NewAtom(js,"width"); diff --git a/source/qjs_imgui.cpp b/source/qjs_imgui.cpp index a67cce3c..60dbcaf0 100644 --- a/source/qjs_imgui.cpp +++ b/source/qjs_imgui.cpp @@ -8,6 +8,8 @@ #include "imgui_impl_sdl3.h" #include "imgui_impl_sdlgpu3.h" +#include "qjs_macros.h" + extern "C" { SDL_GPUDevice *js2SDL_GPUDevice(JSContext *js, JSValue v); SDL_GPURenderPass *js2SDL_GPURenderPass(JSContext *js, JSValue v); @@ -18,30 +20,6 @@ SDL_Window *js2SDL_Window(JSContext *js, JSValue v); static int START = 0; -#define JSC_CCALL(NAME, ...) static JSValue js_##NAME (JSContext *js, JSValue self, int argc, JSValue *argv) { \ - JSValue ret = JS_UNDEFINED; \ - __VA_ARGS__ ;\ - return ret; \ -} \ - -#define JSC_SCALL(NAME, ...) static JSValue js_##NAME (JSContext *js, JSValue self, int argc, JSValue *argv) { \ - JSValue ret = JS_UNDEFINED; \ - const char *str = JS_ToCString(js, argv[0]); \ - __VA_ARGS__ ;\ - JS_FreeCString(js, str); \ - return ret; \ -} \ - -#define JSC_SSALL(NAME, ...) static JSValue js_##NAME (JSContext *js, JSValue self, int argc, JSValue *argv) { \ - JSValue ret = JS_UNDEFINED; \ - const char *str = JS_ToCString(js, argv[0]); \ - const char *str2 = JS_ToCString(js, argv[1]); \ - __VA_ARGS__ ; \ - JS_FreeCString(js, str); \ - JS_FreeCString(js, str2); \ - return ret; \ -} \ - static inline int js_arrlen(JSContext *js, JSValue v) { JSValue len = JS_GetPropertyStr(js, v, "length"); @@ -275,7 +253,7 @@ JSC_CCALL(imgui_plothovered, return JS_NewBool(js,ImPlot::IsPlotHovered()); ) -JSC_SSALL(imgui_plotaxes, +JSC_SSCALL(imgui_plotaxes, ImPlot::SetupAxes(str,str2); ) @@ -292,7 +270,7 @@ JSC_CCALL(imgui_fitaxis, ImPlot::SetNextAxisToFit((js2number(js, argv[0]) == 0) ? ImAxis_X1 : ImAxis_Y1); ) -JSC_SSALL(imgui_textinput, +JSC_SSCALL(imgui_textinput, char buffer[512]; if (JS_IsUndefined(argv[1])) buffer[0] = 0; @@ -306,7 +284,7 @@ JSC_SSALL(imgui_textinput, ret = JS_DupValue(js,argv[1]); ) -JSC_SSALL(imgui_textbox, +JSC_SSCALL(imgui_textbox, char buffer[512]; if (JS_IsUndefined(argv[1])) buffer[0] = 0; @@ -822,8 +800,8 @@ JSC_CCALL(imgui_init, START = 1; ) -#define MIST_FUNC_DEF(CLASS,NAME,AMT) JS_CFUNC_DEF(#NAME, AMT, js_##CLASS##_##NAME) -static const JSCFunctionListEntry js_imgui_funcs[] = { +extern "C" { +const JSCFunctionListEntry js_imgui_funcs[] = { MIST_FUNC_DEF(imgui, windowpos, 0), MIST_FUNC_DEF(imgui, plot2pixels, 1), MIST_FUNC_DEF(imgui, plotpos, 0), @@ -920,14 +898,13 @@ static const JSCFunctionListEntry js_imgui_funcs[] = { MIST_FUNC_DEF(imgui, init, 2), }; -extern "C" { void gui_input(SDL_Event *e) { if (!START) return; ImGui_ImplSDL3_ProcessEvent(e); } -JSValue js_imgui(JSContext *js) +JSValue js_imgui_use(JSContext *js) { JSValue imgui = JS_NewObject(js); JS_SetPropertyFunctionList(js, imgui, js_imgui_funcs, sizeof(js_imgui_funcs)/sizeof(js_imgui_funcs[0])); @@ -938,7 +915,7 @@ JSValue js_imgui(JSContext *js) static int js_init_imgui(JSContext *js, JSModuleDef *m) { JS_SetModuleExportList(js, m, js_imgui_funcs, sizeof(js_imgui_funcs)/sizeof(JSCFunctionListEntry)); - JS_SetModuleExport(js, m, "default", js_imgui(js)); + JS_SetModuleExport(js, m, "default", js_imgui_use(js)); return 0; } diff --git a/source/qjs_macros.h b/source/qjs_macros.h index b62a6a0c..2511937b 100644 --- a/source/qjs_macros.h +++ b/source/qjs_macros.h @@ -140,4 +140,14 @@ JSValue TYPE##_proto = JS_NewObject(js); \ JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \ +#define MISTUSE(NAME) \ +JSValue js_##NAME##_use(JSContext *js) { \ + JSValue mod = JS_NewObject(js); \ + JS_SetPropertyFunctionList(js,mod,js_##NAME##_funcs,countof(js_##NAME##_funcs)); \ + return mod; } \ + +#define MISTLINE(NAME) (ModuleEntry){ #NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs) } + #define countof(x) (sizeof(x)/sizeof((x)[0])) + +