src/joystick/emscripten/SDL_sysjoystick.c
author Sam Lantinga
Fri, 27 Jan 2017 21:23:27 -0800
changeset 10861 71d8f9afb690
parent 10780 4ea5472ed455
child 11002 ba0ce5b958d2
permissions -rw-r--r--
Fixed bug 3569 - GL_UpdateViewport leaves PROJECTION matrix selected

Tom Seddon

GL_ActivateRenderer may call GL_UpdateViewport, which leaves the GL_PROJECTION matrix selected. But after GL_ResetState, the GL_MODELVIEW matrix is selected, suggesting that's the intended default state.

It seems at least like these should be consistent. Presumably GL_UpdateViewport should be doing a glMatrixMode(GL_MODELVIEW) before it finishes.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 #include "../../SDL_internal.h"
    23 
    24 #ifdef SDL_JOYSTICK_EMSCRIPTEN
    25 
    26 #include <stdio.h>              /* For the definition of NULL */
    27 #include "SDL_error.h"
    28 #include "SDL_events.h"
    29 
    30 #include "SDL_joystick.h"
    31 #include "SDL_hints.h"
    32 #include "SDL_assert.h"
    33 #include "SDL_timer.h"
    34 #include "SDL_log.h"
    35 #include "SDL_sysjoystick_c.h"
    36 #include "../SDL_joystick_c.h"
    37 
    38 static SDL_joylist_item * JoystickByIndex(int index);
    39 
    40 static SDL_joylist_item *SDL_joylist = NULL;
    41 static SDL_joylist_item *SDL_joylist_tail = NULL;
    42 static int numjoysticks = 0;
    43 static int instance_counter = 0;
    44 
    45 EM_BOOL
    46 Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
    47 {
    48     int i;
    49 
    50     SDL_joylist_item *item;
    51 
    52     if (JoystickByIndex(gamepadEvent->index) != NULL) {
    53       return 1;
    54     }
    55 
    56     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
    57     if (item == NULL) {
    58         return 1;
    59     }
    60 
    61     SDL_zerop(item);
    62     item->index = gamepadEvent->index;
    63 
    64     item->name = SDL_strdup(gamepadEvent->id);
    65     if ( item->name == NULL ) {
    66         SDL_free(item);
    67         return 1;
    68     }
    69 
    70     item->mapping = SDL_strdup(gamepadEvent->mapping);
    71     if ( item->mapping == NULL ) {
    72         SDL_free(item->name);
    73         SDL_free(item);
    74         return 1;
    75     }
    76 
    77     item->naxes = gamepadEvent->numAxes;
    78     item->nbuttons = gamepadEvent->numButtons;
    79     item->device_instance = instance_counter++;
    80 
    81     item->timestamp = gamepadEvent->timestamp;
    82 
    83     for( i = 0; i < item->naxes; i++) {
    84         item->axis[i] = gamepadEvent->axis[i];
    85     }
    86 
    87     for( i = 0; i < item->nbuttons; i++) {
    88         item->analogButton[i] = gamepadEvent->analogButton[i];
    89         item->digitalButton[i] = gamepadEvent->digitalButton[i];
    90     }
    91 
    92     if (SDL_joylist_tail == NULL) {
    93         SDL_joylist = SDL_joylist_tail = item;
    94     } else {
    95         SDL_joylist_tail->next = item;
    96         SDL_joylist_tail = item;
    97     }
    98 
    99     ++numjoysticks;
   100 
   101     SDL_PrivateJoystickAdded(numjoysticks - 1);
   102 
   103 #ifdef DEBUG_JOYSTICK
   104     SDL_Log("Number of joysticks is %d", numjoysticks);
   105 #endif
   106 
   107 #ifdef DEBUG_JOYSTICK
   108     SDL_Log("Added joystick with index %d", item->index);
   109 #endif
   110 
   111     return 1;
   112 }
   113 
   114 EM_BOOL
   115 Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
   116 {
   117     SDL_joylist_item *item = SDL_joylist;
   118     SDL_joylist_item *prev = NULL;
   119 
   120     while (item != NULL) {
   121         if (item->index == gamepadEvent->index) {
   122             break;
   123         }
   124         prev = item;
   125         item = item->next;
   126     }
   127 
   128     if (item == NULL) {
   129         return 1;
   130     }
   131 
   132     if (item->joystick) {
   133         item->joystick->hwdata = NULL;
   134     }
   135 
   136     if (prev != NULL) {
   137         prev->next = item->next;
   138     } else {
   139         SDL_assert(SDL_joylist == item);
   140         SDL_joylist = item->next;
   141     }
   142     if (item == SDL_joylist_tail) {
   143         SDL_joylist_tail = prev;
   144     }
   145 
   146     /* Need to decrement the joystick count before we post the event */
   147     --numjoysticks;
   148 
   149     SDL_PrivateJoystickRemoved(item->device_instance);
   150 
   151 #ifdef DEBUG_JOYSTICK
   152     SDL_Log("Removed joystick with id %d", item->device_instance);
   153 #endif
   154     SDL_free(item->name);
   155     SDL_free(item->mapping);
   156     SDL_free(item);
   157     return 1;
   158 }
   159 
   160 /* Function to scan the system for joysticks.
   161  * It should return 0, or -1 on an unrecoverable fatal error.
   162  */
   163 int
   164 SDL_SYS_JoystickInit(void)
   165 {
   166     int retval, i, numjs;
   167     EmscriptenGamepadEvent gamepadState;
   168 
   169     numjoysticks = 0;
   170     numjs = emscripten_get_num_gamepads();
   171 
   172     /* Check if gamepad is supported by browser */
   173     if (numjs == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
   174         return SDL_SetError("Gamepads not supported");
   175     }
   176 
   177     /* handle already connected gamepads */
   178     if (numjs > 0) {
   179         for(i = 0; i < numjs; i++) {
   180             retval = emscripten_get_gamepad_status(i, &gamepadState);
   181             if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
   182                 Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
   183                                              &gamepadState,
   184                                              NULL);
   185             }
   186         }
   187     }
   188 
   189     retval = emscripten_set_gamepadconnected_callback(NULL,
   190                                                       0,
   191                                                       Emscripten_JoyStickConnected);
   192 
   193     if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
   194         SDL_SYS_JoystickQuit();
   195         return SDL_SetError("Could not set gamepad connect callback");
   196     }
   197 
   198     retval = emscripten_set_gamepaddisconnected_callback(NULL,
   199                                                          0,
   200                                                          Emscripten_JoyStickDisconnected);
   201     if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
   202         SDL_SYS_JoystickQuit();
   203         return SDL_SetError("Could not set gamepad disconnect callback");
   204     }
   205 
   206     return 0;
   207 }
   208 
   209 /* Returns item matching given SDL device index. */
   210 static SDL_joylist_item *
   211 JoystickByDeviceIndex(int device_index)
   212 {
   213     SDL_joylist_item *item = SDL_joylist;
   214 
   215     while (0 < device_index) {
   216         --device_index;
   217         item = item->next;
   218     }
   219 
   220     return item;
   221 }
   222 
   223 /* Returns item matching given HTML gamepad index. */
   224 static SDL_joylist_item *
   225 JoystickByIndex(int index)
   226 {
   227     SDL_joylist_item *item = SDL_joylist;
   228 
   229     if (index < 0) {
   230         return NULL;
   231     }
   232 
   233     while (item != NULL) {
   234         if (item->index == index) {
   235             break;
   236         }
   237         item = item->next;
   238     }
   239 
   240     return item;
   241 }
   242 
   243 int
   244 SDL_SYS_NumJoysticks(void)
   245 {
   246     return numjoysticks;
   247 }
   248 
   249 void
   250 SDL_SYS_JoystickDetect(void)
   251 {
   252 }
   253 
   254 /* Function to get the device-dependent name of a joystick */
   255 const char *
   256 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   257 {
   258     return JoystickByDeviceIndex(device_index)->name;
   259 }
   260 
   261 /* Function to perform the mapping from device index to the instance id for this index */
   262 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   263 {
   264     return JoystickByDeviceIndex(device_index)->device_instance;
   265 }
   266 
   267 /* Function to open a joystick for use.
   268    The joystick to open is specified by the device index.
   269    This should fill the nbuttons and naxes fields of the joystick structure.
   270    It returns 0, or -1 if there is an error.
   271  */
   272 int
   273 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   274 {
   275     SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
   276 
   277     if (item == NULL ) {
   278         return SDL_SetError("No such device");
   279     }
   280 
   281     if (item->joystick != NULL) {
   282         return SDL_SetError("Joystick already opened");
   283     }
   284 
   285     joystick->instance_id = item->device_instance;
   286     joystick->hwdata = (struct joystick_hwdata *) item;
   287     item->joystick = joystick;
   288 
   289     /* HTML5 Gamepad API doesn't say anything about these */
   290     joystick->nhats = 0;
   291     joystick->nballs = 0;
   292 
   293     joystick->nbuttons = item->nbuttons;
   294     joystick->naxes = item->naxes;
   295 
   296     return (0);
   297 }
   298 
   299 /* Function to determine if this joystick is attached to the system right now */
   300 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   301 {
   302     return joystick->hwdata != NULL;
   303 }
   304 
   305 /* Function to update the state of a joystick - called as a device poll.
   306  * This function shouldn't update the joystick structure directly,
   307  * but instead should call SDL_PrivateJoystick*() to deliver events
   308  * and update joystick device state.
   309  */
   310 void
   311 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   312 {
   313     EmscriptenGamepadEvent gamepadState;
   314     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
   315     int i, result, buttonState;
   316 
   317     if (item) {
   318         result = emscripten_get_gamepad_status(item->index, &gamepadState);
   319         if( result == EMSCRIPTEN_RESULT_SUCCESS) {
   320             if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
   321                 for(i = 0; i < item->nbuttons; i++) {
   322                     if(item->digitalButton[i] != gamepadState.digitalButton[i]) {
   323                         buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
   324                         SDL_PrivateJoystickButton(item->joystick, i, buttonState);
   325                     }
   326 
   327                     /* store values to compare them in the next update */
   328                     item->analogButton[i] = gamepadState.analogButton[i];
   329                     item->digitalButton[i] = gamepadState.digitalButton[i];
   330                 }
   331 
   332                 for(i = 0; i < item->naxes; i++) {
   333                     if(item->axis[i] != gamepadState.axis[i]) {
   334                         /* do we need to do conversion? */
   335                         SDL_PrivateJoystickAxis(item->joystick, i,
   336                                                   (Sint16) (32767.*gamepadState.axis[i]));
   337                     }
   338 
   339                     /* store to compare in next update */
   340                     item->axis[i] = gamepadState.axis[i];
   341                 }
   342 
   343                 item->timestamp = gamepadState.timestamp;
   344             }
   345         }
   346     }
   347 }
   348 
   349 /* Function to close a joystick after use */
   350 void
   351 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   352 {
   353     SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
   354     if (item) {
   355         item->joystick = NULL;
   356     }
   357 }
   358 
   359 /* Function to perform any system-specific joystick related cleanup */
   360 void
   361 SDL_SYS_JoystickQuit(void)
   362 {
   363     SDL_joylist_item *item = NULL;
   364     SDL_joylist_item *next = NULL;
   365 
   366     for (item = SDL_joylist; item; item = next) {
   367         next = item->next;
   368         SDL_free(item->mapping);
   369         SDL_free(item->name);
   370         SDL_free(item);
   371     }
   372 
   373     SDL_joylist = SDL_joylist_tail = NULL;
   374 
   375     numjoysticks = 0;
   376     instance_counter = 0;
   377 
   378     emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
   379     emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
   380 }
   381 
   382 SDL_JoystickGUID
   383 SDL_SYS_JoystickGetDeviceGUID(int device_index)
   384 {
   385     SDL_JoystickGUID guid;
   386     /* the GUID is just the first 16 chars of the name for now */
   387     const char *name = SDL_SYS_JoystickNameForDeviceIndex(device_index);
   388     SDL_zero(guid);
   389     SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
   390     return guid;
   391 }
   392 
   393 SDL_JoystickGUID
   394 SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   395 {
   396     SDL_JoystickGUID guid;
   397     /* the GUID is just the first 16 chars of the name for now */
   398     const char *name = joystick->name;
   399     SDL_zero(guid);
   400     SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
   401     return guid;
   402 }
   403 
   404 #endif /* SDL_JOYSTICK_EMSCRIPTEN */