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