SDL 2.0
SDL_emscriptenvideo.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../../SDL_internal.h"
22
23#if SDL_VIDEO_DRIVER_EMSCRIPTEN
24
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"
32
33#include "SDL_emscriptenvideo.h"
37#include "SDL_emscriptenmouse.h"
38
39#define EMSCRIPTENVID_DRIVER_NAME "emscripten"
40
41/* Initialization/Query functions */
42static int Emscripten_VideoInit(_THIS);
43static int Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
44static void Emscripten_VideoQuit(_THIS);
45
46static int Emscripten_CreateWindow(_THIS, SDL_Window * window);
47static void Emscripten_SetWindowSize(_THIS, SDL_Window * window);
48static void Emscripten_DestroyWindow(_THIS, SDL_Window * window);
49static void Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
50static void Emscripten_PumpEvents(_THIS);
51static void Emscripten_SetWindowTitle(_THIS, SDL_Window * window);
52
53
54/* Emscripten driver bootstrap functions */
55
56static int
57Emscripten_Available(void)
58{
59 return (1);
60}
61
62static void
63Emscripten_DeleteDevice(SDL_VideoDevice * device)
64{
66}
67
68static SDL_VideoDevice *
69Emscripten_CreateDevice(int devindex)
70{
72
73 /* Initialize all variables that we clean on shutdown */
75 if (!device) {
77 return (0);
78 }
79
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
83 */
85
86 /* Set the function pointers */
87 device->VideoInit = Emscripten_VideoInit;
88 device->VideoQuit = Emscripten_VideoQuit;
89 device->SetDisplayMode = Emscripten_SetDisplayMode;
90
91
92 device->PumpEvents = Emscripten_PumpEvents;
93
94 device->CreateSDLWindow = Emscripten_CreateWindow;
95 device->SetWindowTitle = Emscripten_SetWindowTitle;
96 /*device->SetWindowIcon = Emscripten_SetWindowIcon;
97 device->SetWindowPosition = Emscripten_SetWindowPosition;*/
98 device->SetWindowSize = Emscripten_SetWindowSize;
99 /*device->ShowWindow = Emscripten_ShowWindow;
100 device->HideWindow = Emscripten_HideWindow;
101 device->RaiseWindow = Emscripten_RaiseWindow;
102 device->MaximizeWindow = Emscripten_MaximizeWindow;
103 device->MinimizeWindow = Emscripten_MinimizeWindow;
104 device->RestoreWindow = Emscripten_RestoreWindow;
105 device->SetWindowGrab = Emscripten_SetWindowGrab;*/
106 device->DestroyWindow = Emscripten_DestroyWindow;
107 device->SetWindowFullscreen = Emscripten_SetWindowFullscreen;
108
109 device->CreateWindowFramebuffer = Emscripten_CreateWindowFramebuffer;
110 device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
111 device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer;
112
113#if SDL_VIDEO_OPENGL_EGL
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;
124#endif
125
126 device->free = Emscripten_DeleteDevice;
127
128 return device;
129}
130
132 EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver",
133 Emscripten_Available, Emscripten_CreateDevice
134};
135
136
137int
138Emscripten_VideoInit(_THIS)
139{
141
142 /* Use a fake 32-bpp desktop mode */
144
145 mode.w = EM_ASM_INT_V({
146 return screen.width;
147 });
148
149 mode.h = EM_ASM_INT_V({
150 return screen.height;
151 });
152
153 mode.refresh_rate = 0;
154 mode.driverdata = NULL;
155 if (SDL_AddBasicVideoDisplay(&mode) < 0) {
156 return -1;
157 }
158
160
162
163 /* We're done! */
164 return 0;
165}
166
167static int
168Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
169{
170 /* can't do this */
171 return 0;
172}
173
174static void
175Emscripten_VideoQuit(_THIS)
176{
178}
179
180static void
181Emscripten_PumpEvents(_THIS)
182{
183 /* do nothing. */
184}
185
186static int
187Emscripten_CreateWindow(_THIS, SDL_Window * window)
188{
189 SDL_WindowData *wdata;
190 double scaled_w, scaled_h;
191 double css_w, css_h;
192
193 /* Allocate window internal data */
194 wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
195 if (wdata == NULL) {
196 return SDL_OutOfMemory();
197 }
198
199 wdata->canvas_id = SDL_strdup("#canvas");
200
201 if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
202 wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
203 } else {
204 wdata->pixel_ratio = 1.0f;
205 }
206
207 scaled_w = SDL_floor(window->w * wdata->pixel_ratio);
208 scaled_h = SDL_floor(window->h * wdata->pixel_ratio);
209
210 /* set a fake size to check if there is any CSS sizing the canvas */
211 emscripten_set_canvas_element_size(wdata->canvas_id, 1, 1);
212 emscripten_get_element_css_size(wdata->canvas_id, &css_w, &css_h);
213
214 wdata->external_size = SDL_floor(css_w) != 1 || SDL_floor(css_h) != 1;
215
216 if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) {
217 /* external css has resized us */
218 scaled_w = css_w * wdata->pixel_ratio;
219 scaled_h = css_h * wdata->pixel_ratio;
220
222 }
223 emscripten_set_canvas_element_size(wdata->canvas_id, scaled_w, scaled_h);
224
225 /* if the size is not being controlled by css, we need to scale down for hidpi */
226 if (!wdata->external_size) {
227 if (wdata->pixel_ratio != 1.0f) {
228 /*scale canvas down*/
229 emscripten_set_element_css_size(wdata->canvas_id, window->w, window->h);
230 }
231 }
232
233#if SDL_VIDEO_OPENGL_EGL
234 if (window->flags & SDL_WINDOW_OPENGL) {
235 if (!_this->egl_data) {
236 if (SDL_GL_LoadLibrary(NULL) < 0) {
237 return -1;
238 }
239 }
240 wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0);
241
242 if (wdata->egl_surface == EGL_NO_SURFACE) {
243 return SDL_SetError("Could not create GLES window surface");
244 }
245 }
246#endif
247
248 wdata->window = window;
249
250 /* Setup driver data for this window */
251 window->driverdata = wdata;
252
253 /* One window, it always has focus */
256
258
259 /* Window has been successfully created */
260 return 0;
261}
262
263static void Emscripten_SetWindowSize(_THIS, SDL_Window * window)
264{
266
267 if (window->driverdata) {
268 data = (SDL_WindowData *) window->driverdata;
269 /* update pixel ratio */
270 if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
271 data->pixel_ratio = emscripten_get_device_pixel_ratio();
272 }
273 emscripten_set_canvas_element_size(data->canvas_id, window->w * data->pixel_ratio, window->h * data->pixel_ratio);
274
275 /*scale canvas down*/
276 if (!data->external_size && data->pixel_ratio != 1.0f) {
277 emscripten_set_element_css_size(data->canvas_id, window->w, window->h);
278 }
279 }
280}
281
282static void
283Emscripten_DestroyWindow(_THIS, SDL_Window * window)
284{
286
287 if(window->driverdata) {
288 data = (SDL_WindowData *) window->driverdata;
289
291#if SDL_VIDEO_OPENGL_EGL
292 if (data->egl_surface != EGL_NO_SURFACE) {
293 SDL_EGL_DestroySurface(_this, data->egl_surface);
294 data->egl_surface = EGL_NO_SURFACE;
295 }
296#endif
297
298 /* We can't destroy the canvas, so resize it to zero instead */
299 emscripten_set_canvas_element_size(data->canvas_id, 0, 0);
300 SDL_free(data->canvas_id);
301
302 SDL_free(window->driverdata);
303 window->driverdata = NULL;
304 }
305}
306
307static void
308Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
309{
311 if(window->driverdata) {
312 data = (SDL_WindowData *) window->driverdata;
313
314 if(fullscreen) {
315 EmscriptenFullscreenStrategy strategy;
317 int res;
318
319 strategy.scaleMode = is_desktop_fullscreen ? EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH : EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT;
320
321 if(!is_desktop_fullscreen) {
322 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE;
323 } else if(window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
324 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
325 } else {
326 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
327 }
328
329 strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
330
331 strategy.canvasResizedCallback = Emscripten_HandleCanvasResize;
332 strategy.canvasResizedCallbackUserData = data;
333
334 data->requested_fullscreen_mode = window->flags & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
335 data->fullscreen_resize = is_desktop_fullscreen;
336
337 res = emscripten_request_fullscreen_strategy(data->canvas_id, 1, &strategy);
338 if(res != EMSCRIPTEN_RESULT_SUCCESS && res != EMSCRIPTEN_RESULT_DEFERRED) {
339 /* unset flags, fullscreen failed */
341 }
342 }
343 else
344 emscripten_exit_fullscreen();
345 }
346}
347
348static void
349Emscripten_SetWindowTitle(_THIS, SDL_Window * window) {
350 EM_ASM_INT({
351 if (typeof Module['setWindowTitle'] !== 'undefined') {
352 Module['setWindowTitle'](UTF8ToString($0));
353 }
354 return 0;
355 }, window->title);
356}
357
358#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
359
360/* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_SetError
#define SDL_floor
#define SDL_GL_LoadLibrary
#define SDL_free
#define SDL_strdup
#define SDL_SetHint
#define SDL_calloc
void Emscripten_RegisterEventHandlers(SDL_WindowData *data)
EM_BOOL Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
void Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window *window)
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
void Emscripten_FiniMouse()
void Emscripten_InitMouse()
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#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:332
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:211
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint res
GLenum mode
@ SDL_PIXELFORMAT_RGB888
Definition: SDL_pixels.h:236
SDL_bool
Definition: SDL_stdinc.h:162
int SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode)
Definition: SDL_video.c:589
VideoBootStrap Emscripten_bootstrap
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:751
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
@ SDL_WINDOW_ALLOW_HIGHDPI
Definition: SDL_video.h:113
@ SDL_WINDOW_OPENGL
Definition: SDL_video.h:101
@ SDL_WINDOW_RESIZABLE
Definition: SDL_video.h:105
@ SDL_WINDOW_FULLSCREEN_DESKTOP
Definition: SDL_video.h:111
@ SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:100
@ SDL_WINDOWEVENT_RESIZED
Definition: SDL_video.h:155
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
#define NULL
Definition: begin_code.h:167
#define EGL_NO_SURFACE
Definition: egl.h:100
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
static SDL_AudioDeviceID device
Definition: loopwave.c:37
The structure that defines a display mode.
Definition: SDL_video.h:54
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:316
SDL_Window * window
EGLSurface egl_surface
The type used to identify a window.
Definition: SDL_sysvideo.h:74
SDL_Renderer * screen