34#include <SDL2/SDL_events.h>
35#include <SDL2/SDL_timer.h>
36#include <SDL2/SDL_video.h>
38#include <SDL2/SDL_scancode.h>
89 if( !win || !win->
isValid() ) {
return; }
90 SDL_Window* sdl_win =
reinterpret_cast<SDL_Window*
>(win->
windowHandle());
92 printf(
"Window::resized:: %d x %d: %s\n", wwidth, wheight, win->
toString().c_str());
96 int wwidth2 = 0, wheight2 = 0;
97 SDL_GetWindowSize(sdl_win, &wwidth2, &wheight2);
99 printf(
"Window::resized: Size %d x %d -> %d x %d (given), %d x %d (query)\n", window_size.
x, window_size.
y, wwidth, wheight, wwidth2, wheight2);
101 if (0 == wwidth || 0 == wheight) {
106 window_size.
set(wwidth, wheight);
109 int fb_width =
static_cast<int>(
static_cast<float>(wwidth) *
devicePixelRatio.x);
110 int fb_height =
static_cast<int>(
static_cast<float>(wheight) *
devicePixelRatio.y);
112 printf(
"Window::resized: DevicePixelRatio Size %f x %f -> %d x %d\n",
118 printf(
"Window::resized: VP Size %s\n", surface_size.
toString().c_str());
121 SDL_DisplayMode mode;
122 const int win_display_idx = SDL_GetWindowDisplayIndex(sdl_win);
124 SDL_GetCurrentDisplayMode(win_display_idx, &mode);
126 printf(
"Window::resized: WindowDisplayMode: %d x %d @ %d Hz @ display %d\n", mode.w, mode.h, mode.refresh_rate, win_display_idx);
128 if( mode.refresh_rate > 0 ) {
151 bool exp_init_called =
false;
159 if (SDL_Init(SDL_INIT_TIMER) != 0) {
160 printf(
"SDL: Error initializing TIMER: %s\n", SDL_GetError());
166 const uint32_t sdl_ms = SDL_GetTicks();
167 const int64_t s = sdl_ms/1000;
168 const int64_t ns = ( sdl_ms - s*1000 ) *1'000'000;
176 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
177 printf(
"SDL: Error initializing VIDEO/EVENTS: %s\n", SDL_GetError());
181 if ( ( IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG ) != IMG_INIT_PNG ) {
182 printf(
"SDL_image: Error initializing: %s\n", SDL_GetError());
185 if( 0 != TTF_Init() ) {
186 printf(
"SDL_TTF: Error initializing: %s\n", SDL_GetError());
200 printf(
"Window::create: '%s', %d x %d\n", title, wwidth, wheight);
204 const Uint32 win_flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
206 SDL_Window* sdl_win =
nullptr;
207 Uint32 sdl_win_id = 0;
209 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
210 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
211 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
212 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
213 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
214 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 1);
216 sdl_win = SDL_CreateWindow(title,
217 SDL_WINDOWPOS_UNDEFINED,
218 SDL_WINDOWPOS_UNDEFINED,
221 if (
nullptr == sdl_win) {
222 printf(
"SDL: Error initializing window: %s\n", SDL_GetError());
226 sdl_win_id = SDL_GetWindowID(sdl_win);
227 if (0 == sdl_win_id) {
228 printf(
"SDL: Error retrieving window ID: %s\n", SDL_GetError());
229 SDL_DestroyWindow(sdl_win);
247void Window::disposeImpl(
handle_t handle)
noexcept {
248 SDL_Window* sdl_win =
reinterpret_cast<SDL_Window*
>(handle);
249 if(
nullptr == sdl_win ) {
252 SDL_DestroyWindow(sdl_win);
255 [
this](
const WindowRef& a)
noexcept ->
bool {
return a.get() ==
this; } );
256 }
catch (std::exception &err) {
257 ERR_PRINT(
"gamp::handle_events: Caught exception %s", err.what());
274 static bool warn_once =
true;
275 if (win_size.
x != ww || win_size.
y != wh ||
277 if (devPixelRatioX >= 0.5f && devPixelRatioY >= 0.5f) {
281 if (std::abs(win_size.
x - ww) > 1 || std::abs(win_size.
y - wh) > 1) {
282 if( initial_call || 0 == win_size.
x || 0 == win_size.
y) {
283 printf(
"JS Window Initial Size: Win %d x %d -> %d x %d, devPixelRatio %s\n",
288 printf(
"JS Window Resized: Win %d x %d -> %d x %d, devPixelRatio %s\n",
290 SDL_SetWindowSize(
reinterpret_cast<SDL_Window*
>(win->
windowHandle()), ww, wh);
294 }
else if (warn_once) {
296 printf(
"JS Window Resize Ignored: Win %d x %d -> %d x %d, devPixelRatio %s\n",
300 printf(
"JS Window Resize Same-Size: Win %d x %d -> %d x %d, devPixelRatio %s\n",
309 if( swapAllWindows ) {
328 }
else if( td >= fps_avg_period ) {
338 constexpr uint64_t ns_per_ms = 1'000'000UL;
343 if( td_diff > fudge ) {
345 ts.tv_sec =
static_cast<decltype(ts.tv_sec)
>(td_diff.
tv_sec);
347 nanosleep( &ts,
nullptr );
369static std::pair<VKeyCode, InputModifier>
to_VKeyCode(SDL_Scancode scancode) {
370 if (SDL_SCANCODE_A <= scancode && scancode <= SDL_SCANCODE_Z) {
373 if (SDL_SCANCODE_1 <= scancode && scancode <= SDL_SCANCODE_9) {
376 if (SDL_SCANCODE_0 == scancode) {
380 case SDL_SCANCODE_ESCAPE:
382 case SDL_SCANCODE_LSHIFT:
384 case SDL_SCANCODE_RSHIFT:
386 case SDL_SCANCODE_LALT:
388 case SDL_SCANCODE_RALT:
390 case SDL_SCANCODE_LCTRL:
392 case SDL_SCANCODE_RCTRL:
394 case SDL_SCANCODE_PAUSE:
396 case SDL_SCANCODE_UP:
398 case SDL_SCANCODE_LEFT:
400 case SDL_SCANCODE_DOWN:
402 case SDL_SCANCODE_RIGHT:
404 case SDL_SCANCODE_KP_ENTER:
406 case SDL_SCANCODE_RETURN:
409 case SDL_SCANCODE_SEMICOLON:
412 case SDL_SCANCODE_MINUS:
414 case SDL_SCANCODE_KP_MINUS:
417 case SDL_SCANCODE_KP_PLUS:
420 case SDL_SCANCODE_KP_MULTIPLY:
423 case SDL_SCANCODE_SLASH:
425 case SDL_SCANCODE_KP_DIVIDE:
428 case SDL_SCANCODE_KP_PERCENT:
431 case SDL_SCANCODE_KP_LEFTPAREN:
433 case SDL_SCANCODE_KP_LEFTBRACE:
435 case SDL_SCANCODE_LEFTBRACKET:
438 case SDL_SCANCODE_KP_RIGHTPAREN:
440 case SDL_SCANCODE_KP_RIGHTBRACE:
442 case SDL_SCANCODE_RIGHTBRACKET:
445 case SDL_SCANCODE_COMMA:
448 case SDL_SCANCODE_PERIOD:
451 case SDL_SCANCODE_SPACE:
453 case SDL_SCANCODE_TAB:
456 case SDL_SCANCODE_BACKSPACE:
466 if (SDL_SCANCODE_A <= scancode && scancode <= SDL_SCANCODE_Z) {
468 return 'A' + (scancode - SDL_SCANCODE_A);
470 return 'a' + (scancode - SDL_SCANCODE_A);
473 if (SDL_SCANCODE_1 <= scancode && scancode <= SDL_SCANCODE_9) {
474 return '1' + (scancode - SDL_SCANCODE_1);
476 if (SDL_SCANCODE_0 == scancode) {
477 return '0' + (scancode - SDL_SCANCODE_0);
480 case SDL_SCANCODE_SEMICOLON:
483 case SDL_SCANCODE_MINUS:
485 case SDL_SCANCODE_KP_MINUS:
488 case SDL_SCANCODE_KP_PLUS:
491 case SDL_SCANCODE_KP_MULTIPLY:
494 case SDL_SCANCODE_SLASH:
496 case SDL_SCANCODE_KP_DIVIDE:
499 case SDL_SCANCODE_KP_PERCENT:
502 case SDL_SCANCODE_KP_LEFTPAREN:
504 case SDL_SCANCODE_KP_LEFTBRACE:
506 case SDL_SCANCODE_LEFTBRACKET:
509 case SDL_SCANCODE_KP_RIGHTPAREN:
511 case SDL_SCANCODE_KP_RIGHTBRACE:
513 case SDL_SCANCODE_RIGHTBRACKET:
516 case SDL_SCANCODE_COMMA:
519 case SDL_SCANCODE_PERIOD:
522 case SDL_SCANCODE_SPACE:
524 case SDL_SCANCODE_TAB:
527 case SDL_SCANCODE_RETURN:
529 case SDL_SCANCODE_KP_ENTER:
532 case SDL_SCANCODE_BACKSPACE:
542 SDL_Window *p = SDL_GetWindowFromID(
id);
548 if( win && win->windowHandle() == h ) {
559 size_t event_count = 0;
562 while (SDL_PollEvent(&sdl_event)) {
564 const int64_t s = sdl_event.common.timestamp/1000;
565 const int64_t ns = ( sdl_event.common.timestamp - s*1000 ) *1'000'000;
567 switch (sdl_event.type) {
569 printf(
"App Close Requested\n");
576 case SDL_WINDOWEVENT: {
579 switch (sdl_event.window.event) {
580 case SDL_WINDOWEVENT_CLOSE: {
584 case SDL_WINDOWEVENT_SHOWN:
588 case SDL_WINDOWEVENT_HIDDEN:
589 printf(
"Window Hidden\n");
592 case SDL_WINDOWEVENT_MOVED:
593 printf(
"Window Moved: %d x %d\n", sdl_event.window.data1, sdl_event.window.data2);
596 case SDL_WINDOWEVENT_RESIZED:
597 printf(
"Window Resized: %d x %d\n", sdl_event.window.data1, sdl_event.window.data2);
600 case SDL_WINDOWEVENT_SIZE_CHANGED:
601 printf(
"Window SizeChanged: %d x %d\n", sdl_event.window.data1, sdl_event.window.data2);
609 case SDL_MOUSEMOTION: {
622 case SDL_MOUSEBUTTONDOWN: {
631 sdl_event.button.clicks,
636 case SDL_MOUSEBUTTONUP: {
645 sdl_event.button.clicks,
650 case SDL_MOUSEWHEEL: {
653 float rotX = sdl_event.wheel.preciseX;
654 float rotY = sdl_event.wheel.preciseY;
656 std::swap(rotX, rotY);
668 const SDL_Scancode scancode = sdl_event.key.keysym.scancode;
669 const std::pair<VKeyCode, InputModifier> r =
to_VKeyCode(scancode);
676 const SDL_Scancode scancode = sdl_event.key.keysym.scancode;
677 const std::pair<VKeyCode, InputModifier> r =
to_VKeyCode(scancode);
678 if( sdl_event.key.repeat ) {
697 if( windows.
size() == 0 ) {
701 if( win && win->isValid() ) {
715 printf(
"Exit Application\n");
716 #if defined(__EMSCRIPTEN__)
717 emscripten_cancel_main_loop();
#define EMSCRIPTEN_KEEPALIVE
constexpr const Vec2i & surfaceSize() const noexcept
Returns the surface size of the client area excluding insets (window decorations) in pixel units.
constexpr handle_t windowHandle() const noexcept
Returns the handle to the surface for this NativeSurface.
void notifyKeyReleased(const jau::fraction_timespec &when, VKeyCode keySym, InputModifier keySymMods, uint16_t keyChar) noexcept
bool isValid() const noexcept override
void notifyWindowEvent(uint16_t type, const jau::fraction_timespec &when, bool value=true) noexcept
constexpr Vec2i windowSize() const noexcept
Returns the window size of the client area excluding insets (window decorations) in window units.
void notifyWindowResize(const jau::fraction_timespec &when, const jau::math::Vec2i &winSize, const jau::math::Vec2i &surfSize) noexcept
void notifyWindowMoved(const jau::fraction_timespec &when, const jau::math::Vec2i &winPos) noexcept
void notifyKeyPressed(const jau::fraction_timespec &when, VKeyCode keySym, InputModifier keySymMods, uint16_t keyChar) noexcept
void notifyPointer(uint16_t type, const jau::fraction_timespec &when, PointerType ptype, uint16_t id, jau::math::Vec2i pos, uint16_t clickCount, InputButton button, jau::math::Vec3f rotation, float rotationScale) noexcept
static WindowRef create(const char *title, int wwidth, int wheight, bool verbose=false)
Create an new instance using a native windowing toolkit.
static WindowRef wrapNative(handle_t window_handle, const Recti &window_bounds, handle_t surface_handle, const Vec2i &surface_size)
Create an new instance, wrapping the native windowing toolkit's handle/resources.
const KeyboardTracker & keyTracker() const noexcept
void dispose(const jau::fraction_timespec &when) noexcept override
std::string toString() const noexcept
constexpr bool isPointerBLOriented() const noexcept
Returns true if this window delivers PointerEvent in OpenGL's coordinate system, origin at bottom lef...
virtual InputModifier modifier() const noexcept=0
Implementation of a Copy-On-Write (CoW) using jau::darray as the underlying storage,...
std::shared_ptr< storage_t > storage_ref_t
darray< value_type, size_type, allocator_type, use_memmove, use_secmem > storage_t
constexpr size_type size() const noexcept
Like std::vector::size().
constexpr Vector2I & set(const value_type vx, const value_type vy) noexcept
TODO constexpr bool operator<=>(const vec2i_t& rhs ) const noexcept { return ... }...
std::string toString() const noexcept
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
static std::pair< VKeyCode, InputModifier > to_VKeyCode(SDL_Scancode scancode)
static jau::fraction_timespec init_gfx_t0
static uint16_t to_ascii(SDL_Scancode scancode, const InputModifier &mods)
static void gamp_swap_gpu_buffer(bool swapAllWindows, int fps) noexcept
static jau::fraction_timespec gpu_fps_t0
static jau::fraction_timespec gpu_swap_t1
static void on_window_resized(Window *win, int wwidth, int wheight, const jau::fraction_timespec &when, bool verbose=false) noexcept
static void reset_gpu_fps(int fps)
Width of the framebuffer coordinate in pixels.
static int gpu_forced_fps_
static Window * getWin(Uint32 id)
static jau::fraction_timespec gpu_fdur
static int monitor_frames_per_sec
static jau::math::Vec2f devicePixelRatio(1, 1)
Ratio pixel-size / window-size, a DPI derivative per axis.
EMSCRIPTEN_KEEPALIVE void set_window_size(int ww, int wh, float devPixelRatioX, float devPixelRatioY) noexcept
static jau::cow_darray< WindowRef > window_list
static std::atomic_bool gfx_subsystem_init_called
static bool gpu_fps_resync
static jau::fraction_timespec gpu_swap_t0
static int64_t gpu_frame_count
EMSCRIPTEN_KEEPALIVE int get_forced_fps() noexcept
static bool gamp_show_fps
static std::atomic_bool gfx_subsystem_init
EMSCRIPTEN_KEEPALIVE void set_forced_fps(int v) noexcept
constexpr bool has_any(const E mask, const E bits) noexcept
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
static constexpr short EVENT_POINTER_WHEEL
static constexpr short EVENT_POINTER_PRESSED
static constexpr short EVENT_POINTER_RELEASED
VKeyCode
Virtual key code following UTF16 specification.
std::shared_ptr< Window > WindowRef
static constexpr short EVENT_POINTER_MOVED
static constexpr uint16_t EVENT_WINDOW_VISIBILITY_CHANGED
@ repeat
Event is caused by auto-repeat.
@ VK_SEMICOLON
Constant for the semicolon keyu, "u,".
@ VK_PLUS
Constant for the "+" key.
@ VK_ESCAPE
Constant for the ESCAPE function key.
@ VK_PERCENT
Constant for the "%" key.
@ VK_BACK_SPACE
Constant for the BACK SPACE key "\b"u, matching ASCII.
@ VK_RIGHT
Constant for the cursor- or numerical-pad right arrow key.
@ VK_DOWN
Constant for the cursor- or numerical pad down arrow key.
@ VK_CONTROL
Constant for the CTRL function key.
@ VK_COMMA
Constant for the comma keyu, "u,".
@ VK_A
VK_A thru VK_Z are the same as Capital UTF16/ASCII 'A' thru 'Z' (0x41 - 0x5A)
@ VK_ENTER
Constant for the ENTER keyu, i.e.
@ VK_UP
Constant for the cursor- or numerical-pad up arrow key.
@ VK_PERIOD
Constant for the period keyu, ".".
@ VK_TAB
Constant for the HORIZ TAB key "\t"u, matching ASCII.
@ VK_UNDEFINED
This value, {@value}, is used to indicate that the keyCode is unknown.
@ VK_LEFT
Constant for the cursor- or numerical-pad left arrow key.
@ VK_SHIFT
Constant for the SHIFT function key.
@ VK_LEFT_PARENTHESIS
Constant for the "(" key.
@ VK_RIGHT_PARENTHESIS
Constant for the ")" key.
@ VK_0
VK_0 thru VK_9 are the same as UTF16/ASCII '0' thru '9' [0x30 - 0x39].
@ VK_ALT
Constant for the ALT function key.
@ VK_MINUS
Constant for the minus keyu, "-".
@ VK_SLASH
Constant for the forward slash keyu, "/".
@ VK_PAUSE
Constant for the PAUSE function key.
@ VK_MULTIPLY
Numeric keypad multiply key.
std::string lookup_and_register_asset_dir(const char *exe_path, const char *asset_file="fonts/freefont/FreeSansBold.ttf", const char *asset_install_subdir="gamp") noexcept
const jau::fraction_timespec & gpu_avg_framedur() noexcept
Returns the measured gpu frame duration in [s] each 5s, starting with 1/gpu_avg_fps()
uintptr_t handle_t
A native handle type, big enough to store a pointer.
void mainloop_void() noexcept
Calls mainloop_default(), but exits application if returning false.
jau::fraction_timespec getElapsedMonotonicTime() noexcept
Returns the elapsed monotonic time since init_gfx_subsystem, synchronized with the gfx subsystem time...
bool init_gfx_subsystem(const char *exe_path)
GFX Toolkit: Initialize the subsystem once.
float gpu_avg_fps() noexcept
Returns the measured gpu fps each 5s, starting with monitor_fps()
bool is_gfx_subsystem_initialized() noexcept
bool mainloop_default() noexcept
Performs the whole tasks for all created gamp::wt::Window instances.
int gpu_forced_fps() noexcept
Returns optional forced frames per seconds or -1 if unset, set via set_gpu_forced_fps().
size_t handle_events() noexcept
GFX Toolkit: Handle windowing and keyboard events.
void swap_gpu_buffer(int fps) noexcept
GFX Toolkit: Swap GPU back to front framebuffer of all windows using given fps, maintaining vertical ...
int monitor_fps() noexcept
Monitor frames per seconds.
const jau::util::VersionNumberString VERSION
void set_gpu_forced_fps(int fps) noexcept
Optional forced frames per seconds, pass to swap_gpu_buffer() by default.
std::string get_platform_info(std::string &sb) noexcept
void zero_bytes_sec(void *s, size_t n) noexcept __attrdecl_no_optimize__
Wrapper to ::explicit_bzero(), ::bzero() or ::memset(), whichever is available in that order.
Gamp: Graphics, Audio, Multimedia and Processing Framework (Native C++, WebAssembly,...
Author: Sven Gothel sgothel@jausoft.com Copyright Gothel Software e.K.
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
int64_t tv_nsec
Nanoseconds component with its absolute value in range [0..1'000'000'000[ or [0..1'000'000'000).
int64_t tv_sec
Seconds component, with its absolute value in range [0..inf[ or [0..inf).
std::string to_string() const noexcept
Return simple string representation in seconds and nanoseconds.
constexpr uint64_t to_us() const noexcept
Returns time in microseconds.
int printf(const char *format,...)
Operating Systems predefined macros.