SDL  2.0
SDL_emscriptenvideo.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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"
34 #include "SDL_emscriptenopengles.h"
36 #include "SDL_emscriptenevents.h"
37 #include "SDL_emscriptenmouse.h"
38 
39 #define EMSCRIPTENVID_DRIVER_NAME "emscripten"
40 
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);
45 
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);
52 
53 
54 /* Emscripten driver bootstrap functions */
55 
56 static int
57 Emscripten_Available(void)
58 {
59  return (1);
60 }
61 
62 static void
63 Emscripten_DeleteDevice(SDL_VideoDevice * device)
64 {
65  SDL_free(device);
66 }
67 
68 static SDL_VideoDevice *
69 Emscripten_CreateDevice(int devindex)
70 {
72 
73  /* Initialize all variables that we clean on shutdown */
74  device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
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 
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 
137 int
138 Emscripten_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 
159  SDL_zero(mode);
160  SDL_AddDisplayMode(&_this->displays[0], &mode);
161 
163 
164  /* We're done! */
165  return 0;
166 }
167 
168 static int
169 Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
170 {
171  /* can't do this */
172  return 0;
173 }
174 
175 static void
176 Emscripten_VideoQuit(_THIS)
177 {
179 }
180 
181 static void
182 Emscripten_PumpEvents(_THIS)
183 {
184  /* do nothing. */
185 }
186 
187 static int
188 Emscripten_CreateWindow(_THIS, SDL_Window * window)
189 {
190  SDL_WindowData *wdata;
191  double scaled_w, scaled_h;
192  double css_w, css_h;
193 
194  /* Allocate window internal data */
195  wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
196  if (wdata == NULL) {
197  return SDL_OutOfMemory();
198  }
199 
200  if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
201  wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
202  } else {
203  wdata->pixel_ratio = 1.0f;
204  }
205 
206  scaled_w = SDL_floor(window->w * wdata->pixel_ratio);
207  scaled_h = SDL_floor(window->h * wdata->pixel_ratio);
208 
209  emscripten_set_canvas_size(scaled_w, scaled_h);
210 
211  emscripten_get_element_css_size(NULL, &css_w, &css_h);
212 
213  wdata->external_size = SDL_floor(css_w) != scaled_w || SDL_floor(css_h) != scaled_h;
214 
215  if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) {
216  /* external css has resized us */
217  scaled_w = css_w * wdata->pixel_ratio;
218  scaled_h = css_h * wdata->pixel_ratio;
219 
220  emscripten_set_canvas_size(scaled_w, scaled_h);
221  SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
222  }
223 
224  /* if the size is not being controlled by css, we need to scale down for hidpi */
225  if (!wdata->external_size) {
226  if (wdata->pixel_ratio != 1.0f) {
227  /*scale canvas down*/
228  emscripten_set_element_css_size(NULL, window->w, window->h);
229  }
230  }
231 
232 #if SDL_VIDEO_OPENGL_EGL
233  if (window->flags & SDL_WINDOW_OPENGL) {
234  if (!_this->egl_data) {
235  if (SDL_GL_LoadLibrary(NULL) < 0) {
236  return -1;
237  }
238  }
239  wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0);
240 
241  if (wdata->egl_surface == EGL_NO_SURFACE) {
242  return SDL_SetError("Could not create GLES window surface");
243  }
244  }
245 #endif
246 
247  wdata->window = window;
248 
249  /* Setup driver data for this window */
250  window->driverdata = wdata;
251 
252  /* One window, it always has focus */
253  SDL_SetMouseFocus(window);
254  SDL_SetKeyboardFocus(window);
255 
257 
258  /* Window has been successfully created */
259  return 0;
260 }
261 
262 static void Emscripten_SetWindowSize(_THIS, SDL_Window * window)
263 {
265 
266  if (window->driverdata) {
267  data = (SDL_WindowData *) window->driverdata;
268  /* update pixel ratio */
269  if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
270  data->pixel_ratio = emscripten_get_device_pixel_ratio();
271  }
272  emscripten_set_canvas_size(window->w * data->pixel_ratio, window->h * data->pixel_ratio);
273 
274  /*scale canvas down*/
275  if (!data->external_size && data->pixel_ratio != 1.0f) {
276  emscripten_set_element_css_size(NULL, window->w, window->h);
277  }
278  }
279 }
280 
281 static void
282 Emscripten_DestroyWindow(_THIS, SDL_Window * window)
283 {
285 
286  if(window->driverdata) {
287  data = (SDL_WindowData *) window->driverdata;
288 
290 #if SDL_VIDEO_OPENGL_EGL
291  if (data->egl_surface != EGL_NO_SURFACE) {
292  SDL_EGL_DestroySurface(_this, data->egl_surface);
293  data->egl_surface = EGL_NO_SURFACE;
294  }
295 #endif
296  SDL_free(window->driverdata);
297  window->driverdata = NULL;
298  }
299 }
300 
301 static void
302 Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
303 {
305  if(window->driverdata) {
306  data = (SDL_WindowData *) window->driverdata;
307 
308  if(fullscreen) {
309  EmscriptenFullscreenStrategy strategy;
310  SDL_bool is_desktop_fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
311  int res;
312 
313  strategy.scaleMode = is_desktop_fullscreen ? EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH : EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT;
314 
315  if(!is_desktop_fullscreen) {
316  strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE;
317  } else if(window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
318  strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
319  } else {
320  strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
321  }
322 
323  strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
324 
325  strategy.canvasResizedCallback = Emscripten_HandleCanvasResize;
326  strategy.canvasResizedCallbackUserData = data;
327 
329  data->fullscreen_resize = is_desktop_fullscreen;
330 
331  res = emscripten_request_fullscreen_strategy(NULL, 1, &strategy);
332  if(res != EMSCRIPTEN_RESULT_SUCCESS && res != EMSCRIPTEN_RESULT_DEFERRED) {
333  /* unset flags, fullscreen failed */
335  }
336  }
337  else
338  emscripten_exit_fullscreen();
339  }
340 }
341 
342 static void
343 Emscripten_SetWindowTitle(_THIS, SDL_Window * window) {
344  EM_ASM_INT({
345  if (typeof Module['setWindowTitle'] !== 'undefined') {
346  Module['setWindowTitle'](Module['Pointer_stringify']($0));
347  }
348  return 0;
349  }, window->title);
350 }
351 
352 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
353 
354 /* vi: set ts=4 sw=4 expandtab: */
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
EM_BOOL Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData)
#define EGL_NO_SURFACE
Definition: egl.h:100
void Emscripten_FiniMouse()
void(* free)(_THIS)
Definition: SDL_sysvideo.h:390
#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
int SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode)
Definition: SDL_video.c:592
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:260
The structure that defines a display mode.
Definition: SDL_video.h:53
void(* SetWindowSize)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:215
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
SDL_Window * window
VideoBootStrap Emscripten_bootstrap
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:151
void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window *window)
#define SDL_GL_LoadLibrary
#define SDL_floor
void Emscripten_RegisterEventHandlers(SDL_WindowData *data)
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:254
GLuint res
int(* SetDisplayMode)(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
Definition: SDL_sysvideo.h:204
void(* GL_GetDrawableSize)(_THIS, SDL_Window *window, int *w, int *h)
Definition: SDL_sysvideo.h:259
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
static SDL_AudioDeviceID device
Definition: loopwave.c:37
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:257
#define _THIS
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:258
#define SDL_free
void * driverdata
Definition: SDL_video.h:59
GLenum mode
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:312
void(* DestroyWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:234
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
char * title
Definition: SDL_sysvideo.h:77
void(* DestroyWindowFramebuffer)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:237
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:256
#define NULL
Definition: begin_code.h:164
int(* CreateSDLWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:210
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
void(* VideoQuit)(_THIS)
Definition: SDL_sysvideo.h:166
#define SDL_SetError
#define SDL_calloc
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
#define SDL_SetHint
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:262
The type used to identify a window.
Definition: SDL_sysvideo.h:73
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:743
int(* VideoInit)(_THIS)
Definition: SDL_sysvideo.h:160
void(* SetWindowFullscreen)(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
Definition: SDL_sysvideo.h:230
int(* UpdateWindowFramebuffer)(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
Definition: SDL_sysvideo.h:236
void * driverdata
Definition: SDL_sysvideo.h:111
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:263
Uint32 format
Definition: SDL_video.h:55
void(* SetWindowTitle)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:212
void Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:261
Uint32 flags
Definition: SDL_sysvideo.h:83
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
SDL_Renderer * screen
SDL_bool fullscreen_resize
int(* CreateWindowFramebuffer)(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
Definition: SDL_sysvideo.h:235
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:255
EGLSurface egl_surface
void Emscripten_InitMouse()
void(* PumpEvents)(_THIS)
Definition: SDL_sysvideo.h:280