src/video/emscripten/SDL_emscriptenmouse.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Jan 2018 10:03:25 -0800
changeset 11811 5d94cb6b24d3
parent 11673 9c7602bf7385
child 12121 4358e537000a
permissions -rw-r--r--
Updated copyright for 2018
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 
    23 #include "../../SDL_internal.h"
    24 
    25 #if SDL_VIDEO_DRIVER_EMSCRIPTEN
    26 
    27 #include <emscripten/emscripten.h>
    28 #include <emscripten/html5.h>
    29 
    30 #include "SDL_emscriptenmouse.h"
    31 
    32 #include "../../events/SDL_mouse_c.h"
    33 #include "SDL_assert.h"
    34 
    35 static SDL_Cursor*
    36 Emscripten_CreateCursorFromString(const char* cursor_str, SDL_bool is_custom)
    37 {
    38     SDL_Cursor* cursor;
    39     Emscripten_CursorData *curdata;
    40 
    41     cursor = SDL_calloc(1, sizeof(SDL_Cursor));
    42     if (cursor) {
    43         curdata = (Emscripten_CursorData *) SDL_calloc(1, sizeof(*curdata));
    44         if (!curdata) {
    45             SDL_OutOfMemory();
    46             SDL_free(cursor);
    47             return NULL;
    48         }
    49 
    50         curdata->system_cursor = cursor_str;
    51         curdata->is_custom = is_custom;
    52         cursor->driverdata = curdata;
    53     }
    54     else {
    55         SDL_OutOfMemory();
    56     }
    57 
    58     return cursor;
    59 }
    60 
    61 static SDL_Cursor*
    62 Emscripten_CreateDefaultCursor()
    63 {
    64     return Emscripten_CreateCursorFromString("default", SDL_FALSE);
    65 }
    66 
    67 static SDL_Cursor*
    68 Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
    69 {
    70     const char *cursor_url = NULL;
    71     SDL_Surface *conv_surf;
    72 
    73     conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
    74 
    75     if (!conv_surf) {
    76         return NULL;
    77     }
    78 
    79     cursor_url = (const char *)EM_ASM_INT({
    80         var w = $0;
    81         var h = $1;
    82         var hot_x = $2;
    83         var hot_y = $3;
    84         var pixels = $4;
    85 
    86         var canvas = document.createElement("canvas");
    87         canvas.width = w;
    88         canvas.height = h;
    89 
    90         var ctx = canvas.getContext("2d");
    91 
    92         var image = ctx.createImageData(w, h);
    93         var data = image.data;
    94         var src = pixels >> 2;
    95         var dst = 0;
    96         var num;
    97         if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) {
    98             // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray,
    99             // not UInt8ClampedArray. These don't have buffers, so we need to revert
   100             // to copying a byte at a time. We do the undefined check because modern
   101             // browsers do not define CanvasPixelArray anymore.
   102             num = data.length;
   103             while (dst < num) {
   104                 var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
   105                 data[dst  ] = val & 0xff;
   106                 data[dst+1] = (val >> 8) & 0xff;
   107                 data[dst+2] = (val >> 16) & 0xff;
   108                 data[dst+3] = (val >> 24) & 0xff;
   109                 src++;
   110                 dst += 4;
   111             }
   112         } else {
   113             var data32 = new Int32Array(data.buffer);
   114             num = data32.length;
   115             data32.set(HEAP32.subarray(src, src + num));
   116         }
   117 
   118         ctx.putImageData(image, 0, 0);
   119         var url = hot_x === 0 && hot_y === 0
   120             ? "url(" + canvas.toDataURL() + "), auto"
   121             : "url(" + canvas.toDataURL() + ") " + hot_x + " " + hot_y + ", auto";
   122 
   123         var urlBuf = _malloc(url.length + 1);
   124         stringToUTF8(url, urlBuf, url.length + 1);
   125 
   126         return urlBuf;
   127     }, surface->w, surface->h, hot_x, hot_y, conv_surf->pixels);
   128 
   129     SDL_FreeSurface(conv_surf);
   130 
   131     return Emscripten_CreateCursorFromString(cursor_url, SDL_TRUE);
   132 }
   133 
   134 static SDL_Cursor*
   135 Emscripten_CreateSystemCursor(SDL_SystemCursor id)
   136 {
   137     const char *cursor_name = NULL;
   138 
   139     switch(id) {
   140         case SDL_SYSTEM_CURSOR_ARROW:
   141             cursor_name = "default";
   142             break;
   143         case SDL_SYSTEM_CURSOR_IBEAM:
   144             cursor_name = "text";
   145             break;
   146         case SDL_SYSTEM_CURSOR_WAIT:
   147             cursor_name = "wait";
   148             break;
   149         case SDL_SYSTEM_CURSOR_CROSSHAIR:
   150             cursor_name = "crosshair";
   151             break;
   152         case SDL_SYSTEM_CURSOR_WAITARROW:
   153             cursor_name = "progress";
   154             break;
   155         case SDL_SYSTEM_CURSOR_SIZENWSE:
   156             cursor_name = "nwse-resize";
   157             break;
   158         case SDL_SYSTEM_CURSOR_SIZENESW:
   159             cursor_name = "nesw-resize";
   160             break;
   161         case SDL_SYSTEM_CURSOR_SIZEWE:
   162             cursor_name = "ew-resize";
   163             break;
   164         case SDL_SYSTEM_CURSOR_SIZENS:
   165             cursor_name = "ns-resize";
   166             break;
   167         case SDL_SYSTEM_CURSOR_SIZEALL:
   168             break;
   169         case SDL_SYSTEM_CURSOR_NO:
   170             cursor_name = "not-allowed";
   171             break;
   172         case SDL_SYSTEM_CURSOR_HAND:
   173             cursor_name = "pointer";
   174             break;
   175         default:
   176             SDL_assert(0);
   177             return NULL;
   178     }
   179 
   180     return Emscripten_CreateCursorFromString(cursor_name, SDL_FALSE);
   181 }
   182 
   183 static void
   184 Emscripten_FreeCursor(SDL_Cursor* cursor)
   185 {
   186     Emscripten_CursorData *curdata;
   187     if (cursor) {
   188         curdata = (Emscripten_CursorData *) cursor->driverdata;
   189 
   190         if (curdata != NULL) {
   191             if (curdata->is_custom) {
   192                 SDL_free((char *)curdata->system_cursor);
   193             }
   194             SDL_free(cursor->driverdata);
   195         }
   196 
   197         SDL_free(cursor);
   198     }
   199 }
   200 
   201 static int
   202 Emscripten_ShowCursor(SDL_Cursor* cursor)
   203 {
   204     Emscripten_CursorData *curdata;
   205     if (SDL_GetMouseFocus() != NULL) {
   206         if(cursor && cursor->driverdata) {
   207             curdata = (Emscripten_CursorData *) cursor->driverdata;
   208 
   209             if(curdata->system_cursor) {
   210                 EM_ASM_INT({
   211                     if (Module['canvas']) {
   212                         Module['canvas'].style['cursor'] = Module['Pointer_stringify']($0);
   213                     }
   214                     return 0;
   215                 }, curdata->system_cursor);
   216             }
   217         }
   218         else {
   219             EM_ASM(
   220                 if (Module['canvas']) {
   221                     Module['canvas'].style['cursor'] = 'none';
   222                 }
   223             );
   224         }
   225     }
   226     return 0;
   227 }
   228 
   229 static void
   230 Emscripten_WarpMouse(SDL_Window* window, int x, int y)
   231 {
   232     SDL_Unsupported();
   233 }
   234 
   235 static int
   236 Emscripten_SetRelativeMouseMode(SDL_bool enabled)
   237 {
   238     /* TODO: pointer lock isn't actually enabled yet */
   239     if(enabled) {
   240         if(emscripten_request_pointerlock(NULL, 1) >= EMSCRIPTEN_RESULT_SUCCESS) {
   241             return 0;
   242         }
   243     } else {
   244         if(emscripten_exit_pointerlock() >= EMSCRIPTEN_RESULT_SUCCESS) {
   245             return 0;
   246         }
   247     }
   248     return -1;
   249 }
   250 
   251 void
   252 Emscripten_InitMouse()
   253 {
   254     SDL_Mouse* mouse = SDL_GetMouse();
   255 
   256     mouse->CreateCursor         = Emscripten_CreateCursor;
   257     mouse->ShowCursor           = Emscripten_ShowCursor;
   258     mouse->FreeCursor           = Emscripten_FreeCursor;
   259     mouse->WarpMouse            = Emscripten_WarpMouse;
   260     mouse->CreateSystemCursor   = Emscripten_CreateSystemCursor;
   261     mouse->SetRelativeMouseMode = Emscripten_SetRelativeMouseMode;
   262 
   263     SDL_SetDefaultCursor(Emscripten_CreateDefaultCursor());
   264 }
   265 
   266 void
   267 Emscripten_FiniMouse()
   268 {
   269 }
   270 
   271 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
   272 
   273 /* vi: set ts=4 sw=4 expandtab: */
   274