diff --git a/scripts/core/_sdl_video.js b/scripts/core/_sdl_video.js index e2b60da3..3184b52c 100644 --- a/scripts/core/_sdl_video.js +++ b/scripts/core/_sdl_video.js @@ -59,7 +59,8 @@ var resources = { window: {}, renderer: {}, texture: {}, - surface: {} + surface: {}, + cursor: {} }; // ID counter for resource allocation @@ -93,6 +94,9 @@ $_.receiver(function(msg) { case 'surface': response = handle_surface(msg); break; + case 'cursor': + response = handle_cursor(msg); + break; default: response = {error: "Unknown kind: " + msg.kind}; } @@ -605,6 +609,39 @@ function handle_surface(msg) { } } +// Cursor operations +function handle_cursor(msg) { + switch (msg.op) { + case 'create': + var surf = new surface(msg.data) + + var hotspot = msg.data.hotspot || [0, 0]; + var cursor = prosperon.endowments.createCursor(surf, hotspot); + + var cursor_id = allocate_id(); + resources.cursor[cursor_id] = cursor; + return {id: cursor_id}; + + case 'set': + var cursor = null; + if (msg.id && resources.cursor[msg.id]) { + cursor = resources.cursor[msg.id]; + } + prosperon.endowments.setCursor(cursor); + return {success: true}; + + case 'destroy': + if (!msg.id || !resources.cursor[msg.id]) { + return {error: "Invalid cursor id: " + msg.id}; + } + delete resources.cursor[msg.id]; + return {success: true}; + + default: + return {error: "Unknown cursor operation: " + msg.op}; + } +} + // Utility function to create window and renderer prosperon.endowments = prosperon.endowments || {}; diff --git a/scripts/modules/graphics.js b/scripts/modules/graphics.js index 1521fa23..92f1ddbc 100644 --- a/scripts/modules/graphics.js +++ b/scripts/modules/graphics.js @@ -429,11 +429,6 @@ graphics.cull_sprites[prosperon.DOC] = ` Filter an array of sprites to only those visible in the provided camera’s view. ` -graphics.make_cursor[prosperon.DOC] = ` -:param opts: An object with {surface, hotx, hoty} or similar. -:return: An SDL_Cursor object referencing the given surface for a custom mouse cursor. -` - graphics.make_font[prosperon.DOC] = ` :param data: TTF/OTF file data as an ArrayBuffer. :param size: Pixel size for rendering glyphs. diff --git a/source/jsffi.c b/source/jsffi.c index 3a3a19d3..89c25523 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -1199,19 +1199,6 @@ JSC_CCALL(os_make_aseprite, cute_aseprite_free(ase); ) - -// TODO: Implement this correctly -JSC_CCALL(os_make_cursor, - /*if (SDL_GetCurrentThreadID() != main_thread) - return JS_ThrowInternalError(js, "This can only be called from the root actor."); - - SDL_Surface *s = js2SDL_Surface(js,argv[0]); - HMM_Vec2 hot = js2vec2(js,argv[1]); - SDL_Cursor *c = SDL_CreateColorCursor(s, hot.x, hot.y); - if (!c) return JS_ThrowReferenceError(js,"couldn't make cursor: %s", SDL_GetError()); - return SDL_Cursor2js(js,c);*/ -) - JSC_CCALL(os_make_font, size_t len; void *data = JS_GetArrayBuffer(js,&len,argv[0]); @@ -1501,7 +1488,6 @@ static const JSCFunctionListEntry js_graphics_funcs[] = { MIST_FUNC_DEF(os, make_gif, 1), MIST_FUNC_DEF(os, make_aseprite, 1), MIST_FUNC_DEF(os, cull_sprites, 2), - MIST_FUNC_DEF(os, make_cursor, 1), MIST_FUNC_DEF(os, make_font, 2), MIST_FUNC_DEF(os, make_line_prim, 5), MIST_FUNC_DEF(graphics, hsl_to_rgb, 3), diff --git a/source/qjs_sdl.c b/source/qjs_sdl.c index 6f3aa19b..2f2da6e7 100644 --- a/source/qjs_sdl.c +++ b/source/qjs_sdl.c @@ -10,17 +10,11 @@ void SDL_Camera_free(JSRuntime *rt, SDL_Camera *cam) SDL_CloseCamera(cam); } -void SDL_Cursor_free(JSRuntime *rt, SDL_Cursor *c) -{ - SDL_DestroyCursor(c); -} - void SDL_AudioStream_free(JSRuntime *rt, SDL_AudioStream *st) { SDL_DestroyAudioStream(st); } // Class definitions for SDL types -QJSCLASS(SDL_Cursor,) QJSCLASS(SDL_Camera,) QJSCLASS(SDL_AudioStream,) @@ -59,12 +53,6 @@ JSC_CCALL(input_mouse_show, SDL_HideCursor(); ) -JSC_CCALL(input_cursor_set, - SDL_Cursor *c = js2SDL_Cursor(js,argv[0]); - if (!SDL_SetCursor(c)) - return JS_ThrowReferenceError(js, "could not set cursor: %s", SDL_GetError()); -) - JSC_CCALL(input_keyname, return JS_NewString(js, SDL_GetKeyName(js2number(js,argv[0]))); ) @@ -97,7 +85,6 @@ JSC_CCALL(input_mousestate, static const JSCFunctionListEntry js_input_funcs[] = { MIST_FUNC_DEF(input, mouse_show, 1), MIST_FUNC_DEF(input, mouse_lock, 1), - MIST_FUNC_DEF(input, cursor_set, 1), MIST_FUNC_DEF(input, keyname, 1), MIST_FUNC_DEF(input, keymod, 0), MIST_FUNC_DEF(input, mousestate, 0), @@ -109,7 +96,6 @@ JSValue js_input_use(JSContext *js) { // Initialize SDL cursor class (no functions) JSValue c_types = JS_GetPropertyStr(js, JS_GetGlobalObject(js), "c_types"); - QJSCLASSPREP_NO_FUNCS(SDL_Cursor) JS_FreeValue(js, c_types); return mod; diff --git a/source/qjs_sdl_video.c b/source/qjs_sdl_video.c index 1824f14b..550aa902 100644 --- a/source/qjs_sdl_video.c +++ b/source/qjs_sdl_video.c @@ -43,6 +43,13 @@ QJSCLASS(SDL_Texture, QJSCLASS(SDL_Renderer,) QJSCLASS(SDL_Window,) +void SDL_Cursor_free(JSRuntime *rt, SDL_Cursor *c) +{ + SDL_DestroyCursor(c); +} + +QJSCLASS(SDL_Cursor,) + // External function declarations extern JSValue rect2js(JSContext *js, rect r); extern rect js2rect(JSContext *js, JSValue v); @@ -1555,6 +1562,29 @@ static const JSCFunctionListEntry js_sdl_video_funcs[] = { JS_PROP_INT32_DEF("BLENDMODE_MUL", SDL_BLENDMODE_MUL, JS_PROP_CONFIGURABLE), }; +// Cursor creation function +JSC_CCALL(sdl_create_cursor, + SDL_Surface *surf = js2SDL_Surface(js, argv[0]); + if (!surf) return JS_ThrowReferenceError(js, "Invalid surface"); + + HMM_Vec2 hot = {0, 0}; + if (argc > 1) hot = js2vec2(js, argv[1]); + + SDL_Cursor *cursor = SDL_CreateColorCursor(surf, hot.x, hot.y); + if (!cursor) return JS_ThrowReferenceError(js, "Failed to create cursor: %s", SDL_GetError()); + + return SDL_Cursor2js(js, cursor); +) + +// Set cursor function +JSC_CCALL(sdl_set_cursor, + SDL_Cursor *cursor = js2SDL_Cursor(js, argv[0]); + + if (!cursor) return JS_ThrowReferenceError(js, "Invalid cursor"); + + SDL_SetCursor(cursor); +) + // Texture getter/setter functions // Alpha mod getter/setter @@ -1759,6 +1789,7 @@ static void video_actor_hook(JSContext *js) { QJSCLASSPREP_FUNCS(SDL_Window) QJSCLASSPREP_FUNCS(SDL_Renderer) QJSCLASSPREP_FUNCS(SDL_Texture) + QJSCLASSPREP_NO_FUNCS(SDL_Cursor) JS_FreeValue(js, c_types); @@ -1789,6 +1820,12 @@ static void video_actor_hook(JSContext *js) { JS_SetPropertyStr(js, endowments, "createWindowAndRenderer", JS_NewCFunction(js, js_sdl_createWindowAndRenderer, "createWindowAndRenderer", 4)); + // Add cursor functions + JS_SetPropertyStr(js, endowments, "createCursor", + JS_NewCFunction(js, js_sdl_create_cursor, "createCursor", 2)); + JS_SetPropertyStr(js, endowments, "setCursor", + JS_NewCFunction(js, js_sdl_set_cursor, "setCursor", 1)); + JS_FreeValue(js, endowments); JS_FreeValue(js, prosperon); } diff --git a/tests/draw2d.js b/tests/draw2d.js index 86072032..c794a699 100644 --- a/tests/draw2d.js +++ b/tests/draw2d.js @@ -56,13 +56,11 @@ function start_drawing() { var start_time = os.now(); // Load an image - var bunny_image = null; - try { - bunny_image = graphics.texture('tests/bunny.png'); - } catch (e) { - console.log("Failed to load bunny image:", e); - console.log(e) - } + var bunny_image = graphics.texture('tests/bunny.png') + + send(video_actor, {kind: "cursor", op: "create", data: bunny_image.cpu}, ({id}) => { + send(video_actor, {kind:"cursor", op: "set", id}) + }) function draw_frame() { frame++;