SDL_emscriptenvideo.c
Go to the documentation of this file.
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 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_hints.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);
static void Emscripten_SetWindowTitle(_THIS, SDL_Window * window);
/* 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();
return (0);
}
/* Firefox sends blur event which would otherwise prevent full screen
* when the user clicks to allow full screen.
* See https://bugzilla.mozilla.org/show_bug.cgi?id=1144964
*/
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
/* Set the function pointers */
device->VideoInit = Emscripten_VideoInit;
device->VideoQuit = Emscripten_VideoQuit;
device->SetDisplayMode = Emscripten_SetDisplayMode;
device->PumpEvents = Emscripten_PumpEvents;
device->CreateSDLWindow = Emscripten_CreateWindow;
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;
#if SDL_VIDEO_OPENGL_EGL
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;
#endif
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;
/* Use a fake 32-bpp desktop mode */
mode.format = SDL_PIXELFORMAT_RGB888;
mode.w = EM_ASM_INT_V({
return screen.width;
});
mode.h = EM_ASM_INT_V({
return screen.height;
});
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 = SDL_floor(css_w) != scaled_w || SDL_floor(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);
}
}
#if SDL_VIDEO_OPENGL_EGL
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, 0);
if (wdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface");
}
}
#endif
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;
/* update pixel ratio */
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
data->pixel_ratio = emscripten_get_device_pixel_ratio();
}
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 SDL_VIDEO_OPENGL_EGL
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_DestroySurface(_this, data->egl_surface);
data->egl_surface = EGL_NO_SURFACE;
}
#endif
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) {
EmscriptenFullscreenStrategy strategy;
SDL_bool is_desktop_fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
int res;
strategy.scaleMode = is_desktop_fullscreen ? EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH : EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT;
if(!is_desktop_fullscreen) {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE;
} else if(window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
} else {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
}
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
strategy.canvasResizedCallback = Emscripten_HandleCanvasResize;
strategy.canvasResizedCallbackUserData = data;
data->requested_fullscreen_mode = window->flags & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
data->fullscreen_resize = is_desktop_fullscreen;
res = emscripten_request_fullscreen_strategy(NULL, 1, &strategy);
if(res != EMSCRIPTEN_RESULT_SUCCESS && res != EMSCRIPTEN_RESULT_DEFERRED) {
/* unset flags, fullscreen failed */
window->flags &= ~(SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
}
}
else
emscripten_exit_fullscreen();
}
}
static void
Emscripten_SetWindowTitle(_THIS, SDL_Window * window) {
EM_ASM_INT({
if (typeof Module['setWindowTitle'] !== 'undefined') {
Module['setWindowTitle'](Module['Pointer_stringify']($0));
}
return 0;
}, window->title);
}
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
/* vi: set ts=4 sw=4 expandtab: */
SDL_WindowData::pixel_ratio
float pixel_ratio
Definition: SDL_emscriptenvideo.h:43
SDL_SetKeyboardFocus
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
SDL_emscriptenvideo.h
SDL_Window::w
int w
Definition: SDL_sysvideo.h:80
Emscripten_HandleCanvasResize
EM_BOOL Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
EGL_NO_SURFACE
#define EGL_NO_SURFACE
Definition: egl.h:100
SDL_DisplayMode::w
int w
Definition: SDL_video.h:56
Emscripten_FiniMouse
void Emscripten_FiniMouse()
SDL_VideoDevice::free
void(* free)(_THIS)
Definition: SDL_sysvideo.h:390
SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS
#define SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS
Minimize your SDL_Window if it loses key focus when in fullscreen mode. Defaults to true...
Definition: SDL_hints.h:312
SDL_AddBasicVideoDisplay
int SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode)
Definition: SDL_video.c:592
SDL_emscriptenmouse.h
SDL_VideoDevice::GL_SetSwapInterval
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:260
SDL_DisplayMode
The structure that defines a display mode.
Definition: SDL_video.h:53
SDL_VideoDevice::SetWindowSize
void(* SetWindowSize)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:215
SDL_DisplayMode::refresh_rate
int refresh_rate
Definition: SDL_video.h:58
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_SendWindowEvent
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
Definition: SDL_windowevents.c:88
SDL_WindowData::window
SDL_Window * window
Definition: SDL_cocoawindow.h:114
SDL_emscriptenevents.h
Emscripten_bootstrap
VideoBootStrap Emscripten_bootstrap
SDL_SetMouseFocus
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:151
Emscripten_DestroyWindowFramebuffer
void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window *window)
SDL_GL_LoadLibrary
#define SDL_GL_LoadLibrary
Definition: SDL_dynapi_overrides.h:553
SDL_floor
#define SDL_floor
Definition: SDL_dynapi_overrides.h:431
Emscripten_RegisterEventHandlers
void Emscripten_RegisterEventHandlers(SDL_WindowData *data)
SDL_VideoDevice::GL_LoadLibrary
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:254
SDL_PIXELFORMAT_RGB888
Definition: SDL_pixels.h:236
res
GLuint res
Definition: SDL_opengl_glext.h:7937
SDL_VideoDevice::SetDisplayMode
int(* SetDisplayMode)(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
Definition: SDL_sysvideo.h:204
SDL_WindowData
Definition: SDL_androidwindow.h:35
SDL_VideoDevice::GL_GetDrawableSize
void(* GL_GetDrawableSize)(_THIS, SDL_Window *window, int *w, int *h)
Definition: SDL_sysvideo.h:259
_this
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
Emscripten_CreateWindowFramebuffer
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
SDL_video.h
SDL_VideoDevice::GL_CreateContext
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:257
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_VideoDevice::GL_MakeCurrent
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:258
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_WindowData::external_size
SDL_bool external_size
Definition: SDL_emscriptenvideo.h:45
SDL_DisplayMode::driverdata
void * driverdata
Definition: SDL_video.h:59
SDL_mouse.h
VideoBootStrap
Definition: SDL_sysvideo.h:393
SDL_WINDOW_ALLOW_HIGHDPI
Definition: SDL_video.h:113
SDL_emscriptenopengles.h
mode
GLenum mode
Definition: SDL_opengl_glext.h:1122
SDL_hints.h
SDL_VideoDevice::displays
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:312
SDL_VideoDevice::DestroyWindow
void(* DestroyWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:234
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_DisplayMode::h
int h
Definition: SDL_video.h:57
SDL_Window::title
char * title
Definition: SDL_sysvideo.h:77
SDL_VideoDisplay
Definition: SDL_sysvideo.h:125
SDL_VideoDevice::DestroyWindowFramebuffer
void(* DestroyWindowFramebuffer)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:237
SDL_Window::h
int h
Definition: SDL_sysvideo.h:80
SDL_VideoDevice::GL_UnloadLibrary
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:256
NULL
#define NULL
Definition: begin_code.h:164
SDL_VideoDevice::CreateSDLWindow
int(* CreateSDLWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:210
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:139
SDL_WINDOW_RESIZABLE
Definition: SDL_video.h:105
SDL_VideoDevice::VideoQuit
void(* VideoQuit)(_THIS)
Definition: SDL_sysvideo.h:166
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_WindowData::requested_fullscreen_mode
int requested_fullscreen_mode
Definition: SDL_emscriptenvideo.h:47
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_emscriptenframebuffer.h
window
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
SDL_SetHint
#define SDL_SetHint
Definition: SDL_dynapi_overrides.h:190
SDL_VideoDevice::GL_SwapWindow
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:262
SDL_Window
The type used to identify a window.
Definition: SDL_sysvideo.h:73
SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:100
SDL_VideoDevice
Definition: SDL_sysvideo.h:147
SDL_AddDisplayMode
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:743
SDL_VideoDevice::VideoInit
int(* VideoInit)(_THIS)
Definition: SDL_sysvideo.h:160
SDL_VideoDevice::SetWindowFullscreen
void(* SetWindowFullscreen)(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
Definition: SDL_sysvideo.h:230
SDL_WINDOW_OPENGL
Definition: SDL_video.h:101
SDL_WINDOWEVENT_RESIZED
Definition: SDL_video.h:155
SDL_VideoDevice::UpdateWindowFramebuffer
int(* UpdateWindowFramebuffer)(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
Definition: SDL_sysvideo.h:236
SDL_Window::driverdata
void * driverdata
Definition: SDL_sysvideo.h:111
SDL_VideoDevice::GL_DeleteContext
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:263
SDL_DisplayMode::format
Uint32 format
Definition: SDL_video.h:55
SDL_VideoDevice::SetWindowTitle
void(* SetWindowTitle)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:212
Emscripten_UnregisterEventHandlers
void Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
SDL_VideoDevice::GL_GetSwapInterval
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:261
SDL_Window::flags
Uint32 flags
Definition: SDL_sysvideo.h:83
Emscripten_UpdateWindowFramebuffer
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
screen
SDL_Renderer * screen
Definition: testgamecontroller.c:64
SDL_WindowData::fullscreen_resize
SDL_bool fullscreen_resize
Definition: SDL_emscriptenvideo.h:48
SDL_VideoDevice::CreateWindowFramebuffer
int(* CreateWindowFramebuffer)(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
Definition: SDL_sysvideo.h:235
SDL_VideoDevice::GL_GetProcAddress
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:255
SDL_WINDOW_FULLSCREEN_DESKTOP
Definition: SDL_video.h:111
SDL_WindowData::egl_surface
EGLSurface egl_surface
Definition: SDL_androidwindow.h:37
Emscripten_InitMouse
void Emscripten_InitMouse()
SDL_VideoDevice::PumpEvents
void(* PumpEvents)(_THIS)
Definition: SDL_sysvideo.h:280