2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_DRIVER_EMSCRIPTEN
25 #include "SDL_video.h"
26 #include "SDL_mouse.h"
27 #include "SDL_hints.h"
28 #include "../SDL_sysvideo.h"
29 #include "../SDL_pixels_c.h"
30 #include "../SDL_egl_c.h"
31 #include "../../events/SDL_events_c.h"
33 #include "SDL_emscriptenvideo.h"
34 #include "SDL_emscriptenopengles.h"
35 #include "SDL_emscriptenframebuffer.h"
36 #include "SDL_emscriptenevents.h"
37 #include "SDL_emscriptenmouse.h"
39 #define EMSCRIPTENVID_DRIVER_NAME "emscripten"
41 /* Initialization/Query functions */
42 static int Emscripten_VideoInit(_THIS);
43 static int Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
44 static void Emscripten_VideoQuit(_THIS);
46 static int Emscripten_CreateWindow(_THIS, SDL_Window * window);
47 static void Emscripten_SetWindowSize(_THIS, SDL_Window * window);
48 static void Emscripten_DestroyWindow(_THIS, SDL_Window * window);
49 static void Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
50 static void Emscripten_PumpEvents(_THIS);
51 static void Emscripten_SetWindowTitle(_THIS, SDL_Window * window);
54 /* Emscripten driver bootstrap functions */
57 Emscripten_Available(void)
63 Emscripten_DeleteDevice(SDL_VideoDevice * device)
68 static SDL_VideoDevice *
69 Emscripten_CreateDevice(int devindex)
71 SDL_VideoDevice *device;
73 /* Initialize all variables that we clean on shutdown */
74 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
80 /* Firefox sends blur event which would otherwise prevent full screen
81 * when the user clicks to allow full screen.
82 * See https://bugzilla.mozilla.org/show_bug.cgi?id=1144964
84 SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
86 /* Set the function pointers */
87 device->VideoInit = Emscripten_VideoInit;
88 device->VideoQuit = Emscripten_VideoQuit;
89 device->SetDisplayMode = Emscripten_SetDisplayMode;
92 device->PumpEvents = Emscripten_PumpEvents;
94 device->CreateWindow = Emscripten_CreateWindow;
95 /*device->CreateWindowFrom = Emscripten_CreateWindowFrom;*/
96 device->SetWindowTitle = Emscripten_SetWindowTitle;
97 /*device->SetWindowIcon = Emscripten_SetWindowIcon;
98 device->SetWindowPosition = Emscripten_SetWindowPosition;*/
99 device->SetWindowSize = Emscripten_SetWindowSize;
100 /*device->ShowWindow = Emscripten_ShowWindow;
101 device->HideWindow = Emscripten_HideWindow;
102 device->RaiseWindow = Emscripten_RaiseWindow;
103 device->MaximizeWindow = Emscripten_MaximizeWindow;
104 device->MinimizeWindow = Emscripten_MinimizeWindow;
105 device->RestoreWindow = Emscripten_RestoreWindow;
106 device->SetWindowGrab = Emscripten_SetWindowGrab;*/
107 device->DestroyWindow = Emscripten_DestroyWindow;
108 device->SetWindowFullscreen = Emscripten_SetWindowFullscreen;
110 device->CreateWindowFramebuffer = Emscripten_CreateWindowFramebuffer;
111 device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
112 device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer;
114 device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary;
115 device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress;
116 device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary;
117 device->GL_CreateContext = Emscripten_GLES_CreateContext;
118 device->GL_MakeCurrent = Emscripten_GLES_MakeCurrent;
119 device->GL_SetSwapInterval = Emscripten_GLES_SetSwapInterval;
120 device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval;
121 device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
122 device->GL_DeleteContext = Emscripten_GLES_DeleteContext;
123 device->GL_GetDrawableSize = Emscripten_GLES_GetDrawableSize;
125 device->free = Emscripten_DeleteDevice;
130 VideoBootStrap Emscripten_bootstrap = {
131 EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver",
132 Emscripten_Available, Emscripten_CreateDevice
137 Emscripten_VideoInit(_THIS)
139 SDL_DisplayMode mode;
141 /* Use a fake 32-bpp desktop mode */
142 mode.format = SDL_PIXELFORMAT_RGB888;
144 mode.w = EM_ASM_INT_V({
148 mode.h = EM_ASM_INT_V({
149 return screen.height;
152 mode.refresh_rate = 0;
153 mode.driverdata = NULL;
154 if (SDL_AddBasicVideoDisplay(&mode) < 0) {
159 SDL_AddDisplayMode(&_this->displays[0], &mode);
161 Emscripten_InitMouse();
168 Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
175 Emscripten_VideoQuit(_THIS)
177 Emscripten_FiniMouse();
181 Emscripten_PumpEvents(_THIS)
187 Emscripten_CreateWindow(_THIS, SDL_Window * window)
189 SDL_WindowData *wdata;
190 double scaled_w, scaled_h;
193 /* Allocate window internal data */
194 wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
196 return SDL_OutOfMemory();
199 if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
200 wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
202 wdata->pixel_ratio = 1.0f;
205 scaled_w = SDL_floor(window->w * wdata->pixel_ratio);
206 scaled_h = SDL_floor(window->h * wdata->pixel_ratio);
208 emscripten_set_canvas_size(scaled_w, scaled_h);
210 emscripten_get_element_css_size(NULL, &css_w, &css_h);
212 wdata->external_size = SDL_floor(css_w) != scaled_w || SDL_floor(css_h) != scaled_h;
214 if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) {
215 /* external css has resized us */
216 scaled_w = css_w * wdata->pixel_ratio;
217 scaled_h = css_h * wdata->pixel_ratio;
219 emscripten_set_canvas_size(scaled_w, scaled_h);
220 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
223 /* if the size is not being controlled by css, we need to scale down for hidpi */
224 if (!wdata->external_size) {
225 if (wdata->pixel_ratio != 1.0f) {
226 /*scale canvas down*/
227 emscripten_set_element_css_size(NULL, window->w, window->h);
231 if (window->flags & SDL_WINDOW_OPENGL) {
232 if (!_this->egl_data) {
233 if (SDL_GL_LoadLibrary(NULL) < 0) {
237 wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0);
239 if (wdata->egl_surface == EGL_NO_SURFACE) {
240 return SDL_SetError("Could not create GLES window surface");
244 wdata->window = window;
246 /* Setup driver data for this window */
247 window->driverdata = wdata;
249 /* One window, it always has focus */
250 SDL_SetMouseFocus(window);
251 SDL_SetKeyboardFocus(window);
253 Emscripten_RegisterEventHandlers(wdata);
255 /* Window has been successfully created */
259 static void Emscripten_SetWindowSize(_THIS, SDL_Window * window)
261 SDL_WindowData *data;
263 if (window->driverdata) {
264 data = (SDL_WindowData *) window->driverdata;
265 /* update pixel ratio */
266 data->pixel_ratio = emscripten_get_device_pixel_ratio();
267 emscripten_set_canvas_size(window->w * data->pixel_ratio, window->h * data->pixel_ratio);
269 /*scale canvas down*/
270 if (!data->external_size && data->pixel_ratio != 1.0f) {
271 emscripten_set_element_css_size(NULL, window->w, window->h);
277 Emscripten_DestroyWindow(_THIS, SDL_Window * window)
279 SDL_WindowData *data;
281 if(window->driverdata) {
282 data = (SDL_WindowData *) window->driverdata;
284 Emscripten_UnregisterEventHandlers(data);
285 if (data->egl_surface != EGL_NO_SURFACE) {
286 SDL_EGL_DestroySurface(_this, data->egl_surface);
287 data->egl_surface = EGL_NO_SURFACE;
289 SDL_free(window->driverdata);
290 window->driverdata = NULL;
295 Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
297 SDL_WindowData *data;
298 if(window->driverdata) {
299 data = (SDL_WindowData *) window->driverdata;
302 EmscriptenFullscreenStrategy strategy;
303 SDL_bool is_desktop_fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
306 strategy.scaleMode = is_desktop_fullscreen ? EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH : EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT;
308 if(!is_desktop_fullscreen) {
309 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE;
310 } else if(window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
311 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
313 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
316 strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
318 strategy.canvasResizedCallback = Emscripten_HandleCanvasResize;
319 strategy.canvasResizedCallbackUserData = data;
321 data->requested_fullscreen_mode = window->flags & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
322 data->fullscreen_resize = is_desktop_fullscreen;
324 res = emscripten_request_fullscreen_strategy(NULL, 1, &strategy);
325 if(res != EMSCRIPTEN_RESULT_SUCCESS && res != EMSCRIPTEN_RESULT_DEFERRED) {
326 /* unset flags, fullscreen failed */
327 window->flags &= ~(SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
331 emscripten_exit_fullscreen();
336 Emscripten_SetWindowTitle(_THIS, SDL_Window * window) {
338 if (typeof Module['setWindowTitle'] !== 'undefined') {
339 Module['setWindowTitle'](Module['Pointer_stringify']($0));
345 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
347 /* vi: set ts=4 sw=4 expandtab: */