19 #include <emscripten.h>
20 #include <emscripten/html5.h>
23 #ifdef SDL_VIDEO_DRIVER_COCOA
31 #define PRINT_DEBUG(s) std::cerr << s
33 #define PRINT_DEBUG(s) {}
38 SdlWindow::Handle::Handle(
const std::string& title,
int x,
int y,
int w,
int h,
43 hwnd = SDL_CreateWindow(title.c_str(), x, y, w, h, wndflags);
46 PRINT_DEBUG(
"SDL window creation failed with error: "
47 << SDL_GetError() << endl);
50 gl_ctx = SDL_GL_CreateContext(hwnd);
53 PRINT_DEBUG(
"OpenGL context creation failed with error: "
54 << SDL_GetError() << endl);
58 SdlWindow::Handle::~Handle()
62 SDL_GL_DeleteContext(gl_ctx);
66 SDL_DestroyWindow(hwnd);
78 return (handle.gl_ctx != 0);
94 is_multithreaded =
false;
100 if (!handle.isInitialized())
105 window_id = SDL_GetWindowID(handle.hwnd);
107 GLenum err = glewInit();
108 #ifdef GLEW_ERROR_NO_GLX_DISPLAY
111 if (err == GLEW_ERROR_NO_GLX_DISPLAY)
113 cerr <<
"GLEW: No GLX display found. If you are using Wayland this can "
114 <<
"be ignored." << endl;
120 cerr <<
"FATAL: Failed to initialize GLEW: "
121 << glewGetErrorString(err) << endl;
126 PRINT_DEBUG(
"Using GLEW " << glewGetString(GLEW_VERSION) << std::endl);
127 PRINT_DEBUG(
"Using GL " << glGetString(GL_VERSION) << std::endl);
131 #ifndef __EMSCRIPTEN__
132 if (!GLEW_VERSION_1_1)
134 cerr <<
"FATAL: Minimum of OpenGL 1.1 is required." << endl;
137 if (!GLEW_VERSION_1_3)
142 if (GLEW_ARB_multitexture)
144 glActiveTexture = glActiveTextureARB;
145 glClientActiveTexture = glClientActiveTextureARB;
146 glMultiTexCoord2f = glMultiTexCoord2fARB;
150 cerr <<
"FATAL: Missing OpenGL multitexture support." << endl;
154 if (!GLEW_VERSION_3_0 && GLEW_EXT_transform_feedback)
156 glBindBufferBase = glBindBufferBaseEXT;
159 glTransformFeedbackVaryings =
160 (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)glTransformFeedbackVaryingsEXT;
161 glBeginTransformFeedback = glBeginTransformFeedbackEXT;
162 glEndTransformFeedback = glEndTransformFeedbackEXT;
164 if (!legacyGlOnly && (GLEW_VERSION_3_0
165 || (GLEW_VERSION_2_0 && GLEW_EXT_transform_feedback)))
169 PRINT_DEBUG(
"Loading CoreGLDevice..." << endl);
174 PRINT_DEBUG(
"Shader support missing, loading FFGLDevice..." << endl);
191 void SdlWindow::windowEvent(SDL_WindowEvent& ew)
195 case SDL_WINDOWEVENT_EXPOSED:
196 case SDL_WINDOWEVENT_RESIZED:
197 update_before_expose =
true;
200 wnd_state = RenderState::ExposePending;
203 case SDL_WINDOWEVENT_CLOSE:
206 case SDL_WINDOWEVENT_MOVED:
207 update_before_expose =
true;
214 void SdlWindow::motionEvent(SDL_MouseMotionEvent& em)
221 if (em.state & SDL_BUTTON_LMASK)
223 if (onMouseMove[SDL_BUTTON_LEFT])
225 onMouseMove[SDL_BUTTON_LEFT](&info);
228 else if (em.state & SDL_BUTTON_RMASK)
230 if (onMouseMove[SDL_BUTTON_RIGHT])
232 onMouseMove[SDL_BUTTON_RIGHT](&info);
235 else if (em.state & SDL_BUTTON_MMASK)
237 if (onMouseMove[SDL_BUTTON_MIDDLE])
239 onMouseMove[SDL_BUTTON_MIDDLE](&info);
244 void SdlWindow::mouseEventDown(SDL_MouseButtonEvent& eb)
246 if (onMouseDown[eb.button])
253 onMouseDown[eb.button](&info);
257 void SdlWindow::mouseEventUp(SDL_MouseButtonEvent& eb)
259 if (onMouseUp[eb.button])
266 onMouseUp[eb.button](&info);
270 void SdlWindow::keyEvent(SDL_Keysym& ks)
272 bool handled =
false;
273 if (ks.sym >= 128 || ks.sym < 32)
275 if (onKeyDown[ks.sym])
277 onKeyDown[ks.sym](ks.mod);
281 else if (ks.sym < 256 && std::isdigit(ks.sym))
283 if (!(SDL_GetModState() & KMOD_SHIFT))
286 onKeyDown[ks.sym](ks.mod);
292 if (onKeyDown[ks.sym])
294 onKeyDown[ks.sym](ks.mod);
298 if (ks.sym == SDLK_RCTRL || ks.sym == SDLK_LCTRL)
304 bool isAlt = ks.mod & (KMOD_ALT);
305 bool isCtrl = ks.mod & (KMOD_CTRL);
307 if (isCtrl) { saved_keys +=
"C-"; }
308 if (isAlt) { saved_keys +=
"Alt-"; }
309 if (ks.sym < 256 && std::isalpha(ks.sym))
313 if (!(ks.mod & KMOD_SHIFT)) { c = std::tolower(c); }
318 saved_keys += SDL_GetKeyName(ks.sym);
324 void SdlWindow::keyEvent(
char c)
326 if (!std::isdigit(c) && onKeyDown[c])
328 SDL_Keymod mods = SDL_GetModState();
329 bool isAlt = mods & (KMOD_ALT);
330 bool isCtrl = mods & (KMOD_CTRL);
335 if (isCtrl) { saved_keys +=
"C-"; }
336 if (isAlt) { saved_keys +=
"Alt-"; }
346 void SdlWindow::multiGestureEvent(SDL_MultiGestureEvent & e)
348 if (e.numFingers == 2)
350 if (onTouchPinch && fabs(e.dDist) > 0.00002)
364 if (!is_multithreaded)
369 bool events_pending =
false;
372 lock_guard<mutex> evt_guard{event_mutex};
373 events_pending = !waiting_events.empty();
383 lock_guard<mutex> evt_guard{event_mutex};
384 e = waiting_events.front();
385 waiting_events.pop_front();
386 events_pending = !waiting_events.empty();
394 case SDL_WINDOWEVENT:
395 windowEvent(e.window);
396 if (wnd_state != RenderState::ExposePending)
401 case SDL_MULTIGESTURE:
402 multiGestureEvent(e.mgesture);
406 keyEvent(e.key.keysym);
409 if (e.key.keysym.sym == SDLK_LCTRL
410 || e.key.keysym.sym == SDLK_RCTRL)
416 keyEvent(e.text.text[0]);
418 case SDL_MOUSEMOTION:
419 motionEvent(e.motion);
423 case SDL_MOUSEBUTTONDOWN:
424 mouseEventDown(e.button);
426 case SDL_MOUSEBUTTONUP:
427 mouseEventUp(e.button);
431 while (keep_going && events_pending);
436 unique_lock<mutex> event_lock{event_mutex};
437 call_idle_func =
false;
446 if (wnd_state == RenderState::ExposePending)
448 #ifdef SDL_VIDEO_DRIVER_COCOA
449 if (update_before_expose)
465 update_before_expose =
false;
469 wnd_state = RenderState::SwapPending;
471 else if (is_multithreaded && sleep)
474 unique_lock<mutex> event_lock{event_mutex};
475 events_available.wait(event_lock, [
this]()
478 return !waiting_events.empty() || call_idle_func;
486 #ifdef __EMSCRIPTEN__
487 emscripten_set_main_loop_arg([](
void* arg)
498 takeScreenshot =
false;
500 if (wnd_state == RenderState::SwapPending)
502 #ifdef SDL_VIDEO_DRIVER_COCOA
513 SDL_GL_SwapWindow(handle.hwnd);
516 SDL_GL_SwapWindow(handle.hwnd);
518 wnd_state = RenderState::Updated;
528 lock_guard<mutex> evt_guard{event_mutex};
529 call_idle_func =
true;
531 events_available.notify_all();
538 if (handle.isInitialized())
540 #ifdef __EMSCRIPTEN__
541 if (canvas_id_.empty())
543 std::cerr <<
"error: id is undefined: " << canvas_id_ << std::endl;
547 auto err = emscripten_get_element_css_size(canvas_id_.c_str(), &dw, &dh);
550 if (err != EMSCRIPTEN_RESULT_SUCCESS)
552 std::cerr <<
"error (emscripten_get_element_css_size): " << err << std::endl;
556 SDL_GetWindowSize(handle.hwnd, &w, &h);
565 SDL_GL_GetDrawableSize(handle.hwnd, &w, &h);
572 if (!handle.isInitialized())
574 PRINT_DEBUG(
"warning: unable to get dpi: handle is null" << endl);
577 int disp = SDL_GetWindowDisplayIndex(handle.hwnd);
580 PRINT_DEBUG(
"warning: problem getting display index: " << SDL_GetError()
582 PRINT_DEBUG(
"returning default dpi of " << default_dpi << endl);
587 if (SDL_GetDisplayDPI(disp, NULL, &f_w, &f_h))
589 PRINT_DEBUG(
"warning: problem getting dpi, setting to " << default_dpi
590 <<
": " << SDL_GetError() << endl);
594 PRINT_DEBUG(
"Screen DPI: w = " << f_w <<
" ppi, h = " << f_h <<
" ppi");
597 PRINT_DEBUG(
" (" << w <<
" x " << h <<
')' << endl);
603 setWindowTitle(title.c_str());
614 update_before_expose =
true;
620 bool uc_x = SDL_WINDOWPOS_ISUNDEFINED(x) ||
621 SDL_WINDOWPOS_ISCENTERED(x);
622 bool uc_y = SDL_WINDOWPOS_ISUNDEFINED(y) ||
623 SDL_WINDOWPOS_ISCENTERED(y);
625 uc_x ? x : pixel_scale_x*x,
626 uc_y ? y : pixel_scale_y*y);
627 update_before_expose =
true;
633 if (k >= 32 && k < 128)
635 event.type = SDL_TEXTINPUT;
636 event.text.windowID = window_id;
637 event.text.text[0] = k;
641 event.type = SDL_KEYDOWN;
642 event.key.windowID = window_id;
643 event.key.keysym.sym = k;
644 event.key.keysym.mod = m;
646 queueEvents({
event });
651 SDL_GL_SwapWindow(handle.hwnd);
SdlMainThread & GetMainThread()
void signalKeyDown(SDL_Keycode k, SDL_Keymod m=KMOD_NONE)
int Screenshot(const char *fname, bool convert)
Take a screenshot using libtiff, libpng or sdl2.
void getGLDrawSize(int &w, int &h)
bool isGlInitialized()
Returns true if the OpenGL context was successfully initialized.
void mainLoop()
Runs the window loop.
void setWindowTitle(std::string &title)
void setWindowPos(int x, int y)
void SetWindowTitle(const Handle &handle, std::string title)
void getWindowSize(int &w, int &h)
SdlNativePlatform * GetPlatform() const
Handle GetHandle(SdlWindow *wnd, const std::string &title, int x, int y, int w, int h, bool legacyGlOnly)
static void StartSDL(bool server_mode)
void MainLoop(bool server_mode)
void SetWindowPosition(const Handle &handle, int x, int y)
bool createWindow(const char *title, int x, int y, int w, int h, bool legacyGlOnly)
void DeleteHandle(Handle to_delete)
void SetWindowSize(const Handle &handle, int w, int h)
void getDpi(int &wdpi, int &hdpi)
void setWindowSize(int w, int h)