Emscripten: implement custom cursors
authorCharlie Birks
Fri, 17 Feb 2017 10:13:17 +0000
changeset 108985c01b36afb14
parent 10897 19203215ca8e
child 10899 6816d648aa34
Emscripten: implement custom cursors
src/video/emscripten/SDL_emscriptenmouse.c
src/video/emscripten/SDL_emscriptenmouse.h
     1.1 --- a/src/video/emscripten/SDL_emscriptenmouse.c	Fri Feb 17 10:13:12 2017 +0000
     1.2 +++ b/src/video/emscripten/SDL_emscriptenmouse.c	Fri Feb 17 10:13:17 2017 +0000
     1.3 @@ -33,7 +33,7 @@
     1.4  #include "SDL_assert.h"
     1.5  
     1.6  static SDL_Cursor*
     1.7 -Emscripten_CreateCursorFromString(const char* cursor_str)
     1.8 +Emscripten_CreateCursorFromString(const char* cursor_str, SDL_bool is_custom)
     1.9  {
    1.10      SDL_Cursor* cursor;
    1.11      Emscripten_CursorData *curdata;
    1.12 @@ -48,6 +48,7 @@
    1.13          }
    1.14  
    1.15          curdata->system_cursor = cursor_str;
    1.16 +        curdata->is_custom = is_custom;
    1.17          cursor->driverdata = curdata;
    1.18      }
    1.19      else {
    1.20 @@ -60,16 +61,71 @@
    1.21  static SDL_Cursor*
    1.22  Emscripten_CreateDefaultCursor()
    1.23  {
    1.24 -    return Emscripten_CreateCursorFromString("default");
    1.25 +    return Emscripten_CreateCursorFromString("default", SDL_FALSE);
    1.26  }
    1.27  
    1.28 -/*
    1.29  static SDL_Cursor*
    1.30 -Emscripten_CreateCursor(SDL_Surface* sruface, int hot_x, int hot_y)
    1.31 +Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
    1.32  {
    1.33 -    return Emscripten_CreateDefaultCursor();
    1.34 +    const char *cursor_url = NULL;
    1.35 +    SDL_Surface *conv_surf;
    1.36 +
    1.37 +    conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
    1.38 +
    1.39 +    if (!conv_surf) {
    1.40 +        return NULL;
    1.41 +    }
    1.42 +
    1.43 +    cursor_url = (const char *)EM_ASM_INT({
    1.44 +        var w = $0;
    1.45 +        var h = $1;
    1.46 +        var pixels = $2;
    1.47 +
    1.48 +        var canvas = document.createElement("canvas");
    1.49 +        canvas.width = w;
    1.50 +        canvas.height = h;
    1.51 +
    1.52 +        var ctx = canvas.getContext("2d");
    1.53 +
    1.54 +        var image = ctx.createImageData(w, h);
    1.55 +        var data = image.data;
    1.56 +        var src = pixels >> 2;
    1.57 +        var dst = 0;
    1.58 +        var num;
    1.59 +        if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) {
    1.60 +            // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray,
    1.61 +            // not UInt8ClampedArray. These don't have buffers, so we need to revert
    1.62 +            // to copying a byte at a time. We do the undefined check because modern
    1.63 +            // browsers do not define CanvasPixelArray anymore.
    1.64 +            num = data.length;
    1.65 +            while (dst < num) {
    1.66 +                var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
    1.67 +                data[dst  ] = val & 0xff;
    1.68 +                data[dst+1] = (val >> 8) & 0xff;
    1.69 +                data[dst+2] = (val >> 16) & 0xff;
    1.70 +                data[dst+3] = (val >> 24) & 0xff;
    1.71 +                src++;
    1.72 +                dst += 4;
    1.73 +            }
    1.74 +        } else {
    1.75 +            var data32 = new Int32Array(data.buffer);
    1.76 +            num = data32.length;
    1.77 +            data32.set(HEAP32.subarray(src, src + num));
    1.78 +        }
    1.79 +
    1.80 +        ctx.putImageData(image, 0, 0);
    1.81 +        var url = "url(" + canvas.toDataURL() + "), auto";
    1.82 +
    1.83 +        var urlBuf = _malloc(url.length + 1);
    1.84 +        stringToUTF8(url, urlBuf, url.length + 1);
    1.85 +
    1.86 +        return urlBuf;
    1.87 +    }, surface->w, surface->h, conv_surf->pixels);
    1.88 +
    1.89 +    SDL_FreeSurface(conv_surf);
    1.90 +
    1.91 +    return Emscripten_CreateCursorFromString(cursor_url, SDL_TRUE);
    1.92  }
    1.93 -*/
    1.94  
    1.95  static SDL_Cursor*
    1.96  Emscripten_CreateSystemCursor(SDL_SystemCursor id)
    1.97 @@ -117,7 +173,7 @@
    1.98              return NULL;
    1.99      }
   1.100  
   1.101 -    return Emscripten_CreateCursorFromString(cursor_name);
   1.102 +    return Emscripten_CreateCursorFromString(cursor_name, SDL_FALSE);
   1.103  }
   1.104  
   1.105  static void
   1.106 @@ -128,6 +184,9 @@
   1.107          curdata = (Emscripten_CursorData *) cursor->driverdata;
   1.108  
   1.109          if (curdata != NULL) {
   1.110 +            if (curdata->is_custom) {
   1.111 +                SDL_free((char *)curdata->system_cursor);
   1.112 +            }
   1.113              SDL_free(cursor->driverdata);
   1.114          }
   1.115  
   1.116 @@ -190,9 +249,7 @@
   1.117  {
   1.118      SDL_Mouse* mouse = SDL_GetMouse();
   1.119  
   1.120 -/*
   1.121      mouse->CreateCursor         = Emscripten_CreateCursor;
   1.122 -*/ 
   1.123      mouse->ShowCursor           = Emscripten_ShowCursor;
   1.124      mouse->FreeCursor           = Emscripten_FreeCursor;
   1.125      mouse->WarpMouse            = Emscripten_WarpMouse;
     2.1 --- a/src/video/emscripten/SDL_emscriptenmouse.h	Fri Feb 17 10:13:12 2017 +0000
     2.2 +++ b/src/video/emscripten/SDL_emscriptenmouse.h	Fri Feb 17 10:13:17 2017 +0000
     2.3 @@ -23,9 +23,12 @@
     2.4  #ifndef _SDL_emscriptenmouse_h
     2.5  #define _SDL_emscriptenmouse_h
     2.6  
     2.7 +#include "SDL_stdinc.h"
     2.8 +
     2.9  typedef struct _Emscripten_CursorData
    2.10  {
    2.11      const char *system_cursor;
    2.12 +    SDL_bool is_custom;
    2.13  } Emscripten_CursorData;
    2.14  
    2.15  extern void