SDL  2.0
SDL_emscriptenvideo.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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_sysvideo.h"
28 #include "../SDL_pixels_c.h"
29 #include "../SDL_egl_c.h"
30 #include "../../events/SDL_events_c.h"
31 
32 #include "SDL_emscriptenvideo.h"
33 #include "SDL_emscriptenopengles.h"
35 #include "SDL_emscriptenevents.h"
36 #include "SDL_emscriptenmouse.h"
37 
38 #define EMSCRIPTENVID_DRIVER_NAME "emscripten"
39 
40 /* Initialization/Query functions */
41 static int Emscripten_VideoInit(_THIS);
42 static int Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
43 static void Emscripten_VideoQuit(_THIS);
44 
45 static int Emscripten_CreateWindow(_THIS, SDL_Window * window);
46 static void Emscripten_SetWindowSize(_THIS, SDL_Window * window);
47 static void Emscripten_DestroyWindow(_THIS, SDL_Window * window);
48 static void Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
49 static void Emscripten_PumpEvents(_THIS);
50 
51 
52 /* Emscripten driver bootstrap functions */
53 
54 static int
55 Emscripten_Available(void)
56 {
57  return (1);
58 }
59 
60 static void
61 Emscripten_DeleteDevice(SDL_VideoDevice * device)
62 {
63  SDL_free(device);
64 }
65 
66 static SDL_VideoDevice *
67 Emscripten_CreateDevice(int devindex)
68 {
69  SDL_VideoDevice *device;
70 
71  /* Initialize all variables that we clean on shutdown */
72  device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
73  if (!device) {
75  return (0);
76  }
77 
78  /* Set the function pointers */
79  device->VideoInit = Emscripten_VideoInit;
80  device->VideoQuit = Emscripten_VideoQuit;
81  device->SetDisplayMode = Emscripten_SetDisplayMode;
82 
83 
84  device->PumpEvents = Emscripten_PumpEvents;
85 
86  device->CreateWindow = Emscripten_CreateWindow;
87  /*device->CreateWindowFrom = Emscripten_CreateWindowFrom;
88  device->SetWindowTitle = Emscripten_SetWindowTitle;
89  device->SetWindowIcon = Emscripten_SetWindowIcon;
90  device->SetWindowPosition = Emscripten_SetWindowPosition;*/
91  device->SetWindowSize = Emscripten_SetWindowSize;
92  /*device->ShowWindow = Emscripten_ShowWindow;
93  device->HideWindow = Emscripten_HideWindow;
94  device->RaiseWindow = Emscripten_RaiseWindow;
95  device->MaximizeWindow = Emscripten_MaximizeWindow;
96  device->MinimizeWindow = Emscripten_MinimizeWindow;
97  device->RestoreWindow = Emscripten_RestoreWindow;
98  device->SetWindowGrab = Emscripten_SetWindowGrab;*/
99  device->DestroyWindow = Emscripten_DestroyWindow;
100  device->SetWindowFullscreen = Emscripten_SetWindowFullscreen;
101 
105 
106  device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary;
107  device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress;
108  device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary;
109  device->GL_CreateContext = Emscripten_GLES_CreateContext;
110  device->GL_MakeCurrent = Emscripten_GLES_MakeCurrent;
111  device->GL_SetSwapInterval = Emscripten_GLES_SetSwapInterval;
112  device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval;
113  device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
114  device->GL_DeleteContext = Emscripten_GLES_DeleteContext;
115  device->GL_GetDrawableSize = Emscripten_GLES_GetDrawableSize;
116 
117  device->free = Emscripten_DeleteDevice;
118 
119  return device;
120 }
121 
122 VideoBootStrap Emscripten_bootstrap = {
123  EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver",
124  Emscripten_Available, Emscripten_CreateDevice
125 };
126 
127 
128 int
129 Emscripten_VideoInit(_THIS)
130 {
132  double css_w, css_h;
133 
134  /* Use a fake 32-bpp desktop mode */
136 
137  emscripten_get_element_css_size(NULL, &css_w, &css_h);
138 
139  mode.w = css_w;
140  mode.h = css_h;
141 
142  mode.refresh_rate = 0;
143  mode.driverdata = NULL;
144  if (SDL_AddBasicVideoDisplay(&mode) < 0) {
145  return -1;
146  }
147 
148  SDL_zero(mode);
149  SDL_AddDisplayMode(&_this->displays[0], &mode);
150 
152 
153  /* We're done! */
154  return 0;
155 }
156 
157 static int
158 Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
159 {
160  /* can't do this */
161  return 0;
162 }
163 
164 static void
165 Emscripten_VideoQuit(_THIS)
166 {
168 }
169 
170 static void
171 Emscripten_PumpEvents(_THIS)
172 {
173  /* do nothing. */
174 }
175 
176 static int
177 Emscripten_CreateWindow(_THIS, SDL_Window * window)
178 {
179  SDL_WindowData *wdata;
180  double scaled_w, scaled_h;
181  double css_w, css_h;
182 
183  /* Allocate window internal data */
184  wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
185  if (wdata == NULL) {
186  return SDL_OutOfMemory();
187  }
188 
189  if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
190  wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
191  } else {
192  wdata->pixel_ratio = 1.0f;
193  }
194 
195  scaled_w = SDL_floor(window->w * wdata->pixel_ratio);
196  scaled_h = SDL_floor(window->h * wdata->pixel_ratio);
197 
198  emscripten_set_canvas_size(scaled_w, scaled_h);
199 
200  emscripten_get_element_css_size(NULL, &css_w, &css_h);
201 
202  wdata->external_size = css_w != scaled_w || css_h != scaled_h;
203 
204  if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) {
205  /* external css has resized us */
206  scaled_w = css_w * wdata->pixel_ratio;
207  scaled_h = css_h * wdata->pixel_ratio;
208 
209  emscripten_set_canvas_size(scaled_w, scaled_h);
210  SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
211  }
212 
213  /* if the size is not being controlled by css, we need to scale down for hidpi */
214  if (!wdata->external_size) {
215  if (wdata->pixel_ratio != 1.0f) {
216  /*scale canvas down*/
217  emscripten_set_element_css_size(NULL, window->w, window->h);
218  }
219  }
220 
221  wdata->windowed_width = scaled_w;
222  wdata->windowed_height = scaled_h;
223 
224  if (window->flags & SDL_WINDOW_OPENGL) {
225  if (!_this->egl_data) {
226  if (SDL_GL_LoadLibrary(NULL) < 0) {
227  return -1;
228  }
229  }
230  wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0);
231 
232  if (wdata->egl_surface == EGL_NO_SURFACE) {
233  return SDL_SetError("Could not create GLES window surface");
234  }
235  }
236 
237  wdata->window = window;
238 
239  /* Setup driver data for this window */
240  window->driverdata = wdata;
241 
242  /* One window, it always has focus */
243  SDL_SetMouseFocus(window);
244  SDL_SetKeyboardFocus(window);
245 
247 
248  /* Window has been successfully created */
249  return 0;
250 }
251 
252 static void Emscripten_SetWindowSize(_THIS, SDL_Window * window)
253 {
255 
256  if (window->driverdata) {
257  data = (SDL_WindowData *) window->driverdata;
258  emscripten_set_canvas_size(window->w * data->pixel_ratio, window->h * data->pixel_ratio);
259 
260  /*scale canvas down*/
261  if (!data->external_size && data->pixel_ratio != 1.0f) {
262  emscripten_set_element_css_size(NULL, window->w, window->h);
263  }
264  }
265 }
266 
267 static void
268 Emscripten_DestroyWindow(_THIS, SDL_Window * window)
269 {
271 
272  if(window->driverdata) {
273  data = (SDL_WindowData *) window->driverdata;
274 
276  if (data->egl_surface != EGL_NO_SURFACE) {
277  SDL_EGL_DestroySurface(_this, data->egl_surface);
278  data->egl_surface = EGL_NO_SURFACE;
279  }
280  SDL_free(window->driverdata);
281  window->driverdata = NULL;
282  }
283 }
284 
285 static void
286 Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
287 {
289  if(window->driverdata) {
290  data = (SDL_WindowData *) window->driverdata;
291 
292  if(fullscreen) {
294  /*unset the fullscreen flags as we're not actually fullscreen yet*/
296 
297  EM_ASM({
298  //reparent canvas (similar to Module.requestFullscreen)
299  var canvas = Module['canvas'];
300  if(canvas.parentNode.id != "SDLFullscreenElement") {
301  var canvasContainer = document.createElement("div");
302  canvasContainer.id = "SDLFullscreenElement";
303  canvas.parentNode.insertBefore(canvasContainer, canvas);
304  canvasContainer.appendChild(canvas);
305  }
306  });
307 
308  int is_fullscreen;
309  emscripten_get_canvas_size(&data->windowed_width, &data->windowed_height, &is_fullscreen);
310  emscripten_request_fullscreen("SDLFullscreenElement", 1);
311  }
312  else
313  emscripten_exit_fullscreen();
314  }
315 }
316 
317 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
318 
319 /* vi: set ts=4 sw=4 expandtab: */
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:612
SDL_Window * window
void Emscripten_FiniMouse()
void(* free)(_THIS)
Definition: SDL_sysvideo.h:345
int SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode)
Definition: SDL_video.c:579
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:240
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
The structure that defines a display mode.
Definition: SDL_video.h:53
void(* SetWindowSize)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:200
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
SDL_Window * window
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:103
void(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:242
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:234
int(* SetDisplayMode)(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
Definition: SDL_sysvideo.h:189
void(* GL_GetDrawableSize)(_THIS, SDL_Window *window, int *w, int *h)
Definition: SDL_sysvideo.h:239
static SDL_VideoDevice * _this
Definition: SDL_video.c:114
SDL_bool
Definition: SDL_stdinc.h:126
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
void * SDL_calloc(size_t nmemb, size_t size)
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:237
#define _THIS
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:238
void SDL_free(void *mem)
void * driverdata
Definition: SDL_video.h:59
GLenum mode
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:280
void(* DestroyWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:214
#define SDL_zero(x)
Definition: SDL_stdinc.h:355
void(* DestroyWindowFramebuffer)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:217
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:236
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
void(* VideoQuit)(_THIS)
Definition: SDL_sysvideo.h:161
#define SDL_SetError
int(* CreateWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:195
The type used to identify a window.
Definition: SDL_sysvideo.h:71
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:709
int(* VideoInit)(_THIS)
Definition: SDL_sysvideo.h:155
void(* SetWindowFullscreen)(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
Definition: SDL_sysvideo.h:210
int(* UpdateWindowFramebuffer)(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
Definition: SDL_sysvideo.h:216
void * driverdata
Definition: SDL_sysvideo.h:106
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:243
Uint32 format
Definition: SDL_video.h:55
void Emscripten_UnregisterEventHandlers(SDL_WindowData *data)
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:241
Uint32 flags
Definition: SDL_sysvideo.h:81
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
int(* CreateWindowFramebuffer)(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
Definition: SDL_sysvideo.h:215
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:235
EGLSurface egl_surface
void Emscripten_InitMouse()
void(* PumpEvents)(_THIS)
Definition: SDL_sysvideo.h:249