mirror of
https://github.com/encounter/SDL.git
synced 2025-12-11 14:41:56 +00:00
Initial merge of Emscripten port!
With this commit, you can compile SDL2 with Emscripten ( http://emscripten.org/ ), and make your SDL-based C/C++ program into a web app. This port was due to the efforts of several people, including: Charlie Birks, Sathyanarayanan Gunasekaran, Jukka Jyl?nki, Alon Zakai, Edward Rudd, Bruce Mitchener, and Martin Gerhardy. (Thanks, everyone!)
This commit is contained in:
@@ -71,6 +71,7 @@ extern AudioBootStrap FUSIONSOUND_bootstrap;
|
||||
extern AudioBootStrap ANDROIDAUD_bootstrap;
|
||||
extern AudioBootStrap PSPAUD_bootstrap;
|
||||
extern AudioBootStrap SNDIO_bootstrap;
|
||||
extern AudioBootStrap EmscriptenAudio_bootstrap;
|
||||
|
||||
|
||||
/* Available audio drivers */
|
||||
@@ -140,6 +141,9 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_PSP
|
||||
&PSPAUD_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||
&EmscriptenAudio_bootstrap,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
271
src/audio/emscripten/SDL_emscriptenaudio.c
Normal file
271
src/audio/emscripten/SDL_emscriptenaudio.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_log.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_emscriptenaudio.h"
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
|
||||
static int
|
||||
copyData(_THIS)
|
||||
{
|
||||
int byte_len;
|
||||
|
||||
if (this->hidden->write_off + this->convert.len_cvt > this->hidden->mixlen) {
|
||||
if (this->hidden->write_off > this->hidden->read_off) {
|
||||
SDL_memmove(this->hidden->mixbuf,
|
||||
this->hidden->mixbuf + this->hidden->read_off,
|
||||
this->hidden->mixlen - this->hidden->read_off);
|
||||
this->hidden->write_off = this->hidden->write_off - this->hidden->read_off;
|
||||
} else {
|
||||
this->hidden->write_off = 0;
|
||||
}
|
||||
this->hidden->read_off = 0;
|
||||
}
|
||||
|
||||
SDL_memcpy(this->hidden->mixbuf + this->hidden->write_off,
|
||||
this->convert.buf,
|
||||
this->convert.len_cvt);
|
||||
this->hidden->write_off += this->convert.len_cvt;
|
||||
byte_len = this->hidden->write_off - this->hidden->read_off;
|
||||
|
||||
return byte_len;
|
||||
}
|
||||
|
||||
static void
|
||||
HandleAudioProcess(_THIS)
|
||||
{
|
||||
Uint8 *buf = NULL;
|
||||
int byte_len = 0;
|
||||
int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
|
||||
int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
|
||||
int i;
|
||||
|
||||
/* Only do soemthing if audio is enabled */
|
||||
if (!this->enabled)
|
||||
return;
|
||||
|
||||
if (this->paused)
|
||||
return;
|
||||
|
||||
if (this->convert.needed) {
|
||||
if (this->hidden->conv_in_len != 0) {
|
||||
this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels;
|
||||
}
|
||||
|
||||
(*this->spec.callback) (this->spec.userdata,
|
||||
this->convert.buf,
|
||||
this->convert.len);
|
||||
SDL_ConvertAudio(&this->convert);
|
||||
buf = this->convert.buf;
|
||||
byte_len = this->convert.len_cvt;
|
||||
|
||||
/* size mismatch*/
|
||||
if (byte_len != this->spec.size) {
|
||||
if (!this->hidden->mixbuf) {
|
||||
this->hidden->mixlen = this->spec.size > byte_len ? this->spec.size * 2 : byte_len * 2;
|
||||
this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen);
|
||||
}
|
||||
|
||||
/* copy existing data */
|
||||
byte_len = copyData(this);
|
||||
|
||||
/* read more data*/
|
||||
while (byte_len < this->spec.size) {
|
||||
(*this->spec.callback) (this->spec.userdata,
|
||||
this->convert.buf,
|
||||
this->convert.len);
|
||||
SDL_ConvertAudio(&this->convert);
|
||||
byte_len = copyData(this);
|
||||
}
|
||||
|
||||
byte_len = this->spec.size;
|
||||
buf = this->hidden->mixbuf + this->hidden->read_off;
|
||||
this->hidden->read_off += byte_len;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!this->hidden->mixbuf) {
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen);
|
||||
}
|
||||
(*this->spec.callback) (this->spec.userdata,
|
||||
this->hidden->mixbuf,
|
||||
this->hidden->mixlen);
|
||||
buf = this->hidden->mixbuf;
|
||||
byte_len = this->hidden->mixlen;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
EM_ASM_ARGS({
|
||||
var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels'];
|
||||
for (var c = 0; c < numChannels; ++c) {
|
||||
var channelData = SDL2.audio.currentOutputBuffer['getChannelData'](c);
|
||||
if (channelData.length != $1) {
|
||||
throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||
}
|
||||
|
||||
for (var j = 0; j < $1; ++j) {
|
||||
channelData[j] = getValue($0 + (j*numChannels + c)*4, 'float');
|
||||
}
|
||||
}
|
||||
}, buf, byte_len / bytes / this->spec.channels);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden != NULL) {
|
||||
if (this->hidden->mixbuf != NULL) {
|
||||
/* Clean up the audio buffer */
|
||||
SDL_free(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
Emscripten_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||
{
|
||||
SDL_bool valid_format = SDL_FALSE;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
int i;
|
||||
float f;
|
||||
|
||||
while ((!valid_format) && (test_format)) {
|
||||
switch (test_format) {
|
||||
case AUDIO_F32: /* web audio only supports floats */
|
||||
this->spec.format = test_format;
|
||||
|
||||
valid_format = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
|
||||
if (!valid_format) {
|
||||
/* Didn't find a compatible format :( */
|
||||
return SDL_SetError("No compatible audio format!");
|
||||
}
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* based on parts of library_sdl.js */
|
||||
|
||||
/* create context (TODO: this puts stuff in the global namespace...)*/
|
||||
EM_ASM({
|
||||
if(typeof(SDL2) === 'undefined')
|
||||
SDL2 = {};
|
||||
|
||||
if(typeof(SDL2.audio) === 'undefined')
|
||||
SDL2.audio = {};
|
||||
|
||||
if (!SDL2.audioContext) {
|
||||
if (typeof(AudioContext) !== 'undefined') {
|
||||
SDL2.audioContext = new AudioContext();
|
||||
} else if (typeof(webkitAudioContext) !== 'undefined') {
|
||||
SDL2.audioContext = new webkitAudioContext();
|
||||
} else {
|
||||
throw 'Web Audio API is not available!';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* limit to native freq */
|
||||
int sampleRate = EM_ASM_INT_V({
|
||||
return SDL2.audioContext['sampleRate'];
|
||||
});
|
||||
|
||||
if(this->spec.freq != sampleRate) {
|
||||
for (i = this->spec.samples; i > 0; i--) {
|
||||
f = (float)i / (float)sampleRate * (float)this->spec.freq;
|
||||
if (SDL_floor(f) == f) {
|
||||
this->hidden->conv_in_len = SDL_floor(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->spec.freq = sampleRate;
|
||||
}
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* setup a ScriptProcessorNode */
|
||||
EM_ASM_ARGS({
|
||||
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
|
||||
SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
|
||||
SDL2.audio.currentOutputBuffer = e['outputBuffer'];
|
||||
Runtime.dynCall('vi', $2, [$3]);
|
||||
};
|
||||
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
|
||||
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
Emscripten_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = Emscripten_OpenDevice;
|
||||
impl->CloseDevice = Emscripten_CloseDevice;
|
||||
|
||||
/* only one output */
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
|
||||
/* no threads here */
|
||||
impl->SkipMixerLock = 1;
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
|
||||
/* check availability */
|
||||
int available = EM_ASM_INT_V({
|
||||
if (typeof(AudioContext) !== 'undefined') {
|
||||
return 1;
|
||||
} else if (typeof(webkitAudioContext) !== 'undefined') {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
AudioBootStrap EmscriptenAudio_bootstrap = {
|
||||
"emscripten", "SDL emscripten audio driver", Emscripten_Init, 0
|
||||
};
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
42
src/audio/emscripten/SDL_emscriptenaudio.h
Normal file
42
src/audio/emscripten/SDL_emscriptenaudio.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_emscriptenaudio_h
|
||||
#define _SDL_emscriptenaudio_h
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
Uint8 *mixbuf;
|
||||
Uint32 mixlen;
|
||||
|
||||
Uint32 conv_in_len;
|
||||
|
||||
Uint32 write_off, read_off;
|
||||
};
|
||||
|
||||
#endif /* _SDL_emscriptenaudio_h */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -79,6 +79,7 @@ CPU_haveCPUID(void)
|
||||
{
|
||||
int has_CPUID = 0;
|
||||
/* *INDENT-OFF* */
|
||||
#ifndef SDL_CPUINFO_DISABLED
|
||||
#if defined(__GNUC__) && defined(i386)
|
||||
__asm__ (
|
||||
" pushfl # Get original EFLAGS \n"
|
||||
@@ -165,6 +166,7 @@ done:
|
||||
"1: \n"
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
return has_CPUID;
|
||||
}
|
||||
@@ -272,6 +274,7 @@ static int
|
||||
CPU_haveAltiVec(void)
|
||||
{
|
||||
volatile int altivec = 0;
|
||||
#ifndef SDL_CPUINFO_DISABLED
|
||||
#if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
|
||||
#ifdef __OpenBSD__
|
||||
int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
|
||||
@@ -291,6 +294,7 @@ CPU_haveAltiVec(void)
|
||||
altivec = 1;
|
||||
}
|
||||
signal(SIGILL, handler);
|
||||
#endif
|
||||
#endif
|
||||
return altivec;
|
||||
}
|
||||
@@ -418,6 +422,7 @@ int
|
||||
SDL_GetCPUCount(void)
|
||||
{
|
||||
if (!SDL_CPUCount) {
|
||||
#ifndef SDL_CPUINFO_DISABLED
|
||||
#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
|
||||
if (SDL_CPUCount <= 0) {
|
||||
SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
|
||||
@@ -435,6 +440,7 @@ SDL_GetCPUCount(void)
|
||||
GetSystemInfo(&info);
|
||||
SDL_CPUCount = info.dwNumberOfProcessors;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* There has to be at least 1, right? :) */
|
||||
if (SDL_CPUCount <= 0) {
|
||||
@@ -723,6 +729,7 @@ int
|
||||
SDL_GetSystemRAM(void)
|
||||
{
|
||||
if (!SDL_SystemRAM) {
|
||||
#ifndef SDL_CPUINFO_DISABLED
|
||||
#if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
|
||||
if (SDL_SystemRAM <= 0) {
|
||||
SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
|
||||
@@ -756,6 +763,7 @@ SDL_GetSystemRAM(void)
|
||||
SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return SDL_SystemRAM;
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE || __native_client__ /* probably not useful on iOS or NACL. */
|
||||
#if TARGET_OS_IPHONE || __native_client__ || __EMSCRIPTEN__ /* probably not useful on iOS, NACL or Emscripten. */
|
||||
#define SDL_DYNAMIC_API 0
|
||||
#elif SDL_BUILDING_WINRT /* probaly not useful on WinRT, given current .dll loading restrictions */
|
||||
#define SDL_DYNAMIC_API 0
|
||||
|
||||
68
src/filesystem/emscripten/SDL_sysfilesystem.c
Normal file
68
src/filesystem/emscripten/SDL_sysfilesystem.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_FILESYSTEM_EMSCRIPTEN
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* System dependent filesystem routines */
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_filesystem.h"
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
|
||||
char *
|
||||
SDL_GetBasePath(void)
|
||||
{
|
||||
char *retval = "/";
|
||||
return SDL_strdup(retval);
|
||||
}
|
||||
|
||||
char *
|
||||
SDL_GetPrefPath(const char *org, const char *app)
|
||||
{
|
||||
const char *append = "/libsdl/";
|
||||
char *retval;
|
||||
size_t len = 0;
|
||||
|
||||
len = SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3;
|
||||
retval = (char *) SDL_malloc(len);
|
||||
if (!retval) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_snprintf(retval, len, "%s%s/%s/", append, org, app);
|
||||
|
||||
if (mkdir(retval, 0700) != 0 && errno != EEXIST) {
|
||||
SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* SDL_FILESYSTEM_EMSCRIPTEN */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -89,6 +89,7 @@ typedef struct _ControllerMapping_t
|
||||
|
||||
static ControllerMapping_t *s_pSupportedControllers = NULL;
|
||||
static ControllerMapping_t *s_pXInputMapping = NULL;
|
||||
static ControllerMapping_t *s_pEmscriptenMapping = NULL;
|
||||
|
||||
/* The SDL game controller structure */
|
||||
struct _SDL_GameController
|
||||
@@ -263,7 +264,13 @@ ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
|
||||
return s_pXInputMapping;
|
||||
}
|
||||
else
|
||||
#endif /* SDL_JOYSTICK_XINPUT */
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
|
||||
if (s_pEmscriptenMapping) {
|
||||
return s_pEmscriptenMapping;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index);
|
||||
return SDL_PrivateGetControllerMappingForGUID(&jGUID);
|
||||
@@ -668,6 +675,7 @@ SDL_GameControllerAddMapping(const char *mappingString)
|
||||
SDL_JoystickGUID jGUID;
|
||||
ControllerMapping_t *pControllerMapping;
|
||||
SDL_bool is_xinput_mapping = SDL_FALSE;
|
||||
SDL_bool is_emscripten_mapping = SDL_FALSE;
|
||||
|
||||
if (!mappingString) {
|
||||
return SDL_InvalidParamError("mappingString");
|
||||
@@ -680,6 +688,9 @@ SDL_GameControllerAddMapping(const char *mappingString)
|
||||
if (!SDL_strcasecmp(pchGUID, "xinput")) {
|
||||
is_xinput_mapping = SDL_TRUE;
|
||||
}
|
||||
if (!SDL_strcasecmp(pchGUID, "emscripten")) {
|
||||
is_emscripten_mapping = SDL_TRUE;
|
||||
}
|
||||
jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
|
||||
SDL_free(pchGUID);
|
||||
|
||||
@@ -715,6 +726,9 @@ SDL_GameControllerAddMapping(const char *mappingString)
|
||||
if (is_xinput_mapping) {
|
||||
s_pXInputMapping = pControllerMapping;
|
||||
}
|
||||
if (is_emscripten_mapping) {
|
||||
s_pEmscriptenMapping = pControllerMapping;
|
||||
}
|
||||
pControllerMapping->guid = jGUID;
|
||||
pControllerMapping->name = pchName;
|
||||
pControllerMapping->mapping = pchMapping;
|
||||
|
||||
@@ -76,6 +76,8 @@ static const char *s_ControllerMappings [] =
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
#elif defined(SDL_JOYSTICK_EMSCRIPTEN)
|
||||
"emscripten,Standard Gamepad,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
426
src/joystick/emscripten/SDL_sysjoystick.c
Normal file
426
src/joystick/emscripten/SDL_sysjoystick.c
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_EMSCRIPTEN
|
||||
|
||||
#include <stdio.h> /* For the definition of NULL */
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_events.h"
|
||||
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#endif
|
||||
|
||||
#include "SDL_joystick.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_log.h"
|
||||
#include "SDL_sysjoystick_c.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
|
||||
static SDL_joylist_item * JoystickByIndex(int index);
|
||||
|
||||
static SDL_joylist_item *SDL_joylist = NULL;
|
||||
static SDL_joylist_item *SDL_joylist_tail = NULL;
|
||||
static int numjoysticks = 0;
|
||||
static int instance_counter = 0;
|
||||
|
||||
int
|
||||
Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||
{
|
||||
int i;
|
||||
|
||||
SDL_joylist_item *item;
|
||||
|
||||
if (JoystickByIndex(gamepadEvent->index) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
SDL_Event event;
|
||||
#endif
|
||||
|
||||
item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
|
||||
if (item == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
SDL_zerop(item);
|
||||
item->index = gamepadEvent->index;
|
||||
|
||||
item->name = SDL_strdup(gamepadEvent->id);
|
||||
if ( item->name == NULL ) {
|
||||
SDL_free(item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
item->mapping = SDL_strdup(gamepadEvent->mapping);
|
||||
if ( item->mapping == NULL ) {
|
||||
SDL_free(item->name);
|
||||
SDL_free(item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
item->naxes = gamepadEvent->numAxes;
|
||||
item->nbuttons = gamepadEvent->numButtons;
|
||||
item->device_instance = instance_counter++;
|
||||
|
||||
item->timestamp = gamepadEvent->timestamp;
|
||||
|
||||
for( i = 0; i < item->naxes; i++) {
|
||||
item->axis[i] = gamepadEvent->axis[i];
|
||||
}
|
||||
|
||||
for( i = 0; i < item->nbuttons; i++) {
|
||||
item->analogButton[i] = gamepadEvent->analogButton[i];
|
||||
item->digitalButton[i] = gamepadEvent->digitalButton[i];
|
||||
}
|
||||
|
||||
if (SDL_joylist_tail == NULL) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
} else {
|
||||
SDL_joylist_tail->next = item;
|
||||
SDL_joylist_tail = item;
|
||||
}
|
||||
|
||||
++numjoysticks;
|
||||
SDL_Log("%d",numjoysticks);
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
event.type = SDL_JOYDEVICEADDED;
|
||||
|
||||
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
|
||||
event.jdevice.which = item->device_instance - 1;
|
||||
if ( (SDL_EventOK == NULL) ||
|
||||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
|
||||
SDL_Log("Added joystick with index %d", item->index);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||
{
|
||||
SDL_joylist_item *item = SDL_joylist;
|
||||
SDL_joylist_item *prev = NULL;
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
SDL_Event event;
|
||||
#endif
|
||||
|
||||
while (item != NULL) {
|
||||
if (item->index == gamepadEvent->index) {
|
||||
break;
|
||||
}
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
if (item == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int retval = item->device_instance;
|
||||
if (item->joystick) {
|
||||
item->joystick->hwdata = NULL;
|
||||
}
|
||||
|
||||
if (prev != NULL) {
|
||||
prev->next = item->next;
|
||||
} else {
|
||||
SDL_assert(SDL_joylist == item);
|
||||
SDL_joylist = item->next;
|
||||
}
|
||||
if (item == SDL_joylist_tail) {
|
||||
SDL_joylist_tail = prev;
|
||||
}
|
||||
|
||||
/* Need to decrement the joystick count before we post the event */
|
||||
--numjoysticks;
|
||||
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
event.type = SDL_JOYDEVICEREMOVED;
|
||||
|
||||
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
|
||||
event.jdevice.which = item->device_instance;
|
||||
if ( (SDL_EventOK == NULL) ||
|
||||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
|
||||
SDL_Log("Removed joystick with index %d", retval);
|
||||
SDL_free(item->name);
|
||||
SDL_free(item->mapping);
|
||||
SDL_free(item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* It should return 0, or -1 on an unrecoverable fatal error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
{
|
||||
int retval, i, numjs;
|
||||
EmscriptenGamepadEvent gamepadState;
|
||||
|
||||
numjoysticks = 0;
|
||||
numjs = emscripten_get_num_gamepads();
|
||||
|
||||
/* Check if gamepad is supported by browser */
|
||||
if (numjs == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* handle already connected gamepads */
|
||||
if (numjs > 0) {
|
||||
for(i = 0; i < numjs; i++) {
|
||||
retval = emscripten_get_gamepad_status(i, &gamepadState);
|
||||
if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
|
||||
&gamepadState,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = emscripten_set_gamepadconnected_callback(NULL,
|
||||
0,
|
||||
Emscripten_JoyStickConnected);
|
||||
|
||||
if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
retval = emscripten_set_gamepaddisconnected_callback(NULL,
|
||||
0,
|
||||
Emscripten_JoyStickDisconnected);
|
||||
if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_joylist_item *
|
||||
JoystickByIndex(int index)
|
||||
{
|
||||
SDL_joylist_item *item = SDL_joylist;
|
||||
|
||||
if (index < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (item != NULL) {
|
||||
if (item->index == index) {
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
int SDL_SYS_NumJoysticks()
|
||||
{
|
||||
return numjoysticks;
|
||||
}
|
||||
|
||||
void SDL_SYS_JoystickDetect()
|
||||
{
|
||||
}
|
||||
|
||||
// we need to poll to see if the gamepad state has changed
|
||||
SDL_bool SDL_SYS_JoystickNeedsPolling()
|
||||
{
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int index)
|
||||
{
|
||||
SDL_joylist_item *item = JoystickByIndex(index);
|
||||
if (item == NULL) {
|
||||
SDL_SetError("Joystick with index %d not found", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return item->name;
|
||||
}
|
||||
|
||||
/* Function to perform the mapping from device index to the instance id for this index */
|
||||
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int index)
|
||||
{
|
||||
SDL_joylist_item *item = JoystickByIndex(index);
|
||||
if (item == NULL) {
|
||||
SDL_SetError("Joystick with index %d not found", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return item->device_instance;
|
||||
}
|
||||
|
||||
/* Function to open a joystick for use.
|
||||
The joystick to open is specified by the index field of the joystick.
|
||||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int index)
|
||||
{
|
||||
SDL_joylist_item *item = JoystickByIndex(index);
|
||||
|
||||
if (item == NULL ) {
|
||||
return SDL_SetError("No such device");
|
||||
}
|
||||
|
||||
if (item->joystick != NULL) {
|
||||
return SDL_SetError("Joystick already opened");
|
||||
}
|
||||
|
||||
joystick->instance_id = item->device_instance;
|
||||
joystick->hwdata = (struct joystick_hwdata *) item;
|
||||
item->joystick = joystick;
|
||||
|
||||
/* HTML5 Gamepad API doesn't say anything about these */
|
||||
joystick->nhats = 0;
|
||||
joystick->nballs = 0;
|
||||
|
||||
joystick->nbuttons = item->nbuttons;
|
||||
joystick->naxes = item->naxes;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Function to determine is this joystick is attached to the system right now */
|
||||
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
||||
{
|
||||
return !joystick->closed && (joystick->hwdata != NULL);
|
||||
}
|
||||
|
||||
/* Function to update the state of a joystick - called as a device poll.
|
||||
* This function shouldn't update the joystick structure directly,
|
||||
* but instead should call SDL_PrivateJoystick*() to deliver events
|
||||
* and update joystick device state.
|
||||
*/
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
EmscriptenGamepadEvent gamepadState;
|
||||
SDL_joylist_item *item = SDL_joylist;
|
||||
int i, result, button, buttonState;
|
||||
|
||||
while (item != NULL) {
|
||||
result = emscripten_get_gamepad_status(item->index, &gamepadState);
|
||||
if( result == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
|
||||
for(i = 0; i < item->nbuttons; i++) {
|
||||
if(item->digitalButton[i] != gamepadState.digitalButton[i]) {
|
||||
buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED;
|
||||
SDL_PrivateJoystickButton(item->joystick, i, buttonState);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < item->naxes; i++) {
|
||||
if(item->axis[i] != gamepadState.axis[i]) {
|
||||
// do we need to do conversion?
|
||||
SDL_PrivateJoystickAxis(item->joystick, i,
|
||||
(Sint16) (32767.*gamepadState.axis[i]));
|
||||
}
|
||||
}
|
||||
|
||||
item->timestamp = gamepadState.timestamp;
|
||||
for( i = 0; i < item->naxes; i++) {
|
||||
item->axis[i] = gamepadState.axis[i];
|
||||
}
|
||||
|
||||
for( i = 0; i < item->nbuttons; i++) {
|
||||
item->analogButton[i] = gamepadState.analogButton[i];
|
||||
item->digitalButton[i] = gamepadState.digitalButton[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
if (joystick->hwdata) {
|
||||
((SDL_joylist_item*)joystick->hwdata)->joystick = NULL;
|
||||
joystick->hwdata = NULL;
|
||||
}
|
||||
joystick->closed = 1;
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
{
|
||||
SDL_joylist_item *item = NULL;
|
||||
SDL_joylist_item *next = NULL;
|
||||
|
||||
for (item = SDL_joylist; item; item = next) {
|
||||
next = item->next;
|
||||
SDL_free(item->mapping);
|
||||
SDL_free(item->name);
|
||||
SDL_free(item);
|
||||
}
|
||||
|
||||
SDL_joylist = SDL_joylist_tail = NULL;
|
||||
|
||||
numjoysticks = 0;
|
||||
instance_counter = 0;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int index)
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
/* the GUID is just the first 16 chars of the name for now */
|
||||
const char *name = SDL_SYS_JoystickNameForDeviceIndex(index);
|
||||
SDL_zero(guid);
|
||||
SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
|
||||
return guid;
|
||||
}
|
||||
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
/* the GUID is just the first 16 chars of the name for now */
|
||||
const char *name = joystick->name;
|
||||
SDL_zero(guid);
|
||||
SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
|
||||
return guid;
|
||||
}
|
||||
|
||||
#endif /* SDL_JOYSTICK_EMSCRIPTEN */
|
||||
76
src/joystick/emscripten/SDL_sysjoystick_c.h
Normal file
76
src/joystick/emscripten/SDL_sysjoystick_c.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_EMSCRIPTEN
|
||||
#include "../SDL_sysjoystick.h"
|
||||
|
||||
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_INVALID = -1,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_A,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_B,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_X,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_Y,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_L1,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_R1,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_L2,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_R2,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_BACK,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_START,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_LEFTSTICK,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_RIGHTSTICK,
|
||||
EMSCRIPTEN_CONTROLLER_DPAD_UP,
|
||||
EMSCRIPTEN_CONTROLLER_DPAD_DOWN,
|
||||
EMSCRIPTEN_CONTROLLER_DPAD_LEFT,
|
||||
EMSCRIPTEN_CONTROLLER_DPAD_RIGHT,
|
||||
EMSCRIPTEN_CONTROLLER_BUTTON_GUIDE,
|
||||
} Emscripten_GameControllerButton;
|
||||
|
||||
static int EMSCRIPTEN_MAX_NBUTTONS = 18;
|
||||
|
||||
/* A linked list of available joysticks */
|
||||
typedef struct SDL_joylist_item
|
||||
{
|
||||
int index;
|
||||
char *name;
|
||||
char *mapping;
|
||||
SDL_JoystickID device_instance;
|
||||
SDL_Joystick *joystick;
|
||||
int nbuttons;
|
||||
int naxes;
|
||||
double timestamp;
|
||||
double axis[64];
|
||||
double analogButton[64];
|
||||
EM_BOOL digitalButton[64];
|
||||
|
||||
struct SDL_joylist_item *next;
|
||||
} SDL_joylist_item;
|
||||
|
||||
typedef SDL_joylist_item joystick_hwdata;
|
||||
|
||||
#endif /* SDL_JOYSTICK_EMSCRIPTEN */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -38,6 +38,7 @@ SDL_bool SDL_GetPowerInfo_UIKit(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_Android(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_PSP(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_WinRT(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_Emscripten(SDL_PowerState *, int *, int *);
|
||||
|
||||
#ifndef SDL_POWER_DISABLED
|
||||
#ifdef SDL_POWER_HARDWIRED
|
||||
@@ -81,6 +82,9 @@ static SDL_GetPowerInfo_Impl implementations[] = {
|
||||
#ifdef SDL_POWER_WINRT /* handles WinRT */
|
||||
SDL_GetPowerInfo_WinRT,
|
||||
#endif
|
||||
#ifdef SDL_POWER_EMSCRIPTEN /* handles Emscripten */
|
||||
SDL_GetPowerInfo_Emscripten,
|
||||
#endif
|
||||
|
||||
#ifdef SDL_POWER_HARDWIRED
|
||||
SDL_GetPowerInfo_Hardwired,
|
||||
|
||||
62
src/power/emscripten/SDL_syspower.c
Normal file
62
src/power/emscripten/SDL_syspower.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_POWER_DISABLED
|
||||
#if SDL_POWER_EMSCRIPTEN
|
||||
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
#include "SDL_power.h"
|
||||
|
||||
SDL_bool
|
||||
SDL_GetPowerInfo_Emscripten(SDL_PowerState *state, int *seconds, int *percent)
|
||||
{
|
||||
EmscriptenBatteryEvent batteryState;
|
||||
int haveBattery = 0;
|
||||
|
||||
if (emscripten_get_battery_status(&batteryState) == EMSCRIPTEN_RESULT_NOT_SUPPORTED)
|
||||
return SDL_FALSE;
|
||||
|
||||
haveBattery = batteryState.level != 1.0 || !batteryState.charging || batteryState.chargingTime != 0.0;
|
||||
|
||||
if (!haveBattery) {
|
||||
*state = SDL_POWERSTATE_NO_BATTERY;
|
||||
*seconds = -1;
|
||||
*percent = -1;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
if (batteryState.charging)
|
||||
*state = batteryState.chargingTime == 0.0 ? SDL_POWERSTATE_CHARGED : SDL_POWERSTATE_CHARGING;
|
||||
else
|
||||
*state = SDL_POWERSTATE_ON_BATTERY;
|
||||
|
||||
*seconds = batteryState.dischargingTime;
|
||||
*percent = batteryState.level * 100;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
#endif /* SDL_POWER_EMSCRIPTEN */
|
||||
#endif /* SDL_POWER_DISABLED */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -69,3 +69,7 @@ SDL_PROC(GLenum, glCheckFramebufferStatus, (GLenum))
|
||||
SDL_PROC(void, glDeleteFramebuffers, (GLsizei, const GLuint *))
|
||||
SDL_PROC(GLint, glGetAttribLocation, (GLuint, const GLchar *))
|
||||
SDL_PROC(void, glGetProgramInfoLog, (GLuint, GLsizei, GLsizei*, GLchar*))
|
||||
SDL_PROC(void, glGenBuffers, (GLsizei, GLuint *))
|
||||
SDL_PROC(void, glBindBuffer, (GLenum, GLuint))
|
||||
SDL_PROC(void, glBufferData, (GLenum, GLsizeiptr, const GLvoid *, GLenum))
|
||||
SDL_PROC(void, glBufferSubData, (GLenum, GLintptr, GLsizeiptr, const GLvoid *))
|
||||
|
||||
@@ -180,6 +180,9 @@ typedef struct GLES2_DriverContext
|
||||
GLES2_ProgramCache program_cache;
|
||||
GLES2_ProgramCacheEntry *current_program;
|
||||
Uint8 clear_r, clear_g, clear_b, clear_a;
|
||||
|
||||
GLuint vertex_buffers[4];
|
||||
GLsizeiptr vertex_buffer_size[4];
|
||||
} GLES2_DriverContext;
|
||||
|
||||
#define GLES2_MAX_CACHED_PROGRAMS 8
|
||||
@@ -1385,6 +1388,32 @@ GLES2_SetDrawingState(SDL_Renderer * renderer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
GLES2_UpdateVertexBuffer(SDL_Renderer *renderer, GLES2_Attribute attr,
|
||||
const void *vertexData, size_t dataSizeInBytes)
|
||||
{
|
||||
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
|
||||
#if 0
|
||||
data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, vertexData);
|
||||
#else
|
||||
|
||||
if (!data->vertex_buffers[attr])
|
||||
data->glGenBuffers(1, &data->vertex_buffers[attr]);
|
||||
|
||||
data->glBindBuffer(GL_ARRAY_BUFFER, data->vertex_buffers[attr]);
|
||||
|
||||
if (data->vertex_buffer_size[attr] < dataSizeInBytes) {
|
||||
data->glBufferData(GL_ARRAY_BUFFER, dataSizeInBytes, vertexData, GL_STREAM_DRAW);
|
||||
data->vertex_buffer_size[attr] = dataSizeInBytes;
|
||||
} else {
|
||||
data->glBufferSubData(GL_ARRAY_BUFFER, 0, dataSizeInBytes, vertexData);
|
||||
}
|
||||
|
||||
data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
|
||||
{
|
||||
@@ -1405,7 +1434,8 @@ GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int cou
|
||||
vertices[idx * 2] = x;
|
||||
vertices[(idx * 2) + 1] = y;
|
||||
}
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
/*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
|
||||
data->glDrawArrays(GL_POINTS, 0, count);
|
||||
SDL_stack_free(vertices);
|
||||
return 0;
|
||||
@@ -1431,7 +1461,8 @@ GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int coun
|
||||
vertices[idx * 2] = x;
|
||||
vertices[(idx * 2) + 1] = y;
|
||||
}
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
/*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
|
||||
data->glDrawArrays(GL_LINE_STRIP, 0, count);
|
||||
|
||||
/* We need to close the endpoint of the line */
|
||||
@@ -1472,7 +1503,8 @@ GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
|
||||
vertices[5] = yMax;
|
||||
vertices[6] = xMax;
|
||||
vertices[7] = yMax;
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
/*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
|
||||
data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
return GL_CheckError("", renderer);
|
||||
@@ -1668,7 +1700,8 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s
|
||||
vertices[5] = (dstrect->y + dstrect->h);
|
||||
vertices[6] = (dstrect->x + dstrect->w);
|
||||
vertices[7] = (dstrect->y + dstrect->h);
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
/*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
|
||||
texCoords[0] = srcrect->x / (GLfloat)texture->w;
|
||||
texCoords[1] = srcrect->y / (GLfloat)texture->h;
|
||||
texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
|
||||
@@ -1677,7 +1710,8 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s
|
||||
texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
|
||||
texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
|
||||
texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
|
||||
/*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
|
||||
data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
return GL_CheckError("", renderer);
|
||||
@@ -1727,9 +1761,13 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
|
||||
vertices[5] = vertices[7] = tmp;
|
||||
}
|
||||
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle);
|
||||
/*data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle);
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, translate);
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
|
||||
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_ANGLE, fAngle, 4 * sizeof(GLfloat));
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_CENTER, translate, 8 * sizeof(GLfloat));
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
|
||||
|
||||
texCoords[0] = srcrect->x / (GLfloat)texture->w;
|
||||
texCoords[1] = srcrect->y / (GLfloat)texture->h;
|
||||
@@ -1739,7 +1777,8 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
|
||||
texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
|
||||
texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
|
||||
texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
|
||||
data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
|
||||
/*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
|
||||
GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
|
||||
data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
|
||||
data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
|
||||
|
||||
@@ -394,6 +394,9 @@ extern VideoBootStrap NACL_bootstrap;
|
||||
#if SDL_VIDEO_DRIVER_VIVANTE
|
||||
extern VideoBootStrap VIVANTE_bootstrap;
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
extern VideoBootStrap Emscripten_bootstrap;
|
||||
#endif
|
||||
|
||||
extern SDL_VideoDevice *SDL_GetVideoDevice(void);
|
||||
extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode);
|
||||
|
||||
@@ -98,6 +98,9 @@ static VideoBootStrap *bootstrap[] = {
|
||||
#if SDL_VIDEO_DRIVER_NACL
|
||||
&NACL_bootstrap,
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
&Emscripten_bootstrap,
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_DUMMY
|
||||
&DUMMY_bootstrap,
|
||||
#endif
|
||||
|
||||
638
src/video/emscripten/SDL_emscriptenevents.c
Normal file
638
src/video/emscripten/SDL_emscriptenevents.c
Normal file
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/SDL_touch_c.h"
|
||||
|
||||
#include "SDL_emscriptenevents.h"
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
|
||||
#include "SDL_hints.h"
|
||||
|
||||
#define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN )
|
||||
|
||||
/*
|
||||
.which to scancode
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Constants
|
||||
*/
|
||||
static const SDL_Scancode emscripten_scancode_table[] = {
|
||||
/* 0 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 1 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 2 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 3 */ SDL_SCANCODE_CANCEL,
|
||||
/* 4 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 5 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 6 */ SDL_SCANCODE_HELP,
|
||||
/* 7 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 8 */ SDL_SCANCODE_BACKSPACE,
|
||||
/* 9 */ SDL_SCANCODE_TAB,
|
||||
/* 10 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 11 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 12 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 13 */ SDL_SCANCODE_RETURN,
|
||||
/* 14 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 15 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 16 */ SDL_SCANCODE_LSHIFT,
|
||||
/* 17 */ SDL_SCANCODE_LCTRL,
|
||||
/* 18 */ SDL_SCANCODE_LALT,
|
||||
/* 19 */ SDL_SCANCODE_PAUSE,
|
||||
/* 20 */ SDL_SCANCODE_CAPSLOCK,
|
||||
/* 21 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 22 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 23 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 24 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 25 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 26 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 27 */ SDL_SCANCODE_ESCAPE,
|
||||
/* 28 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 29 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 30 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 31 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 32 */ SDL_SCANCODE_SPACE,
|
||||
/* 33 */ SDL_SCANCODE_PAGEUP,
|
||||
/* 34 */ SDL_SCANCODE_PAGEDOWN,
|
||||
/* 35 */ SDL_SCANCODE_END,
|
||||
/* 36 */ SDL_SCANCODE_HOME,
|
||||
/* 37 */ SDL_SCANCODE_LEFT,
|
||||
/* 38 */ SDL_SCANCODE_UP,
|
||||
/* 39 */ SDL_SCANCODE_RIGHT,
|
||||
/* 40 */ SDL_SCANCODE_DOWN,
|
||||
/* 41 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 42 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 43 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 44 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 45 */ SDL_SCANCODE_INSERT,
|
||||
/* 46 */ SDL_SCANCODE_DELETE,
|
||||
/* 47 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 48 */ SDL_SCANCODE_0,
|
||||
/* 49 */ SDL_SCANCODE_1,
|
||||
/* 50 */ SDL_SCANCODE_2,
|
||||
/* 51 */ SDL_SCANCODE_3,
|
||||
/* 52 */ SDL_SCANCODE_4,
|
||||
/* 53 */ SDL_SCANCODE_5,
|
||||
/* 54 */ SDL_SCANCODE_6,
|
||||
/* 55 */ SDL_SCANCODE_7,
|
||||
/* 56 */ SDL_SCANCODE_8,
|
||||
/* 57 */ SDL_SCANCODE_9,
|
||||
/* 58 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 59 */ SDL_SCANCODE_SEMICOLON,
|
||||
/* 60 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 61 */ SDL_SCANCODE_EQUALS,
|
||||
/* 62 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 63 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 64 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 65 */ SDL_SCANCODE_A,
|
||||
/* 66 */ SDL_SCANCODE_B,
|
||||
/* 67 */ SDL_SCANCODE_C,
|
||||
/* 68 */ SDL_SCANCODE_D,
|
||||
/* 69 */ SDL_SCANCODE_E,
|
||||
/* 70 */ SDL_SCANCODE_F,
|
||||
/* 71 */ SDL_SCANCODE_G,
|
||||
/* 72 */ SDL_SCANCODE_H,
|
||||
/* 73 */ SDL_SCANCODE_I,
|
||||
/* 74 */ SDL_SCANCODE_J,
|
||||
/* 75 */ SDL_SCANCODE_K,
|
||||
/* 76 */ SDL_SCANCODE_L,
|
||||
/* 77 */ SDL_SCANCODE_M,
|
||||
/* 78 */ SDL_SCANCODE_N,
|
||||
/* 79 */ SDL_SCANCODE_O,
|
||||
/* 80 */ SDL_SCANCODE_P,
|
||||
/* 81 */ SDL_SCANCODE_Q,
|
||||
/* 82 */ SDL_SCANCODE_R,
|
||||
/* 83 */ SDL_SCANCODE_S,
|
||||
/* 84 */ SDL_SCANCODE_T,
|
||||
/* 85 */ SDL_SCANCODE_U,
|
||||
/* 86 */ SDL_SCANCODE_V,
|
||||
/* 87 */ SDL_SCANCODE_W,
|
||||
/* 88 */ SDL_SCANCODE_X,
|
||||
/* 89 */ SDL_SCANCODE_Y,
|
||||
/* 90 */ SDL_SCANCODE_Z,
|
||||
/* 91 */ SDL_SCANCODE_LGUI,
|
||||
/* 92 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 93 */ SDL_SCANCODE_APPLICATION,
|
||||
/* 94 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 95 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 96 */ SDL_SCANCODE_KP_0,
|
||||
/* 97 */ SDL_SCANCODE_KP_1,
|
||||
/* 98 */ SDL_SCANCODE_KP_2,
|
||||
/* 99 */ SDL_SCANCODE_KP_3,
|
||||
/* 100 */ SDL_SCANCODE_KP_4,
|
||||
/* 101 */ SDL_SCANCODE_KP_5,
|
||||
/* 102 */ SDL_SCANCODE_KP_6,
|
||||
/* 103 */ SDL_SCANCODE_KP_7,
|
||||
/* 104 */ SDL_SCANCODE_KP_8,
|
||||
/* 105 */ SDL_SCANCODE_KP_9,
|
||||
/* 106 */ SDL_SCANCODE_KP_MULTIPLY,
|
||||
/* 107 */ SDL_SCANCODE_KP_PLUS,
|
||||
/* 108 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 109 */ SDL_SCANCODE_KP_MINUS,
|
||||
/* 110 */ SDL_SCANCODE_KP_PERIOD,
|
||||
/* 111 */ SDL_SCANCODE_KP_DIVIDE,
|
||||
/* 112 */ SDL_SCANCODE_F1,
|
||||
/* 113 */ SDL_SCANCODE_F2,
|
||||
/* 114 */ SDL_SCANCODE_F3,
|
||||
/* 115 */ SDL_SCANCODE_F4,
|
||||
/* 116 */ SDL_SCANCODE_F5,
|
||||
/* 117 */ SDL_SCANCODE_F6,
|
||||
/* 118 */ SDL_SCANCODE_F7,
|
||||
/* 119 */ SDL_SCANCODE_F8,
|
||||
/* 120 */ SDL_SCANCODE_F9,
|
||||
/* 121 */ SDL_SCANCODE_F10,
|
||||
/* 122 */ SDL_SCANCODE_F11,
|
||||
/* 123 */ SDL_SCANCODE_F12,
|
||||
/* 124 */ SDL_SCANCODE_F13,
|
||||
/* 125 */ SDL_SCANCODE_F14,
|
||||
/* 126 */ SDL_SCANCODE_F15,
|
||||
/* 127 */ SDL_SCANCODE_F16,
|
||||
/* 128 */ SDL_SCANCODE_F17,
|
||||
/* 129 */ SDL_SCANCODE_F18,
|
||||
/* 130 */ SDL_SCANCODE_F19,
|
||||
/* 131 */ SDL_SCANCODE_F20,
|
||||
/* 132 */ SDL_SCANCODE_F21,
|
||||
/* 133 */ SDL_SCANCODE_F22,
|
||||
/* 134 */ SDL_SCANCODE_F23,
|
||||
/* 135 */ SDL_SCANCODE_F24,
|
||||
/* 136 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 137 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 138 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 139 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 140 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 141 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 142 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 143 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 144 */ SDL_SCANCODE_NUMLOCKCLEAR,
|
||||
/* 145 */ SDL_SCANCODE_SCROLLLOCK,
|
||||
/* 146 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 147 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 148 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 149 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 150 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 151 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 152 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 153 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 154 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 155 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 156 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 157 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 158 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 159 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 160 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 161 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 162 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 163 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 164 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 165 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 166 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 167 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 168 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 169 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 170 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 171 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 172 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 173 */ SDL_SCANCODE_MINUS, /*FX*/
|
||||
/* 174 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 175 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 176 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 177 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 178 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 179 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 180 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 181 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 182 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 183 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 184 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 185 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 186 */ SDL_SCANCODE_SEMICOLON, /*IE, Chrome, D3E legacy*/
|
||||
/* 187 */ SDL_SCANCODE_EQUALS, /*IE, Chrome, D3E legacy*/
|
||||
/* 188 */ SDL_SCANCODE_COMMA,
|
||||
/* 189 */ SDL_SCANCODE_MINUS, /*IE, Chrome, D3E legacy*/
|
||||
/* 190 */ SDL_SCANCODE_PERIOD,
|
||||
/* 191 */ SDL_SCANCODE_SLASH,
|
||||
/* 192 */ SDL_SCANCODE_GRAVE, /*FX, D3E legacy (SDL_SCANCODE_APOSTROPHE in IE/Chrome)*/
|
||||
/* 193 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 194 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 195 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 196 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 197 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 198 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 199 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 200 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 201 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 202 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 203 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 204 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 205 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 206 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 207 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 208 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 209 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 210 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 211 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 212 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 213 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 214 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 215 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 216 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 217 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 218 */ SDL_SCANCODE_UNKNOWN,
|
||||
/* 219 */ SDL_SCANCODE_LEFTBRACKET,
|
||||
/* 220 */ SDL_SCANCODE_BACKSLASH,
|
||||
/* 221 */ SDL_SCANCODE_RIGHTBRACKET,
|
||||
/* 222 */ SDL_SCANCODE_APOSTROPHE, /*FX, D3E legacy*/
|
||||
};
|
||||
|
||||
|
||||
/* "borrowed" from SDL_windowsevents.c */
|
||||
int
|
||||
Emscripten_ConvertUTF32toUTF8(Uint32 codepoint, char * text)
|
||||
{
|
||||
if (codepoint <= 0x7F) {
|
||||
text[0] = (char) codepoint;
|
||||
text[1] = '\0';
|
||||
} else if (codepoint <= 0x7FF) {
|
||||
text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
|
||||
text[1] = 0x80 | (char) (codepoint & 0x3F);
|
||||
text[2] = '\0';
|
||||
} else if (codepoint <= 0xFFFF) {
|
||||
text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
|
||||
text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
|
||||
text[2] = 0x80 | (char) (codepoint & 0x3F);
|
||||
text[3] = '\0';
|
||||
} else if (codepoint <= 0x10FFFF) {
|
||||
text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
|
||||
text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
|
||||
text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
|
||||
text[3] = 0x80 | (char) (codepoint & 0x3F);
|
||||
text[4] = '\0';
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
SDL_WindowData *window_data = userData;
|
||||
int mx = mouseEvent->canvasX, my = mouseEvent->canvasY;
|
||||
EmscriptenPointerlockChangeEvent pointerlock_status;
|
||||
|
||||
/* check for pointer lock */
|
||||
emscripten_get_pointerlock_status(&pointerlock_status);
|
||||
|
||||
if (pointerlock_status.isActive) {
|
||||
mx = mouseEvent->movementX;
|
||||
my = mouseEvent->movementY;
|
||||
}
|
||||
|
||||
/* rescale (in case canvas is being scaled)*/
|
||||
double client_w, client_h;
|
||||
emscripten_get_element_css_size(NULL, &client_w, &client_h);
|
||||
|
||||
mx = mx * (window_data->window->w / (client_w * window_data->pixel_ratio));
|
||||
my = my * (window_data->window->h / (client_h * window_data->pixel_ratio));
|
||||
|
||||
SDL_SendMouseMotion(window_data->window, 0, pointerlock_status.isActive, mx, my);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
SDL_WindowData *window_data = userData;
|
||||
uint32_t sdl_button;
|
||||
switch (mouseEvent->button) {
|
||||
case 0:
|
||||
sdl_button = SDL_BUTTON_LEFT;
|
||||
break;
|
||||
case 1:
|
||||
sdl_button = SDL_BUTTON_MIDDLE;
|
||||
break;
|
||||
case 2:
|
||||
sdl_button = SDL_BUTTON_RIGHT;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
SDL_SendMouseButton(window_data->window, 0, eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED, sdl_button);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
SDL_WindowData *window_data = userData;
|
||||
SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? SDL_WINDOWEVENT_ENTER : SDL_WINDOWEVENT_LEAVE, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
|
||||
{
|
||||
SDL_WindowData *window_data = userData;
|
||||
SDL_SendMouseWheel(window_data->window, 0, wheelEvent->deltaX, -wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData)
|
||||
{
|
||||
SDL_WindowData *window_data = userData;
|
||||
SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||
{
|
||||
/*SDL_WindowData *window_data = userData;*/
|
||||
int i;
|
||||
|
||||
SDL_TouchID deviceId = 0;
|
||||
if (!SDL_GetTouch(deviceId)) {
|
||||
if (SDL_AddTouch(deviceId, "") < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < touchEvent->numTouches; i++) {
|
||||
long x, y, id;
|
||||
|
||||
if (!touchEvent->touches[i].isChanged)
|
||||
continue;
|
||||
|
||||
id = touchEvent->touches[i].identifier;
|
||||
x = touchEvent->touches[i].canvasX;
|
||||
y = touchEvent->touches[i].canvasY;
|
||||
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) {
|
||||
SDL_SendTouchMotion(deviceId, id, x, y, 1.0f);
|
||||
} else if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) {
|
||||
SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f);
|
||||
} else {
|
||||
SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
|
||||
{
|
||||
Uint32 scancode;
|
||||
|
||||
/* .keyCode is deprecated, but still the most reliable way to get keys */
|
||||
if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) {
|
||||
scancode = emscripten_scancode_table[keyEvent->keyCode];
|
||||
|
||||
if (scancode != SDL_SCANCODE_UNKNOWN) {
|
||||
|
||||
if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) {
|
||||
switch (scancode) {
|
||||
case SDL_SCANCODE_LSHIFT:
|
||||
scancode = SDL_SCANCODE_RSHIFT;
|
||||
break;
|
||||
case SDL_SCANCODE_LCTRL:
|
||||
scancode = SDL_SCANCODE_RCTRL;
|
||||
break;
|
||||
case SDL_SCANCODE_LALT:
|
||||
scancode = SDL_SCANCODE_RALT;
|
||||
break;
|
||||
case SDL_SCANCODE_LGUI:
|
||||
scancode = SDL_SCANCODE_RGUI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ?
|
||||
SDL_PRESSED : SDL_RELEASED, scancode);
|
||||
}
|
||||
}
|
||||
|
||||
/* if we prevent keydown, we won't get keypress
|
||||
* also we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX
|
||||
*/
|
||||
return SDL_GetEventState(SDL_TEXTINPUT) != SDL_ENABLE || eventType != EMSCRIPTEN_EVENT_KEYDOWN
|
||||
|| keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
|
||||
{
|
||||
char text[5];
|
||||
Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text);
|
||||
SDL_SendKeyboardText(text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)
|
||||
{
|
||||
/*make sure this is actually our element going fullscreen*/
|
||||
if(SDL_strcmp(fullscreenChangeEvent->id, "SDLFullscreenElement") != 0)
|
||||
return 0;
|
||||
|
||||
SDL_WindowData *window_data = userData;
|
||||
if(fullscreenChangeEvent->isFullscreen)
|
||||
{
|
||||
SDL_bool is_desktop_fullscreen;
|
||||
window_data->window->flags |= window_data->requested_fullscreen_mode;
|
||||
|
||||
if(!window_data->requested_fullscreen_mode)
|
||||
window_data->window->flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; /*we didn't reqest fullscreen*/
|
||||
|
||||
window_data->requested_fullscreen_mode = 0;
|
||||
|
||||
is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
|
||||
/*update size*/
|
||||
if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
|
||||
{
|
||||
emscripten_set_canvas_size(fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
|
||||
SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*preserve ratio*/
|
||||
double w = window_data->window->w;
|
||||
double h = window_data->window->h;
|
||||
double factor = SDL_min(fullscreenChangeEvent->screenWidth / w, fullscreenChangeEvent->screenHeight / h);
|
||||
emscripten_set_element_css_size(NULL, w * factor, h * factor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EM_ASM({
|
||||
//un-reparent canvas (similar to Module.requestFullscreen)
|
||||
var canvas = Module['canvas'];
|
||||
if(canvas.parentNode.id == "SDLFullscreenElement") {
|
||||
var canvasContainer = canvas.parentNode;
|
||||
canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
|
||||
canvasContainer.parentNode.removeChild(canvasContainer);
|
||||
}
|
||||
});
|
||||
double unscaled_w = window_data->windowed_width / window_data->pixel_ratio;
|
||||
double unscaled_h = window_data->windowed_height / window_data->pixel_ratio;
|
||||
emscripten_set_canvas_size(window_data->windowed_width, window_data->windowed_height);
|
||||
|
||||
if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
|
||||
emscripten_set_element_css_size(NULL, unscaled_w, unscaled_h);
|
||||
}
|
||||
|
||||
SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, unscaled_w, unscaled_h);
|
||||
|
||||
window_data->window->flags &= ~FULLSCREEN_MASK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
|
||||
{
|
||||
SDL_WindowData *window_data = userData;
|
||||
if(window_data->window->flags & FULLSCREEN_MASK)
|
||||
{
|
||||
SDL_bool is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
|
||||
if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen)
|
||||
{
|
||||
emscripten_set_canvas_size(uiEvent->windowInnerWidth * window_data->pixel_ratio, uiEvent->windowInnerHeight * window_data->pixel_ratio);
|
||||
SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, uiEvent->windowInnerWidth, uiEvent->windowInnerHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this will only work if the canvas size is set through css */
|
||||
if(window_data->window->flags & SDL_WINDOW_RESIZABLE)
|
||||
{
|
||||
double w = window_data->window->w;
|
||||
double h = window_data->window->h;
|
||||
|
||||
if(window_data->external_size) {
|
||||
emscripten_get_element_css_size(NULL, &w, &h);
|
||||
}
|
||||
|
||||
emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio);
|
||||
|
||||
/* set_canvas_size unsets this */
|
||||
if (!window_data->external_size && window_data->pixel_ratio != 1.0f) {
|
||||
emscripten_set_element_css_size(NULL, w, h);
|
||||
}
|
||||
|
||||
SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
|
||||
{
|
||||
SDL_WindowData *window_data = userData;
|
||||
SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Emscripten_RegisterEventHandlers(SDL_WindowData *data)
|
||||
{
|
||||
/* There is only one window and that window is the canvas */
|
||||
emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove);
|
||||
|
||||
emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
|
||||
emscripten_set_mouseup_callback("#canvas", data, 0, Emscripten_HandleMouseButton);
|
||||
|
||||
emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
|
||||
emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus);
|
||||
|
||||
emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel);
|
||||
|
||||
emscripten_set_focus_callback("#canvas", data, 0, Emscripten_HandleFocus);
|
||||
emscripten_set_blur_callback("#canvas", data, 0, Emscripten_HandleFocus);
|
||||
|
||||
emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch);
|
||||
emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
|
||||
emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
|
||||
emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
|
||||
|
||||
/* Keyboard events are awkward */
|
||||
const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
|
||||
if (!keyElement) keyElement = "#window";
|
||||
|
||||
emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey);
|
||||
emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey);
|
||||
emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress);
|
||||
|
||||
emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange);
|
||||
|
||||
emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize);
|
||||
|
||||
emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange);
|
||||
}
|
||||
|
||||
void
|
||||
Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
|
||||
{
|
||||
/* only works due to having one window */
|
||||
emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL);
|
||||
emscripten_set_mouseup_callback("#canvas", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL);
|
||||
emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_wheel_callback("#canvas", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_focus_callback("#canvas", NULL, 0, NULL);
|
||||
emscripten_set_blur_callback("#canvas", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL);
|
||||
emscripten_set_touchend_callback("#canvas", NULL, 0, NULL);
|
||||
emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL);
|
||||
emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_keydown_callback("#window", NULL, 0, NULL);
|
||||
emscripten_set_keyup_callback("#window", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_keypress_callback("#window", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_resize_callback("#window", NULL, 0, NULL);
|
||||
|
||||
emscripten_set_visibilitychange_callback(NULL, 0, NULL);
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
36
src/video/emscripten/SDL_emscriptenevents.h
Normal file
36
src/video/emscripten/SDL_emscriptenevents.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDL_emscriptenevents_h
|
||||
#define _SDL_emscriptenevents_h
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
|
||||
extern void
|
||||
Emscripten_RegisterEventHandlers(SDL_WindowData *data);
|
||||
|
||||
extern void
|
||||
Emscripten_UnregisterEventHandlers(SDL_WindowData *data);
|
||||
#endif /* _SDL_emscriptenevents_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
136
src/video/emscripten/SDL_emscriptenframebuffer.c
Normal file
136
src/video/emscripten/SDL_emscriptenframebuffer.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
#include "SDL_emscriptenframebuffer.h"
|
||||
|
||||
|
||||
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
|
||||
{
|
||||
SDL_Surface *surface;
|
||||
const Uint32 surface_format = SDL_PIXELFORMAT_BGR888;
|
||||
int w, h;
|
||||
int bpp;
|
||||
Uint32 Rmask, Gmask, Bmask, Amask;
|
||||
|
||||
/* Free the old framebuffer surface */
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
surface = data->surface;
|
||||
SDL_FreeSurface(surface);
|
||||
|
||||
/* Create a new one */
|
||||
SDL_PixelFormatEnumToMasks(surface_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
|
||||
surface = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask);
|
||||
if (!surface) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Save the info and return! */
|
||||
data->surface = surface;
|
||||
*format = surface_format;
|
||||
*pixels = surface->pixels;
|
||||
*pitch = surface->pitch;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
|
||||
{
|
||||
static int frame_number;
|
||||
SDL_Surface *surface;
|
||||
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
surface = data->surface;
|
||||
if (!surface) {
|
||||
return SDL_SetError("Couldn't find dummy surface for window");
|
||||
}
|
||||
|
||||
/* Send the data to the display */
|
||||
|
||||
EM_ASM_INT({
|
||||
//TODO: don't create context every update
|
||||
var ctx = Module['canvas'].getContext('2d');
|
||||
|
||||
//library_sdl.js SDL_UnlockSurface
|
||||
var image = ctx.createImageData($0, $1);
|
||||
var data = image.data;
|
||||
var src = $2 >> 2;
|
||||
var dst = 0;
|
||||
var isScreen = true;
|
||||
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] = isScreen ? 0xff : ((val >> 24) & 0xff);
|
||||
src++;
|
||||
dst += 4;
|
||||
}
|
||||
} else {
|
||||
var data32 = new Uint32Array(data.buffer);
|
||||
num = data32.length;
|
||||
if (isScreen) {
|
||||
while (dst < num) {
|
||||
// HEAP32[src++] is an optimization. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
|
||||
data32[dst++] = HEAP32[src++] | 0xff000000;
|
||||
}
|
||||
} else {
|
||||
while (dst < num) {
|
||||
data32[dst++] = HEAP32[src++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(image, 0, 0);
|
||||
return 0;
|
||||
}, surface->w, surface->h, surface->pixels);
|
||||
|
||||
/*if (SDL_getenv("SDL_VIDEO_Emscripten_SAVE_FRAMES")) {
|
||||
char file[128];
|
||||
SDL_snprintf(file, sizeof(file), "SDL_window%d-%8.8d.bmp",
|
||||
SDL_GetWindowID(window), ++frame_number);
|
||||
SDL_SaveBMP(surface, file);
|
||||
}*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
|
||||
SDL_FreeSurface(data->surface);
|
||||
data->surface = NULL;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
32
src/video/emscripten/SDL_emscriptenframebuffer.h
Normal file
32
src/video/emscripten/SDL_emscriptenframebuffer.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_emscriptenframebuffer_h
|
||||
#define _SDL_emscriptenframebuffer_h
|
||||
|
||||
extern int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch);
|
||||
extern int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects);
|
||||
extern void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window * window);
|
||||
|
||||
#endif /* _SDL_emsctiptenframebuffer_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
218
src/video/emscripten/SDL_emscriptenmouse.c
Normal file
218
src/video/emscripten/SDL_emscriptenmouse.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
#include "SDL_emscriptenmouse.h"
|
||||
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
|
||||
static SDL_Cursor*
|
||||
Emscripten_CreateDefaultCursor()
|
||||
{
|
||||
SDL_Cursor* cursor;
|
||||
Emscripten_CursorData *curdata;
|
||||
|
||||
cursor = SDL_calloc(1, sizeof(SDL_Cursor));
|
||||
if (cursor) {
|
||||
curdata = (Emscripten_CursorData *) SDL_calloc(1, sizeof(*curdata));
|
||||
|
||||
curdata->system_cursor = "default";
|
||||
cursor->driverdata = curdata;
|
||||
}
|
||||
else {
|
||||
SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static SDL_Cursor*
|
||||
Emscripten_CreateCursor(SDL_Surface* sruface, int hot_x, int hot_y)
|
||||
{
|
||||
return Emscripten_CreateDefaultCursor();
|
||||
}
|
||||
|
||||
static SDL_Cursor*
|
||||
Emscripten_CreateSystemCursor(SDL_SystemCursor id)
|
||||
{
|
||||
SDL_Cursor *cursor;
|
||||
Emscripten_CursorData *curdata;
|
||||
const char *cursor_name = NULL;
|
||||
|
||||
switch(id) {
|
||||
case SDL_SYSTEM_CURSOR_ARROW:
|
||||
cursor_name = "default";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_IBEAM:
|
||||
cursor_name = "text";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WAIT:
|
||||
cursor_name = "wait";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_CROSSHAIR:
|
||||
cursor_name = "crosshair";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WAITARROW:
|
||||
cursor_name = "progress";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZENWSE:
|
||||
cursor_name = "nwse-resize";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZENESW:
|
||||
cursor_name = "nesw-resize";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZEWE:
|
||||
cursor_name = "ew-resize";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZENS:
|
||||
cursor_name = "ns-resize";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZEALL:
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_NO:
|
||||
cursor_name = "not-allowed";
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_HAND:
|
||||
cursor_name = "pointer";
|
||||
break;
|
||||
default:
|
||||
SDL_assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
|
||||
curdata = (Emscripten_CursorData *) SDL_calloc(1, sizeof(*curdata));
|
||||
|
||||
curdata->system_cursor = cursor_name;
|
||||
cursor->driverdata = curdata;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_FreeCursor(SDL_Cursor* cursor)
|
||||
{
|
||||
Emscripten_CursorData *curdata;
|
||||
if (cursor) {
|
||||
curdata = (Emscripten_CursorData *) cursor->driverdata;
|
||||
|
||||
if (curdata != NULL) {
|
||||
SDL_free(cursor->driverdata);
|
||||
}
|
||||
|
||||
SDL_free(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
Emscripten_ShowCursor(SDL_Cursor* cursor)
|
||||
{
|
||||
Emscripten_CursorData *curdata;
|
||||
if (SDL_GetMouseFocus() != NULL) {
|
||||
if(cursor && cursor->driverdata) {
|
||||
curdata = (Emscripten_CursorData *) cursor->driverdata;
|
||||
|
||||
if(curdata->system_cursor) {
|
||||
EM_ASM_INT({
|
||||
if (Module['canvas']) {
|
||||
Module['canvas'].style['cursor'] = Module['Pointer_stringify']($0);
|
||||
}
|
||||
return 0;
|
||||
}, curdata->system_cursor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
EM_ASM(
|
||||
if (Module['canvas']) {
|
||||
Module['canvas'].style['cursor'] = 'none';
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_WarpMouse(SDL_Window* window, int x, int y)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
static int
|
||||
Emscripten_SetRelativeMouseMode(SDL_bool enabled)
|
||||
{
|
||||
/* TODO: pointer lock isn't actually enabled yet */
|
||||
if(enabled) {
|
||||
if(emscripten_request_pointerlock(NULL, 1) >= EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(emscripten_exit_pointerlock() >= EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
Emscripten_InitMouse()
|
||||
{
|
||||
SDL_Mouse* mouse = SDL_GetMouse();
|
||||
|
||||
mouse->CreateCursor = Emscripten_CreateCursor;
|
||||
mouse->ShowCursor = Emscripten_ShowCursor;
|
||||
mouse->FreeCursor = Emscripten_FreeCursor;
|
||||
mouse->WarpMouse = Emscripten_WarpMouse;
|
||||
mouse->CreateSystemCursor = Emscripten_CreateSystemCursor;
|
||||
mouse->SetRelativeMouseMode = Emscripten_SetRelativeMouseMode;
|
||||
|
||||
SDL_SetDefaultCursor(Emscripten_CreateDefaultCursor());
|
||||
}
|
||||
|
||||
void
|
||||
Emscripten_FiniMouse()
|
||||
{
|
||||
SDL_Mouse* mouse = SDL_GetMouse();
|
||||
|
||||
Emscripten_FreeCursor(mouse->def_cursor);
|
||||
mouse->def_cursor = NULL;
|
||||
|
||||
mouse->CreateCursor = NULL;
|
||||
mouse->ShowCursor = NULL;
|
||||
mouse->FreeCursor = NULL;
|
||||
mouse->WarpMouse = NULL;
|
||||
mouse->CreateSystemCursor = NULL;
|
||||
mouse->SetRelativeMouseMode = NULL;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
39
src/video/emscripten/SDL_emscriptenmouse.h
Normal file
39
src/video/emscripten/SDL_emscriptenmouse.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDL_emscriptenmouse_h
|
||||
#define _SDL_emscriptenmouse_h
|
||||
|
||||
typedef struct _Emscripten_CursorData
|
||||
{
|
||||
const char *system_cursor;
|
||||
} Emscripten_CursorData;
|
||||
|
||||
extern void
|
||||
Emscripten_InitMouse();
|
||||
|
||||
extern void
|
||||
Emscripten_FiniMouse();
|
||||
|
||||
#endif /* _SDL_emscriptenmouse_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
117
src/video/emscripten/SDL_emscriptenopengles.c
Normal file
117
src/video/emscripten/SDL_emscriptenopengles.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
#include "SDL_emscriptenopengles.h"
|
||||
|
||||
#define LOAD_FUNC(NAME) _this->egl_data->NAME = NAME;
|
||||
|
||||
/* EGL implementation of SDL OpenGL support */
|
||||
|
||||
int
|
||||
Emscripten_GLES_LoadLibrary(_THIS, const char *path) {
|
||||
/*we can't load EGL dynamically*/
|
||||
_this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
|
||||
if (!_this->egl_data) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
LOAD_FUNC(eglGetDisplay);
|
||||
LOAD_FUNC(eglInitialize);
|
||||
LOAD_FUNC(eglTerminate);
|
||||
LOAD_FUNC(eglGetProcAddress);
|
||||
LOAD_FUNC(eglChooseConfig);
|
||||
LOAD_FUNC(eglGetConfigAttrib);
|
||||
LOAD_FUNC(eglCreateContext);
|
||||
LOAD_FUNC(eglDestroyContext);
|
||||
LOAD_FUNC(eglCreateWindowSurface);
|
||||
LOAD_FUNC(eglDestroySurface);
|
||||
LOAD_FUNC(eglMakeCurrent);
|
||||
LOAD_FUNC(eglSwapBuffers);
|
||||
LOAD_FUNC(eglSwapInterval);
|
||||
LOAD_FUNC(eglWaitNative);
|
||||
LOAD_FUNC(eglWaitGL);
|
||||
LOAD_FUNC(eglBindAPI);
|
||||
|
||||
_this->egl_data->egl_display = _this->egl_data->eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (!_this->egl_data->egl_display) {
|
||||
return SDL_SetError("Could not get EGL display");
|
||||
}
|
||||
|
||||
if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
|
||||
return SDL_SetError("Could not initialize EGL");
|
||||
}
|
||||
|
||||
_this->gl_config.driver_loaded = 1;
|
||||
|
||||
if (path) {
|
||||
SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
|
||||
} else {
|
||||
*_this->gl_config.driver_path = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context)
|
||||
{
|
||||
/*
|
||||
WebGL contexts can't actually be deleted, so we need to reset it.
|
||||
ES2 renderer resets state on init anyway, clearing the canvas should be enough
|
||||
*/
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
SDL_EGL_DeleteContext(_this, context);
|
||||
}
|
||||
|
||||
SDL_EGL_CreateContext_impl(Emscripten)
|
||||
SDL_EGL_SwapWindow_impl(Emscripten)
|
||||
SDL_EGL_MakeCurrent_impl(Emscripten)
|
||||
|
||||
void
|
||||
Emscripten_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
if (window->driverdata) {
|
||||
data = (SDL_WindowData *) window->driverdata;
|
||||
|
||||
if (w) {
|
||||
*w = window->w * data->pixel_ratio;
|
||||
}
|
||||
|
||||
if (h) {
|
||||
*h = window->h * data->pixel_ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
49
src/video/emscripten/SDL_emscriptenopengles.h
Normal file
49
src/video/emscripten/SDL_emscriptenopengles.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_emscriptenopengles_h
|
||||
#define _SDL_emscriptenopengles_h
|
||||
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../SDL_egl_c.h"
|
||||
|
||||
/* OpenGLES functions */
|
||||
#define Emscripten_GLES_GetAttribute SDL_EGL_GetAttribute
|
||||
#define Emscripten_GLES_GetProcAddress SDL_EGL_GetProcAddress
|
||||
#define Emscripten_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
|
||||
#define Emscripten_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
|
||||
#define Emscripten_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
|
||||
|
||||
extern int Emscripten_GLES_LoadLibrary(_THIS, const char *path);
|
||||
extern void Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context);
|
||||
extern SDL_GLContext Emscripten_GLES_CreateContext(_THIS, SDL_Window * window);
|
||||
extern void Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window);
|
||||
extern int Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
|
||||
extern void Emscripten_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h);
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */
|
||||
|
||||
#endif /* _SDL_emscriptenopengles_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
320
src/video/emscripten/SDL_emscriptenvideo.c
Normal file
320
src/video/emscripten/SDL_emscriptenvideo.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_VIDEO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include "SDL_video.h"
|
||||
#include "SDL_mouse.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../SDL_egl_c.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#include "SDL_emscriptenvideo.h"
|
||||
#include "SDL_emscriptenopengles.h"
|
||||
#include "SDL_emscriptenframebuffer.h"
|
||||
#include "SDL_emscriptenevents.h"
|
||||
#include "SDL_emscriptenmouse.h"
|
||||
|
||||
#define EMSCRIPTENVID_DRIVER_NAME "emscripten"
|
||||
|
||||
/* Initialization/Query functions */
|
||||
static int Emscripten_VideoInit(_THIS);
|
||||
static int Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
|
||||
static void Emscripten_VideoQuit(_THIS);
|
||||
|
||||
static int Emscripten_CreateWindow(_THIS, SDL_Window * window);
|
||||
static void Emscripten_SetWindowSize(_THIS, SDL_Window * window);
|
||||
static void Emscripten_DestroyWindow(_THIS, SDL_Window * window);
|
||||
static void Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
|
||||
static void Emscripten_PumpEvents(_THIS);
|
||||
|
||||
|
||||
/* Emscripten driver bootstrap functions */
|
||||
|
||||
static int
|
||||
Emscripten_Available(void)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_DeleteDevice(SDL_VideoDevice * device)
|
||||
{
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_VideoDevice *
|
||||
Emscripten_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_VideoDevice *device;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
|
||||
if (!device) {
|
||||
SDL_OutOfMemory();
|
||||
SDL_free(device);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
device->VideoInit = Emscripten_VideoInit;
|
||||
device->VideoQuit = Emscripten_VideoQuit;
|
||||
device->SetDisplayMode = Emscripten_SetDisplayMode;
|
||||
|
||||
|
||||
device->PumpEvents = Emscripten_PumpEvents;
|
||||
|
||||
device->CreateWindow = Emscripten_CreateWindow;
|
||||
/*device->CreateWindowFrom = Emscripten_CreateWindowFrom;
|
||||
device->SetWindowTitle = Emscripten_SetWindowTitle;
|
||||
device->SetWindowIcon = Emscripten_SetWindowIcon;
|
||||
device->SetWindowPosition = Emscripten_SetWindowPosition;*/
|
||||
device->SetWindowSize = Emscripten_SetWindowSize;
|
||||
/*device->ShowWindow = Emscripten_ShowWindow;
|
||||
device->HideWindow = Emscripten_HideWindow;
|
||||
device->RaiseWindow = Emscripten_RaiseWindow;
|
||||
device->MaximizeWindow = Emscripten_MaximizeWindow;
|
||||
device->MinimizeWindow = Emscripten_MinimizeWindow;
|
||||
device->RestoreWindow = Emscripten_RestoreWindow;
|
||||
device->SetWindowGrab = Emscripten_SetWindowGrab;*/
|
||||
device->DestroyWindow = Emscripten_DestroyWindow;
|
||||
device->SetWindowFullscreen = Emscripten_SetWindowFullscreen;
|
||||
|
||||
device->CreateWindowFramebuffer = Emscripten_CreateWindowFramebuffer;
|
||||
device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
|
||||
device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer;
|
||||
|
||||
device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary;
|
||||
device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress;
|
||||
device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary;
|
||||
device->GL_CreateContext = Emscripten_GLES_CreateContext;
|
||||
device->GL_MakeCurrent = Emscripten_GLES_MakeCurrent;
|
||||
device->GL_SetSwapInterval = Emscripten_GLES_SetSwapInterval;
|
||||
device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval;
|
||||
device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
|
||||
device->GL_DeleteContext = Emscripten_GLES_DeleteContext;
|
||||
device->GL_GetDrawableSize = Emscripten_GLES_GetDrawableSize;
|
||||
|
||||
device->free = Emscripten_DeleteDevice;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
VideoBootStrap Emscripten_bootstrap = {
|
||||
EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver",
|
||||
Emscripten_Available, Emscripten_CreateDevice
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
Emscripten_VideoInit(_THIS)
|
||||
{
|
||||
SDL_DisplayMode mode;
|
||||
double css_w, css_h;
|
||||
|
||||
/* Use a fake 32-bpp desktop mode */
|
||||
mode.format = SDL_PIXELFORMAT_RGB888;
|
||||
|
||||
emscripten_get_element_css_size(NULL, &css_w, &css_h);
|
||||
|
||||
mode.w = css_w;
|
||||
mode.h = css_h;
|
||||
|
||||
mode.refresh_rate = 0;
|
||||
mode.driverdata = NULL;
|
||||
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_zero(mode);
|
||||
SDL_AddDisplayMode(&_this->displays[0], &mode);
|
||||
|
||||
Emscripten_InitMouse();
|
||||
|
||||
/* We're done! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
||||
{
|
||||
/* can't do this */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_VideoQuit(_THIS)
|
||||
{
|
||||
Emscripten_FiniMouse();
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_PumpEvents(_THIS)
|
||||
{
|
||||
/* do nothing. */
|
||||
}
|
||||
|
||||
static int
|
||||
Emscripten_CreateWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *wdata;
|
||||
double scaled_w, scaled_h;
|
||||
double css_w, css_h;
|
||||
|
||||
/* Allocate window internal data */
|
||||
wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
|
||||
if (wdata == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
|
||||
wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
|
||||
} else {
|
||||
wdata->pixel_ratio = 1.0f;
|
||||
}
|
||||
|
||||
scaled_w = SDL_floor(window->w * wdata->pixel_ratio);
|
||||
scaled_h = SDL_floor(window->h * wdata->pixel_ratio);
|
||||
|
||||
emscripten_set_canvas_size(scaled_w, scaled_h);
|
||||
|
||||
emscripten_get_element_css_size(NULL, &css_w, &css_h);
|
||||
|
||||
wdata->external_size = css_w != scaled_w || css_h != scaled_h;
|
||||
|
||||
if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) {
|
||||
/* external css has resized us */
|
||||
scaled_w = css_w * wdata->pixel_ratio;
|
||||
scaled_h = css_h * wdata->pixel_ratio;
|
||||
|
||||
emscripten_set_canvas_size(scaled_w, scaled_h);
|
||||
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
|
||||
}
|
||||
|
||||
/* if the size is not being controlled by css, we need to scale down for hidpi */
|
||||
if (!wdata->external_size) {
|
||||
if (wdata->pixel_ratio != 1.0f) {
|
||||
/*scale canvas down*/
|
||||
emscripten_set_element_css_size(NULL, window->w, window->h);
|
||||
}
|
||||
}
|
||||
|
||||
wdata->windowed_width = scaled_w;
|
||||
wdata->windowed_height = scaled_h;
|
||||
|
||||
if (window->flags & SDL_WINDOW_OPENGL) {
|
||||
if (!_this->egl_data) {
|
||||
if (SDL_GL_LoadLibrary(NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
wdata->egl_surface = SDL_EGL_CreateSurface(_this, NULL);
|
||||
|
||||
if (wdata->egl_surface == EGL_NO_SURFACE) {
|
||||
return SDL_SetError("Could not create GLES window surface");
|
||||
}
|
||||
}
|
||||
|
||||
wdata->window = window;
|
||||
|
||||
/* Setup driver data for this window */
|
||||
window->driverdata = wdata;
|
||||
|
||||
/* One window, it always has focus */
|
||||
SDL_SetMouseFocus(window);
|
||||
SDL_SetKeyboardFocus(window);
|
||||
|
||||
Emscripten_RegisterEventHandlers(wdata);
|
||||
|
||||
/* Window has been successfully created */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Emscripten_SetWindowSize(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
|
||||
if (window->driverdata) {
|
||||
data = (SDL_WindowData *) window->driverdata;
|
||||
emscripten_set_canvas_size(window->w * data->pixel_ratio, window->h * data->pixel_ratio);
|
||||
|
||||
/*scale canvas down*/
|
||||
if (!data->external_size && data->pixel_ratio != 1.0f) {
|
||||
emscripten_set_element_css_size(NULL, window->w, window->h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_DestroyWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
|
||||
if(window->driverdata) {
|
||||
data = (SDL_WindowData *) window->driverdata;
|
||||
|
||||
Emscripten_UnregisterEventHandlers(data);
|
||||
if (data->egl_surface != EGL_NO_SURFACE) {
|
||||
SDL_EGL_DestroySurface(_this, data->egl_surface);
|
||||
data->egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
SDL_free(window->driverdata);
|
||||
window->driverdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
if(window->driverdata) {
|
||||
data = (SDL_WindowData *) window->driverdata;
|
||||
|
||||
if(fullscreen) {
|
||||
data->requested_fullscreen_mode = window->flags & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
|
||||
/*unset the fullscreen flags as we're not actually fullscreen yet*/
|
||||
window->flags &= ~(SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
|
||||
|
||||
EM_ASM({
|
||||
//reparent canvas (similar to Module.requestFullscreen)
|
||||
var canvas = Module['canvas'];
|
||||
if(canvas.parentNode.id != "SDLFullscreenElement") {
|
||||
var canvasContainer = document.createElement("div");
|
||||
canvasContainer.id = "SDLFullscreenElement";
|
||||
canvas.parentNode.insertBefore(canvasContainer, canvas);
|
||||
canvasContainer.appendChild(canvas);
|
||||
}
|
||||
});
|
||||
|
||||
int is_fullscreen;
|
||||
emscripten_get_canvas_size(&data->windowed_width, &data->windowed_height, &is_fullscreen);
|
||||
emscripten_request_fullscreen("SDLFullscreenElement", 1);
|
||||
}
|
||||
else
|
||||
emscripten_exit_fullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
52
src/video/emscripten/SDL_emscriptenvideo.h
Normal file
52
src/video/emscripten/SDL_emscriptenvideo.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_emscriptenvideo_h
|
||||
#define _SDL_emscriptenvideo_h
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
typedef struct SDL_WindowData
|
||||
{
|
||||
#if SDL_VIDEO_OPENGL_EGL
|
||||
EGLSurface egl_surface;
|
||||
#endif
|
||||
SDL_Window *window;
|
||||
SDL_Surface *surface;
|
||||
|
||||
int windowed_width;
|
||||
int windowed_height;
|
||||
|
||||
float pixel_ratio;
|
||||
|
||||
SDL_bool external_size;
|
||||
|
||||
int requested_fullscreen_mode;
|
||||
} SDL_WindowData;
|
||||
|
||||
#endif /* _SDL_emscriptenvideo_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
Reference in New Issue
Block a user