Emscripten: implement custom cursors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
diff --git a/src/video/emscripten/SDL_emscriptenmouse.c b/src/video/emscripten/SDL_emscriptenmouse.c
index 2d39487..22fbd13 100644
--- a/src/video/emscripten/SDL_emscriptenmouse.c
+++ b/src/video/emscripten/SDL_emscriptenmouse.c
@@ -33,7 +33,7 @@
#include "SDL_assert.h"
static SDL_Cursor*
-Emscripten_CreateCursorFromString(const char* cursor_str)
+Emscripten_CreateCursorFromString(const char* cursor_str, SDL_bool is_custom)
{
SDL_Cursor* cursor;
Emscripten_CursorData *curdata;
@@ -48,6 +48,7 @@ Emscripten_CreateCursorFromString(const char* cursor_str)
}
curdata->system_cursor = cursor_str;
+ curdata->is_custom = is_custom;
cursor->driverdata = curdata;
}
else {
@@ -60,16 +61,71 @@ Emscripten_CreateCursorFromString(const char* cursor_str)
static SDL_Cursor*
Emscripten_CreateDefaultCursor()
{
- return Emscripten_CreateCursorFromString("default");
+ return Emscripten_CreateCursorFromString("default", SDL_FALSE);
}
-/*
static SDL_Cursor*
-Emscripten_CreateCursor(SDL_Surface* sruface, int hot_x, int hot_y)
+Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
{
- return Emscripten_CreateDefaultCursor();
+ const char *cursor_url = NULL;
+ SDL_Surface *conv_surf;
+
+ conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
+
+ if (!conv_surf) {
+ return NULL;
+ }
+
+ cursor_url = (const char *)EM_ASM_INT({
+ var w = $0;
+ var h = $1;
+ var pixels = $2;
+
+ var canvas = document.createElement("canvas");
+ canvas.width = w;
+ canvas.height = h;
+
+ var ctx = canvas.getContext("2d");
+
+ var image = ctx.createImageData(w, h);
+ var data = image.data;
+ var src = pixels >> 2;
+ var dst = 0;
+ var num;
+ if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) {
+ // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray,
+ // not UInt8ClampedArray. These don't have buffers, so we need to revert
+ // to copying a byte at a time. We do the undefined check because modern
+ // browsers do not define CanvasPixelArray anymore.
+ num = data.length;
+ while (dst < num) {
+ var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
+ data[dst ] = val & 0xff;
+ data[dst+1] = (val >> 8) & 0xff;
+ data[dst+2] = (val >> 16) & 0xff;
+ data[dst+3] = (val >> 24) & 0xff;
+ src++;
+ dst += 4;
+ }
+ } else {
+ var data32 = new Int32Array(data.buffer);
+ num = data32.length;
+ data32.set(HEAP32.subarray(src, src + num));
+ }
+
+ ctx.putImageData(image, 0, 0);
+ var url = "url(" + canvas.toDataURL() + "), auto";
+
+ var urlBuf = _malloc(url.length + 1);
+ stringToUTF8(url, urlBuf, url.length + 1);
+
+ return urlBuf;
+ }, surface->w, surface->h, conv_surf->pixels);
+
+ SDL_FreeSurface(conv_surf);
+
+ return Emscripten_CreateCursorFromString(cursor_url, SDL_TRUE);
}
-*/
static SDL_Cursor*
Emscripten_CreateSystemCursor(SDL_SystemCursor id)
@@ -117,7 +173,7 @@ Emscripten_CreateSystemCursor(SDL_SystemCursor id)
return NULL;
}
- return Emscripten_CreateCursorFromString(cursor_name);
+ return Emscripten_CreateCursorFromString(cursor_name, SDL_FALSE);
}
static void
@@ -128,6 +184,9 @@ Emscripten_FreeCursor(SDL_Cursor* cursor)
curdata = (Emscripten_CursorData *) cursor->driverdata;
if (curdata != NULL) {
+ if (curdata->is_custom) {
+ SDL_free((char *)curdata->system_cursor);
+ }
SDL_free(cursor->driverdata);
}
@@ -190,9 +249,7 @@ Emscripten_InitMouse()
{
SDL_Mouse* mouse = SDL_GetMouse();
-/*
mouse->CreateCursor = Emscripten_CreateCursor;
-*/
mouse->ShowCursor = Emscripten_ShowCursor;
mouse->FreeCursor = Emscripten_FreeCursor;
mouse->WarpMouse = Emscripten_WarpMouse;
diff --git a/src/video/emscripten/SDL_emscriptenmouse.h b/src/video/emscripten/SDL_emscriptenmouse.h
index ebe6056..8e2b5f1 100644
--- a/src/video/emscripten/SDL_emscriptenmouse.h
+++ b/src/video/emscripten/SDL_emscriptenmouse.h
@@ -23,9 +23,12 @@
#ifndef _SDL_emscriptenmouse_h
#define _SDL_emscriptenmouse_h
+#include "SDL_stdinc.h"
+
typedef struct _Emscripten_CursorData
{
const char *system_cursor;
+ SDL_bool is_custom;
} Emscripten_CursorData;
extern void