v / thirdparty / sokol / sokol_app.h
17540 lines · 16142 sloc · 632.95 KB · 161d51f83033318e80299998137d6905cd0cdc9f
Raw
1#if defined(SOKOL_IMPL) && !defined(SOKOL_APP_IMPL)
2#define SOKOL_APP_IMPL
3#endif
4#ifndef SOKOL_APP_INCLUDED
5
6/*
7 V language IMPORTANT NOTE: all the V patches in this code, are marked with:
8 // __v_ start
9 // __v_ end
10*/
11
12/*
13 sokol_app.h -- cross-platform application wrapper
14
15 Project URL: https://github.com/floooh/sokol
16
17 Do this:
18 #define SOKOL_IMPL or
19 #define SOKOL_APP_IMPL
20 before you include this file in *one* C or C++ file to create the
21 implementation.
22
23 In the same place define one of the following to select the 3D-API
24 which should be initialized by sokol_app.h (this must also match
25 the backend selected for sokol_gfx.h if both are used in the same
26 project):
27
28 #define SOKOL_GLCORE
29 #define SOKOL_GLES3
30 #define SOKOL_D3D11
31 #define SOKOL_METAL
32 #define SOKOL_WGPU
33 #define SOKOL_VULKAN
34 #define SOKOL_NOAPI
35
36 Optionally provide the following defines with your own implementations:
37
38 SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
39 SOKOL_UNREACHABLE() - a guard macro for unreachable code
40 (default: assert(false)) SOKOL_WIN32_FORCE_MAIN - define this on Win32
41 to add a main() entry point SOKOL_WIN32_FORCE_WINMAIN - define this on
42 Win32 to add a WinMain() entry point (enabled by default unless
43 SOKOL_WIN32_FORCE_MAIN or SOKOL_NO_ENTRY
44 is defined) SOKOL_NO_ENTRY - define this if sokol_app.h
45 shouldn't "hijack" the main() function SOKOL_APP_API_DECL - public
46 function declaration prefix (default: extern) SOKOL_API_DECL -
47 same as SOKOL_APP_API_DECL SOKOL_API_IMPL - public function
48 implementation prefix (default: -)
49
50 Optionally define the following to force debug checks and validations
51 even in release mode:
52
53 SOKOL_DEBUG - by default this is defined if NDEBUG is not
54 defined
55
56 If sokol_app.h is compiled as a DLL, define the following before
57 including the declaration or implementation:
58
59 SOKOL_DLL
60
61 On Windows, SOKOL_DLL will define SOKOL_APP_API_DECL as
62 __declspec(dllexport) or __declspec(dllimport) as needed.
63
64 if SOKOL_WIN32_FORCE_MAIN and SOKOL_WIN32_FORCE_WINMAIN are both defined,
65 it is up to the developer to define the desired subsystem.
66
67 On Linux, SOKOL_GLCORE can use either GLX or EGL.
68 GLX is default, set SOKOL_FORCE_EGL to override.
69
70 For example code, see
71 https://github.com/floooh/sokol-samples/tree/master/sapp
72
73 Portions of the Windows and Linux GL initialization, event-, icon- etc...
74 code have been taken from GLFW (http://www.glfw.org/).
75
76 iOS onscreen keyboard support 'inspired' by libgdx.
77
78 Link with the following system libraries:
79
80 - on macOS:
81 - all backends: Foundation, Cocoa, QuartzCore
82 - with SOKOL_METAL: Metal, MetalKit
83 - with SOKOL_GLCORE: OpenGL
84 - with SOKOL_WGPU: a WebGPU implementation library (tested with
85 webgpu_dawn)
86 - on iOS:
87 - all backends: Foundation, UIKit
88 - with SOKOL_METAL: Metal, MetalKit
89 - with SOKOL_GLES3: OpenGLES, GLKit
90 - on Linux:
91 - all backends: X11, Xi, Xcursor, dl, pthread, m
92 - with SOKOL_GLCORE: GL
93 - with SOKOL_GLES3: GLESv2
94 - with SOKOL_WGPU: a WebGPU implementation library (tested with
95 webgpu_dawn)
96 - with SOKOL_VULKAN: vulkan
97 - with EGL: EGL
98 - on Android: GLESv3, EGL, log, android
99 - on Windows:
100 - with MSVC or Clang: library dependencies are defined via `#pragma
101 comment`
102 - with SOKOL_WGPU: a WebGPU implementation library (tested with
103 webgpu_dawn)
104 - with SOKOL_VULKAN:
105 - install the Vulkan SDK
106 - set a header search path to $VULKAN_SDK/Include
107 - set a library search path to $VULKAN_SDK/Lib
108 - link with vulkan-1.lib
109 - with MINGW/MSYS2 gcc:
110 - compile with '-mwin32' so that _WIN32 is defined
111 - link with the following libs: -lkernel32 -luser32 -lshell32
112 - additionally with the GL backend: -lgdi32
113 - additionally with the D3D11 backend: -ld3d11 -ldxgi
114
115 On Linux, you also need to use the -pthread compiler and linker option,
116 otherwise weird things will happen, see here for details:
117 https://github.com/floooh/sokol/issues/376
118
119 For Linux+Vulkan install the following packages (or equivalents):
120 - libvulkan-dev
121 - vulkan-validationlayers
122 - vulkan-tools
123
124 On macOS and iOS, the implementation must be compiled as Objective-C.
125
126 On Emscripten:
127 - for WebGL2: add the linker option `-s USE_WEBGL2=1`
128 - for WebGPU: compile and link with `--use-port=emdawnwebgpu`
129 (for more exotic situations read:
130 https://dawn.googlesource.com/dawn/+/refs/heads/main/src/emdawnwebgpu/pkg/README.md)
131
132 FEATURE OVERVIEW
133 ================
134 sokol_app.h provides a minimalistic cross-platform API which
135 implements the 'application-wrapper' parts of a 3D application:
136
137 - a common application entry function
138 - creates a window and 3D-API context/device with a swapchain
139 surface, depth-stencil-buffer surface and optionally MSAA surface
140 - makes the rendered frame visible
141 - provides keyboard-, mouse- and low-level touch-events
142 - platforms: MacOS, iOS, HTML5, Win32, Linux/RaspberryPi, Android
143 - 3D-APIs: Metal, D3D11, GL4.1, GL4.3, GLES3, WebGL2, WebGPU, NOAPI
144
145 FEATURE/PLATFORM MATRIX
146 =======================
147 | Windows | macOS | Linux | iOS | Android | HTML5
148 --------------------+---------+-------+-------+-------+---------+--------
149 gl 4.x | YES | YES | YES | --- | --- | ---
150 gles3/webgl2 | --- | --- | YES(2)| YES | YES | YES
151 metal | --- | YES | --- | YES | --- | ---
152 d3d11 | YES | --- | --- | --- | --- | ---
153 webgpu | YES(4) | YES(4)| YES(4)| NO | NO | YES
154 noapi | YES | TODO | TODO | --- | TODO | ---
155 KEY_DOWN | YES | YES | YES | SOME | TODO | YES
156 KEY_UP | YES | YES | YES | SOME | TODO | YES
157 CHAR | YES | YES | YES | YES | TODO | YES
158 MOUSE_DOWN | YES | YES | YES | --- | --- | YES
159 MOUSE_UP | YES | YES | YES | --- | --- | YES
160 MOUSE_SCROLL | YES | YES | YES | --- | --- | YES
161 MOUSE_MOVE | YES | YES | YES | --- | --- | YES
162 MOUSE_ENTER | YES | YES | YES | --- | --- | YES
163 MOUSE_LEAVE | YES | YES | YES | --- | --- | YES
164 TOUCHES_BEGAN | --- | --- | --- | YES | YES | YES
165 TOUCHES_MOVED | --- | --- | --- | YES | YES | YES
166 TOUCHES_ENDED | --- | --- | --- | YES | YES | YES
167 TOUCHES_CANCELLED | --- | --- | --- | YES | YES | YES
168 RESIZED | YES | YES | YES | YES | YES | YES
169 ICONIFIED | YES | YES | YES | --- | --- | ---
170 RESTORED | YES | YES | YES | --- | --- | ---
171 FOCUSED | YES | YES | YES | --- | --- | YES
172 UNFOCUSED | YES | YES | YES | --- | --- | YES
173 SUSPENDED | --- | --- | --- | YES | YES | TODO
174 RESUMED | --- | --- | --- | YES | YES | TODO
175 QUIT_REQUESTED | YES | YES | YES | --- | --- | YES
176 IME | TODO | TODO? | TODO | ??? | TODO | ???
177 key repeat flag | YES | YES | YES | --- | --- | YES
178 windowed | YES | YES | YES | --- | --- | YES
179 fullscreen | YES | YES | YES | YES | YES | YES(3)
180 mouse hide | YES | YES | YES | --- | --- | YES
181 mouse lock | YES | YES | YES | --- | --- | YES
182 set cursor type | YES | YES | YES | --- | --- | YES
183 screen keyboard | --- | --- | --- | YES | TODO | YES
184 swap interval | YES | YES | YES | YES | TODO | YES
185 high-dpi | YES | YES | TODO | YES | YES | YES
186 clipboard | YES | YES | YES | --- | --- | YES
187 MSAA | YES | YES | YES | YES | YES | YES
188 drag'n'drop | YES | YES | YES | --- | --- | YES
189 window icon | YES | YES(1)| YES | --- | --- | YES
190
191 (1) macOS has no regular window icons, instead the dock icon is changed
192 (2) supported with EGL only (not GLX)
193 (3) fullscreen in the browser not supported on iphones
194 (4) WebGPU on native desktop platforms should be considered experimental
195 and mainly useful for debugging and benchmarking
196
197 STEP BY STEP
198 ============
199 --- Add a sokol_main() function to your code which returns a sapp_desc
200 structure with initialization parameters and callback function pointers. This
201 function is called very early, usually at the start of the
202 platform's entry function (e.g. main or WinMain). You should do as
203 little as possible here, since the rest of your code might be called
204 from another thread (this depends on the platform):
205
206 sapp_desc sokol_main(int argc, char* argv[]) {
207 return (sapp_desc) {
208 .width = 640,
209 .height = 480,
210 .init_cb = my_init_func,
211 .frame_cb = my_frame_func,
212 .cleanup_cb = my_cleanup_func,
213 .event_cb = my_event_func,
214 ...
215 };
216 }
217
218 To get any logging output in case of errors you need to provide a log
219 callback. The easiest way is via sokol_log.h:
220
221 #include "sokol_log.h"
222
223 sapp_desc sokol_main(int argc, char* argv[]) {
224 return (sapp_desc) {
225 ...
226 .logger.func = slog_func,
227 };
228 }
229
230 There are many more setup parameters, but these are the most important.
231 For a complete list search for the sapp_desc structure declaration
232 below.
233
234 DO NOT call any sokol-app function from inside sokol_main(), since
235 sokol-app will not be initialized at this point.
236
237 The .width and .height parameters are the preferred size of the 3D
238 rendering canvas. The actual size may differ from this depending on
239 platform and other circumstances. Also the canvas size may change at
240 any time (for instance when the user resizes the application window,
241 or rotates the mobile device). You can just keep .width and .height
242 zero-initialized to open a default-sized window (what "default-size"
243 exactly means is platform-specific, but usually it's a size that covers
244 most of, but not all, of the display).
245
246 All provided function callbacks will be called from the same thread,
247 but this may be different from the thread where sokol_main() was called.
248
249 .init_cb (void (*)(void))
250 This function is called once after the application window,
251 3D rendering context and swap chain have been created. The
252 function takes no arguments and has no return value.
253 .frame_cb (void (*)(void))
254 This is the per-frame callback, which is usually called 60
255 times per second. This is where your application would update
256 most of its state and perform all rendering.
257 .cleanup_cb (void (*)(void))
258 The cleanup callback is called once right before the application
259 quits.
260 .event_cb (void (*)(const sapp_event* event))
261 The event callback is mainly for input handling, but is also
262 used to communicate other types of events to the application. Keep
263 the event_cb struct member zero-initialized if your application doesn't
264 require event handling.
265
266 As you can see, those 'standard callbacks' don't have a user_data
267 argument, so any data that needs to be preserved between callbacks
268 must live in global variables. If keeping state in global variables
269 is not an option, there's an alternative set of callbacks with
270 an additional user_data pointer argument:
271
272 .user_data (void*)
273 The user-data argument for the callbacks below
274 .init_userdata_cb (void (*)(void* user_data))
275 .frame_userdata_cb (void (*)(void* user_data))
276 .cleanup_userdata_cb (void (*)(void* user_data))
277 .event_userdata_cb (void(*)(const sapp_event* event, void* user_data))
278
279 The function sapp_userdata() can be used to query the user_data
280 pointer provided in the sapp_desc struct.
281
282 You can also call sapp_query_desc() to get a copy of the
283 original sapp_desc structure.
284
285 NOTE that there's also an alternative compile mode where sokol_app.h
286 doesn't "hijack" the main() function. Search below for SOKOL_NO_ENTRY.
287
288 --- Implement the initialization callback function (init_cb), this is called
289 once after the rendering surface, 3D API and swap chain have been
290 initialized by sokol_app. All sokol-app functions can be called
291 from inside the initialization callback, the most useful functions
292 at this point are:
293
294 int sapp_width(void)
295 int sapp_height(void)
296 Returns the current width and height of the default framebuffer in
297 pixels, this may change from one frame to the next, and it may be different
298 from the initial size provided in the sapp_desc struct.
299
300 float sapp_widthf(void)
301 float sapp_heightf(void)
302 These are alternatives to sapp_width() and sapp_height() which
303 return the default framebuffer size as float values instead of integer. This
304 may help to prevent casting back and forth between int and float
305 in more strongly typed languages than C and C++.
306
307 double sapp_frame_duration(void)
308 Returns the frame duration in seconds averaged over a number of
309 frames to smooth out any jittering spikes.
310
311 int sapp_color_format(void)
312 int sapp_depth_format(void)
313 The color and depth-stencil pixelformats of the default framebuffer,
314 as integer values which are compatible with sokol-gfx's
315 sg_pixel_format enum (so that they can be plugged directly in places
316 where sg_pixel_format is expected). Possible values are:
317
318 23 == SG_PIXELFORMAT_RGBA8
319 28 == SG_PIXELFORMAT_BGRA8
320 42 == SG_PIXELFORMAT_DEPTH
321 43 == SG_PIXELFORMAT_DEPTH_STENCIL
322
323 int sapp_sample_count(void)
324 Return the MSAA sample count of the default framebuffer.
325
326 const void* sapp_metal_get_device(void)
327 const void* sapp_metal_get_current_drawable(void)
328 const void* sapp_metal_get_depth_stencil_texture(void)
329 const void* sapp_metal_get_msaa_color_texture(void)
330 If the Metal backend has been selected, these functions return
331 pointers to various Metal API objects required for rendering, otherwise they
332 return a null pointer. These void pointers are actually Objective-C ids
333 converted with a (ARC) __bridge cast so that the ids can be tunneled through
334 C code. Also note that the returned pointers may change from one frame to the
335 next, only the Metal device object is guaranteed to stay the same.
336
337 const void* sapp_macos_get_window(void)
338 On macOS, get the NSWindow object pointer, otherwise a null pointer.
339 Before being used as Objective-C object, the void* must be converted
340 back with a (ARC) __bridge cast.
341
342 const void* sapp_ios_get_window(void)
343 On iOS, get the UIWindow object pointer, otherwise a null pointer.
344 Before being used as Objective-C object, the void* must be converted
345 back with a (ARC) __bridge cast.
346
347 const void* sapp_d3d11_get_device(void)
348 const void* sapp_d3d11_get_device_context(void)
349 const void* sapp_d3d11_get_render_view(void)
350 const void* sapp_d3d11_get_resolve_view(void);
351 const void* sapp_d3d11_get_depth_stencil_view(void)
352 Similar to the sapp_metal_* functions, the sapp_d3d11_* functions
353 return pointers to D3D11 API objects required for rendering,
354 only if the D3D11 backend has been selected. Otherwise they
355 return a null pointer. Note that the returned pointers to the
356 render-target-view and depth-stencil-view may change from one
357 frame to the next!
358
359 const void* sapp_win32_get_hwnd(void)
360 On Windows, get the window's HWND, otherwise a null pointer. The
361 HWND has been cast to a void pointer in order to be tunneled
362 through code which doesn't include Windows.h.
363
364 const void* sapp_x11_get_window(void)
365 On Linux, get the X11 Window, otherwise a null pointer. The
366 Window has been cast to a void pointer in order to be tunneled
367 through code which doesn't include X11/Xlib.h.
368
369 const void* sapp_x11_get_display(void)
370 On Linux, get the X11 Display, otherwise a null pointer. The
371 Display has been cast to a void pointer in order to be tunneled
372 through code which doesn't include X11/Xlib.h.
373
374 const void* sapp_wgpu_get_device(void)
375 const void* sapp_wgpu_get_render_view(void)
376 const void* sapp_wgpu_get_resolve_view(void)
377 const void* sapp_wgpu_get_depth_stencil_view(void)
378 These are the WebGPU-specific functions to get the WebGPU
379 objects and values required for rendering. If sokol_app.h
380 is not compiled with SOKOL_WGPU, these functions return null.
381
382 uint32_t sapp_gl_get_framebuffer(void)
383 This returns the 'default framebuffer' of the GL context.
384 Typically this will be zero.
385
386 int sapp_gl_get_major_version(void)
387 int sapp_gl_get_minor_version(void)
388 bool sapp_gl_is_gles(void)
389 Returns the major and minor version of the GL context and
390 whether the GL context is a GLES context
391
392 const void* sapp_android_get_native_activity(void);
393 On Android, get the native activity ANativeActivity pointer,
394 otherwise a null pointer.
395
396 --- Implement the frame-callback function, this function will be called
397 on the same thread as the init callback, but might be on a different
398 thread than the sokol_main() function. Note that the size of
399 the rendering framebuffer might have changed since the frame callback
400 was called last. Call the functions sapp_width() and sapp_height()
401 each frame to get the current size.
402
403 --- Optionally implement the event-callback to handle input events.
404 sokol-app provides the following type of input events:
405 - a 'virtual key' was pressed down or released
406 - a single text character was entered (provided as UTF-32 encoded
407 UNICODE code point)
408 - a mouse button was pressed down or released (left, right, middle)
409 - mouse-wheel or 2D scrolling events
410 - the mouse was moved
411 - the mouse has entered or left the application window boundaries
412 - low-level, portable multi-touch events (began, moved, ended,
413 cancelled)
414 - the application window was resized, iconified or restored
415 - the application was suspended or restored (on mobile platforms)
416 - the user or application code has asked to quit the application
417 - a string was pasted to the system clipboard
418 - one or more files have been dropped onto the application window
419
420 To explicitly 'consume' an event and prevent that the event is
421 forwarded for further handling to the operating system, call
422 sapp_consume_event() from inside the event handler (NOTE that
423 this behaviour is currently only implemented for some HTML5
424 events, support for other platforms and event types will
425 be added as needed, please open a GitHub ticket and/or provide
426 a PR if needed).
427
428 NOTE: Do *not* call any 3D API rendering functions in the event
429 callback function, since the 3D API context may not be active when the
430 event callback is called (it may work on some platforms and 3D APIs,
431 but not others, and the exact behaviour may change between
432 sokol-app versions).
433
434 --- Implement the cleanup-callback function, this is called once
435 after the user quits the application (see the section
436 "APPLICATION QUIT" for detailed information on quitting
437 behaviour, and how to intercept a pending quit - for instance to show a
438 "Really Quit?" dialog box). Note that the cleanup-callback isn't
439 guaranteed to be called on the web and mobile platforms.
440
441 MOUSE CURSOR TYPE AND VISIBILITY
442 ================================
443 You can show and hide the mouse cursor with
444
445 void sapp_show_mouse(bool show)
446
447 And to get the current shown status:
448
449 bool sapp_mouse_shown(void)
450
451 NOTE that hiding the mouse cursor is different and independent from
452 the MOUSE/POINTER LOCK feature which will also hide the mouse pointer when
453 active (MOUSE LOCK is described below).
454
455 To change the mouse cursor to one of several predefined types, call
456 the function:
457
458 void sapp_set_mouse_cursor(sapp_mouse_cursor cursor)
459
460 Setting the default mouse cursor SAPP_MOUSECURSOR_DEFAULT will restore
461 the standard look.
462
463 To get the currently active mouse cursor type, call:
464
465 sapp_mouse_cursor sapp_get_mouse_cursor(void)
466
467 MOUSE LOCK (AKA POINTER LOCK, AKA MOUSE CAPTURE)
468 ================================================
469 In normal mouse mode, no mouse movement events are reported when the
470 mouse leaves the windows client area or hits the screen border (whether
471 it's one or the other depends on the platform), and the mouse move events
472 (SAPP_EVENTTYPE_MOUSE_MOVE) contain absolute mouse positions in
473 framebuffer pixels in the sapp_event items mouse_x and mouse_y, and
474 relative movement in framebuffer pixels in the sapp_event items mouse_dx
475 and mouse_dy.
476
477 To get continuous mouse movement (also when the mouse leaves the window
478 client area or hits the screen border), activate mouse-lock mode
479 by calling:
480
481 sapp_lock_mouse(true)
482
483 When mouse lock is activated, the mouse pointer is hidden, the
484 reported absolute mouse position (sapp_event.mouse_x/y) appears
485 frozen, and the relative mouse movement in sapp_event.mouse_dx/dy
486 no longer has a direct relation to framebuffer pixels but instead
487 uses "raw mouse input" (what "raw mouse input" exactly means also
488 differs by platform).
489
490 To deactivate mouse lock and return to normal mouse mode, call
491
492 sapp_lock_mouse(false)
493
494 And finally, to check if mouse lock is currently active, call
495
496 if (sapp_mouse_locked()) { ... }
497
498 Note that mouse-lock state may not change immediately after
499 sapp_lock_mouse(true/false) is called, instead on some platforms the actual
500 state switch may be delayed to the end of the current frame or even to a
501 later frame.
502
503 The mouse may also be unlocked automatically without calling
504 sapp_lock_mouse(false), most notably when the application window becomes
505 inactive.
506
507 On the web platform there are further restrictions to be aware of, caused
508 by the limitations of the HTML5 Pointer Lock API:
509
510 - sapp_lock_mouse(true) can be called at any time, but it will
511 only take effect in a 'short-lived input event handler of a specific
512 type', meaning when one of the following events happens:
513 - SAPP_EVENTTYPE_MOUSE_DOWN
514 - SAPP_EVENTTYPE_MOUSE_UP
515 - SAPP_EVENTTYPE_MOUSE_SCROLL
516 - SAPP_EVENTTYPE_KEY_UP
517 - SAPP_EVENTTYPE_KEY_DOWN
518 - The mouse lock/unlock action on the web platform is asynchronous,
519 this means that sapp_mouse_locked() won't immediately return
520 the new status after calling sapp_lock_mouse(), instead the
521 reported status will only change when the pointer lock has actually
522 been activated or deactivated in the browser.
523 - On the web, mouse lock can be deactivated by the user at any time
524 by pressing the Esc key. When this happens, sokol_app.h behaves
525 the same as if sapp_lock_mouse(false) is called.
526
527 For things like camera manipulation it's most straightforward to lock
528 and unlock the mouse right from the sokol_app.h event handler, for
529 instance the following code enters and leaves mouse lock when the
530 left mouse button is pressed and released, and then uses the relative
531 movement information to manipulate a camera (taken from the
532 cgltf-sapp.c sample in the sokol-samples repository
533 at https://github.com/floooh/sokol-samples):
534
535 static void input(const sapp_event* ev) {
536 switch (ev->type) {
537 case SAPP_EVENTTYPE_MOUSE_DOWN:
538 if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
539 sapp_lock_mouse(true);
540 }
541 break;
542
543 case SAPP_EVENTTYPE_MOUSE_UP:
544 if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
545 sapp_lock_mouse(false);
546 }
547 break;
548
549 case SAPP_EVENTTYPE_MOUSE_MOVE:
550 if (sapp_mouse_locked()) {
551 cam_orbit(&state.camera, ev->mouse_dx * 0.25f,
552 ev->mouse_dy * 0.25f);
553 }
554 break;
555
556 default:
557 break;
558 }
559 }
560
561 For a 'first person shooter mouse' the following code inside the sokol-app
562 event handler is recommended somewhere in your frame callback:
563
564 if (!sapp_mouse_locked()) {
565 sapp_lock_mouse(true);
566 }
567
568 CLIPBOARD SUPPORT
569 =================
570 Applications can send and receive UTF-8 encoded text data from and to the
571 system clipboard. By default, clipboard support is disabled and
572 must be enabled at startup via the following sapp_desc struct
573 members:
574
575 sapp_desc.enable_clipboard - set to true to enable clipboard support
576 sapp_desc.clipboard_size - size of the internal clipboard buffer in
577 bytes
578
579 Enabling the clipboard will dynamically allocate a clipboard buffer
580 for UTF-8 encoded text data of the requested size in bytes, the default
581 size is 8 KBytes. Strings that don't fit into the clipboard buffer
582 (including the terminating zero) will be silently clipped, so it's
583 important that you provide a big enough clipboard size for your
584 use case.
585
586 To send data to the clipboard, call sapp_set_clipboard_string() with
587 a pointer to an UTF-8 encoded, null-terminated C-string.
588
589 NOTE that on the HTML5 platform, sapp_set_clipboard_string() must be
590 called from inside a 'short-lived event handler', and there are a few
591 other HTML5-specific caveats to workaround. You'll basically have to
592 tinker until it works in all browsers :/ (maybe the situation will
593 improve when all browsers agree on and implement the new
594 HTML5 navigator.clipboard API).
595
596 To get data from the clipboard, check for the
597 SAPP_EVENTTYPE_CLIPBOARD_PASTED event in your event handler function, and
598 then call sapp_get_clipboard_string() to obtain the pasted UTF-8 encoded
599 text.
600
601 NOTE that behaviour of sapp_get_clipboard_string() is slightly different
602 depending on platform:
603
604 - on the HTML5 platform, the internal clipboard buffer will only be
605 updated right before the SAPP_EVENTTYPE_CLIPBOARD_PASTED event is sent, and
606 sapp_get_clipboard_string() will simply return the current content of the
607 clipboard buffer
608 - on 'native' platforms, the call to sapp_get_clipboard_string() will
609 update the internal clipboard buffer with the most recent data
610 from the system clipboard
611
612 Portable code should check for the SAPP_EVENTTYPE_CLIPBOARD_PASTED event,
613 and then call sapp_get_clipboard_string() right in the event handler.
614
615 The SAPP_EVENTTYPE_CLIPBOARD_PASTED event will be generated by sokol-app
616 as follows:
617
618 - on macOS: when the Cmd+V key is pressed down
619 - on HTML5: when the browser sends a 'paste' event to the global
620 'window' object
621 - on all other platforms: when the Ctrl+V key is pressed down
622
623 DRAG AND DROP SUPPORT
624 =====================
625 PLEASE NOTE: the drag'n'drop feature works differently on WASM/HTML5
626 and on the native desktop platforms (Win32, Linux and macOS) because
627 of security-related restrictions in the HTML5 drag'n'drop API. The
628 WASM/HTML5 specifics are described at the end of this documentation
629 section:
630
631 Like clipboard support, drag'n'drop support must be explicitly enabled
632 at startup in the sapp_desc struct.
633
634 sapp_desc sokol_main(void) {
635 return (sapp_desc) {
636 .enable_dragndrop = true, // default is false
637 ...
638 };
639 }
640
641 You can also adjust the maximum number of files that are accepted
642 in a drop operation, and the maximum path length in bytes if needed:
643
644 sapp_desc sokol_main(void) {
645 return (sapp_desc) {
646 .enable_dragndrop = true, // default is false
647 .max_dropped_files = 8, // default is 1
648 .max_dropped_file_path_length = 8192, // in bytes, default is
649 2048
650 ...
651 };
652 }
653
654 When drag'n'drop is enabled, the event callback will be invoked with an
655 event of type SAPP_EVENTTYPE_FILES_DROPPED whenever the user drops files on
656 the application window.
657
658 After the SAPP_EVENTTYPE_FILES_DROPPED is received, you can query the
659 number of dropped files, and their absolute paths by calling separate
660 functions:
661
662 void on_event(const sapp_event* ev) {
663 if (ev->type == SAPP_EVENTTYPE_FILES_DROPPED) {
664
665 // the mouse position where the drop happened
666 float x = ev->mouse_x;
667 float y = ev->mouse_y;
668
669 // get the number of files and their paths like this:
670 const int num_dropped_files = sapp_get_num_dropped_files();
671 for (int i = 0; i < num_dropped_files; i++) {
672 const char* path = sapp_get_dropped_file_path(i);
673 ...
674 }
675 }
676 }
677
678 The returned file paths are UTF-8 encoded strings.
679
680 You can call sapp_get_num_dropped_files() and sapp_get_dropped_file_path()
681 anywhere, also outside the event handler callback, but be aware that the
682 file path strings will be overwritten with the next drop operation.
683
684 In any case, sapp_get_dropped_file_path() will never return a null pointer,
685 instead an empty string "" will be returned if the drag'n'drop feature
686 hasn't been enabled, the last drop-operation failed, or the file path index
687 is out of range.
688
689 Drag'n'drop caveats:
690
691 - if more files are dropped in a single drop-action
692 than sapp_desc.max_dropped_files, the additional
693 files will be silently ignored
694 - if any of the file paths is longer than
695 sapp_desc.max_dropped_file_path_length (in number of bytes, after
696 UTF-8 encoding) the entire drop operation will be silently ignored (this
697 needs some sort of error feedback in the future)
698 - no mouse positions are reported while the drag is in
699 process, this may change in the future
700
701 Drag'n'drop on HTML5/WASM:
702
703 The HTML5 drag'n'drop API doesn't return file paths, but instead
704 black-box 'file objects' which must be used to load the content
705 of dropped files. This is the reason why sokol_app.h adds two
706 HTML5-specific functions to the drag'n'drop API:
707
708 uint32_t sapp_html5_get_dropped_file_size(int index)
709 Returns the size in bytes of a dropped file.
710
711 void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request*
712 request) Asynchronously loads the content of a dropped file into a provided
713 memory buffer (which must be big enough to hold the file content)
714
715 To start loading the first dropped file after an
716 SAPP_EVENTTYPE_FILES_DROPPED event is received:
717
718 sapp_html5_fetch_dropped_file(&(sapp_html5_fetch_request){
719 .dropped_file_index = 0,
720 .callback = fetch_cb
721 .buffer = {
722 .ptr = buf,
723 .size = sizeof(buf)
724 },
725 .user_data = ...
726 });
727
728 Make sure that the memory pointed to by 'buf' stays valid until the
729 callback function is called!
730
731 As result of the asynchronous loading operation (no matter if succeeded or
732 failed) the 'fetch_cb' function will be called:
733
734 void fetch_cb(const sapp_html5_fetch_response* response) {
735 // IMPORTANT: check if the loading operation actually succeeded:
736 if (response->succeeded) {
737 // the size of the loaded file:
738 const size_t num_bytes = response->data.size;
739 // and the pointer to the data (same as 'buf' in the
740 fetch-call): const void* ptr = response->data.ptr; } else {
741 // on error check the error code:
742 switch (response->error_code) {
743 case SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL:
744 ...
745 break;
746 case SAPP_HTML5_FETCH_ERROR_OTHER:
747 ...
748 break;
749 }
750 }
751 }
752
753 Check the droptest-sapp example for a real-world example which works
754 both on native platforms and the web:
755
756 https://github.com/floooh/sokol-samples/blob/master/sapp/droptest-sapp.c
757
758 HIGH-DPI RENDERING
759 ==================
760 You can set the sapp_desc.high_dpi flag during initialization to request
761 a full-resolution framebuffer on HighDPI displays. The default behaviour
762 is sapp_desc.high_dpi=false, this means that the application will
763 render to a lower-resolution framebuffer on HighDPI displays and the
764 rendered content will be upscaled by the window system composer.
765
766 In a HighDPI scenario, you still request the same window size during
767 sokol_main(), but the framebuffer sizes returned by sapp_width()
768 and sapp_height() will be scaled up according to the DPI scaling
769 ratio.
770
771 Note that on some platforms the DPI scaling factor may change at any
772 time (for instance when a window is moved from a high-dpi display
773 to a low-dpi display).
774
775 To query the current DPI scaling factor, call the function:
776
777 float sapp_dpi_scale(void);
778
779 For instance on a Retina Mac, returning the following sapp_desc
780 struct from sokol_main():
781
782 sapp_desc sokol_main(void) {
783 return (sapp_desc) {
784 .width = 640,
785 .height = 480,
786 .high_dpi = true,
787 ...
788 };
789 }
790
791 ...the functions the functions sapp_width(), sapp_height()
792 and sapp_dpi_scale() will return the following values:
793
794 sapp_width: 1280
795 sapp_height: 960
796 sapp_dpi_scale: 2.0
797
798 If the high_dpi flag is false, or you're not running on a Retina display,
799 the values would be:
800
801 sapp_width: 640
802 sapp_height: 480
803 sapp_dpi_scale: 1.0
804
805 If the window is moved from the Retina display to a low-dpi external
806 display, the values would change as follows:
807
808 sapp_width: 1280 => 640
809 sapp_height: 960 => 480
810 sapp_dpi_scale: 2.0 => 1.0
811
812 Currently there is no event associated with a DPI change, but an
813 SAPP_EVENTTYPE_RESIZED will be sent as a side effect of the
814 framebuffer size changing.
815
816 Per-monitor DPI is currently supported on macOS and Windows.
817
818 APPLICATION QUIT
819 ================
820 Without special quit handling, a sokol_app.h application will quit
821 'gracefully' when the user clicks the window close-button unless a
822 platform's application model prevents this (e.g. on web or mobile).
823 'Graceful exit' means that the application-provided cleanup callback will
824 be called before the application quits.
825
826 On native desktop platforms sokol_app.h provides more control over the
827 application-quit-process. It's possible to initiate a 'programmatic quit'
828 from the application code, and a quit initiated by the application user can
829 be intercepted (for instance to show a custom dialog box).
830
831 This 'programmatic quit protocol' is implemented through 3 functions
832 and 1 event:
833
834 - sapp_quit(): This function simply quits the application without
835 giving the user a chance to intervene. Usually this might
836 be called when the user clicks the 'Ok' button in a 'Really Quit?'
837 dialog box
838 - sapp_request_quit(): Calling sapp_request_quit() will send the
839 event SAPP_EVENTTYPE_QUIT_REQUESTED to the applications event handler
840 callback, giving the user code a chance to intervene and cancel the
841 pending quit process (for instance to show a 'Really Quit?' dialog
842 box). If the event handler callback does nothing, the application
843 will be quit as usual. To prevent this, call the function
844 sapp_cancel_quit() from inside the event handler.
845 - sapp_cancel_quit(): Cancels a pending quit request, either initiated
846 by the user clicking the window close button, or programmatically
847 by calling sapp_request_quit(). The only place where calling this
848 function makes sense is from inside the event handler callback when
849 the SAPP_EVENTTYPE_QUIT_REQUESTED event has been received.
850 - SAPP_EVENTTYPE_QUIT_REQUESTED: this event is sent when the user
851 clicks the window's close button or application code calls the
852 sapp_request_quit() function. The event handler callback code can
853 handle this event by calling sapp_cancel_quit() to cancel the quit. If the
854 event is ignored, the application will quit as usual.
855
856 On the web platform, the quit behaviour differs from native platforms,
857 because of web-specific restrictions:
858
859 A `programmatic quit` initiated by calling sapp_quit() or
860 sapp_request_quit() will work as described above: the cleanup callback is
861 called, platform-specific cleanup is performed (on the web
862 this means that JS event handlers are unregistered), and then
863 the request-animation-loop will be exited. However that's all. The
864 web page itself will continue to exist (e.g. it's not possible to
865 programmatically close the browser tab).
866
867 On the web it's also not possible to run custom code when the user
868 closes a browser tab, so it's not possible to prevent this with a
869 fancy custom dialog box.
870
871 Instead the standard "Leave Site?" dialog box can be activated (or
872 deactivated) with the following function:
873
874 sapp_html5_ask_leave_site(bool ask);
875
876 The initial state of the associated internal flag can be provided
877 at startup via sapp_desc.html5.ask_leave_site.
878
879 This feature should only be used sparingly in critical situations - for
880 instance when the user would loose data - since popping up modal dialog
881 boxes is considered quite rude in the web world. Note that there's no way
882 to customize the content of this dialog box or run any code as a result
883 of the user's decision. Also note that the user must have interacted with
884 the site before the dialog box will appear. These are all security measures
885 to prevent fishing.
886
887 The Dear ImGui HighDPI sample contains example code of how to
888 implement a 'Really Quit?' dialog box with Dear ImGui (native desktop
889 platforms only), and for showing the hardwired "Leave Site?" dialog box
890 when running on the web platform:
891
892 https://floooh.github.io/sokol-html5/wasm/imgui-highdpi-sapp.html
893
894 FULLSCREEN
895 ==========
896 If the sapp_desc.fullscreen flag is true, sokol-app will try to create
897 a fullscreen window on platforms with a 'proper' window system
898 (mobile devices will always use fullscreen). The implementation details
899 depend on the target platform, in general sokol-app will use a
900 'soft approach' which doesn't interfere too much with the platform's
901 window system (for instance borderless fullscreen window instead of
902 a 'real' fullscreen mode). Such details might change over time
903 as sokol-app is adapted for different needs.
904
905 The most important effect of fullscreen mode to keep in mind is that
906 the requested canvas width and height will be ignored for the initial
907 window size, calling sapp_width() and sapp_height() will instead return
908 the resolution of the fullscreen canvas (however the provided size
909 might still be used for the non-fullscreen window, in case the user can
910 switch back from fullscreen- to windowed-mode).
911
912 To toggle fullscreen mode programmatically, call sapp_toggle_fullscreen().
913
914 To check if the application window is currently in fullscreen mode,
915 call sapp_is_fullscreen().
916
917 On the web, sapp_desc.fullscreen will have no effect, and the application
918 will always start in non-fullscreen mode. Call sapp_toggle_fullscreen()
919 from within or 'near' an input event to switch to fullscreen
920 programatically. Note that on the web, the fullscreen state may change back
921 to windowed at any time (either because the browser had rejected switching
922 into fullscreen, or the user leaves fullscreen via Esc), this means that the
923 result of sapp_is_fullscreen() may change also without calling
924 sapp_toggle_fullscreen()!
925
926
927 WINDOW ICON SUPPORT
928 ===================
929 Some sokol_app.h backends allow to change the window icon programmatically:
930
931 - on Win32: the small icon in the window's title bar, and the
932 bigger icon in the task bar
933 - on Linux: highly dependent on the used window manager, but usually
934 the window's title bar icon and/or the task bar icon
935 - on HTML5: the favicon shown in the page's browser tab
936 - on macOS: the application icon shown in the dock, but only
937 for currently running applications
938
939 NOTE that it is not possible to set the actual application icon which is
940 displayed by the operating system on the desktop or 'home screen'. Those
941 icons must be provided 'traditionally' through operating-system-specific
942 resources which are associated with the application (sokol_app.h might
943 later support setting the window icon from platform specific resource data
944 though).
945
946 There are two ways to set the window icon:
947
948 - at application start in the sokol_main() function by initializing
949 the sapp_desc.icon nested struct
950 - or later by calling the function sapp_set_icon()
951
952 As a convenient shortcut, sokol_app.h comes with a builtin default-icon
953 (a rainbow-colored 'S', which at least looks a bit better than the Windows
954 default icon for applications), which can be activated like this:
955
956 At startup in sokol_main():
957
958 sapp_desc sokol_main(...) {
959 return (sapp_desc){
960 ...
961 icon.sokol_default = true
962 };
963 }
964
965 Or later by calling:
966
967 sapp_set_icon(&(sapp_icon_desc){ .sokol_default = true });
968
969 NOTE that a completely zero-initialized sapp_icon_desc struct will not
970 update the window icon in any way. This is an 'escape hatch' so that you
971 can handle the window icon update yourself (or if you do this already,
972 sokol_app.h won't get in your way, in this case just leave the
973 sapp_desc.icon struct zero-initialized).
974
975 Providing your own icon images works exactly like in GLFW (down to the
976 data format):
977
978 You provide one or more 'candidate images' in different sizes, and the
979 sokol_app.h platform backends pick the best match for the specific backend
980 and icon type.
981
982 For each candidate image, you need to provide:
983
984 - the width in pixels
985 - the height in pixels
986 - and the actual pixel data in RGBA8 pixel format (e.g. 0xFFCC8844
987 on a little-endian CPU means: alpha=0xFF, blue=0xCC, green=0x88,
988 red=0x44)
989
990 For instance, if you have 3 candidate images (small, medium, big) of
991 sizes 16x16, 32x32 and 64x64 the corresponding sapp_icon_desc struct is
992 setup like this:
993
994 // the actual pixel data (RGBA8, origin top-left)
995 const uint32_t small[16][16] = { ... };
996 const uint32_t medium[32][32] = { ... };
997 const uint32_t big[64][64] = { ... };
998
999 const sapp_icon_desc icon_desc = {
1000 .images = {
1001 { .width = 16, .height = 16, .pixels = SAPP_RANGE(small) },
1002 { .width = 32, .height = 32, .pixels = SAPP_RANGE(medium) },
1003 // ...or without the SAPP_RANGE helper macro:
1004 { .width = 64, .height = 64, .pixels = { .ptr=big,
1005 .size=sizeof(big) } }
1006 }
1007 };
1008
1009 An sapp_icon_desc struct initialized like this can then either be applied
1010 at application start in sokol_main:
1011
1012 sapp_desc sokol_main(...) {
1013 return (sapp_desc){
1014 ...
1015 icon = icon_desc
1016 };
1017 }
1018
1019 ...or later by calling sapp_set_icon():
1020
1021 sapp_set_icon(&icon_desc);
1022
1023 Some window icon caveats:
1024
1025 - once the window icon has been updated, there's no way to go back to
1026 the platform's default icon, this is because some platforms (Linux
1027 and HTML5) don't switch the icon visual back to the default even if
1028 the custom icon is deleted or removed
1029 - on HTML5, if the sokol_app.h icon doesn't show up in the browser
1030 tab, check that there's no traditional favicon 'link' element
1031 is defined in the page's index.html, sokol_app.h will only
1032 append a new favicon link element, but not delete any manually
1033 defined favicon in the page
1034
1035 For an example and test of the window icon feature, check out the
1036 'icon-sapp' sample on the sokol-samples git repository.
1037
1038 ONSCREEN KEYBOARD
1039 =================
1040 On some platforms which don't provide a physical keyboard, sokol-app
1041 can display the platform's integrated onscreen keyboard for text
1042 input. To request that the onscreen keyboard is shown, call
1043
1044 sapp_show_keyboard(true);
1045
1046 Likewise, to hide the keyboard call:
1047
1048 sapp_show_keyboard(false);
1049
1050 Note that onscreen keyboard functionality is no longer supported
1051 on the browser platform (the previous hacks and workarounds to make browser
1052 keyboards work for on web applications that don't use HTML UIs
1053 never really worked across browsers).
1054
1055 INPUT EVENT BUBBLING ON THE WEB PLATFORM
1056 ========================================
1057 By default, input event bubbling on the web platform is configured in
1058 a way that makes the most sense for 'full-canvas' apps that cover the
1059 entire browser client window area:
1060
1061 - mouse, touch and wheel events do not bubble up, this prevents various
1062 ugly side events, like:
1063 - HTML text overlays being selected on double- or triple-click into
1064 the canvas
1065 - 'scroll bumping' even when the canvas covers the entire client area
1066 - key_up/down events for 'character keys' *do* bubble up (otherwise
1067 the browser will not generate UNICODE character events)
1068 - all other key events *do not* bubble up by default (this prevents side
1069 effects like F1 opening help, or F7 starting 'caret browsing')
1070 - character events do not bubble up (although I haven't noticed any side
1071 effects otherwise)
1072
1073 Event bubbling can be enabled for input event categories during
1074 initialization in the sapp_desc struct:
1075
1076 sapp_desc sokol_main(int argc, char* argv[]) {
1077 return (sapp_desc){
1078 //...
1079 .html5 = {
1080 .bubble_mouse_events = true,
1081 .bubble_touch_events = true,
1082 .bubble_wheel_events = true,
1083 .bubble_key_events = true,
1084 .bubble_char_events = true,
1085 }
1086 };
1087 }
1088
1089 This basically opens the floodgates and lets *all* input events bubble up to
1090 the browser.
1091
1092 To prevent individual events from bubbling, call sapp_consume_event() from
1093 within the sokol_app.h event callback when that specific event is reported.
1094
1095
1096 SETTING THE CANVAS OBJECT ON THE WEB PLATFORM
1097 =============================================
1098 On the web, sokol_app.h and the Emscripten SDK functions need to find
1099 the WebGL/WebGPU canvas intended for rendering and attaching event
1100 handlers. This can happen in four ways:
1101
1102 1. do nothing and just set the id of the canvas object to 'canvas'
1103 (preferred)
1104 2. via a CSS Selector string (preferred)
1105 3. by setting the `Module.canvas` property to the canvas object
1106 4. by adding the canvas object to the global variable `specialHTMLTargets[]`
1107 (this is a special variable used by the Emscripten runtime to lookup
1108 event target objects for which document.querySelector() cannot be used)
1109
1110 The easiest way is to just name your canvas object 'canvas':
1111
1112 <canvas id="canvas" ...></canvas>
1113
1114 This works because the default css selector string used by sokol_app.h
1115 is '#canvas'.
1116
1117 If you name your canvas differently, you need to communicate that name to
1118 sokol_app.h via `sapp_desc.html5.canvas_selector` as a regular css selector
1119 string that's compatible with `document.querySelector()`. E.g. if your
1120 canvas object looks like this:
1121
1122 <canvas id="bla" ...></canvas>
1123
1124 The `sapp_desc.html5.canvas_selector` string must be set to '#bla':
1125
1126 .html5.canvas_selector = "#bla"
1127
1128 If the canvas object cannot be looked up via `document.querySelector()` you
1129 need to use one of the alternative methods, both involve the special
1130 Emscripten runtime `Module` object which is usually setup in the index.html
1131 like this before the WASM blob is loaded and instantiated:
1132
1133 <script type='text/javascript'>
1134 var Module = {
1135 // ...
1136 };
1137 </script>
1138
1139 The first option is to set the `Module.canvas` property to your canvas
1140 object:
1141
1142 <script type='text/javascript'>
1143 var Module = {
1144 canvas: my_canvas_object,
1145 };
1146 </script>
1147
1148 When sokol_app.h initializes, it will check the global Module object whether
1149 a `Module.canvas` property exists and is an object. This method will add
1150 a new entry to the `specialHTMLTargets[]` object
1151
1152 The other option is to add the canvas under a name chosen by you to the
1153 special `specialHTMLTargets[]` map, which is used by the Emscripten runtime
1154 to lookup 'event target objects' which are not visible to
1155 `document.querySelector()`. Note that `specialHTMLTargets[]` must be updated
1156 after the Emscripten runtime has started but before the WASM code is running.
1157 A good place for this is the special `Module.preRun` array in index.html:
1158
1159 <script type='text/javascript'>
1160 var Module = {
1161 preRun: [
1162 () => {
1163 specialHTMLTargets['my_canvas'] = my_canvas_object;
1164 }
1165 ],
1166 };
1167 </script>
1168
1169 In that case, pass the same string to sokol_app.h which is used as key
1170 in the specialHTMLTargets[] map:
1171
1172 .html5.canvas_selector = "my_canvas"
1173
1174 If sokol_app.h can't find your canvas for some reason check for warning
1175 messages on the browser console.
1176
1177
1178 OPTIONAL: DON'T HIJACK main() (#define SOKOL_NO_ENTRY)
1179 ======================================================
1180 NOTE: SOKOL_NO_ENTRY and sapp_run() is currently not supported on Android.
1181
1182 In its default configuration, sokol_app.h "hijacks" the platform's
1183 standard main() function. This was done because different platforms
1184 have different entry point conventions which are not compatible with
1185 C's main() (for instance WinMain on Windows has completely different
1186 arguments). However, this "main hijacking" posed a problem for
1187 usage scenarios like integrating sokol_app.h with other languages than
1188 C or C++, so an alternative SOKOL_NO_ENTRY mode has been added
1189 in which the user code provides the platform's main function:
1190
1191 - define SOKOL_NO_ENTRY before including the sokol_app.h implementation
1192 - do *not* provide a sokol_main() function
1193 - instead provide the standard main() function of the platform
1194 - from the main function, call the function ```sapp_run()``` which
1195 takes a pointer to an ```sapp_desc``` structure.
1196 - from here on```sapp_run()``` takes over control and calls the provided
1197 init-, frame-, event- and cleanup-callbacks just like in the default
1198 model.
1199
1200 sapp_run() behaves differently across platforms:
1201
1202 - on some platforms, sapp_run() will return when the application quits
1203 - on other platforms, sapp_run() will never return, even when the
1204 application quits (the operating system is free to simply terminate
1205 the application at any time)
1206 - on Emscripten specifically, sapp_run() will return immediately while
1207 the frame callback keeps being called
1208
1209 This different behaviour of sapp_run() essentially means that there
1210 shouldn't be any code *after* sapp_run(), because that may either never be
1211 called, or in case of Emscripten will be called at an unexpected time (at
1212 application start).
1213
1214 An application also should not depend on the cleanup-callback being called
1215 when cross-platform compatibility is required.
1216
1217 Since sapp_run() returns immediately on Emscripten you shouldn't activate
1218 the 'EXIT_RUNTIME' linker option (this is disabled by default when compiling
1219 for the browser target), since the C/C++ exit runtime would be called
1220 immediately at application start, causing any global objects to be destroyed
1221 and global variables to be zeroed.
1222
1223 WINDOWS CONSOLE OUTPUT
1224 ======================
1225 On Windows, regular windowed applications don't show any stdout/stderr text
1226 output, which can be a bit of a hassle for printf() debugging or generally
1227 logging text to the console. Also, console output by default uses a local
1228 codepage setting and thus international UTF-8 encoded text is printed
1229 as garbage.
1230
1231 To help with these issues, sokol_app.h can be configured at startup
1232 via the following Windows-specific sapp_desc flags:
1233
1234 sapp_desc.win32.console_utf8 (default: false)
1235 When set to true, the output console codepage will be switched
1236 to UTF-8 (and restored to the original codepage on exit)
1237
1238 sapp_desc.win32.console_attach (default: false)
1239 When set to true, stdout and stderr will be attached to the
1240 console of the parent process (if the parent process actually
1241 has a console). This means that if the application was started
1242 in a command line window, stdout and stderr output will be printed
1243 to the terminal, just like a regular command line program. But if
1244 the application is started via double-click, it will behave like
1245 a regular UI application, and stdout/stderr will not be visible.
1246
1247 sapp_desc.win32.console_create (default: false)
1248 When set to true, a new console window will be created and
1249 stdout/stderr will be redirected to that console window. It
1250 doesn't matter if the application is started from the command
1251 line or via double-click.
1252
1253 NOTE: setting both win32.console_attach and win32.console_create
1254 to true also makes sense and has the effect that output
1255 will appear in the existing terminal when started from the cmdline,
1256 and otherwise (when started via double-click) will open a console window.
1257
1258 MEMORY ALLOCATION OVERRIDE
1259 ==========================
1260 You can override the memory allocation functions at initialization time
1261 like this:
1262
1263 void* my_alloc(size_t size, void* user_data) {
1264 return malloc(size);
1265 }
1266
1267 void my_free(void* ptr, void* user_data) {
1268 free(ptr);
1269 }
1270
1271 sapp_desc sokol_main(int argc, char* argv[]) {
1272 return (sapp_desc){
1273 // ...
1274 .allocator = {
1275 .alloc_fn = my_alloc,
1276 .free_fn = my_free,
1277 .user_data = ...,
1278 }
1279 };
1280 }
1281
1282 If no overrides are provided, malloc and free will be used.
1283
1284 This only affects memory allocation calls done by sokol_app.h
1285 itself though, not any allocations in OS libraries.
1286
1287
1288 ERROR REPORTING AND LOGGING
1289 ===========================
1290 To get any logging information at all you need to provide a logging callback
1291 in the setup call the easiest way is to use sokol_log.h:
1292
1293 #include "sokol_log.h"
1294
1295 sapp_desc sokol_main(int argc, char* argv[]) {
1296 return (sapp_desc) {
1297 ...
1298 .logger.func = slog_func,
1299 };
1300 }
1301
1302 To override logging with your own callback, first write a logging function
1303 like this:
1304
1305 void my_log(const char* tag, // e.g. 'sapp'
1306 uint32_t log_level, // 0=panic, 1=error, 2=warn,
1307 3=info uint32_t log_item_id, // SAPP_LOGITEM_* const char*
1308 message_or_null, // a message string, may be nullptr in release mode
1309 uint32_t line_nr, // line number in
1310 sokol_app.h const char* filename_or_null, // source filename, may be
1311 nullptr in release mode void* user_data)
1312 {
1313 ...
1314 }
1315
1316 ...and then setup sokol-app like this:
1317
1318 sapp_desc sokol_main(int argc, char* argv[]) {
1319 return (sapp_desc) {
1320 ...
1321 .logger = {
1322 .func = my_log,
1323 .user_data = my_user_data,
1324 }
1325 };
1326 }
1327
1328 The provided logging function must be reentrant (e.g. be callable from
1329 different threads).
1330
1331 If you don't want to provide your own custom logger it is highly recommended
1332 to use the standard logger in sokol_log.h instead, otherwise you won't see
1333 any warnings or errors.
1334
1335 TEMP NOTE DUMP
1336 ==============
1337 - sapp_desc needs a bool whether to initialize depth-stencil surface
1338 - the Android implementation calls cleanup_cb() and destroys the egl context
1339 in onDestroy at the latest but should do it earlier, in onStop, as an app is
1340 "killable" after onStop on Android Honeycomb and later (it can't be done at
1341 the moment as the app may be started again after onStop and the sokol
1342 lifecycle does not yet handle context teardown/bringup)
1343
1344
1345 LICENSE
1346 =======
1347 zlib/libpng license
1348
1349 Copyright (c) 2018 Andre Weissflog
1350
1351 This software is provided 'as-is', without any express or implied warranty.
1352 In no event will the authors be held liable for any damages arising from the
1353 use of this software.
1354
1355 Permission is granted to anyone to use this software for any purpose,
1356 including commercial applications, and to alter it and redistribute it
1357 freely, subject to the following restrictions:
1358
1359 1. The origin of this software must not be misrepresented; you must not
1360 claim that you wrote the original software. If you use this software in
1361 a product, an acknowledgment in the product documentation would be
1362 appreciated but is not required.
1363
1364 2. Altered source versions must be plainly marked as such, and must not
1365 be misrepresented as being the original software.
1366
1367 3. This notice may not be removed or altered from any source
1368 distribution.
1369*/
1370#define SOKOL_APP_INCLUDED (1)
1371#include <stdbool.h>
1372#include <stddef.h> // size_t
1373#include <stdint.h>
1374
1375#if defined(SOKOL_API_DECL) && !defined(SOKOL_APP_API_DECL)
1376#define SOKOL_APP_API_DECL SOKOL_API_DECL
1377#endif
1378#ifndef SOKOL_APP_API_DECL
1379#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_APP_IMPL)
1380#define SOKOL_APP_API_DECL __declspec(dllexport)
1381#elif defined(_WIN32) && defined(SOKOL_DLL)
1382#define SOKOL_APP_API_DECL __declspec(dllimport)
1383#else
1384#define SOKOL_APP_API_DECL extern
1385#endif
1386#endif
1387
1388#ifdef __cplusplus
1389extern "C" {
1390#endif
1391
1392/* misc constants */
1393enum {
1394 SAPP_MAX_TOUCHPOINTS = 8,
1395 SAPP_MAX_MOUSEBUTTONS = 3,
1396 SAPP_MAX_KEYCODES = 512,
1397 SAPP_MAX_ICONIMAGES = 8,
1398};
1399
1400/*
1401 sapp_event_type
1402
1403 The type of event that's passed to the event handler callback
1404 in the sapp_event.type field. These are not just "traditional"
1405 input events, but also notify the application about state changes
1406 or other user-invoked actions.
1407*/
1408typedef enum sapp_event_type {
1409 SAPP_EVENTTYPE_INVALID,
1410 SAPP_EVENTTYPE_KEY_DOWN,
1411 SAPP_EVENTTYPE_KEY_UP,
1412 SAPP_EVENTTYPE_CHAR,
1413 SAPP_EVENTTYPE_MOUSE_DOWN,
1414 SAPP_EVENTTYPE_MOUSE_UP,
1415 SAPP_EVENTTYPE_MOUSE_SCROLL,
1416 SAPP_EVENTTYPE_MOUSE_MOVE,
1417 SAPP_EVENTTYPE_MOUSE_ENTER,
1418 SAPP_EVENTTYPE_MOUSE_LEAVE,
1419 SAPP_EVENTTYPE_TOUCHES_BEGAN,
1420 SAPP_EVENTTYPE_TOUCHES_MOVED,
1421 SAPP_EVENTTYPE_TOUCHES_ENDED,
1422 SAPP_EVENTTYPE_TOUCHES_CANCELLED,
1423 SAPP_EVENTTYPE_RESIZED,
1424 SAPP_EVENTTYPE_ICONIFIED,
1425 SAPP_EVENTTYPE_RESTORED,
1426 SAPP_EVENTTYPE_FOCUSED,
1427 SAPP_EVENTTYPE_UNFOCUSED,
1428 SAPP_EVENTTYPE_SUSPENDED,
1429 SAPP_EVENTTYPE_RESUMED,
1430 SAPP_EVENTTYPE_QUIT_REQUESTED,
1431 SAPP_EVENTTYPE_CLIPBOARD_PASTED,
1432 SAPP_EVENTTYPE_FILES_DROPPED,
1433 _SAPP_EVENTTYPE_NUM,
1434 _SAPP_EVENTTYPE_FORCE_U32 = 0x7FFFFFFF
1435} sapp_event_type;
1436
1437/*
1438 sapp_keycode
1439
1440 The 'virtual keycode' of a KEY_DOWN or KEY_UP event in the
1441 struct field sapp_event.key_code.
1442
1443 Note that the keycode values are identical with GLFW.
1444*/
1445typedef enum sapp_keycode {
1446 SAPP_KEYCODE_INVALID = 0,
1447 SAPP_KEYCODE_SPACE = 32,
1448 SAPP_KEYCODE_APOSTROPHE = 39, /* ' */
1449 SAPP_KEYCODE_COMMA = 44, /* , */
1450 SAPP_KEYCODE_MINUS = 45, /* - */
1451 SAPP_KEYCODE_PERIOD = 46, /* . */
1452 SAPP_KEYCODE_SLASH = 47, /* / */
1453 SAPP_KEYCODE_0 = 48,
1454 SAPP_KEYCODE_1 = 49,
1455 SAPP_KEYCODE_2 = 50,
1456 SAPP_KEYCODE_3 = 51,
1457 SAPP_KEYCODE_4 = 52,
1458 SAPP_KEYCODE_5 = 53,
1459 SAPP_KEYCODE_6 = 54,
1460 SAPP_KEYCODE_7 = 55,
1461 SAPP_KEYCODE_8 = 56,
1462 SAPP_KEYCODE_9 = 57,
1463 SAPP_KEYCODE_SEMICOLON = 59, /* ; */
1464 SAPP_KEYCODE_EQUAL = 61, /* = */
1465 SAPP_KEYCODE_A = 65,
1466 SAPP_KEYCODE_B = 66,
1467 SAPP_KEYCODE_C = 67,
1468 SAPP_KEYCODE_D = 68,
1469 SAPP_KEYCODE_E = 69,
1470 SAPP_KEYCODE_F = 70,
1471 SAPP_KEYCODE_G = 71,
1472 SAPP_KEYCODE_H = 72,
1473 SAPP_KEYCODE_I = 73,
1474 SAPP_KEYCODE_J = 74,
1475 SAPP_KEYCODE_K = 75,
1476 SAPP_KEYCODE_L = 76,
1477 SAPP_KEYCODE_M = 77,
1478 SAPP_KEYCODE_N = 78,
1479 SAPP_KEYCODE_O = 79,
1480 SAPP_KEYCODE_P = 80,
1481 SAPP_KEYCODE_Q = 81,
1482 SAPP_KEYCODE_R = 82,
1483 SAPP_KEYCODE_S = 83,
1484 SAPP_KEYCODE_T = 84,
1485 SAPP_KEYCODE_U = 85,
1486 SAPP_KEYCODE_V = 86,
1487 SAPP_KEYCODE_W = 87,
1488 SAPP_KEYCODE_X = 88,
1489 SAPP_KEYCODE_Y = 89,
1490 SAPP_KEYCODE_Z = 90,
1491 SAPP_KEYCODE_LEFT_BRACKET = 91, /* [ */
1492 SAPP_KEYCODE_BACKSLASH = 92, /* \ */
1493 SAPP_KEYCODE_RIGHT_BRACKET = 93, /* ] */
1494 SAPP_KEYCODE_GRAVE_ACCENT = 96, /* ` */
1495 SAPP_KEYCODE_WORLD_1 = 161, /* non-US #1 */
1496 SAPP_KEYCODE_WORLD_2 = 162, /* non-US #2 */
1497 SAPP_KEYCODE_ESCAPE = 256,
1498 SAPP_KEYCODE_ENTER = 257,
1499 SAPP_KEYCODE_TAB = 258,
1500 SAPP_KEYCODE_BACKSPACE = 259,
1501 SAPP_KEYCODE_INSERT = 260,
1502 SAPP_KEYCODE_DELETE = 261,
1503 SAPP_KEYCODE_RIGHT = 262,
1504 SAPP_KEYCODE_LEFT = 263,
1505 SAPP_KEYCODE_DOWN = 264,
1506 SAPP_KEYCODE_UP = 265,
1507 SAPP_KEYCODE_PAGE_UP = 266,
1508 SAPP_KEYCODE_PAGE_DOWN = 267,
1509 SAPP_KEYCODE_HOME = 268,
1510 SAPP_KEYCODE_END = 269,
1511 SAPP_KEYCODE_CAPS_LOCK = 280,
1512 SAPP_KEYCODE_SCROLL_LOCK = 281,
1513 SAPP_KEYCODE_NUM_LOCK = 282,
1514 SAPP_KEYCODE_PRINT_SCREEN = 283,
1515 SAPP_KEYCODE_PAUSE = 284,
1516 SAPP_KEYCODE_F1 = 290,
1517 SAPP_KEYCODE_F2 = 291,
1518 SAPP_KEYCODE_F3 = 292,
1519 SAPP_KEYCODE_F4 = 293,
1520 SAPP_KEYCODE_F5 = 294,
1521 SAPP_KEYCODE_F6 = 295,
1522 SAPP_KEYCODE_F7 = 296,
1523 SAPP_KEYCODE_F8 = 297,
1524 SAPP_KEYCODE_F9 = 298,
1525 SAPP_KEYCODE_F10 = 299,
1526 SAPP_KEYCODE_F11 = 300,
1527 SAPP_KEYCODE_F12 = 301,
1528 SAPP_KEYCODE_F13 = 302,
1529 SAPP_KEYCODE_F14 = 303,
1530 SAPP_KEYCODE_F15 = 304,
1531 SAPP_KEYCODE_F16 = 305,
1532 SAPP_KEYCODE_F17 = 306,
1533 SAPP_KEYCODE_F18 = 307,
1534 SAPP_KEYCODE_F19 = 308,
1535 SAPP_KEYCODE_F20 = 309,
1536 SAPP_KEYCODE_F21 = 310,
1537 SAPP_KEYCODE_F22 = 311,
1538 SAPP_KEYCODE_F23 = 312,
1539 SAPP_KEYCODE_F24 = 313,
1540 SAPP_KEYCODE_F25 = 314,
1541 SAPP_KEYCODE_KP_0 = 320,
1542 SAPP_KEYCODE_KP_1 = 321,
1543 SAPP_KEYCODE_KP_2 = 322,
1544 SAPP_KEYCODE_KP_3 = 323,
1545 SAPP_KEYCODE_KP_4 = 324,
1546 SAPP_KEYCODE_KP_5 = 325,
1547 SAPP_KEYCODE_KP_6 = 326,
1548 SAPP_KEYCODE_KP_7 = 327,
1549 SAPP_KEYCODE_KP_8 = 328,
1550 SAPP_KEYCODE_KP_9 = 329,
1551 SAPP_KEYCODE_KP_DECIMAL = 330,
1552 SAPP_KEYCODE_KP_DIVIDE = 331,
1553 SAPP_KEYCODE_KP_MULTIPLY = 332,
1554 SAPP_KEYCODE_KP_SUBTRACT = 333,
1555 SAPP_KEYCODE_KP_ADD = 334,
1556 SAPP_KEYCODE_KP_ENTER = 335,
1557 SAPP_KEYCODE_KP_EQUAL = 336,
1558 SAPP_KEYCODE_LEFT_SHIFT = 340,
1559 SAPP_KEYCODE_LEFT_CONTROL = 341,
1560 SAPP_KEYCODE_LEFT_ALT = 342,
1561 SAPP_KEYCODE_LEFT_SUPER = 343,
1562 SAPP_KEYCODE_RIGHT_SHIFT = 344,
1563 SAPP_KEYCODE_RIGHT_CONTROL = 345,
1564 SAPP_KEYCODE_RIGHT_ALT = 346,
1565 SAPP_KEYCODE_RIGHT_SUPER = 347,
1566 SAPP_KEYCODE_MENU = 348,
1567} sapp_keycode;
1568
1569/*
1570 Android specific 'tool type' enum for touch events. This lets the
1571 application check what type of input device was used for
1572 touch events.
1573
1574 NOTE: the values must remain in sync with the corresponding
1575 Android SDK type, so don't change those.
1576
1577 See
1578 https://developer.android.com/reference/android/view/MotionEvent#TOOL_TYPE_UNKNOWN
1579*/
1580typedef enum sapp_android_tooltype {
1581 SAPP_ANDROIDTOOLTYPE_UNKNOWN = 0, // TOOL_TYPE_UNKNOWN
1582 SAPP_ANDROIDTOOLTYPE_FINGER = 1, // TOOL_TYPE_FINGER
1583 SAPP_ANDROIDTOOLTYPE_STYLUS = 2, // TOOL_TYPE_STYLUS
1584 SAPP_ANDROIDTOOLTYPE_MOUSE = 3, // TOOL_TYPE_MOUSE
1585} sapp_android_tooltype;
1586
1587/*
1588 sapp_touchpoint
1589
1590 Describes a single touchpoint in a multitouch event (TOUCHES_BEGAN,
1591 TOUCHES_MOVED, TOUCHES_ENDED).
1592
1593 Touch points are stored in the nested array sapp_event.touches[],
1594 and the number of touches is stored in sapp_event.num_touches.
1595*/
1596typedef struct sapp_touchpoint {
1597 uintptr_t identifier;
1598 float pos_x;
1599 float pos_y;
1600 sapp_android_tooltype android_tooltype; // only valid on Android
1601 bool changed;
1602} sapp_touchpoint;
1603
1604/*
1605 sapp_mousebutton
1606
1607 The currently pressed mouse button in the events MOUSE_DOWN
1608 and MOUSE_UP, stored in the struct field sapp_event.mouse_button.
1609*/
1610typedef enum sapp_mousebutton {
1611 SAPP_MOUSEBUTTON_LEFT = 0x0,
1612 SAPP_MOUSEBUTTON_RIGHT = 0x1,
1613 SAPP_MOUSEBUTTON_MIDDLE = 0x2,
1614 SAPP_MOUSEBUTTON_INVALID = 0x100,
1615} sapp_mousebutton;
1616
1617/*
1618 These are currently pressed modifier keys (and mouse buttons) which are
1619 passed in the event struct field sapp_event.modifiers.
1620*/
1621enum {
1622 SAPP_MODIFIER_SHIFT = 0x1, // left or right shift key
1623 SAPP_MODIFIER_CTRL = 0x2, // left or right control key
1624 SAPP_MODIFIER_ALT = 0x4, // left or right alt key
1625 SAPP_MODIFIER_SUPER = 0x8, // left or right 'super' key
1626 SAPP_MODIFIER_LMB = 0x100, // left mouse button
1627 SAPP_MODIFIER_RMB = 0x200, // right mouse button
1628 SAPP_MODIFIER_MMB = 0x400, // middle mouse button
1629};
1630
1631/*
1632 sapp_event
1633
1634 This is an all-in-one event struct passed to the event handler
1635 user callback function. Note that it depends on the event
1636 type what struct fields actually contain useful values, so you
1637 should first check the event type before reading other struct
1638 fields.
1639*/
1640typedef struct sapp_event {
1641 uint64_t frame_count; // current frame counter, always valid, useful for
1642 // checking if two events were issued in the same frame
1643 sapp_event_type type; // the event type, always valid
1644 sapp_keycode key_code; // the virtual key code, only valid in KEY_UP, KEY_DOWN
1645 uint32_t char_code; // the UTF-32 character code, only valid in CHAR events
1646 bool key_repeat; // true if this is a key-repeat event, valid in KEY_UP,
1647 // KEY_DOWN and CHAR
1648 uint32_t modifiers; // current modifier keys, valid in all key-, char- and
1649 // mouse-events
1650 sapp_mousebutton mouse_button; // mouse button that was pressed or released,
1651 // valid in MOUSE_DOWN, MOUSE_UP
1652 float mouse_x; // current horizontal mouse position in pixels, always valid
1653 // except during mouse lock
1654 float mouse_y; // current vertical mouse position in pixels, always valid
1655 // except during mouse lock
1656 float mouse_dx; // relative horizontal mouse movement since last frame, always
1657 // valid
1658 float mouse_dy; // relative vertical mouse movement since last frame, always
1659 // valid
1660 float scroll_x; // horizontal mouse wheel scroll distance, valid in
1661 // MOUSE_SCROLL events
1662 float scroll_y; // vertical mouse wheel scroll distance, valid in MOUSE_SCROLL
1663 // events
1664 int num_touches; // number of valid items in the touches[] array
1665 sapp_touchpoint touches[SAPP_MAX_TOUCHPOINTS]; // current touch points, valid
1666 // in TOUCHES_BEGIN,
1667 // TOUCHES_MOVED, TOUCHES_ENDED
1668 int window_width; // current window- and framebuffer sizes in pixels, always
1669 // valid
1670 int window_height;
1671 int framebuffer_width; // = window_width * dpi_scale
1672 int framebuffer_height; // = window_height * dpi_scale
1673} sapp_event;
1674
1675/*
1676 sg_range
1677
1678 A general pointer/size-pair struct and constructor macros for passing binary
1679 blobs into sokol_app.h.
1680*/
1681typedef struct sapp_range {
1682 const void *ptr;
1683 size_t size;
1684} sapp_range;
1685// disabling this for every includer isn't great, but the warnings are also
1686// quite pointless
1687#if defined(_MSC_VER)
1688#pragma warning( \
1689 disable : 4221) /* /W4 only: nonstandard extension used: 'x': cannot be \
1690 initialized using address of automatic variable 'y' */
1691#pragma warning(disable : 4204) /* VS2015: nonstandard extension used: \
1692 non-constant aggregate initializer */
1693#endif
1694#if defined(__cplusplus)
1695#define SAPP_RANGE(x) \
1696 sapp_range { &x, sizeof(x) }
1697#else
1698#define SAPP_RANGE(x) \
1699 (sapp_range) { &x, sizeof(x) }
1700#endif
1701
1702/*
1703 sapp_image_desc
1704
1705 This is used to describe image data to sokol_app.h (window icons and cursor
1706 images).
1707
1708 The pixel format is RGBA8.
1709
1710 cursor_hotspot_x and _y are used only for cursors, to define which pixel
1711 of the image should be aligned with the mouse position.
1712*/
1713typedef struct sapp_image_desc {
1714 int width;
1715 int height;
1716 int cursor_hotspot_x;
1717 int cursor_hotspot_y;
1718 sapp_range pixels;
1719} sapp_image_desc;
1720
1721/*
1722 sapp_icon_desc
1723
1724 An icon description structure for use in sapp_desc.icon and
1725 sapp_set_icon().
1726
1727 When setting a custom image, the application can provide a number of
1728 candidates differing in size, and sokol_app.h will pick the image(s)
1729 closest to the size expected by the platform's window system.
1730
1731 To set sokol-app's default icon, set .sokol_default to true.
1732
1733 Otherwise provide candidate images of different sizes in the
1734 images[] array.
1735
1736 If both the sokol_default flag is set to true, any image candidates
1737 will be ignored and the sokol_app.h default icon will be set.
1738*/
1739typedef struct sapp_icon_desc {
1740 bool sokol_default;
1741 sapp_image_desc images[SAPP_MAX_ICONIMAGES];
1742} sapp_icon_desc;
1743
1744/*
1745 sapp_allocator
1746
1747 Used in sapp_desc to provide custom memory-alloc and -free functions
1748 to sokol_app.h. If memory management should be overridden, both the
1749 alloc_fn and free_fn function must be provided (e.g. it's not valid to
1750 override one function but not the other).
1751*/
1752typedef struct sapp_allocator {
1753 void *(*alloc_fn)(size_t size, void *user_data);
1754 void (*free_fn)(void *ptr, void *user_data);
1755 void *user_data;
1756} sapp_allocator;
1757
1758/*
1759 sapp_log_item
1760
1761 Log items are defined via X-Macros and expanded to an enum
1762 'sapp_log_item', and in debug mode to corresponding
1763 human readable error messages.
1764*/
1765#define _SAPP_LOG_ITEMS \
1766 _SAPP_LOGITEM_XMACRO(OK, "Ok") \
1767 _SAPP_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \
1768 _SAPP_LOGITEM_XMACRO( \
1769 MACOS_INVALID_NSOPENGL_PROFILE, \
1770 "macos: invalid NSOpenGLProfile (valid choices are 1.0 and 4.1)") \
1771 _SAPP_LOGITEM_XMACRO(WIN32_LOAD_OPENGL32_DLL_FAILED, \
1772 "failed loading opengl32.dll") \
1773 _SAPP_LOGITEM_XMACRO(WIN32_CREATE_HELPER_WINDOW_FAILED, \
1774 "failed to create helper window") \
1775 _SAPP_LOGITEM_XMACRO(WIN32_HELPER_WINDOW_GETDC_FAILED, \
1776 "failed to get helper window DC") \
1777 _SAPP_LOGITEM_XMACRO(WIN32_DUMMY_CONTEXT_SET_PIXELFORMAT_FAILED, \
1778 "failed to set pixel format for dummy GL context") \
1779 _SAPP_LOGITEM_XMACRO(WIN32_CREATE_DUMMY_CONTEXT_FAILED, \
1780 "failed to create dummy GL context") \
1781 _SAPP_LOGITEM_XMACRO(WIN32_DUMMY_CONTEXT_MAKE_CURRENT_FAILED, \
1782 "failed to make dummy GL context current") \
1783 _SAPP_LOGITEM_XMACRO(WIN32_GET_PIXELFORMAT_ATTRIB_FAILED, \
1784 "failed to get WGL pixel format attribute") \
1785 _SAPP_LOGITEM_XMACRO(WIN32_WGL_FIND_PIXELFORMAT_FAILED, \
1786 "failed to find matching WGL pixel format") \
1787 _SAPP_LOGITEM_XMACRO(WIN32_WGL_DESCRIBE_PIXELFORMAT_FAILED, \
1788 "failed to get pixel format descriptor") \
1789 _SAPP_LOGITEM_XMACRO(WIN32_WGL_SET_PIXELFORMAT_FAILED, \
1790 "failed to set selected pixel format") \
1791 _SAPP_LOGITEM_XMACRO(WIN32_WGL_ARB_CREATE_CONTEXT_REQUIRED, \
1792 "ARB_create_context required") \
1793 _SAPP_LOGITEM_XMACRO(WIN32_WGL_ARB_CREATE_CONTEXT_PROFILE_REQUIRED, \
1794 "ARB_create_context_profile required") \
1795 _SAPP_LOGITEM_XMACRO(WIN32_WGL_OPENGL_VERSION_NOT_SUPPORTED, \
1796 "requested OpenGL version not supported by GL driver " \
1797 "(ERROR_INVALID_VERSION_ARB)") \
1798 _SAPP_LOGITEM_XMACRO(WIN32_WGL_OPENGL_PROFILE_NOT_SUPPORTED, \
1799 "requested OpenGL profile not support by GL driver " \
1800 "(ERROR_INVALID_PROFILE_ARB)") \
1801 _SAPP_LOGITEM_XMACRO(WIN32_WGL_INCOMPATIBLE_DEVICE_CONTEXT, \
1802 "CreateContextAttribsARB failed with " \
1803 "ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB") \
1804 _SAPP_LOGITEM_XMACRO(WIN32_WGL_CREATE_CONTEXT_ATTRIBS_FAILED_OTHER, \
1805 "CreateContextAttribsARB failed for other reason") \
1806 _SAPP_LOGITEM_XMACRO( \
1807 WIN32_D3D11_CREATE_DEVICE_AND_SWAPCHAIN_WITH_DEBUG_FAILED, \
1808 "D3D11CreateDeviceAndSwapChain() with D3D11_CREATE_DEVICE_DEBUG " \
1809 "failed, retrying without debug flag.") \
1810 _SAPP_LOGITEM_XMACRO(WIN32_D3D11_GET_IDXGIFACTORY_FAILED, \
1811 "could not obtain IDXGIFactory object") \
1812 _SAPP_LOGITEM_XMACRO(WIN32_D3D11_GET_IDXGIADAPTER_FAILED, \
1813 "could not obtain IDXGIAdapter object") \
1814 _SAPP_LOGITEM_XMACRO(WIN32_D3D11_QUERY_INTERFACE_IDXGIDEVICE1_FAILED, \
1815 "could not obtain IDXGIDevice1 interface") \
1816 _SAPP_LOGITEM_XMACRO(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_LOCK, \
1817 "RegisterRawInputDevices() failed (on mouse lock)") \
1818 _SAPP_LOGITEM_XMACRO(WIN32_REGISTER_RAW_INPUT_DEVICES_FAILED_MOUSE_UNLOCK, \
1819 "RegisterRawInputDevices() failed (on mouse unlock)") \
1820 _SAPP_LOGITEM_XMACRO(WIN32_GET_RAW_INPUT_DATA_FAILED, \
1821 "GetRawInputData() failed") \
1822 _SAPP_LOGITEM_XMACRO(WIN32_DESTROYICON_FOR_CURSOR_FAILED, \
1823 "DestroyIcon() for a cursor image failed") \
1824 _SAPP_LOGITEM_XMACRO(LINUX_GLX_LOAD_LIBGL_FAILED, "failed to load libGL") \
1825 _SAPP_LOGITEM_XMACRO(LINUX_GLX_LOAD_ENTRY_POINTS_FAILED, \
1826 "failed to load GLX entry points") \
1827 _SAPP_LOGITEM_XMACRO(LINUX_GLX_EXTENSION_NOT_FOUND, \
1828 "GLX extension not found") \
1829 _SAPP_LOGITEM_XMACRO(LINUX_GLX_QUERY_VERSION_FAILED, \
1830 "failed to query GLX version") \
1831 _SAPP_LOGITEM_XMACRO(LINUX_GLX_VERSION_TOO_LOW, \
1832 "GLX version too low (need at least 1.3)") \
1833 _SAPP_LOGITEM_XMACRO(LINUX_GLX_NO_GLXFBCONFIGS, \
1834 "glXGetFBConfigs() returned no configs") \
1835 _SAPP_LOGITEM_XMACRO(LINUX_GLX_NO_SUITABLE_GLXFBCONFIG, \
1836 "failed to find a suitable GLXFBConfig") \
1837 _SAPP_LOGITEM_XMACRO(LINUX_GLX_GET_VISUAL_FROM_FBCONFIG_FAILED, \
1838 "glXGetVisualFromFBConfig failed") \
1839 _SAPP_LOGITEM_XMACRO(LINUX_GLX_REQUIRED_EXTENSIONS_MISSING, \
1840 "GLX extensions ARB_create_context and " \
1841 "ARB_create_context_profile missing") \
1842 _SAPP_LOGITEM_XMACRO( \
1843 LINUX_GLX_CREATE_CONTEXT_FAILED, \
1844 "Failed to create GL context via glXCreateContextAttribsARB") \
1845 _SAPP_LOGITEM_XMACRO(LINUX_GLX_CREATE_WINDOW_FAILED, \
1846 "glXCreateWindow() failed") \
1847 _SAPP_LOGITEM_XMACRO(LINUX_X11_CREATE_WINDOW_FAILED, \
1848 "XCreateWindow() failed") \
1849 _SAPP_LOGITEM_XMACRO(LINUX_EGL_BIND_OPENGL_API_FAILED, \
1850 "eglBindAPI(EGL_OPENGL_API) failed") \
1851 _SAPP_LOGITEM_XMACRO(LINUX_EGL_BIND_OPENGL_ES_API_FAILED, \
1852 "eglBindAPI(EGL_OPENGL_ES_API) failed") \
1853 _SAPP_LOGITEM_XMACRO(LINUX_EGL_GET_DISPLAY_FAILED, "eglGetDisplay() failed") \
1854 _SAPP_LOGITEM_XMACRO(LINUX_EGL_INITIALIZE_FAILED, "eglInitialize() failed") \
1855 _SAPP_LOGITEM_XMACRO(LINUX_EGL_NO_CONFIGS, \
1856 "eglChooseConfig() returned no configs") \
1857 _SAPP_LOGITEM_XMACRO(LINUX_EGL_NO_NATIVE_VISUAL, \
1858 "eglGetConfigAttrib() for EGL_NATIVE_VISUAL_ID failed") \
1859 _SAPP_LOGITEM_XMACRO(LINUX_EGL_GET_VISUAL_INFO_FAILED, \
1860 "XGetVisualInfo() failed") \
1861 _SAPP_LOGITEM_XMACRO(LINUX_EGL_CREATE_WINDOW_SURFACE_FAILED, \
1862 "eglCreateWindowSurface() failed") \
1863 _SAPP_LOGITEM_XMACRO(LINUX_EGL_CREATE_CONTEXT_FAILED, \
1864 "eglCreateContext() failed") \
1865 _SAPP_LOGITEM_XMACRO(LINUX_EGL_MAKE_CURRENT_FAILED, \
1866 "eglMakeCurrent() failed") \
1867 _SAPP_LOGITEM_XMACRO(LINUX_X11_OPEN_DISPLAY_FAILED, "XOpenDisplay() failed") \
1868 _SAPP_LOGITEM_XMACRO( \
1869 LINUX_X11_QUERY_SYSTEM_DPI_FAILED, \
1870 "failed to query system dpi value, assuming default 96.0") \
1871 _SAPP_LOGITEM_XMACRO(LINUX_X11_DROPPED_FILE_URI_WRONG_SCHEME, \
1872 "dropped file URL doesn't start with 'file://'") \
1873 _SAPP_LOGITEM_XMACRO(LINUX_X11_FAILED_TO_BECOME_OWNER_OF_CLIPBOARD, \
1874 "X11: Failed to become owner of clipboard selection") \
1875 _SAPP_LOGITEM_XMACRO(LINUX_WAYLAND_CONNECT_DISPLAY_FAILED, \
1876 "Failed to connect to Wayland display") \
1877 _SAPP_LOGITEM_XMACRO( \
1878 LINUX_WAYLAND_NO_REQUIRED_PROTOCOLS, \
1879 "Wayland compositor doesn't support required protocols") \
1880 _SAPP_LOGITEM_XMACRO(LINUX_WAYLAND_CREATE_XKB_CONTEXT_FAILED, \
1881 "Failed to create XKB context") \
1882 _SAPP_LOGITEM_XMACRO(LINUX_WAYLAND_CREATE_WINDOW_FAILED, \
1883 "Failed to create wl_egl_window") \
1884 _SAPP_LOGITEM_XMACRO( \
1885 ANDROID_UNSUPPORTED_INPUT_EVENT_INPUT_CB, \
1886 "unsupported input event encountered in _sapp_android_input_cb()") \
1887 _SAPP_LOGITEM_XMACRO( \
1888 ANDROID_UNSUPPORTED_INPUT_EVENT_MAIN_CB, \
1889 "unsupported input event encountered in _sapp_android_main_cb()") \
1890 _SAPP_LOGITEM_XMACRO(ANDROID_READ_MSG_FAILED, \
1891 "failed to read message in _sapp_android_main_cb()") \
1892 _SAPP_LOGITEM_XMACRO(ANDROID_WRITE_MSG_FAILED, \
1893 "failed to write message in _sapp_android_msg") \
1894 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_CREATE, "MSG_CREATE") \
1895 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_RESUME, "MSG_RESUME") \
1896 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_PAUSE, "MSG_PAUSE") \
1897 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_FOCUS, "MSG_FOCUS") \
1898 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_NO_FOCUS, "MSG_NO_FOCUS") \
1899 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_SET_NATIVE_WINDOW, "MSG_SET_NATIVE_WINDOW") \
1900 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_SET_INPUT_QUEUE, "MSG_SET_INPUT_QUEUE") \
1901 _SAPP_LOGITEM_XMACRO(ANDROID_MSG_DESTROY, "MSG_DESTROY") \
1902 _SAPP_LOGITEM_XMACRO(ANDROID_UNKNOWN_MSG, "unknown msg type received") \
1903 _SAPP_LOGITEM_XMACRO(ANDROID_LOOP_THREAD_STARTED, "loop thread started") \
1904 _SAPP_LOGITEM_XMACRO(ANDROID_LOOP_THREAD_DONE, "loop thread done") \
1905 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONSTART, \
1906 "NativeActivity onStart()") \
1907 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONRESUME, \
1908 "NativeActivity onResume") \
1909 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONSAVEINSTANCESTATE, \
1910 "NativeActivity onSaveInstanceState") \
1911 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONWINDOWFOCUSCHANGED, \
1912 "NativeActivity onWindowFocusChanged") \
1913 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONPAUSE, \
1914 "NativeActivity onPause") \
1915 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONSTOP, \
1916 "NativeActivity onStop()") \
1917 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONNATIVEWINDOWCREATED, \
1918 "NativeActivity onNativeWindowCreated") \
1919 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONNATIVEWINDOWDESTROYED, \
1920 "NativeActivity onNativeWindowDestroyed") \
1921 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONINPUTQUEUECREATED, \
1922 "NativeActivity onInputQueueCreated") \
1923 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONINPUTQUEUEDESTROYED, \
1924 "NativeActivity onInputQueueDestroyed") \
1925 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONCONFIGURATIONCHANGED, \
1926 "NativeActivity onConfigurationChanged") \
1927 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONLOWMEMORY, \
1928 "NativeActivity onLowMemory") \
1929 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONDESTROY, \
1930 "NativeActivity onDestroy") \
1931 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_DONE, "NativeActivity done") \
1932 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONCREATE, \
1933 "NativeActivity onCreate") \
1934 _SAPP_LOGITEM_XMACRO(ANDROID_CREATE_THREAD_PIPE_FAILED, \
1935 "failed to create thread pipe") \
1936 _SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_CREATE_SUCCESS, \
1937 "NativeActivity successfully created") \
1938 _SAPP_LOGITEM_XMACRO(WGPU_DEVICE_LOST, "wgpu: device lost") \
1939 _SAPP_LOGITEM_XMACRO(WGPU_DEVICE_LOG, "wgpu: device log") \
1940 _SAPP_LOGITEM_XMACRO(WGPU_DEVICE_UNCAPTURED_ERROR, "wgpu: uncaptured error") \
1941 _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_SURFACE_FAILED, \
1942 "wgpu: failed to create surface for swapchain") \
1943 _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_SURFACE_GET_CAPABILITIES_FAILED, \
1944 "wgpu: wgpuSurfaceGetCapabilities failed") \
1945 _SAPP_LOGITEM_XMACRO( \
1946 WGPU_SWAPCHAIN_CREATE_DEPTH_STENCIL_TEXTURE_FAILED, \
1947 "wgpu: failed to create depth-stencil texture for swapchain") \
1948 _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_DEPTH_STENCIL_VIEW_FAILED, \
1949 "wgpu: failed to create view object for swapchain " \
1950 "depth-stencil texture") \
1951 _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_MSAA_TEXTURE_FAILED, \
1952 "wgpu: failed to create msaa texture for swapchain") \
1953 _SAPP_LOGITEM_XMACRO( \
1954 WGPU_SWAPCHAIN_CREATE_MSAA_VIEW_FAILED, \
1955 "wgpu: failed to create view object for swapchain msaa texture") \
1956 _SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_GETCURRENTTEXTURE_FAILED, \
1957 "wgpu: wgpuSurfaceGetCurrentTexture() failed") \
1958 _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_DEVICE_STATUS_ERROR, \
1959 "wgpu: requesting device failed with status 'error'") \
1960 _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_DEVICE_STATUS_UNKNOWN, \
1961 "wgpu: requesting device failed with status 'unknown'") \
1962 _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_ADAPTER_STATUS_UNAVAILABLE, \
1963 "wgpu: requesting adapter failed with 'unavailable'") \
1964 _SAPP_LOGITEM_XMACRO(WGPU_REQUEST_ADAPTER_STATUS_ERROR, \
1965 "wgpu: requesting adapter failed with status 'error'") \
1966 _SAPP_LOGITEM_XMACRO( \
1967 WGPU_REQUEST_ADAPTER_STATUS_UNKNOWN, \
1968 "wgpu: requesting adapter failed with status 'unknown'") \
1969 _SAPP_LOGITEM_XMACRO(WGPU_CREATE_INSTANCE_FAILED, \
1970 "wgpu: failed to create instance") \
1971 _SAPP_LOGITEM_XMACRO(VULKAN_REQUIRED_INSTANCE_EXTENSION_FUNCTION_MISSING, \
1972 "vulkan: could not lookup a required instance " \
1973 "extension function pointer") \
1974 _SAPP_LOGITEM_XMACRO(VULKAN_ALLOC_DEVICE_MEMORY_NO_SUITABLE_MEMORY_TYPE, \
1975 "vulkan: could not find suitable memory type") \
1976 _SAPP_LOGITEM_XMACRO(VULKAN_ALLOCATE_MEMORY_FAILED, \
1977 "vulkan: vkAllocateMemory() failed!") \
1978 _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_INSTANCE_FAILED, \
1979 "vulkan: vkCreateInstance failed") \
1980 _SAPP_LOGITEM_XMACRO(VULKAN_ENUMERATE_PHYSICAL_DEVICES_FAILED, \
1981 "vulkan: vkEnumeratePhysicalDevices failed") \
1982 _SAPP_LOGITEM_XMACRO(VULKAN_NO_PHYSICAL_DEVICES_FOUND, \
1983 "vulkan: vkEnumeratePhysicalDevices return no devices") \
1984 _SAPP_LOGITEM_XMACRO(VULKAN_NO_SUITABLE_PHYSICAL_DEVICE_FOUND, \
1985 "vulkan: no suitable physical device found") \
1986 _SAPP_LOGITEM_XMACRO( \
1987 VULKAN_CREATE_DEVICE_FAILED_EXTENSION_NOT_PRESENT, \
1988 "vulkan: vkCreateDevice failed (extension not present)") \
1989 _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_DEVICE_FAILED_FEATURE_NOT_PRESENT, \
1990 "vulkan: vkCreateDevice failed (feature not present)") \
1991 _SAPP_LOGITEM_XMACRO( \
1992 VULKAN_CREATE_DEVICE_FAILED_INITIALIZATION_FAILED, \
1993 "vulkan: vkCreateDevice failed (initialization failed)") \
1994 _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_DEVICE_FAILED_OTHER, \
1995 "vulkan: vkCreateDevice failed (other)") \
1996 _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_SURFACE_FAILED, \
1997 "vulkan: vkCreate*SurfaceKHR failed") \
1998 _SAPP_LOGITEM_XMACRO(VULKAN_CREATE_SWAPCHAIN_FAILED, \
1999 "vulkan: vkCreateSwapchainKHR failed") \
2000 _SAPP_LOGITEM_XMACRO(VULKAN_SWAPCHAIN_CREATE_IMAGE_VIEW_FAILED, \
2001 "vulkan: vkCreateImageView for swapchain image failed") \
2002 _SAPP_LOGITEM_XMACRO(VULKAN_SWAPCHAIN_CREATE_IMAGE_FAILED, \
2003 "vulkan: vkCreateImage for depth-stencil image failed") \
2004 _SAPP_LOGITEM_XMACRO( \
2005 VULKAN_SWAPCHAIN_ALLOC_IMAGE_DEVICE_MEMORY_FAILED, \
2006 "vulkan: failed to allocate device memory for depth-stencil image") \
2007 _SAPP_LOGITEM_XMACRO( \
2008 VULKAN_SWAPCHAIN_BIND_IMAGE_MEMORY_FAILED, \
2009 "vulkan: vkBindImageMemory() for depth-stencil image failed") \
2010 _SAPP_LOGITEM_XMACRO(VULKAN_ACQUIRE_NEXT_IMAGE_FAILED, \
2011 "vulkan: vkAcquireNextImageKHR failed") \
2012 _SAPP_LOGITEM_XMACRO(VULKAN_QUEUE_PRESENT_FAILED, \
2013 "vulkan: vkQueuePresentKHR failed") \
2014 _SAPP_LOGITEM_XMACRO( \
2015 IMAGE_DATA_SIZE_MISMATCH, \
2016 "image data size mismatch (must be width*height*4 bytes)") \
2017 _SAPP_LOGITEM_XMACRO( \
2018 DROPPED_FILE_PATH_TOO_LONG, \
2019 "dropped file path too long (sapp_desc.max_dropped_filed_path_length)") \
2020 _SAPP_LOGITEM_XMACRO(CLIPBOARD_STRING_TOO_BIG, \
2021 "clipboard string didn't fit into clipboard buffer")
2022
2023#define _SAPP_LOGITEM_XMACRO(item, msg) SAPP_LOGITEM_##item,
2024typedef enum sapp_log_item { _SAPP_LOG_ITEMS } sapp_log_item;
2025#undef _SAPP_LOGITEM_XMACRO
2026
2027/*
2028 sapp_pixel_format
2029
2030 Defines the pixel format for swapchain surfaces.
2031
2032 NOTE: when using sokol_gfx.h do not assume that the underlying
2033 values are compatible with sg_pixel_format!
2034
2035*/
2036typedef enum sapp_pixel_format {
2037 _SAPP_PIXELFORMAT_DEFAULT,
2038 SAPP_PIXELFORMAT_NONE,
2039 SAPP_PIXELFORMAT_RGBA8,
2040 SAPP_PIXELFORMAT_SRGB8A8,
2041 SAPP_PIXELFORMAT_BGRA8,
2042 SAPP_PIXELFORMAT_SBGRA8,
2043 SAPP_PIXELFORMAT_DEPTH,
2044 SAPP_PIXELFORMAT_DEPTH_STENCIL,
2045 _SA_PPPIXELFORMAT_FORCE_U32 = 0x7FFFFFFF
2046} sapp_pixel_format;
2047
2048/*
2049 sapp_environment
2050
2051 Used to provide runtime environment information to the
2052 outside world (like default pixel formats and the backend
2053 3D API device pointer) via a call to sapp_get_environment().
2054
2055 NOTE: when using sokol_gfx.h, don't assume that sapp_environment
2056 is binary compatible with sg_environment! Always use a translation
2057 function like sglue_environment() to populate sg_environment
2058 from sapp_environment!
2059*/
2060typedef struct sapp_environment_defaults {
2061 sapp_pixel_format color_format;
2062 sapp_pixel_format depth_format;
2063 int sample_count;
2064} sapp_environment_defaults;
2065
2066typedef struct sapp_metal_environment {
2067 const void *device;
2068} sapp_metal_environment;
2069
2070typedef struct sapp_d3d11_environment {
2071 const void *device;
2072 const void *device_context;
2073} sapp_d3d11_environment;
2074
2075typedef struct sapp_wgpu_environment {
2076 const void *device;
2077} sapp_wgpu_environment;
2078
2079typedef struct sapp_vulkan_environment {
2080 const void *instance;
2081 const void *physical_device;
2082 const void *device;
2083 const void *queue;
2084 uint32_t queue_family_index;
2085} sapp_vulkan_environment;
2086
2087typedef struct sapp_environment {
2088 sapp_environment_defaults defaults;
2089 sapp_metal_environment metal;
2090 sapp_d3d11_environment d3d11;
2091 sapp_wgpu_environment wgpu;
2092 sapp_vulkan_environment vulkan;
2093} sapp_environment;
2094
2095/*
2096 sapp_swapchain
2097
2098 Provides swapchain information for the current frame to the outside
2099 world via a call to sapp_get_swapchain().
2100
2101 NOTE: sapp_get_swapchain() must be called exactly once per frame since
2102 on some backends it will also acquire the next swapchain image.
2103
2104 NOTE: when using sokol_gfx.h, don't assume that the sapp_swapchain struct
2105 has the same memory layout as sg_swapchain! Use the sokol_log.h helper
2106 function sglue_swapchain() to translate sapp_swapchain into a
2107 sg_swapchain instead.
2108*/
2109typedef struct sapp_metal_swapchain {
2110 const void *current_drawable; // CAMetalDrawable (NOT MTLDrawable!!!)
2111 const void *depth_stencil_texture; // MTLTexture
2112 const void *msaa_color_texture; // MTLTexture
2113} sapp_metal_swapchain;
2114
2115typedef struct sapp_d3d11_swapchain {
2116 const void *render_view; // ID3D11RenderTargetView
2117 const void *resolve_view; // ID3D11RenderTargetView
2118 const void *depth_stencil_view; // ID3D11DepthStencilView
2119} sapp_d3d11_swapchain;
2120
2121typedef struct sapp_wgpu_swapchain {
2122 const void *render_view; // WGPUTextureView
2123 const void *resolve_view; // WGPUTextureView
2124 const void *depth_stencil_view; // WGPUTextureView
2125} sapp_wgpu_swapchain;
2126
2127typedef struct sapp_vulkan_swapchain {
2128 const void *render_image; // vkImage
2129 const void *render_view; // vkImageView
2130 const void *resolve_image; // vkImage;
2131 const void *resolve_view; // vkImageView
2132 const void *depth_stencil_image; // vkImage
2133 const void *depth_stencil_view; // vkImageView
2134 const void *render_finished_semaphore; // vkSemaphore
2135 const void *present_complete_semaphore; // vkSemaphore
2136} sapp_vulkan_swapchain;
2137
2138typedef struct sapp_gl_swapchain {
2139 uint32_t framebuffer; // GL framebuffer object
2140} sapp_gl_swapchain;
2141
2142typedef struct sapp_swapchain {
2143 int width;
2144 int height;
2145 int sample_count;
2146 sapp_pixel_format color_format;
2147 sapp_pixel_format depth_format;
2148 sapp_metal_swapchain metal;
2149 sapp_d3d11_swapchain d3d11;
2150 sapp_wgpu_swapchain wgpu;
2151 sapp_vulkan_swapchain vulkan;
2152 sapp_gl_swapchain gl;
2153} sapp_swapchain;
2154
2155/*
2156 sapp_logger
2157
2158 Used in sapp_desc to provide a logging function. Please be aware that
2159 without logging function, sokol-app will be completely silent, e.g. it will
2160 not report errors or warnings. For maximum error verbosity, compile in
2161 debug mode (e.g. NDEBUG *not* defined) and install a logger (for instance
2162 the standard logging function from sokol_log.h).
2163*/
2164typedef struct sapp_logger {
2165 void (*func)(const char *tag, // always "sapp"
2166 uint32_t log_level, // 0=panic, 1=error, 2=warning, 3=info
2167 uint32_t log_item_id, // SAPP_LOGITEM_*
2168 const char *message_or_null, // a message string, may be nullptr
2169 // in release mode
2170 uint32_t line_nr, // line number in sokol_app.h
2171 const char *filename_or_null, // source filename, may be nullptr
2172 // in release mode
2173 void *user_data);
2174 void *user_data;
2175} sapp_logger;
2176
2177/*
2178 sokol-app initialization options, used as return value of sokol_main()
2179 or sapp_run() argument.
2180*/
2181typedef struct sapp_gl_desc {
2182 int major_version; // override GL/GLES major and minor version (defaults:
2183 // GL4.1 (macOS) or GL4.3, GLES3.1 (Android) or GLES3.0
2184 int minor_version;
2185} sapp_gl_desc;
2186
2187typedef struct sapp_win32_desc {
2188 bool console_utf8; // if true, set the output console codepage to UTF-8
2189 bool console_create; // if true, attach stdout/stderr to a new console window
2190 bool console_attach; // if true, attach stdout/stderr to parent process
2191} sapp_win32_desc;
2192
2193typedef struct sapp_html5_desc {
2194 const char *canvas_selector; // css selector of the HTML5 canvas element,
2195 // default is "#canvas"
2196 bool
2197 canvas_resize; // if true, the HTML5 canvas size is set to
2198 // sapp_desc.width/height, otherwise canvas size is tracked
2199 bool preserve_drawing_buffer; // HTML5 only: whether to preserve default
2200 // framebuffer content between frames
2201 bool premultiplied_alpha; // HTML5 only: whether the rendered pixels use
2202 // premultiplied alpha convention
2203 bool ask_leave_site; // initial state of the internal html5_ask_leave_site
2204 // flag (see sapp_html5_ask_leave_site())
2205 bool update_document_title; // if true, update the HTML document.title with
2206 // sapp_desc.window_title
2207 bool bubble_mouse_events; // if true, mouse events will bubble up to the web
2208 // page
2209 bool bubble_touch_events; // same for touch events
2210 bool bubble_wheel_events; // same for wheel events
2211 bool bubble_key_events; // if true, bubble up *all* key events to browser, not
2212 // just key events that represent characters
2213 bool bubble_char_events; // if true, bubble up character events to browser
2214 bool
2215 use_emsc_set_main_loop; // if true, use emscripten_set_main_loop() instead
2216 // of emscripten_request_animation_frame_loop()
2217 bool emsc_set_main_loop_simulate_infinite_loop; // this will be passed as the
2218 // simulate_infinite_loop arg
2219 // to
2220 // emscripten_set_main_loop()
2221} sapp_html5_desc;
2222
2223typedef struct sapp_ios_desc {
2224 bool keyboard_resizes_canvas; // if true, showing the iOS keyboard shrinks the
2225 // canvas
2226} sapp_ios_desc;
2227
2228typedef struct sapp_desc {
2229 void (*init_cb)(
2230 void); // these are the user-provided callbacks without user data
2231 void (*frame_cb)(void);
2232 void (*cleanup_cb)(void);
2233 void (*event_cb)(const sapp_event *);
2234
2235 void *user_data; // these are the user-provided callbacks with user data
2236 void (*init_userdata_cb)(void *);
2237 void (*frame_userdata_cb)(void *);
2238 void (*cleanup_userdata_cb)(void *);
2239 void (*event_userdata_cb)(const sapp_event *, void *);
2240
2241 int width; // the preferred width of the window / canvas
2242 int height; // the preferred height of the window / canvas
2243 int sample_count; // MSAA sample count
2244 int swap_interval; // the preferred swap interval (ignored on some platforms)
2245 bool high_dpi; // whether the rendering canvas is full-resolution on HighDPI
2246 // displays
2247 bool fullscreen; // whether the window should be created in fullscreen mode
2248 bool alpha; // whether the framebuffer should have an alpha channel (ignored
2249 // on some platforms)
2250 const char *window_title; // the window title as UTF-8 encoded string
2251 bool enable_clipboard; // enable clipboard access, default is false
2252 int clipboard_size; // max size of clipboard content in bytes
2253 bool enable_dragndrop; // enable file dropping (drag'n'drop), default is false
2254 int max_dropped_files; // max number of dropped files to process (default: 1)
2255 int max_dropped_file_path_length; // max length in bytes of a dropped UTF-8
2256 // file path (default: 2048)
2257 sapp_icon_desc icon; // the initial window icon to set
2258 sapp_allocator
2259 allocator; // optional memory allocation overrides (default: malloc/free)
2260 sapp_logger logger; // logging callback override (default: NO LOGGING!)
2261
2262 // backend-specific options
2263 sapp_gl_desc gl;
2264 sapp_win32_desc win32;
2265 sapp_html5_desc html5;
2266 sapp_ios_desc ios;
2267
2268 // __v_ start
2269 bool __v_native_render; // V patch to allow for native rendering
2270 int min_width;
2271 int min_height;
2272 bool borderless_window; // V patch to remove native window decorations
2273 // __v_ end
2274} sapp_desc;
2275
2276/* HTML5 specific: request and response structs for
2277 asynchronously loading dropped-file content.
2278*/
2279typedef enum sapp_html5_fetch_error {
2280 SAPP_HTML5_FETCH_ERROR_NO_ERROR,
2281 SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL,
2282 SAPP_HTML5_FETCH_ERROR_OTHER,
2283} sapp_html5_fetch_error;
2284
2285typedef struct sapp_html5_fetch_response {
2286 bool succeeded; // true if the loading operation has succeeded
2287 sapp_html5_fetch_error error_code;
2288 int file_index; // index of the dropped file
2289 // (0..sapp_get_num_dropped_filed()-1)
2290 sapp_range data; // pointer and size of the fetched data (data.ptr ==
2291 // buffer.ptr, data.size <= buffer.size)
2292 sapp_range buffer; // the user-provided buffer ptr/size pair (buffer.ptr ==
2293 // data.ptr, buffer.size >= data.size)
2294 void *user_data; // user-provided user data pointer
2295} sapp_html5_fetch_response;
2296
2297typedef struct sapp_html5_fetch_request {
2298 int dropped_file_index; // 0..sapp_get_num_dropped_files()-1
2299 void (*callback)(const sapp_html5_fetch_response
2300 *); // response callback function pointer (required)
2301 sapp_range buffer; // ptr/size of a memory buffer to load the data into
2302 void *user_data; // optional userdata pointer
2303} sapp_html5_fetch_request;
2304
2305/*
2306 sapp_mouse_cursor
2307
2308 Predefined cursor image definitions, set with
2309 sapp_set_mouse_cursor(sapp_mouse_cursor cursor)
2310*/
2311typedef enum sapp_mouse_cursor {
2312 SAPP_MOUSECURSOR_DEFAULT = 0, // equivalent with system default cursor
2313 SAPP_MOUSECURSOR_ARROW,
2314 SAPP_MOUSECURSOR_IBEAM,
2315 SAPP_MOUSECURSOR_CROSSHAIR,
2316 SAPP_MOUSECURSOR_POINTING_HAND,
2317 SAPP_MOUSECURSOR_RESIZE_EW,
2318 SAPP_MOUSECURSOR_RESIZE_NS,
2319 SAPP_MOUSECURSOR_RESIZE_NWSE,
2320 SAPP_MOUSECURSOR_RESIZE_NESW,
2321 SAPP_MOUSECURSOR_RESIZE_ALL,
2322 SAPP_MOUSECURSOR_NOT_ALLOWED,
2323 SAPP_MOUSECURSOR_CUSTOM_0,
2324 SAPP_MOUSECURSOR_CUSTOM_1,
2325 SAPP_MOUSECURSOR_CUSTOM_2,
2326 SAPP_MOUSECURSOR_CUSTOM_3,
2327 SAPP_MOUSECURSOR_CUSTOM_4,
2328 SAPP_MOUSECURSOR_CUSTOM_5,
2329 SAPP_MOUSECURSOR_CUSTOM_6,
2330 SAPP_MOUSECURSOR_CUSTOM_7,
2331 SAPP_MOUSECURSOR_CUSTOM_8,
2332 SAPP_MOUSECURSOR_CUSTOM_9,
2333 SAPP_MOUSECURSOR_CUSTOM_10,
2334 SAPP_MOUSECURSOR_CUSTOM_11,
2335 SAPP_MOUSECURSOR_CUSTOM_12,
2336 SAPP_MOUSECURSOR_CUSTOM_13,
2337 SAPP_MOUSECURSOR_CUSTOM_14,
2338 SAPP_MOUSECURSOR_CUSTOM_15,
2339 _SAPP_MOUSECURSOR_NUM,
2340} sapp_mouse_cursor;
2341
2342/* user-provided functions */
2343extern sapp_desc sokol_main(int argc, char *argv[]);
2344
2345/* returns true after sokol-app has been initialized */
2346SOKOL_APP_API_DECL bool sapp_isvalid(void);
2347/* returns the current framebuffer width in pixels */
2348SOKOL_APP_API_DECL int sapp_width(void);
2349/* same as sapp_width(), but returns float */
2350SOKOL_APP_API_DECL float sapp_widthf(void);
2351/* returns the current framebuffer height in pixels */
2352SOKOL_APP_API_DECL int sapp_height(void);
2353/* same as sapp_height(), but returns float */
2354SOKOL_APP_API_DECL float sapp_heightf(void);
2355/* get default framebuffer color pixel format */
2356SOKOL_APP_API_DECL sapp_pixel_format sapp_color_format(void);
2357/* get default framebuffer depth pixel format */
2358SOKOL_APP_API_DECL sapp_pixel_format sapp_depth_format(void);
2359/* get default framebuffer sample count */
2360SOKOL_APP_API_DECL int sapp_sample_count(void);
2361/* returns true when high_dpi was requested and actually running in a high-dpi
2362 * scenario */
2363SOKOL_APP_API_DECL bool sapp_high_dpi(void);
2364/* returns the dpi scaling factor (window pixels to framebuffer pixels) */
2365SOKOL_APP_API_DECL float sapp_dpi_scale(void);
2366/* show or hide the mobile device onscreen keyboard */
2367SOKOL_APP_API_DECL void sapp_show_keyboard(bool show);
2368/* return true if the mobile device onscreen keyboard is currently shown */
2369SOKOL_APP_API_DECL bool sapp_keyboard_shown(void);
2370/* query fullscreen mode */
2371SOKOL_APP_API_DECL bool sapp_is_fullscreen(void);
2372/* toggle fullscreen mode */
2373SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void);
2374/* show or hide the mouse cursor */
2375SOKOL_APP_API_DECL void sapp_show_mouse(bool show);
2376/* show or hide the mouse cursor */
2377SOKOL_APP_API_DECL bool sapp_mouse_shown(void);
2378/* enable/disable mouse-pointer-lock mode */
2379SOKOL_APP_API_DECL void sapp_lock_mouse(bool lock);
2380/* return true if in mouse-pointer-lock mode (this may toggle a few frames
2381 * later) */
2382SOKOL_APP_API_DECL bool sapp_mouse_locked(void);
2383/* set mouse cursor type */
2384SOKOL_APP_API_DECL void sapp_set_mouse_cursor(sapp_mouse_cursor cursor);
2385/* get current mouse cursor type */
2386SOKOL_APP_API_DECL sapp_mouse_cursor sapp_get_mouse_cursor(void);
2387/* associate a custom mouse cursor image to a sapp_mouse_cursor enum entry */
2388SOKOL_APP_API_DECL sapp_mouse_cursor sapp_bind_mouse_cursor_image(
2389 sapp_mouse_cursor cursor, const sapp_image_desc *desc);
2390/* restore the sapp_mouse_cursor enum entry to it's default system appearance */
2391SOKOL_APP_API_DECL void
2392sapp_unbind_mouse_cursor_image(sapp_mouse_cursor cursor);
2393/* return the userdata pointer optionally provided in sapp_desc */
2394SOKOL_APP_API_DECL void *sapp_userdata(void);
2395/* return a copy of the sapp_desc structure */
2396SOKOL_APP_API_DECL sapp_desc sapp_query_desc(void);
2397/* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */
2398SOKOL_APP_API_DECL void sapp_request_quit(void);
2399/* cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received)
2400 */
2401SOKOL_APP_API_DECL void sapp_cancel_quit(void);
2402/* initiate a "hard quit" (quit application without sending
2403 * SAPP_EVENTTYPE_QUIT_REQUESTED) */
2404SOKOL_APP_API_DECL void sapp_quit(void);
2405/* call from inside event callback to consume the current event (don't forward
2406 * to platform) */
2407SOKOL_APP_API_DECL void sapp_consume_event(void);
2408/* get the current frame counter (for comparison with sapp_event.frame_count) */
2409SOKOL_APP_API_DECL uint64_t sapp_frame_count(void);
2410/* get an averaged/smoothed frame duration in seconds */
2411SOKOL_APP_API_DECL double sapp_frame_duration(void);
2412/* write string into clipboard */
2413SOKOL_APP_API_DECL void sapp_set_clipboard_string(const char *str);
2414/* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED)
2415 */
2416SOKOL_APP_API_DECL const char *sapp_get_clipboard_string(void);
2417/* set the window title (only on desktop platforms) */
2418SOKOL_APP_API_DECL void sapp_set_window_title(const char *str);
2419/* set the window icon (only on Windows and Linux) */
2420SOKOL_APP_API_DECL void sapp_set_icon(const sapp_icon_desc *icon_desc);
2421/* gets the total number of dropped files (after an SAPP_EVENTTYPE_FILES_DROPPED
2422 * event) */
2423SOKOL_APP_API_DECL int sapp_get_num_dropped_files(void);
2424/* gets the dropped file paths */
2425SOKOL_APP_API_DECL const char *sapp_get_dropped_file_path(int index);
2426
2427/* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty
2428 * stub) */
2429SOKOL_APP_API_DECL void sapp_run(const sapp_desc *desc);
2430
2431/* get runtime environment information */
2432sapp_environment sapp_get_environment(void);
2433/* get current frame's swapchain information (call once per frame!) */
2434sapp_swapchain sapp_get_swapchain(void);
2435
2436/* EGL: get EGLDisplay object */
2437SOKOL_APP_API_DECL const void *sapp_egl_get_display(void);
2438/* EGL: get EGLContext object */
2439SOKOL_APP_API_DECL const void *sapp_egl_get_context(void);
2440
2441/* HTML5: enable or disable the hardwired "Leave Site?" dialog box */
2442SOKOL_APP_API_DECL void sapp_html5_ask_leave_site(bool ask);
2443/* HTML5: get byte size of a dropped file */
2444SOKOL_APP_API_DECL uint32_t sapp_html5_get_dropped_file_size(int index);
2445/* HTML5: asynchronously load the content of a dropped file */
2446SOKOL_APP_API_DECL void
2447sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request *request);
2448
2449/* macOS: get bridged pointer to macOS NSWindow */
2450SOKOL_APP_API_DECL const void *sapp_macos_get_window(void);
2451/* iOS: get bridged pointer to iOS UIWindow */
2452SOKOL_APP_API_DECL const void *sapp_ios_get_window(void);
2453
2454/* D3D11: get pointer to IDXGISwapChain object */
2455SOKOL_APP_API_DECL const void *sapp_d3d11_get_swap_chain(void);
2456
2457/* Win32: get the HWND window handle */
2458SOKOL_APP_API_DECL const void *sapp_win32_get_hwnd(void);
2459
2460/* GL: get major version */
2461SOKOL_APP_API_DECL int sapp_gl_get_major_version(void);
2462/* GL: get minor version */
2463SOKOL_APP_API_DECL int sapp_gl_get_minor_version(void);
2464/* GL: return true if the context is GLES */
2465SOKOL_APP_API_DECL bool sapp_gl_is_gles(void);
2466/* GL: get default framebuffer */
2467SOKOL_APP_API_DECL uint32_t sapp_gl_get_framebuffer(void);
2468
2469/* X11: get Window */
2470SOKOL_APP_API_DECL const void *sapp_x11_get_window(void);
2471/* X11: get Display */
2472SOKOL_APP_API_DECL const void *sapp_x11_get_display(void);
2473
2474/* Android: get native activity handle */
2475SOKOL_APP_API_DECL const void *sapp_android_get_native_activity(void);
2476
2477#ifdef __cplusplus
2478} /* extern "C" */
2479
2480/* reference-based equivalents for C++ */
2481inline void sapp_run(const sapp_desc &desc) { return sapp_run(&desc); }
2482
2483#endif
2484
2485#endif // SOKOL_APP_INCLUDED
2486
2487// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████
2488// █████ ████████ ██ ██████ ███ ██ ██ ████ ████ ██ ██ ██ ██ ████
2489// ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██
2490// ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████
2491// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
2492// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
2493// ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██
2494// ██████ ██ ████
2495//
2496// >>implementation
2497#ifdef SOKOL_APP_IMPL
2498#ifndef SOKOL_APP_IMPL_INCLUDED
2499#define SOKOL_APP_IMPL_INCLUDED
2500
2501#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE)
2502#error \
2503 "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sapp_desc.allocator to override memory allocation functions"
2504#endif
2505
2506#include <math.h> // roundf
2507#include <stddef.h> // size_t
2508#include <stdlib.h> // malloc, free
2509#include <string.h> // memset, strncmp
2510
2511// helper macros
2512#define _sapp_def(val, def) (((val) == 0) ? (def) : (val))
2513#define _sapp_absf(a) (((a) < 0.0f) ? -(a) : (a))
2514
2515#ifdef __cplusplus
2516#define _SAPP_STRUCT(TYPE, NAME) TYPE NAME = {}
2517#else
2518#define _SAPP_STRUCT(TYPE, NAME) TYPE NAME = {0}
2519#endif
2520
2521#define _SAPP_MAX_TITLE_LENGTH (128)
2522#define _SAPP_FALLBACK_DEFAULT_WINDOW_WIDTH (640)
2523#define _SAPP_FALLBACK_DEFAULT_WINDOW_HEIGHT (480)
2524
2525// check if the config defines are alright
2526#if defined(__APPLE__)
2527// see
2528// https://clang.llvm.org/docs/LanguageExtensions.html#automatic-reference-counting
2529#if !defined(__cplusplus)
2530#if __has_feature(objc_arc) && !__has_feature(objc_arc_fields)
2531#error \
2532 "sokol_app.h requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)"
2533#endif
2534#endif
2535#define _SAPP_APPLE (1)
2536#include <TargetConditionals.h>
2537#if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
2538// MacOS
2539#define _SAPP_MACOS (1)
2540#if !defined(SOKOL_METAL) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU)
2541#error ("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL, SOKOL_GLCORE or SOKOL_WGPU")
2542#endif
2543#else
2544// iOS or iOS Simulator
2545#define _SAPP_IOS (1)
2546#if !defined(SOKOL_METAL) && !defined(SOKOL_GLES3)
2547#error ("sokol_app.h: unknown 3D API selected for iOS, must be SOKOL_METAL or SOKOL_GLES3")
2548#endif
2549#if TARGET_OS_TV
2550#define _SAPP_TVOS (1)
2551#endif
2552#endif
2553#elif defined(__EMSCRIPTEN__)
2554// Emscripten
2555#define _SAPP_EMSCRIPTEN (1)
2556#if !defined(SOKOL_GLES3) && !defined(SOKOL_WGPU)
2557#error ("sokol_app.h: unknown 3D API selected for emscripten, must be SOKOL_GLES3 or SOKOL_WGPU")
2558#endif
2559#elif defined(_WIN32)
2560// Windows (D3D11 or GL)
2561#define _SAPP_WIN32 (1)
2562#if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU) && \
2563 !defined(SOKOL_VULKAN) && !defined(SOKOL_NOAPI)
2564#error ("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE, SOKOL_WGPU, SOKOL_VULKAN or SOKOL_NOAPI")
2565#endif
2566#if defined(SOKOL_VULKAN)
2567#define VK_USE_PLATFORM_WIN32_KHR
2568#include <vulkan/vulkan.h>
2569#endif
2570#elif defined(__ANDROID__)
2571// Android
2572#define _SAPP_ANDROID (1)
2573#if !defined(SOKOL_GLES3)
2574#error ("sokol_app.h: unknown 3D API selected for Android, must be SOKOL_GLES3")
2575#endif
2576#if defined(SOKOL_NO_ENTRY)
2577#error ("sokol_app.h: SOKOL_NO_ENTRY is not supported on Android")
2578#endif
2579#elif defined(__linux__) || defined(__unix__)
2580// Linux
2581#define _SAPP_LINUX (1)
2582
2583// Define POSIX features early for clock_gettime and other POSIX functions
2584#ifndef _POSIX_C_SOURCE
2585#define _POSIX_C_SOURCE 199309L
2586#endif
2587
2588// Wayland/X11 platform selection
2589// Default to X11 on Linux unless SOKOL_WAYLAND or SOKOL_X11 is explicitly defined
2590// Note: This must come AFTER sokol_app.h checks for SOKOL_GLCORE etc.
2591#if defined(__linux__) && !defined(SOKOL_WAYLAND) && !defined(SOKOL_X11)
2592#define SOKOL_X11 (1)
2593#endif
2594#if !defined(SOKOL_DISABLE_WAYLAND)
2595#if defined(SOKOL_WAYLAND) || (!defined(SOKOL_X11) && defined(__linux__))
2596#define _SAPP_WAYLAND (1)
2597#endif
2598#endif
2599#if !defined(_SAPP_WAYLAND)
2600#define _SAPP_X11 (1)
2601#endif
2602
2603#if !defined(SOKOL_GLCORE) && !defined(SOKOL_GLES3) && !defined(SOKOL_WGPU) && \
2604 !defined(SOKOL_VULKAN)
2605#error ("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE, SOKOL_GLES3, SOKOL_WGPU or SOKOL_VULKAN")
2606#endif
2607#if defined(SOKOL_GLCORE)
2608#if defined(SOKOL_FORCE_EGL) || defined(_SAPP_WAYLAND)
2609#define _SAPP_EGL (1)
2610#else
2611#define _SAPP_GLX (1)
2612#endif
2613#define GL_GLEXT_PROTOTYPES
2614#include <GL/gl.h>
2615#elif defined(SOKOL_GLES3)
2616#define _SAPP_EGL (1)
2617#include <GLES3/gl3.h>
2618#include <GLES3/gl3ext.h>
2619#elif defined(SOKOL_VULKAN)
2620#if defined(_SAPP_WAYLAND)
2621#define VK_USE_PLATFORM_WAYLAND_KHR
2622#else
2623#define VK_USE_PLATFORM_XLIB_KHR
2624#endif
2625#include <vulkan/vulkan.h>
2626#endif
2627#else
2628#error "sokol_app.h: Unknown platform"
2629#endif
2630
2631#if defined(SOKOL_GLCORE) || defined(SOKOL_GLES3)
2632#define _SAPP_ANY_GL (1)
2633#endif
2634
2635#ifndef SOKOL_API_IMPL
2636#define SOKOL_API_IMPL
2637#endif
2638#ifndef SOKOL_DEBUG
2639#ifndef NDEBUG
2640#define SOKOL_DEBUG
2641#endif
2642#endif
2643#ifndef SOKOL_ASSERT
2644#include <assert.h>
2645#define SOKOL_ASSERT(c) assert(c)
2646#endif
2647#ifndef SOKOL_UNREACHABLE
2648#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
2649#endif
2650
2651#ifndef _SOKOL_PRIVATE
2652#if defined(__GNUC__) || defined(__clang__)
2653#define _SOKOL_PRIVATE __attribute__((unused)) static
2654#else
2655#define _SOKOL_PRIVATE static
2656#endif
2657#endif
2658#ifndef _SOKOL_UNUSED
2659#define _SOKOL_UNUSED(x) (void)(x)
2660#endif
2661
2662#if defined(SOKOL_WGPU)
2663#include <webgpu/webgpu.h>
2664#if !defined(__EMSCRIPTEN__)
2665#define _SAPP_WGPU_HAS_WAIT (1)
2666#endif
2667#endif
2668
2669#if defined(_SAPP_APPLE)
2670#ifndef GL_SILENCE_DEPRECATION
2671#define GL_SILENCE_DEPRECATION
2672#endif
2673#if defined(SOKOL_METAL)
2674#import <Metal/Metal.h>
2675#import <MetalKit/MetalKit.h>
2676#endif
2677#if defined(_SAPP_MACOS)
2678#import <Cocoa/Cocoa.h>
2679#if defined(_SAPP_ANY_GL)
2680#include <OpenGL/gl3.h>
2681#endif
2682#if defined(SOKOL_WGPU)
2683#import <QuartzCore/CADisplayLink.h>
2684#import <QuartzCore/CAMetalLayer.h>
2685#endif
2686#elif defined(_SAPP_IOS)
2687#import <UIKit/UIKit.h>
2688#if defined(_SAPP_ANY_GL)
2689#import <GLKit/GLKit.h>
2690#include <OpenGLES/ES3/gl.h>
2691#endif
2692#endif
2693#include <AvailabilityMacros.h>
2694#include <mach/mach_time.h>
2695#elif defined(_SAPP_EMSCRIPTEN)
2696#if defined(SOKOL_GLES3)
2697#include <GLES3/gl3.h>
2698#endif
2699#include <emscripten/emscripten.h>
2700#include <emscripten/html5.h>
2701#elif defined(_SAPP_WIN32)
2702#ifdef _MSC_VER
2703#pragma warning(push)
2704#pragma warning( \
2705 disable : 4201) /* nonstandard extension used: nameless struct/union */
2706#pragma warning(disable : 4204) /* nonstandard extension used: non-constant \
2707 aggregate initializer */
2708#pragma warning(disable : 4054) /* 'type cast': from function pointer */
2709#pragma warning(disable : 4055) /* 'type cast': from data pointer */
2710#pragma warning(disable \
2711 : 4505) /* unreferenced local function has been removed */
2712#pragma warning(disable : 4115) /* /W4: 'ID3D11ModuleInstance': named type \
2713 definition in parentheses (in d3d11.h) */
2714#endif
2715#ifndef WIN32_LEAN_AND_MEAN
2716#define WIN32_LEAN_AND_MEAN
2717#endif
2718#ifndef NOMINMAX
2719#define NOMINMAX
2720#endif
2721#include <shellapi.h>
2722#include <windows.h>
2723#include <windowsx.h>
2724
2725#if defined(__GNUC__)
2726#pragma GCC diagnostic push
2727#pragma GCC diagnostic ignored "-Wunknown-pragmas"
2728#endif
2729
2730#if !defined( \
2731 SOKOL_NO_ENTRY) // if SOKOL_NO_ENTRY is defined, it's the application's
2732 // responsibility to use the right subsystem
2733
2734#if defined(SOKOL_WIN32_FORCE_MAIN) && defined(SOKOL_WIN32_FORCE_WINMAIN)
2735// If both are defined, it's the application's responsibility to use the right
2736// subsystem
2737#elif defined(SOKOL_WIN32_FORCE_MAIN)
2738#pragma comment(linker, "/subsystem:console")
2739#else
2740#pragma comment(linker, "/subsystem:windows")
2741#endif
2742#endif
2743#include <stdio.h> /* freopen_s() */
2744#include <wchar.h> /* wcslen() */
2745
2746#pragma comment(lib, "kernel32")
2747#pragma comment(lib, "user32")
2748#pragma comment( \
2749 lib, "shell32") /* CommandLineToArgvW, DragQueryFileW, DragFinished */
2750#pragma comment(lib, "gdi32")
2751#if defined(SOKOL_D3D11)
2752#pragma comment(lib, "dxgi")
2753#pragma comment(lib, "d3d11")
2754#endif
2755
2756#if defined(__GNUC__)
2757#pragma GCC diagnostic pop
2758#endif
2759
2760#if defined(SOKOL_D3D11)
2761#ifndef D3D11_NO_HELPERS
2762#define D3D11_NO_HELPERS
2763#endif
2764#include <d3d11.h>
2765#include <dxgi.h>
2766// DXGI_SWAP_EFFECT_FLIP_DISCARD is only defined in newer Windows SDKs, so don't
2767// depend on it
2768#define _SAPP_DXGI_SWAP_EFFECT_FLIP_DISCARD (4)
2769#endif
2770#ifndef WM_MOUSEHWHEEL /* see https://github.com/floooh/sokol/issues/138 */
2771#define WM_MOUSEHWHEEL (0x020E)
2772#endif
2773#ifndef WM_DPICHANGED
2774#define WM_DPICHANGED (0x02E0)
2775#endif
2776#elif defined(_SAPP_ANDROID)
2777#include <EGL/egl.h>
2778#include <GLES3/gl3.h>
2779#include <android/looper.h>
2780#include <android/native_activity.h>
2781#include <pthread.h>
2782#include <time.h>
2783#include <unistd.h>
2784#elif defined(_SAPP_LINUX)
2785#define GL_GLEXT_PROTOTYPES
2786#if defined(_SAPP_X11)
2787#include <X11/XKBlib.h>
2788#include <X11/Xatom.h>
2789#include <X11/Xcursor/Xcursor.h>
2790#include <X11/Xlib.h>
2791#include <X11/Xmd.h> /* CARD32 */
2792#include <X11/Xresource.h>
2793#include <X11/Xutil.h>
2794#include <X11/cursorfont.h> /* XC_* font cursors */
2795#include <X11/extensions/XInput2.h>
2796#include <X11/keysym.h>
2797#endif
2798#if defined(_SAPP_WAYLAND)
2799#include <linux/input-event-codes.h>
2800#include <string.h>
2801#include <sys/mman.h>
2802#include <sys/timerfd.h>
2803#include <wayland-client.h>
2804#include <wayland-cursor.h>
2805#include <wayland-egl.h>
2806#include <xkbcommon/xkbcommon-compose.h>
2807#include <xkbcommon/xkbcommon.h>
2808
2809// struct forward declarations
2810struct xdg_wm_base;
2811struct xdg_surface;
2812struct xdg_toplevel;
2813struct zwp_pointer_constraints_v1;
2814struct zwp_locked_pointer_v1;
2815struct zwp_relative_pointer_manager_v1;
2816struct zwp_relative_pointer_v1;
2817struct wp_cursor_shape_manager_v1;
2818struct wp_cursor_shape_device_v1;
2819struct wp_fractional_scale_manager_v1;
2820struct wp_fractional_scale_v1;
2821struct zxdg_decoration_manager_v1;
2822struct zxdg_toplevel_decoration_v1;
2823
2824// interface forward declarations
2825extern const struct wl_interface wl_compositor_interface;
2826extern const struct wl_interface wl_surface_interface;
2827extern const struct wl_interface wl_seat_interface;
2828extern const struct wl_interface wl_shm_interface;
2829extern const struct wl_interface xdg_wm_base_interface;
2830extern const struct wl_interface xdg_surface_interface;
2831extern const struct wl_interface xdg_toplevel_interface;
2832extern const struct wl_interface wl_data_device_manager_interface;
2833extern const struct wl_interface zwp_pointer_constraints_v1_interface;
2834extern const struct wl_interface zwp_relative_pointer_manager_v1_interface;
2835extern const struct wl_interface wp_cursor_shape_manager_v1_interface;
2836extern const struct wl_interface wp_fractional_scale_manager_v1_interface;
2837extern const struct wl_interface wp_viewporter_interface;
2838extern const struct wl_interface zxdg_decoration_manager_v1_interface;
2839#endif
2840#if defined(_SAPP_EGL)
2841#include <EGL/egl.h>
2842#endif
2843#if defined(_SAPP_WAYLAND)
2844#include "cursor-shape-v1-client-protocol.h"
2845#include "fractional-scale-v1-client-protocol.h"
2846#include "pointer-constraints-unstable-v1-client-protocol.h"
2847#include "relative-pointer-unstable-v1-client-protocol.h"
2848#include "viewporter-client-protocol.h"
2849#include "xdg-decoration-unstable-v1-client-protocol.h"
2850#include "xdg-shell-client-protocol.h"
2851#endif
2852#include <dlfcn.h> /* dlopen, dlsym, dlclose */
2853#include <limits.h> /* LONG_MAX */
2854#include <poll.h>
2855#include <pthread.h> /* only used a linker-guard, search for _sapp_linux_run() and see first comment */
2856#include <time.h>
2857#include <unistd.h>
2858#endif
2859
2860#if defined(_SAPP_APPLE)
2861// this is ARC compatible
2862#if defined(__cplusplus)
2863#define _SAPP_CLEAR_ARC_STRUCT(type, item) \
2864 { \
2865 item = type(); \
2866 }
2867#else
2868#define _SAPP_CLEAR_ARC_STRUCT(type, item) \
2869 { \
2870 item = (type){0}; \
2871 }
2872#endif
2873#else
2874#define _SAPP_CLEAR_ARC_STRUCT(type, item) \
2875 { \
2876 _sapp_clear(&item, sizeof(item)); \
2877 }
2878#endif
2879
2880// ███████ ██████ █████ ███ ███ ███████ ████████ ██ ███ ███ ██ ███
2881// ██ ██████ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ████
2882// ████ ██ ████ ██ ██ █████ ██████ ███████ ██ ████ ██ █████ ██ ██
2883// ██ ████ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
2884// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████
2885// ██ ██ ██ ██ ██ ██ ████ ██████
2886//
2887// >>frame timing
2888#define _SAPP_RING_NUM_SLOTS (256)
2889typedef struct {
2890 int head;
2891 int tail;
2892 double buf[_SAPP_RING_NUM_SLOTS];
2893} _sapp_ring_t;
2894
2895_SOKOL_PRIVATE int _sapp_ring_idx(int i) { return i % _SAPP_RING_NUM_SLOTS; }
2896
2897_SOKOL_PRIVATE void _sapp_ring_init(_sapp_ring_t *ring) {
2898 ring->head = 0;
2899 ring->tail = 0;
2900}
2901
2902_SOKOL_PRIVATE bool _sapp_ring_full(_sapp_ring_t *ring) {
2903 return _sapp_ring_idx(ring->head + 1) == ring->tail;
2904}
2905
2906_SOKOL_PRIVATE bool _sapp_ring_empty(_sapp_ring_t *ring) {
2907 return ring->head == ring->tail;
2908}
2909
2910_SOKOL_PRIVATE int _sapp_ring_count(_sapp_ring_t *ring) {
2911 int count;
2912 if (ring->head >= ring->tail) {
2913 count = ring->head - ring->tail;
2914 } else {
2915 count = (ring->head + _SAPP_RING_NUM_SLOTS) - ring->tail;
2916 }
2917 SOKOL_ASSERT((count >= 0) && (count < _SAPP_RING_NUM_SLOTS));
2918 return count;
2919}
2920
2921_SOKOL_PRIVATE void _sapp_ring_enqueue(_sapp_ring_t *ring, double val) {
2922 SOKOL_ASSERT(!_sapp_ring_full(ring));
2923 ring->buf[ring->head] = val;
2924 ring->head = _sapp_ring_idx(ring->head + 1);
2925}
2926
2927_SOKOL_PRIVATE double _sapp_ring_dequeue(_sapp_ring_t *ring) {
2928 SOKOL_ASSERT(!_sapp_ring_empty(ring));
2929 double val = ring->buf[ring->tail];
2930 ring->tail = _sapp_ring_idx(ring->tail + 1);
2931 return val;
2932}
2933
2934/*
2935 NOTE:
2936
2937 Q: Why not use CAMetalDrawable.presentedTime on macOS and iOS?
2938 A: The value appears to be highly unstable during the first few
2939 seconds, sometimes several frames are dropped in sequence, or
2940 switch between 120 and 60 Hz for a few frames. Simply measuring
2941 and averaging the frame time yielded a more stable frame duration.
2942 Maybe switching to CVDisplayLink would yield better results.
2943 Until then just measure the time.
2944*/
2945typedef struct {
2946#if defined(_SAPP_APPLE)
2947 struct {
2948 mach_timebase_info_data_t timebase;
2949 uint64_t start;
2950 } mach;
2951#elif defined(_SAPP_EMSCRIPTEN)
2952 // empty
2953#elif defined(_SAPP_WIN32)
2954 struct {
2955 LARGE_INTEGER freq;
2956 LARGE_INTEGER start;
2957 } win;
2958#else // Linux, Android, ...
2959#ifdef CLOCK_MONOTONIC
2960#define _SAPP_CLOCK_MONOTONIC CLOCK_MONOTONIC
2961#else
2962// on some embedded platforms, CLOCK_MONOTONIC isn't defined
2963#define _SAPP_CLOCK_MONOTONIC (1)
2964#endif
2965 struct {
2966 uint64_t start;
2967 } posix;
2968#endif
2969} _sapp_timestamp_t;
2970
2971_SOKOL_PRIVATE int64_t _sapp_int64_muldiv(int64_t value, int64_t numer,
2972 int64_t denom) {
2973 int64_t q = value / denom;
2974 int64_t r = value % denom;
2975 return q * numer + r * numer / denom;
2976}
2977
2978_SOKOL_PRIVATE void _sapp_timestamp_init(_sapp_timestamp_t *ts) {
2979#if defined(_SAPP_APPLE)
2980 mach_timebase_info(&ts->mach.timebase);
2981 ts->mach.start = mach_absolute_time();
2982#elif defined(_SAPP_EMSCRIPTEN)
2983 (void)ts;
2984#elif defined(_SAPP_WIN32)
2985 QueryPerformanceFrequency(&ts->win.freq);
2986 QueryPerformanceCounter(&ts->win.start);
2987#else
2988// Ensure clock_gettime is declared
2989#if !defined(CLOCK_MONOTONIC)
2990#define CLOCK_MONOTONIC 1
2991#endif
2992#if !defined(_SAPP_CLOCK_MONOTONIC)
2993#define _SAPP_CLOCK_MONOTONIC CLOCK_MONOTONIC
2994#endif
2995 extern int clock_gettime(int, struct timespec *);
2996 struct timespec tspec;
2997 clock_gettime(_SAPP_CLOCK_MONOTONIC, &tspec);
2998 ts->posix.start =
2999 (uint64_t)tspec.tv_sec * 1000000000 + (uint64_t)tspec.tv_nsec;
3000#endif
3001}
3002
3003_SOKOL_PRIVATE double _sapp_timestamp_now(_sapp_timestamp_t *ts) {
3004#if defined(_SAPP_APPLE)
3005 const uint64_t traw = mach_absolute_time() - ts->mach.start;
3006 const uint64_t now = (uint64_t)_sapp_int64_muldiv(
3007 (int64_t)traw, (int64_t)ts->mach.timebase.numer,
3008 (int64_t)ts->mach.timebase.denom);
3009 return (double)now / 1000000000.0;
3010#elif defined(_SAPP_EMSCRIPTEN)
3011 (void)ts;
3012 SOKOL_ASSERT(false);
3013 return 0.0;
3014#elif defined(_SAPP_WIN32)
3015 LARGE_INTEGER qpc;
3016 QueryPerformanceCounter(&qpc);
3017 const uint64_t now = (uint64_t)_sapp_int64_muldiv(
3018 qpc.QuadPart - ts->win.start.QuadPart, 1000000000, ts->win.freq.Qu