1#pragma once
2/*
3 sokol_app.h -- cross-platform application wrapper
4
5 Do this:
6 #define SOKOL_IMPL
7 before you include this file in *one* C or C++ file to create the
8 implementation.
9
10 Optionally provide the following defines with your own implementations:
11
12 SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
13 SOKOL_LOG(msg) - your own logging function (default: puts(msg))
14 SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
15 SOKOL_ABORT() - called after an unrecoverable error (default: abort())
16 SOKOL_WIN32_FORCE_MAIN - define this on Win32 to use a main() entry point instead of WinMain
17 SOKOL_API_DECL - public function declaration prefix (default: extern)
18 SOKOL_API_IMPL - public function implementation prefix (default: -)
19
20 Optionally define the following to force debug checks and validations
21 even in release mode:
22
23 SOKOL_DEBUG - by default this is defined if _DEBUG is defined
24
25 Portions of the Windows and Linux GL initialization and event code have been
26 taken from GLFW (http://www.glfw.org/)
27
28 iOS onscreen keyboard support 'inspired' by libgdx.
29
30 If you use sokol_app.h together with sokol_gfx.h, include both headers
31 in the implementation source file, and include sokol_app.h before
32 sokol_gfx.h since sokol_app.h will also include the required 3D-API
33 headers.
34
35 On Windows, a minimal 'GL header' and function loader is integrated which
36 contains just enough of GL for sokol_gfx.h. If you want to use your own
37 GL header-generator/loader instead, define SOKOL_WIN32_NO_GL_LOADER
38 before including the implementation part of sokol_app.h.
39
40 TEMP NOTE DUMP
41 ==============
42 - need a way to quit application programmatically (sapp_request_quit())
43 - need a way to intercept a pending quit via UI close button (could be
44 done via frame_cb return value, and a sapp_quit_requested() function)
45 - onscreen keyboard support on Android requires Java :(, should we even bother?
46 - sapp_desc needs a bool whether to initialize depth-stencil surface
47 - GL context initialization needs more control (at least what GL version to initialize)
48 - application icon
49 - mouse pointer visibility(?)
50 - the UPDATE_CURSOR event currently behaves differently between Win32 and OSX
51 (Win32 sends the event each frame when the mouse moves and is inside the window
52 client area, OSX sends it only once when the mouse enters the client area)
53
54 FIXME: ERROR HANDLING (this will need an error callback function)
55
56 FEATURE OVERVIEW
57 ================
58 sokol_app.h provides a minimalistic cross-platform API which
59 implements the 'application-wrapper' parts of a 3D application:
60
61 - a common application entry function
62 - creates a window and 3D-API context/device with a 'default framebuffer'
63 - makes the rendered frame visible
64 - provides keyboard-, mouse- and low-level touch-events
65 - platforms: MacOS, iOS, HTML5, Win32, Linux (planned: Android, RaspberryPi)
66 - 3D-APIs: Metal, D3D11, GL3.2, GLES2, GLES3, WebGL, WebGL2
67
68 FEATURE/PLATFORM MATRIX
69 =======================
70 | Windows | macOS | Linux | iOS | Android | Raspi | HTML5
71 --------------------+---------+-------+-------+-------+---------+-------+-------
72 gl 3.x | YES | --- | YES | --- | --- | --- | ---
73 gles2/webgl | --- | --- | --- | YES | TODO | TODO | YES
74 gles3/webgl2 | --- | --- | --- | YES | TODO | --- | YES
75 metal | --- | YES | --- | YES | --- | --- | ---
76 d3d11 | YES | --- | --- | --- | --- | --- | ---
77 KEY_DOWN | YES | YES | YES | SOME | TODO | TODO | YES
78 KEY_UP | YES | YES | YES | SOME | TODO | TODO | YES
79 CHAR | YES | YES | YES | YES | TODO | TODO | YES
80 MOUSE_DOWN | YES | YES | YES | --- | --- | TODO | YES
81 MOUSE_UP | YES | YES | YES | --- | --- | TODO | YES
82 MOUSE_SCROLL | YES | YES | YES | --- | --- | TODO | YES
83 MOUSE_MOVE | YES | YES | YES | --- | --- | TODO | YES
84 MOUSE_ENTER | YES | YES | YES | --- | --- | TODO | YES
85 MOUSE_LEAVE | YES | YES | YES | --- | --- | TODO | YES
86 TOUCHES_BEGAN | --- | --- | --- | YES | TODO | --- | YES
87 TOUCHES_MOVED | --- | --- | --- | YES | TODO | --- | YES
88 TOUCHES_ENDED | --- | --- | --- | YES | TODO | --- | YES
89 TOUCHES_CANCELLED | --- | --- | --- | YES | TODO | --- | YES
90 RESIZED | YES | YES | YES | YES | TODO | --- | YES
91 ICONIFIED | YES | YES | YES | --- | --- | --- | ---
92 RESTORED | YES | YES | YES | --- | --- | --- | ---
93 SUSPENDED | --- | --- | --- | YES | TODO | --- | TODO
94 RESUMED | --- | --- | --- | YES | TODO | --- | TODO
95 UPDATE_CURSOR | YES | YES | TODO | --- | --- | --- | TODO
96 IME | TODO | TODO? | TODO | ??? | TODO | ??? | ???
97 windowed | YES | YES | YES | --- | --- | TODO | YES
98 fullscreen | YES | YES | TODO | YES | TODO | TODO | ---
99 pointer lock | TODO | TODO | TODO | --- | --- | TODO | TODO
100 screen keyboard | --- | --- | --- | YES | TODO | --- | YES
101 swap interval | YES | YES | YES | YES | TODO | TODO | YES
102 high-dpi | YES | YES | TODO | YES | TODO | TODO | YES
103
104 - what about bluetooth keyboard / mouse on mobile platforms?
105
106 STEP BY STEP
107 ============
108 --- Add a sokol_main() to your code which returns a sapp_desc structure
109 with initialization parameters and callback function pointers. This
110 function is called very early, usually at the start of the
111 platform's entry function (e.g. main or WinMain). You should do as
112 little as possible here, since the rest of your code might be called
113 from another thread (this depends on the platform):
114
115 sapp_desc sokol_main(int argc, char* argv[]) {
116 return (sapp_desc) {
117 .width = 640,
118 .height = 480,
119 .init_cb = my_init_func,
120 .frame_cb = my_frame_func,
121 .cleanup_cb = my_cleanup_func,
122 .event_cb = my_event_func,
123 ...
124 };
125 }
126
127 There are many more setup parameters, but these are the most important.
128 For a complete list search for the sapp_desc structure declaration
129 below.
130
131 DO NOT call any sokol-app function from inside sokol_main(), since
132 sokol-app will not be initialized at this point.
133
134 The .width and .height parameters are the preferred size of the 3D
135 rendering canvas. The actual size may differ from this depending on
136 platform and other circumstances. Also the canvas size may change at
137 any time (for instance when the user resizes the application window,
138 or rotates the mobile device).
139
140 All provided function callbacks will be called from the same thread,
141 but this may be different from the thread where sokol_main() was called.
142
143 .init_cb (void (init_cb*)(void))
144 This function is called once after the application window,
145 3D rendering context and swap chain have been created. The
146 function takes no arguments and has no return value.
147 .frame_cb (void (frame_cb*)(void))
148 This is the per-frame callback, which is usually called 60
149 times per second. This is where your application would update
150 most of its state and perform all rendering.
151 .cleanup_cb (void (cleanup_cb*)(void))
152 The cleanup callback is called once right before the application
153 quits.
154 .event_cb (void (event-cb*)(const sapp_event* event))
155 The event callback is mainly for input handling, but in the
156 future may also be used to communicate other types of events
157 to the application. Keep the event_cb struct member zero-initialized
158 if your application doesn't require event handling.
159
160 --- Implement the initialization callback function, this is called once
161 after the rendering surface, 3D API and swap chain have been
162 initialized by sokol_app. All sokol-app functions can be called
163 from inside the initialization callback, the most useful functions
164 at this point are:
165
166 int sapp_width(void)
167 Returns the current width of the default framebuffer, this may change
168 from one frame to the next.
169 int sapp_height(void)
170 Likewise, returns the current height of the default framebuffer.
171
172 bool sapp_gles2(void)
173 Returns true if as GLES2 or WebGL2 context had been created (for
174 instance because GLES3/WebGL2 isn't available on the device)
175
176 const void* sapp_metal_get_device(void)
177 const void* sapp_metal_get_renderpass_descriptor(void)
178 const void* sapp_metal_get_drawable(void)
179 If the Metal backend has been selected, these functions return pointers
180 to various Metal API objects required for rendering, otherwise
181 they return a null pointer. Note that the returned pointers
182 to the renderpass-descriptor and drawable may change from one
183 frame to the next!
184
185 const void* sapp_macos_get_window(void)
186 On macOS, get the NSWindow object pointer, otherwise a null pointer.
187
188 const void* sapp_ios_get_window(void)
189 On iOS, get the UIWindow object pointer, otherwise a null pointer.
190
191 const void* sapp_win32_get_hwnd(void)
192 On Windows, get the window's HWND, otherwise a null pointer.
193
194 const void* sapp_d3d11_get_device(void);
195 const void* sapp_d3d11_get_device_context(void);
196 const void* sapp_d3d11_get_render_target_view(void);
197 const void* sapp_d3d11_get_depth_stencil_view(void);
198 Similar to the sapp_metal_* functions, the sapp_d3d11_* functions
199 return pointers to D3D11 API objects required for rendering,
200 only if the D3D11 backend has been selected. Otherwise they
201 return a null pointer. Note that the returned pointers to the
202 render-target-view and depth-stencil-view may change from one
203 frame to the next!
204
205 --- Implement the frame-callback function, this function will be called
206 on the same thread as the init callback, but might be on a different
207 thread than the sokol_main() function. Note that the size of
208 the rendering framebuffer might have change since the frame callback
209 was called last. Call the functions sapp_width() and sapp_height()
210 to get the current size.
211
212 --- Optionally implement the event-callback to handle input events.
213 sokol-app provides the following type of input events:
214 - a 'virtual key' was pressed down or released
215 - a single text character was entered (provided as UTF-32 code point)
216 - a mouse button was pressed down or released (left, right, middle)
217 - mouse-wheel or 2D scrolling events
218 - the mouse was moved
219 - the mouse has entered or left the application window boundaries
220 - low-level, portable multi-touch events (began, moved, ended, cancelled)
221 More types of events will be added in the future (like window
222 minimized, maximized, application life cycle events, etc...)
223
224 --- Implement the cleanup-callback function, this is called once
225 after the user quits the application (currently there's now way
226 to quite the application programmatically)
227
228
229 HIGH-DPI RENDERING
230 ==================
231 You can set the sapp_desc.high_dpi flag during initialization to request
232 a full-resolution framebuffer on HighDPI displays. The default behaviour
233 is sapp_desc.high_dpi=false, this means that the application will
234 render to a lower-resolution framebuffer on HighDPI displays and the
235 rendered content will be upscaled by the window system composer.
236
237 In a HighDPI scenario, you still request the same window size during
238 sokol_main(), but the framebuffer sizes returned by sapp_width()
239 and sapp_height() will be scaled up according to the DPI scaling
240 ratio. You can also get a DPI scaling factor with the function
241 sapp_dpi_scale().
242
243 Here's an example on a Mac with Retina display:
244
245 sapp_desc sokol_main() {
246 return (sapp_desc) {
247 .width = 640,
248 .height = 480,
249 .high_dpi = true,
250 ...
251 };
252 }
253
254 The functions sapp_width(), sapp_height() and sapp_dpi_scale() will
255 return the following values:
256
257 sapp_width -> 1280
258 sapp_height -> 960
259 sapp_dpi_scale -> 2.0
260
261 If the high_dpi flag is false, or you're not running on a Retina display,
262 the values would be:
263
264 sapp_width -> 640
265 sapp_height -> 480
266 sapp_dpi_scale -> 1.0
267
268 FULLSCREEN
269 ==========
270 If the sapp_desc.fullscreen flag is true, sokol-app will try to create
271 a fullscreen window on platforms with a 'proper' window system
272 (mobile devices will always use fullscreen). The implementation details
273 depend on the target platform, in general sokol-app will use a
274 'soft approach' which doesn't interfere too much with the platform's
275 window system (for instance borderless fullscreen window instead of
276 a 'real' fullscreen mode). Such details might change over time
277 as sokol-app is adapted for different needs.
278
279 The most important effect of fullscreen mode to keep in mind is that
280 the requested canvas width and height will be ignored for the initial
281 window size, calling sapp_width() and sapp_height() will instead return
282 the resolution of the fullscreen canvas (however the provided size
283 might still be used for the non-fullscreen window, in case the user can
284 switch back from fullscreen- to windowed-mode).
285
286 ONSCREEN KEYBOARD
287 =================
288 On some platforms which don't provide a physical keyboard, sokol-app
289 can display the platform's integrated onscreen keyboard for text
290 input. To request that the onscreen keyboard is shown, call
291
292 sapp_show_keyboard(true);
293
294 Likewise, to hide the keyboard call:
295
296 sapp_show_keyboard(false);
297
298 Note that on the web platform, the keyboard can only be shown from
299 inside an input handler. On such platforms, sapp_show_keyboard()
300 will only work as expected when it is called from inside the
301 sokol-app event callback function. When called from other places,
302 an internal flag will be set, and the onscreen keyboard will be
303 called at the next 'legal' opportunity (when the next input event
304 is handled).
305
306 zlib/libpng license
307
308 Copyright (c) 2018 Andre Weissflog
309
310 This software is provided 'as-is', without any express or implied warranty.
311 In no event will the authors be held liable for any damages arising from the
312 use of this software.
313
314 Permission is granted to anyone to use this software for any purpose,
315 including commercial applications, and to alter it and redistribute it
316 freely, subject to the following restrictions:
317
318 1. The origin of this software must not be misrepresented; you must not
319 claim that you wrote the original software. If you use this software in a
320 product, an acknowledgment in the product documentation would be
321 appreciated but is not required.
322
323 2. Altered source versions must be plainly marked as such, and must not
324 be misrepresented as being the original software.
325
326 3. This notice may not be removed or altered from any source
327 distribution.
328*/
329#include <stdint.h>
330#include <stdbool.h>
331
332#ifndef SOKOL_API_DECL
333 #define SOKOL_API_DECL extern
334#endif
335
336#ifdef __cplusplus
337extern "C" {
338#endif
339
340enum {
341 SAPP_MAX_TOUCHPOINTS = 8,
342 SAPP_MAX_MOUSEBUTTONS = 3,
343 SAPP_MAX_KEYCODES = 512,
344};
345
346typedef enum {
347 SAPP_EVENTTYPE_INVALID,
348 SAPP_EVENTTYPE_KEY_DOWN,
349 SAPP_EVENTTYPE_KEY_UP,
350 SAPP_EVENTTYPE_CHAR,
351 SAPP_EVENTTYPE_MOUSE_DOWN,
352 SAPP_EVENTTYPE_MOUSE_UP,
353 SAPP_EVENTTYPE_MOUSE_SCROLL,
354 SAPP_EVENTTYPE_MOUSE_MOVE,
355 SAPP_EVENTTYPE_MOUSE_ENTER,
356 SAPP_EVENTTYPE_MOUSE_LEAVE,
357 SAPP_EVENTTYPE_TOUCHES_BEGAN,
358 SAPP_EVENTTYPE_TOUCHES_MOVED,
359 SAPP_EVENTTYPE_TOUCHES_ENDED,
360 SAPP_EVENTTYPE_TOUCHES_CANCELLED,
361 SAPP_EVENTTYPE_RESIZED,
362 SAPP_EVENTTYPE_ICONIFIED,
363 SAPP_EVENTTYPE_RESTORED,
364 SAPP_EVENTTYPE_SUSPENDED,
365 SAPP_EVENTTYPE_RESUMED,
366 SAPP_EVENTTYPE_UPDATE_CURSOR,
367 _SAPP_EVENTTYPE_NUM,
368 _SAPP_EVENTTYPE_FORCE_U32 = 0x7FFFFFF
369} sapp_event_type;
370
371/* key codes are the same names and values as GLFW */
372typedef enum {
373 SAPP_KEYCODE_INVALID = 0,
374 SAPP_KEYCODE_SPACE = 32,
375 SAPP_KEYCODE_APOSTROPHE = 39, /* ' */
376 SAPP_KEYCODE_COMMA = 44, /* , */
377 SAPP_KEYCODE_MINUS = 45, /* - */
378 SAPP_KEYCODE_PERIOD = 46, /* . */
379 SAPP_KEYCODE_SLASH = 47, /* / */
380 SAPP_KEYCODE_0 = 48,
381 SAPP_KEYCODE_1 = 49,
382 SAPP_KEYCODE_2 = 50,
383 SAPP_KEYCODE_3 = 51,
384 SAPP_KEYCODE_4 = 52,
385 SAPP_KEYCODE_5 = 53,
386 SAPP_KEYCODE_6 = 54,
387 SAPP_KEYCODE_7 = 55,
388 SAPP_KEYCODE_8 = 56,
389 SAPP_KEYCODE_9 = 57,
390 SAPP_KEYCODE_SEMICOLON = 59, /* ; */
391 SAPP_KEYCODE_EQUAL = 61, /* = */
392 SAPP_KEYCODE_A = 65,
393 SAPP_KEYCODE_B = 66,
394 SAPP_KEYCODE_C = 67,
395 SAPP_KEYCODE_D = 68,
396 SAPP_KEYCODE_E = 69,
397 SAPP_KEYCODE_F = 70,
398 SAPP_KEYCODE_G = 71,
399 SAPP_KEYCODE_H = 72,
400 SAPP_KEYCODE_I = 73,
401 SAPP_KEYCODE_J = 74,
402 SAPP_KEYCODE_K = 75,
403 SAPP_KEYCODE_L = 76,
404 SAPP_KEYCODE_M = 77,
405 SAPP_KEYCODE_N = 78,
406 SAPP_KEYCODE_O = 79,
407 SAPP_KEYCODE_P = 80,
408 SAPP_KEYCODE_Q = 81,
409 SAPP_KEYCODE_R = 82,
410 SAPP_KEYCODE_S = 83,
411 SAPP_KEYCODE_T = 84,
412 SAPP_KEYCODE_U = 85,
413 SAPP_KEYCODE_V = 86,
414 SAPP_KEYCODE_W = 87,
415 SAPP_KEYCODE_X = 88,
416 SAPP_KEYCODE_Y = 89,
417 SAPP_KEYCODE_Z = 90,
418 SAPP_KEYCODE_LEFT_BRACKET = 91, /* [ */
419 SAPP_KEYCODE_BACKSLASH = 92, /* \ */
420 SAPP_KEYCODE_RIGHT_BRACKET = 93, /* ] */
421 SAPP_KEYCODE_GRAVE_ACCENT = 96, /* ` */
422 SAPP_KEYCODE_WORLD_1 = 161, /* non-US #1 */
423 SAPP_KEYCODE_WORLD_2 = 162, /* non-US #2 */
424 SAPP_KEYCODE_ESCAPE = 256,
425 SAPP_KEYCODE_ENTER = 257,
426 SAPP_KEYCODE_TAB = 258,
427 SAPP_KEYCODE_BACKSPACE = 259,
428 SAPP_KEYCODE_INSERT = 260,
429 SAPP_KEYCODE_DELETE = 261,
430 SAPP_KEYCODE_RIGHT = 262,
431 SAPP_KEYCODE_LEFT = 263,
432 SAPP_KEYCODE_DOWN = 264,
433 SAPP_KEYCODE_UP = 265,
434 SAPP_KEYCODE_PAGE_UP = 266,
435 SAPP_KEYCODE_PAGE_DOWN = 267,
436 SAPP_KEYCODE_HOME = 268,
437 SAPP_KEYCODE_END = 269,
438 SAPP_KEYCODE_CAPS_LOCK = 280,
439 SAPP_KEYCODE_SCROLL_LOCK = 281,
440 SAPP_KEYCODE_NUM_LOCK = 282,
441 SAPP_KEYCODE_PRINT_SCREEN = 283,
442 SAPP_KEYCODE_PAUSE = 284,
443 SAPP_KEYCODE_F1 = 290,
444 SAPP_KEYCODE_F2 = 291,
445 SAPP_KEYCODE_F3 = 292,
446 SAPP_KEYCODE_F4 = 293,
447 SAPP_KEYCODE_F5 = 294,
448 SAPP_KEYCODE_F6 = 295,
449 SAPP_KEYCODE_F7 = 296,
450 SAPP_KEYCODE_F8 = 297,
451 SAPP_KEYCODE_F9 = 298,
452 SAPP_KEYCODE_F10 = 299,
453 SAPP_KEYCODE_F11 = 300,
454 SAPP_KEYCODE_F12 = 301,
455 SAPP_KEYCODE_F13 = 302,
456 SAPP_KEYCODE_F14 = 303,
457 SAPP_KEYCODE_F15 = 304,
458 SAPP_KEYCODE_F16 = 305,
459 SAPP_KEYCODE_F17 = 306,
460 SAPP_KEYCODE_F18 = 307,
461 SAPP_KEYCODE_F19 = 308,
462 SAPP_KEYCODE_F20 = 309,
463 SAPP_KEYCODE_F21 = 310,
464 SAPP_KEYCODE_F22 = 311,
465 SAPP_KEYCODE_F23 = 312,
466 SAPP_KEYCODE_F24 = 313,
467 SAPP_KEYCODE_F25 = 314,
468 SAPP_KEYCODE_KP_0 = 320,
469 SAPP_KEYCODE_KP_1 = 321,
470 SAPP_KEYCODE_KP_2 = 322,
471 SAPP_KEYCODE_KP_3 = 323,
472 SAPP_KEYCODE_KP_4 = 324,
473 SAPP_KEYCODE_KP_5 = 325,
474 SAPP_KEYCODE_KP_6 = 326,
475 SAPP_KEYCODE_KP_7 = 327,
476 SAPP_KEYCODE_KP_8 = 328,
477 SAPP_KEYCODE_KP_9 = 329,
478 SAPP_KEYCODE_KP_DECIMAL = 330,
479 SAPP_KEYCODE_KP_DIVIDE = 331,
480 SAPP_KEYCODE_KP_MULTIPLY = 332,
481 SAPP_KEYCODE_KP_SUBTRACT = 333,
482 SAPP_KEYCODE_KP_ADD = 334,
483 SAPP_KEYCODE_KP_ENTER = 335,
484 SAPP_KEYCODE_KP_EQUAL = 336,
485 SAPP_KEYCODE_LEFT_SHIFT = 340,
486 SAPP_KEYCODE_LEFT_CONTROL = 341,
487 SAPP_KEYCODE_LEFT_ALT = 342,
488 SAPP_KEYCODE_LEFT_SUPER = 343,
489 SAPP_KEYCODE_RIGHT_SHIFT = 344,
490 SAPP_KEYCODE_RIGHT_CONTROL = 345,
491 SAPP_KEYCODE_RIGHT_ALT = 346,
492 SAPP_KEYCODE_RIGHT_SUPER = 347,
493 SAPP_KEYCODE_MENU = 348,
494} sapp_keycode;
495
496typedef struct {
497 uintptr_t identifier;
498 float pos_x;
499 float pos_y;
500 bool changed;
501} sapp_touchpoint;
502
503typedef enum {
504 SAPP_MOUSEBUTTON_INVALID = -1,
505 SAPP_MOUSEBUTTON_LEFT = 0,
506 SAPP_MOUSEBUTTON_RIGHT = 1,
507 SAPP_MOUSEBUTTON_MIDDLE = 2,
508} sapp_mousebutton;
509
510enum {
511 SAPP_MODIFIER_SHIFT = (1<<0),
512 SAPP_MODIFIER_CTRL = (1<<1),
513 SAPP_MODIFIER_ALT = (1<<2),
514 SAPP_MODIFIER_SUPER = (1<<3)
515};
516
517typedef struct {
518 sapp_event_type type;
519 uint32_t frame_count;
520 sapp_keycode key_code;
521 uint32_t char_code;
522 uint32_t modifiers;
523 sapp_mousebutton mouse_button;
524 float mouse_x;
525 float mouse_y;
526 float scroll_x;
527 float scroll_y;
528 int num_touches;
529 sapp_touchpoint touches[SAPP_MAX_TOUCHPOINTS];
530 int window_width;
531 int window_height;
532 int framebuffer_width;
533 int framebuffer_height;
534} sapp_event;
535
536typedef struct {
537 void (*init_cb)(void);
538 void (*frame_cb)(void);
539 void (*cleanup_cb)(void);
540 void (*event_cb)(const sapp_event*);
541 void (*fail_cb)(const char*);
542 int width;
543 int height;
544 int sample_count;
545 int swap_interval;
546 bool high_dpi;
547 bool fullscreen;
548 bool alpha;
549 bool premultiplied_alpha;
550 bool preserve_drawing_buffer;
551 const char* window_title;
552 const char* html5_canvas_name;
553 bool html5_canvas_resize;
554 bool ios_keyboard_resizes_canvas;
555 /* use GLES2 even if GLES3 is available */
556 bool gl_force_gles2;
557 /* if true, user is expected to manage cursor image and visibility on SAPP_EVENTTYPE_UPDATE_CURSOR */
558 bool user_cursor;
559} sapp_desc;
560
561/* user-provided functions */
562extern sapp_desc sokol_main(int argc, char* argv[]);
563
564/* sokol_app API functions */
565SOKOL_API_DECL bool sapp_isvalid(void);
566SOKOL_API_DECL int sapp_width(void);
567SOKOL_API_DECL int sapp_height(void);
568SOKOL_API_DECL bool sapp_high_dpi(void);
569SOKOL_API_DECL float sapp_dpi_scale(void);
570SOKOL_API_DECL void sapp_show_keyboard(bool visible);
571SOKOL_API_DECL bool sapp_keyboard_shown(void);
572
573/* GL/GLES specific functions */
574SOKOL_API_DECL bool sapp_gles2(void);
575
576/* OSX/Metal specific functions */
577SOKOL_API_DECL const void* sapp_metal_get_device(void);
578SOKOL_API_DECL const void* sapp_metal_get_renderpass_descriptor(void);
579SOKOL_API_DECL const void* sapp_metal_get_drawable(void);
580SOKOL_API_DECL const void* sapp_macos_get_window(void);
581SOKOL_API_DECL const void* sapp_ios_get_window(void);
582
583/* Win32/D3D11 specific functions */
584SOKOL_API_DECL const void* sapp_d3d11_get_device(void);
585SOKOL_API_DECL const void* sapp_d3d11_get_device_context(void);
586SOKOL_API_DECL const void* sapp_d3d11_get_render_target_view(void);
587SOKOL_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void);
588SOKOL_API_DECL const void* sapp_win32_get_hwnd(void);
589
590#ifdef __cplusplus
591} /* extern "C" */
592#endif
593
594/*-- IMPLEMENTATION ----------------------------------------------------------*/
595#ifdef SOKOL_IMPL
596
597#ifdef _MSC_VER
598#pragma warning(push)
599#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */
600#pragma warning(disable:4115) /* named type definition in parentheses */
601#pragma warning(disable:4054) /* 'type cast': from function pointer */
602#pragma warning(disable:4055) /* 'type cast': from data pointer */
603#pragma warning(disable:4505) /* unreferenced local function has been removed */
604#endif
605
606#include <string.h> /* memset */
607
608/* check if the config defines are alright */
609#if defined(__APPLE__)
610 #if !__has_feature(objc_arc)
611 #error "sokol_app.h requires ARC (Automatic Reference Counting) on MacOS and iOS"
612 #endif
613 #include <TargetConditionals.h>
614 #if TARGET_OS_IPHONE
615 /* iOS */
616 #if !defined(SOKOL_METAL) && !defined(SOKOL_GLES3)
617 #error("sokol_app.h: unknown 3D API selected for iOS, must be SOKOL_METAL or SOKOL_GLES3")
618 #endif
619 #else
620 /* MacOS */
621 #if !defined(SOKOL_METAL)
622 #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL")
623 #endif
624 #endif
625#elif defined(__EMSCRIPTEN__)
626 /* emscripten (asm.js or wasm) */
627 #if !defined(SOKOL_GLES3) && !defined(SOKOL_GLES2)
628 #error("sokol_app.h: unknown 3D API selected for emscripten, must be SOKOL_GLES3 or SOKOL_GLES2")
629 #endif
630#elif defined(_WIN32)
631 /* Windows (D3D11 or GL) */
632 #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE33)
633 #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11 or SOKOL_GLCORE33")
634 #endif
635#elif defined(linux)
636 #if !defined(SOKOL_GLCORE33)
637 #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE33")
638 #endif
639#else
640#error "sokol_app.h: Unknown platform"
641#endif
642
643#ifndef SOKOL_API_IMPL
644 #define SOKOL_API_IMPL
645#endif
646#ifndef SOKOL_DEBUG
647 #ifdef _DEBUG
648 #define SOKOL_DEBUG (1)
649 #endif
650#endif
651#ifndef SOKOL_ASSERT
652 #include <assert.h>
653 #define SOKOL_ASSERT(c) assert(c)
654#endif
655#if !defined(SOKOL_CALLOC) && !defined(SOKOL_FREE)
656 #include <stdlib.h>
657#endif
658#if !defined(SOKOL_CALLOC)
659 #define SOKOL_CALLOC(n,s) calloc(n,s)
660#endif
661#if !defined(SOKOL_FREE)
662 #define SOKOL_FREE(p) free(p)
663#endif
664#ifndef SOKOL_LOG
665 #ifdef SOKOL_DEBUG
666 #include <stdio.h>
667 #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
668 #else
669 #define SOKOL_LOG(s)
670 #endif
671#endif
672#ifndef SOKOL_ABORT
673 #include <stdlib.h>
674 #define SOKOL_ABORT() abort()
675#endif
676#ifndef _SOKOL_PRIVATE
677 #if defined(__GNUC__)
678 #define _SOKOL_PRIVATE __attribute__((unused)) static
679 #else
680 #define _SOKOL_PRIVATE static
681 #endif
682#endif
683#ifndef _SOKOL_UNUSED
684 #define _SOKOL_UNUSED(x) (void)(x)
685#endif
686
687/* helper macros */
688#define _sapp_def(val, def) (((val) == 0) ? (def) : (val))
689#define _sapp_absf(a) (((a)<0.0f)?-(a):(a))
690
691enum {
692 _SAPP_MAX_TITLE_LENGTH = 128,
693};
694
695typedef struct {
696 bool valid;
697 int window_width;
698 int window_height;
699 int framebuffer_width;
700 int framebuffer_height;
701 int sample_count;
702 int swap_interval;
703 float dpi_scale;
704 bool gles2_fallback;
705 bool first_frame;
706 bool init_called;
707 bool html5_canvas_resize;
708 const char* html5_canvas_name;
709 char window_title[_SAPP_MAX_TITLE_LENGTH]; /* UTF-8 */
710 wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; /* UTF-32 or UCS-2 */
711 uint32_t frame_count;
712 float mouse_x;
713 float mouse_y;
714 bool win32_mouse_tracked;
715 bool onscreen_keyboard_shown;
716 sapp_event event;
717 sapp_desc desc;
718 int argc;
719 char** argv;
720 sapp_keycode keycodes[SAPP_MAX_KEYCODES];
721} _sapp_state;
722static _sapp_state _sapp;
723
724_SOKOL_PRIVATE void _sapp_fail(const char* msg) {
725 if (_sapp.desc.fail_cb) {
726 _sapp.desc.fail_cb(msg);
727 }
728 else {
729 SOKOL_LOG(msg);
730 }
731 SOKOL_ABORT();
732}
733
734_SOKOL_PRIVATE void _sapp_strcpy(const char* src, char* dst, int max_len) {
735 SOKOL_ASSERT(src && dst && (max_len > 0));
736 char* const end = &(dst[max_len-1]);
737 char c = 0;
738 for (int i = 0; i < max_len; i++) {
739 c = *src;
740 if (c != 0) {
741 src++;
742 }
743 *dst++ = c;
744 }
745 /* truncated? */
746 if (c != 0) {
747 *end = 0;
748 }
749}
750
751_SOKOL_PRIVATE void _sapp_init_state(sapp_desc* desc, int argc, char* argv[]) {
752 SOKOL_ASSERT(desc->init_cb);
753 SOKOL_ASSERT(desc->frame_cb);
754 SOKOL_ASSERT(desc->cleanup_cb);
755 memset(&_sapp, 0, sizeof(_sapp));
756 _sapp.argc = argc;
757 _sapp.argv = argv;
758 _sapp.desc = *desc;
759 _sapp.first_frame = true;
760 _sapp.window_width = _sapp_def(_sapp.desc.width, 640);
761 _sapp.window_height = _sapp_def(_sapp.desc.height, 480);
762 _sapp.framebuffer_width = _sapp.window_width;
763 _sapp.framebuffer_height = _sapp.window_height;
764 _sapp.sample_count = _sapp_def(_sapp.desc.sample_count, 1);
765 _sapp.swap_interval = _sapp_def(_sapp.desc.swap_interval, 1);
766 _sapp.html5_canvas_name = _sapp_def(_sapp.desc.html5_canvas_name, "#canvas");
767 _sapp.html5_canvas_resize = _sapp.desc.html5_canvas_resize;
768 if (_sapp.desc.window_title) {
769 _sapp_strcpy(_sapp.desc.window_title, _sapp.window_title, sizeof(_sapp.window_title));
770 }
771 else {
772 _sapp_strcpy("sokol_app", _sapp.window_title, sizeof(_sapp.window_title));
773 }
774 _sapp.dpi_scale = 1.0f;
775}
776
777_SOKOL_PRIVATE void _sapp_init_event(sapp_event_type type) {
778 memset(&_sapp.event, 0, sizeof(_sapp.event));
779 _sapp.event.type = type;
780 _sapp.event.frame_count = _sapp.frame_count;
781 _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID;
782 _sapp.event.window_width = _sapp.window_width;
783 _sapp.event.window_height = _sapp.window_height;
784 _sapp.event.framebuffer_width = _sapp.framebuffer_width;
785 _sapp.event.framebuffer_height = _sapp.framebuffer_height;
786}
787
788_SOKOL_PRIVATE bool _sapp_events_enabled(void) {
789 /* only send events when an event callback is set, and the init function was called */
790 return _sapp.desc.event_cb && _sapp.init_called;
791}
792
793_SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) {
794 if ((scan_code >= 0) && (scan_code < SAPP_MAX_KEYCODES)) {
795 return _sapp.keycodes[scan_code];
796 }
797 else {
798 return SAPP_KEYCODE_INVALID;
799 }
800}
801
802_SOKOL_PRIVATE void _sapp_frame(void) {
803 if (_sapp.first_frame) {
804 _sapp.first_frame = false;
805 _sapp.desc.init_cb();
806 _sapp.init_called = true;
807 }
808 _sapp.desc.frame_cb();
809 _sapp.frame_count++;
810}
811
812/*== MacOS/iOS ===============================================================*/
813
814#if defined(__APPLE__)
815
816/*== MacOS ===================================================================*/
817#if !TARGET_OS_IPHONE
818#import <Metal/Metal.h>
819#import <MetalKit/MetalKit.h>
820
821@interface _sapp_macos_app_delegate : NSObject<NSApplicationDelegate>
822@end
823@interface _sapp_macos_window_delegate : NSObject<NSWindowDelegate>
824@end
825@interface _sapp_macos_mtk_view_dlg : NSObject<MTKViewDelegate>
826@end
827@interface _sapp_macos_view : MTKView
828{
829 NSTrackingArea* trackingArea;
830}
831@end
832
833static NSWindow* _sapp_macos_window_obj;
834static _sapp_macos_window_delegate* _sapp_macos_win_dlg_obj;
835static _sapp_macos_app_delegate* _sapp_macos_app_dlg_obj;
836static _sapp_macos_view* _sapp_view_obj;
837static _sapp_macos_mtk_view_dlg* _sapp_macos_mtk_view_dlg_obj;
838static id<MTLDevice> _sapp_mtl_device_obj;
839static uint32_t _sapp_macos_flags_changed_store;
840
841_SOKOL_PRIVATE void _sapp_macos_init_keytable(void) {
842 _sapp.keycodes[0x1D] = SAPP_KEYCODE_0;
843 _sapp.keycodes[0x12] = SAPP_KEYCODE_1;
844 _sapp.keycodes[0x13] = SAPP_KEYCODE_2;
845 _sapp.keycodes[0x14] = SAPP_KEYCODE_3;
846 _sapp.keycodes[0x15] = SAPP_KEYCODE_4;
847 _sapp.keycodes[0x17] = SAPP_KEYCODE_5;
848 _sapp.keycodes[0x16] = SAPP_KEYCODE_6;
849 _sapp.keycodes[0x1A] = SAPP_KEYCODE_7;
850 _sapp.keycodes[0x1C] = SAPP_KEYCODE_8;
851 _sapp.keycodes[0x19] = SAPP_KEYCODE_9;
852 _sapp.keycodes[0x00] = SAPP_KEYCODE_A;
853 _sapp.keycodes[0x0B] = SAPP_KEYCODE_B;
854 _sapp.keycodes[0x08] = SAPP_KEYCODE_C;
855 _sapp.keycodes[0x02] = SAPP_KEYCODE_D;
856 _sapp.keycodes[0x0E] = SAPP_KEYCODE_E;
857 _sapp.keycodes[0x03] = SAPP_KEYCODE_F;
858 _sapp.keycodes[0x05] = SAPP_KEYCODE_G;
859 _sapp.keycodes[0x04] = SAPP_KEYCODE_H;
860 _sapp.keycodes[0x22] = SAPP_KEYCODE_I;
861 _sapp.keycodes[0x26] = SAPP_KEYCODE_J;
862 _sapp.keycodes[0x28] = SAPP_KEYCODE_K;
863 _sapp.keycodes[0x25] = SAPP_KEYCODE_L;
864 _sapp.keycodes[0x2E] = SAPP_KEYCODE_M;
865 _sapp.keycodes[0x2D] = SAPP_KEYCODE_N;
866 _sapp.keycodes[0x1F] = SAPP_KEYCODE_O;
867 _sapp.keycodes[0x23] = SAPP_KEYCODE_P;
868 _sapp.keycodes[0x0C] = SAPP_KEYCODE_Q;
869 _sapp.keycodes[0x0F] = SAPP_KEYCODE_R;
870 _sapp.keycodes[0x01] = SAPP_KEYCODE_S;
871 _sapp.keycodes[0x11] = SAPP_KEYCODE_T;
872 _sapp.keycodes[0x20] = SAPP_KEYCODE_U;
873 _sapp.keycodes[0x09] = SAPP_KEYCODE_V;
874 _sapp.keycodes[0x0D] = SAPP_KEYCODE_W;
875 _sapp.keycodes[0x07] = SAPP_KEYCODE_X;
876 _sapp.keycodes[0x10] = SAPP_KEYCODE_Y;
877 _sapp.keycodes[0x06] = SAPP_KEYCODE_Z;
878 _sapp.keycodes[0x27] = SAPP_KEYCODE_APOSTROPHE;
879 _sapp.keycodes[0x2A] = SAPP_KEYCODE_BACKSLASH;
880 _sapp.keycodes[0x2B] = SAPP_KEYCODE_COMMA;
881 _sapp.keycodes[0x18] = SAPP_KEYCODE_EQUAL;
882 _sapp.keycodes[0x32] = SAPP_KEYCODE_GRAVE_ACCENT;
883 _sapp.keycodes[0x21] = SAPP_KEYCODE_LEFT_BRACKET;
884 _sapp.keycodes[0x1B] = SAPP_KEYCODE_MINUS;
885 _sapp.keycodes[0x2F] = SAPP_KEYCODE_PERIOD;
886 _sapp.keycodes[0x1E] = SAPP_KEYCODE_RIGHT_BRACKET;
887 _sapp.keycodes[0x29] = SAPP_KEYCODE_SEMICOLON;
888 _sapp.keycodes[0x2C] = SAPP_KEYCODE_SLASH;
889 _sapp.keycodes[0x0A] = SAPP_KEYCODE_WORLD_1;
890 _sapp.keycodes[0x33] = SAPP_KEYCODE_BACKSPACE;
891 _sapp.keycodes[0x39] = SAPP_KEYCODE_CAPS_LOCK;
892 _sapp.keycodes[0x75] = SAPP_KEYCODE_DELETE;
893 _sapp.keycodes[0x7D] = SAPP_KEYCODE_DOWN;
894 _sapp.keycodes[0x77] = SAPP_KEYCODE_END;
895 _sapp.keycodes[0x24] = SAPP_KEYCODE_ENTER;
896 _sapp.keycodes[0x35] = SAPP_KEYCODE_ESCAPE;
897 _sapp.keycodes[0x7A] = SAPP_KEYCODE_F1;
898 _sapp.keycodes[0x78] = SAPP_KEYCODE_F2;
899 _sapp.keycodes[0x63] = SAPP_KEYCODE_F3;
900 _sapp.keycodes[0x76] = SAPP_KEYCODE_F4;
901 _sapp.keycodes[0x60] = SAPP_KEYCODE_F5;
902 _sapp.keycodes[0x61] = SAPP_KEYCODE_F6;
903 _sapp.keycodes[0x62] = SAPP_KEYCODE_F7;
904 _sapp.keycodes[0x64] = SAPP_KEYCODE_F8;
905 _sapp.keycodes[0x65] = SAPP_KEYCODE_F9;
906 _sapp.keycodes[0x6D] = SAPP_KEYCODE_F10;
907 _sapp.keycodes[0x67] = SAPP_KEYCODE_F11;
908 _sapp.keycodes[0x6F] = SAPP_KEYCODE_F12;
909 _sapp.keycodes[0x69] = SAPP_KEYCODE_F13;
910 _sapp.keycodes[0x6B] = SAPP_KEYCODE_F14;
911 _sapp.keycodes[0x71] = SAPP_KEYCODE_F15;
912 _sapp.keycodes[0x6A] = SAPP_KEYCODE_F16;
913 _sapp.keycodes[0x40] = SAPP_KEYCODE_F17;
914 _sapp.keycodes[0x4F] = SAPP_KEYCODE_F18;
915 _sapp.keycodes[0x50] = SAPP_KEYCODE_F19;
916 _sapp.keycodes[0x5A] = SAPP_KEYCODE_F20;
917 _sapp.keycodes[0x73] = SAPP_KEYCODE_HOME;
918 _sapp.keycodes[0x72] = SAPP_KEYCODE_INSERT;
919 _sapp.keycodes[0x7B] = SAPP_KEYCODE_LEFT;
920 _sapp.keycodes[0x3A] = SAPP_KEYCODE_LEFT_ALT;
921 _sapp.keycodes[0x3B] = SAPP_KEYCODE_LEFT_CONTROL;
922 _sapp.keycodes[0x38] = SAPP_KEYCODE_LEFT_SHIFT;
923 _sapp.keycodes[0x37] = SAPP_KEYCODE_LEFT_SUPER;
924 _sapp.keycodes[0x6E] = SAPP_KEYCODE_MENU;
925 _sapp.keycodes[0x47] = SAPP_KEYCODE_NUM_LOCK;
926 _sapp.keycodes[0x79] = SAPP_KEYCODE_PAGE_DOWN;
927 _sapp.keycodes[0x74] = SAPP_KEYCODE_PAGE_UP;
928 _sapp.keycodes[0x7C] = SAPP_KEYCODE_RIGHT;
929 _sapp.keycodes[0x3D] = SAPP_KEYCODE_RIGHT_ALT;
930 _sapp.keycodes[0x3E] = SAPP_KEYCODE_RIGHT_CONTROL;
931 _sapp.keycodes[0x3C] = SAPP_KEYCODE_RIGHT_SHIFT;
932 _sapp.keycodes[0x36] = SAPP_KEYCODE_RIGHT_SUPER;
933 _sapp.keycodes[0x31] = SAPP_KEYCODE_SPACE;
934 _sapp.keycodes[0x30] = SAPP_KEYCODE_TAB;
935 _sapp.keycodes[0x7E] = SAPP_KEYCODE_UP;
936 _sapp.keycodes[0x52] = SAPP_KEYCODE_KP_0;
937 _sapp.keycodes[0x53] = SAPP_KEYCODE_KP_1;
938 _sapp.keycodes[0x54] = SAPP_KEYCODE_KP_2;
939 _sapp.keycodes[0x55] = SAPP_KEYCODE_KP_3;
940 _sapp.keycodes[0x56] = SAPP_KEYCODE_KP_4;
941 _sapp.keycodes[0x57] = SAPP_KEYCODE_KP_5;
942 _sapp.keycodes[0x58] = SAPP_KEYCODE_KP_6;
943 _sapp.keycodes[0x59] = SAPP_KEYCODE_KP_7;
944 _sapp.keycodes[0x5B] = SAPP_KEYCODE_KP_8;
945 _sapp.keycodes[0x5C] = SAPP_KEYCODE_KP_9;
946 _sapp.keycodes[0x45] = SAPP_KEYCODE_KP_ADD;
947 _sapp.keycodes[0x41] = SAPP_KEYCODE_KP_DECIMAL;
948 _sapp.keycodes[0x4B] = SAPP_KEYCODE_KP_DIVIDE;
949 _sapp.keycodes[0x4C] = SAPP_KEYCODE_KP_ENTER;
950 _sapp.keycodes[0x51] = SAPP_KEYCODE_KP_EQUAL;
951 _sapp.keycodes[0x43] = SAPP_KEYCODE_KP_MULTIPLY;
952 _sapp.keycodes[0x4E] = SAPP_KEYCODE_KP_SUBTRACT;
953}
954
955/* MacOS entry function */
956int main(int argc, char* argv[]) {
957 sapp_desc desc = sokol_main(argc, argv);
958 _sapp_init_state(&desc, argc, argv);
959 _sapp_macos_init_keytable();
960 [NSApplication sharedApplication];
961 NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
962 _sapp_macos_app_dlg_obj = [[_sapp_macos_app_delegate alloc] init];
963 NSApp.delegate = _sapp_macos_app_dlg_obj;
964 [NSApp activateIgnoringOtherApps:YES];
965 [NSApp run];
966 return 0;
967}
968
969_SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) {
970 const CGSize fb_size = [_sapp_view_obj drawableSize];
971 _sapp.framebuffer_width = fb_size.width;
972 _sapp.framebuffer_height = fb_size.height;
973 const NSRect bounds = [_sapp_view_obj bounds];
974 _sapp.window_width = bounds.size.width;
975 _sapp.window_height = bounds.size.height;
976 SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0));
977 _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width;
978}
979
980_SOKOL_PRIVATE void _sapp_macos_frame(void) {
981 const NSPoint mouse_pos = [_sapp_macos_window_obj mouseLocationOutsideOfEventStream];
982 _sapp.mouse_x = mouse_pos.x * _sapp.dpi_scale;
983 _sapp.mouse_y = _sapp.framebuffer_height - (mouse_pos.y * _sapp.dpi_scale) - 1;
984 _sapp_frame();
985}
986
987@implementation _sapp_macos_app_delegate
988- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
989 if (_sapp.desc.fullscreen) {
990 NSRect screen_rect = NSScreen.mainScreen.frame;
991 _sapp.window_width = screen_rect.size.width;
992 _sapp.window_height = screen_rect.size.height;
993 if (_sapp.desc.high_dpi) {
994 _sapp.framebuffer_width = 2 * _sapp.window_width;
995 _sapp.framebuffer_height = 2 * _sapp.window_height;
996 }
997 else {
998 _sapp.framebuffer_width = _sapp.window_width;
999 _sapp.framebuffer_height = _sapp.window_height;
1000 }
1001 _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width;
1002 }
1003 const NSUInteger style =
1004 NSWindowStyleMaskTitled |
1005 NSWindowStyleMaskClosable |
1006 NSWindowStyleMaskMiniaturizable |
1007 NSWindowStyleMaskResizable;
1008 _sapp_macos_window_obj = [[NSWindow alloc]
1009 initWithContentRect:NSMakeRect(0, 0, _sapp.window_width, _sapp.window_height)
1010 styleMask:style
1011 backing:NSBackingStoreBuffered
1012 defer:NO];
1013 _sapp_macos_window_obj.title = [NSString stringWithUTF8String:_sapp.window_title];
1014 _sapp_macos_window_obj.acceptsMouseMovedEvents = YES;
1015 _sapp_macos_window_obj.restorable = YES;
1016 _sapp_macos_win_dlg_obj = [[_sapp_macos_window_delegate alloc] init];
1017 _sapp_macos_window_obj.delegate = _sapp_macos_win_dlg_obj;
1018 _sapp_mtl_device_obj = MTLCreateSystemDefaultDevice();
1019 _sapp_macos_mtk_view_dlg_obj = [[_sapp_macos_mtk_view_dlg alloc] init];
1020 _sapp_view_obj = [[_sapp_macos_view alloc] init];
1021 [_sapp_view_obj updateTrackingAreas];
1022 _sapp_view_obj.preferredFramesPerSecond = 60 / _sapp.swap_interval;
1023 _sapp_view_obj.delegate = _sapp_macos_mtk_view_dlg_obj;
1024 _sapp_view_obj.device = _sapp_mtl_device_obj;
1025 _sapp_view_obj.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
1026 _sapp_view_obj.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
1027 _sapp_view_obj.sampleCount = _sapp.sample_count;
1028 _sapp_macos_window_obj.contentView = _sapp_view_obj;
1029 [_sapp_macos_window_obj makeFirstResponder:_sapp_view_obj];
1030 if (!_sapp.desc.high_dpi) {
1031 CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height };
1032 _sapp_view_obj.drawableSize = drawable_size;
1033 }
1034 _sapp_macos_update_dimensions();
1035 _sapp_view_obj.layer.magnificationFilter = kCAFilterNearest;
1036 if (_sapp.desc.fullscreen) {
1037 [_sapp_macos_window_obj toggleFullScreen:self];
1038 }
1039 else {
1040 [_sapp_macos_window_obj center];
1041 }
1042 [_sapp_macos_window_obj makeKeyAndOrderFront:nil];
1043 _sapp.valid = true;
1044}
1045
1046- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender {
1047 return YES;
1048}
1049@end
1050
1051_SOKOL_PRIVATE uint32_t _sapp_macos_mod(NSEventModifierFlags f) {
1052 uint32_t m = 0;
1053 if (f & NSEventModifierFlagShift) {
1054 m |= SAPP_MODIFIER_SHIFT;
1055 }
1056 if (f & NSEventModifierFlagControl) {
1057 m |= SAPP_MODIFIER_CTRL;
1058 }
1059 if (f & NSEventModifierFlagOption) {
1060 m |= SAPP_MODIFIER_ALT;
1061 }
1062 if (f & NSEventModifierFlagCommand) {
1063 m |= SAPP_MODIFIER_SUPER;
1064 }
1065 return m;
1066}
1067
1068_SOKOL_PRIVATE void _sapp_macos_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mod) {
1069 if (_sapp_events_enabled()) {
1070 _sapp_init_event(type);
1071 _sapp.event.mouse_button = btn;
1072 _sapp.event.modifiers = mod;
1073 _sapp.event.mouse_x = _sapp.mouse_x;
1074 _sapp.event.mouse_y = _sapp.mouse_y;
1075 _sapp.desc.event_cb(&_sapp.event);
1076 }
1077}
1078
1079_SOKOL_PRIVATE void _sapp_macos_key_event(sapp_event_type type, sapp_keycode key, uint32_t mod) {
1080 if (_sapp_events_enabled()) {
1081 _sapp_init_event(type);
1082 _sapp.event.key_code = key;
1083 _sapp.event.modifiers = mod;
1084 _sapp.desc.event_cb(&_sapp.event);
1085 }
1086}
1087
1088_SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) {
1089 if (_sapp_events_enabled()) {
1090 _sapp_init_event(type);
1091 _sapp.desc.event_cb(&_sapp.event);
1092 }
1093}
1094
1095@implementation _sapp_macos_window_delegate
1096- (BOOL)windowShouldClose:(id)sender {
1097 _sapp.desc.cleanup_cb();
1098 return YES;
1099}
1100
1101- (void)windowDidResize:(NSNotification*)notification {
1102 _sapp_macos_update_dimensions();
1103 _sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED);
1104}
1105
1106- (void)windowDidMiniaturize:(NSNotification*)notification {
1107 _sapp_macos_app_event(SAPP_EVENTTYPE_ICONIFIED);
1108}
1109
1110- (void)windowDidDeminiaturize:(NSNotification*)notification {
1111 _sapp_macos_app_event(SAPP_EVENTTYPE_RESTORED);
1112}
1113@end
1114
1115@implementation _sapp_macos_mtk_view_dlg
1116- (void)drawInMTKView:(MTKView*)view {
1117 @autoreleasepool {
1118 _sapp_macos_frame();
1119 }
1120}
1121- (void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size {
1122 /* this is required by the protocol, but we can't do anything useful here */
1123}
1124@end
1125
1126@implementation _sapp_macos_view
1127- (BOOL)isOpaque {
1128 return YES;
1129}
1130- (BOOL)canBecomeKey {
1131 return YES;
1132}
1133- (BOOL)acceptsFirstResponder {
1134 return YES;
1135}
1136- (void)updateTrackingAreas {
1137 if (trackingArea != nil) {
1138 [self removeTrackingArea:trackingArea];
1139 trackingArea = nil;
1140 }
1141 const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
1142 NSTrackingActiveInKeyWindow |
1143 NSTrackingEnabledDuringMouseDrag |
1144 NSTrackingCursorUpdate |
1145 NSTrackingInVisibleRect |
1146 NSTrackingAssumeInside;
1147 trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil];
1148 [self addTrackingArea:trackingArea];
1149 [super updateTrackingAreas];
1150}
1151- (void)mouseEntered:(NSEvent*)event {
1152 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags));
1153}
1154- (void)mouseExited:(NSEvent*)event {
1155 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags));
1156}
1157- (void)mouseDown:(NSEvent*)event {
1158 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags));
1159}
1160- (void)mouseUp:(NSEvent*)event {
1161 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags));
1162}
1163- (void)rightMouseDown:(NSEvent*)event {
1164 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_RIGHT, _sapp_macos_mod(event.modifierFlags));
1165}
1166- (void)rightMouseUp:(NSEvent*)event {
1167 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_RIGHT, _sapp_macos_mod(event.modifierFlags));
1168}
1169- (void)mouseMoved:(NSEvent*)event {
1170 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags));
1171}
1172- (void)mouseDragged:(NSEvent*)event {
1173 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags));
1174}
1175- (void)rightMouseDragged:(NSEvent*)event {
1176 _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags));
1177}
1178- (void)scrollWheel:(NSEvent*)event {
1179 if (_sapp_events_enabled()) {
1180 float dx = (float) event.scrollingDeltaX;
1181 float dy = (float) event.scrollingDeltaY;
1182 if (event.hasPreciseScrollingDeltas) {
1183 dx *= 0.1;
1184 dy *= 0.1;
1185 }
1186 if ((_sapp_absf(dx) > 0.0f) || (_sapp_absf(dy) > 0.0f)) {
1187 _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
1188 _sapp.event.modifiers = _sapp_macos_mod(event.modifierFlags);
1189 _sapp.event.mouse_x = _sapp.mouse_x;
1190 _sapp.event.mouse_y = _sapp.mouse_y;
1191 _sapp.event.scroll_x = dx;
1192 _sapp.event.scroll_y = dy;
1193 _sapp.desc.event_cb(&_sapp.event);
1194 }
1195 }
1196}
1197- (void)keyDown:(NSEvent*)event {
1198 if (_sapp_events_enabled()) {
1199 const uint32_t mods = _sapp_macos_mod(event.modifierFlags);
1200 _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_DOWN, _sapp_translate_key(event.keyCode), mods);
1201 const NSString* chars = event.characters;
1202 const NSUInteger len = chars.length;
1203 if (len > 0) {
1204 _sapp_init_event(SAPP_EVENTTYPE_CHAR);
1205 _sapp.event.modifiers = mods;
1206 for (NSUInteger i = 0; i < len; i++) {
1207 const unichar codepoint = [chars characterAtIndex:i];
1208 if ((codepoint & 0xFF00) == 0xF700) {
1209 continue;
1210 }
1211 _sapp.event.char_code = codepoint;
1212 _sapp.desc.event_cb(&_sapp.event);
1213 }
1214 }
1215 }
1216}
1217- (void)keyUp:(NSEvent*)event {
1218 _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_UP,
1219 _sapp_translate_key(event.keyCode),
1220 _sapp_macos_mod(event.modifierFlags));
1221}
1222- (void)flagsChanged:(NSEvent*)event {
1223 const uint32_t old_f = _sapp_macos_flags_changed_store;
1224 const uint32_t new_f = event.modifierFlags;
1225 _sapp_macos_flags_changed_store = new_f;
1226 sapp_keycode key_code = SAPP_KEYCODE_INVALID;
1227 bool down = false;
1228 if ((new_f ^ old_f) & NSEventModifierFlagShift) {
1229 key_code = SAPP_KEYCODE_LEFT_SHIFT;
1230 down = 0 != (new_f & NSEventModifierFlagShift);
1231 }
1232 if ((new_f ^ old_f) & NSEventModifierFlagControl) {
1233 key_code = SAPP_KEYCODE_LEFT_CONTROL;
1234 down = 0 != (new_f & NSEventModifierFlagControl);
1235 }
1236 if ((new_f ^ old_f) & NSEventModifierFlagOption) {
1237 key_code = SAPP_KEYCODE_LEFT_ALT;
1238 down = 0 != (new_f & NSEventModifierFlagOption);
1239 }
1240 if ((new_f ^ old_f) & NSEventModifierFlagCommand) {
1241 key_code = SAPP_KEYCODE_LEFT_SUPER;
1242 down = 0 != (new_f & NSEventModifierFlagCommand);
1243 }
1244 if (key_code != SAPP_KEYCODE_INVALID) {
1245 _sapp_macos_key_event(down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP,
1246 key_code,
1247 _sapp_macos_mod(event.modifierFlags));
1248 }
1249}
1250- (void)cursorUpdate:(NSEvent*)event {
1251 if (_sapp.desc.user_cursor) {
1252 _sapp_macos_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR);
1253 }
1254}
1255@end
1256
1257#endif /* MacOS */
1258
1259/*== iOS =====================================================================*/
1260#if TARGET_OS_IPHONE
1261#import <UIKit/UIKit.h>
1262#if defined(SOKOL_METAL)
1263#import <Metal/Metal.h>
1264#import <MetalKit/MetalKit.h>
1265#else
1266#import <GLKit/GLKit.h>
1267#include <OpenGLES/ES3/gl.h>
1268#include <OpenGLES/ES3/glext.h>
1269#endif
1270
1271@interface _sapp_app_delegate : NSObject<UIApplicationDelegate>
1272@end
1273@interface _sapp_textfield_dlg : NSObject<UITextFieldDelegate>
1274- (void)keyboardWasShown:(NSNotification*)notif;
1275- (void)keyboardWillBeHidden:(NSNotification*)notif;
1276- (void)keyboardDidChangeFrame:(NSNotification*)notif;
1277@end
1278#if defined(SOKOL_METAL)
1279@interface _sapp_ios_mtk_view_dlg : NSObject<MTKViewDelegate>
1280@end
1281@interface _sapp_ios_view : MTKView;
1282@end
1283#else
1284@interface _sapp_ios_glk_view_dlg : NSObject<GLKViewDelegate>
1285@end
1286@interface _sapp_ios_view : GLKView
1287@end
1288#endif
1289
1290static bool _sapp_ios_suspended;
1291static UIWindow* _sapp_ios_window_obj;
1292static _sapp_ios_view* _sapp_view_obj;
1293static UITextField* _sapp_ios_textfield_obj;
1294static _sapp_textfield_dlg* _sapp_ios_textfield_dlg_obj;
1295#if defined(SOKOL_METAL)
1296static _sapp_ios_mtk_view_dlg* _sapp_ios_mtk_view_dlg_obj;
1297static UIViewController<MTKViewDelegate>* _sapp_ios_view_ctrl_obj;
1298static id<MTLDevice> _sapp_mtl_device_obj;
1299#else
1300static EAGLContext* _sapp_ios_eagl_ctx_obj;
1301static _sapp_ios_glk_view_dlg* _sapp_ios_glk_view_dlg_obj;
1302static GLKViewController* _sapp_ios_view_ctrl_obj;
1303#endif
1304
1305/* iOS entry function */
1306int main(int argc, char** argv) {
1307 @autoreleasepool {
1308 sapp_desc desc = sokol_main(argc, argv);
1309 _sapp_init_state(&desc, argc, argv);
1310 UIApplicationMain(argc, argv, nil, NSStringFromClass([_sapp_app_delegate class]));
1311 }
1312 return 0;
1313}
1314
1315_SOKOL_PRIVATE void _sapp_ios_app_event(sapp_event_type type) {
1316 if (_sapp_events_enabled()) {
1317 _sapp_init_event(type);
1318 _sapp.desc.event_cb(&_sapp.event);
1319 }
1320}
1321
1322_SOKOL_PRIVATE void _sapp_ios_update_dimensions(void) {
1323 CGRect screen_rect = UIScreen.mainScreen.bounds;
1324 _sapp.window_width = (int) screen_rect.size.width;
1325 _sapp.window_height = (int) screen_rect.size.height;
1326 int cur_fb_width, cur_fb_height;
1327 #if defined(SOKOL_METAL)
1328 const CGSize fb_size = _sapp_view_obj.drawableSize;
1329 cur_fb_width = (int) fb_size.width;
1330 cur_fb_height = (int) fb_size.height;
1331 #else
1332 cur_fb_width = (int) _sapp_view_obj.drawableWidth;
1333 cur_fb_height = (int) _sapp_view_obj.drawableHeight;
1334 #endif
1335 const bool dim_changed =
1336 (_sapp.framebuffer_width != cur_fb_width) ||
1337 (_sapp.framebuffer_height != cur_fb_height);
1338 _sapp.framebuffer_width = cur_fb_width;
1339 _sapp.framebuffer_height = cur_fb_height;
1340 SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0));
1341 _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width;
1342 if (dim_changed) {
1343 _sapp_ios_app_event(SAPP_EVENTTYPE_RESIZED);
1344 }
1345}
1346
1347_SOKOL_PRIVATE void _sapp_ios_frame(void) {
1348 _sapp_ios_update_dimensions();
1349 _sapp_frame();
1350}
1351
1352_SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
1353 /* if not happened yet, create an invisible text field */
1354 if (nil == _sapp_ios_textfield_obj) {
1355 _sapp_ios_textfield_dlg_obj = [[_sapp_textfield_dlg alloc] init];
1356 _sapp_ios_textfield_obj = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 100, 50)];
1357 _sapp_ios_textfield_obj.keyboardType = UIKeyboardTypeDefault;
1358 _sapp_ios_textfield_obj.returnKeyType = UIReturnKeyDefault;
1359 _sapp_ios_textfield_obj.autocapitalizationType = UITextAutocapitalizationTypeNone;
1360 _sapp_ios_textfield_obj.autocorrectionType = UITextAutocorrectionTypeNo;
1361 _sapp_ios_textfield_obj.spellCheckingType = UITextSpellCheckingTypeNo;
1362 _sapp_ios_textfield_obj.hidden = YES;
1363 _sapp_ios_textfield_obj.text = @"x";
1364 _sapp_ios_textfield_obj.delegate = _sapp_ios_textfield_dlg_obj;
1365 [_sapp_ios_view_ctrl_obj.view addSubview:_sapp_ios_textfield_obj];
1366
1367 [[NSNotificationCenter defaultCenter] addObserver:_sapp_ios_textfield_dlg_obj
1368 selector:@selector(keyboardWasShown:)
1369 name:UIKeyboardDidShowNotification object:nil];
1370 [[NSNotificationCenter defaultCenter] addObserver:_sapp_ios_textfield_dlg_obj
1371 selector:@selector(keyboardWillBeHidden:)
1372 name:UIKeyboardWillHideNotification object:nil];
1373 [[NSNotificationCenter defaultCenter] addObserver:_sapp_ios_textfield_dlg_obj
1374 selector:@selector(keyboardDidChangeFrame:)
1375 name:UIKeyboardDidChangeFrameNotification object:nil];
1376 }
1377 if (shown) {
1378 /* setting the text field as first responder brings up the onscreen keyboard */
1379 [_sapp_ios_textfield_obj becomeFirstResponder];
1380 }
1381 else {
1382 [_sapp_ios_textfield_obj resignFirstResponder];
1383 }
1384}
1385
1386@implementation _sapp_app_delegate
1387- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
1388 CGRect screen_rect = UIScreen.mainScreen.bounds;
1389 _sapp_ios_window_obj = [[UIWindow alloc] initWithFrame:screen_rect];
1390 _sapp.window_width = screen_rect.size.width;
1391 _sapp.window_height = screen_rect.size.height;
1392 if (_sapp.desc.high_dpi) {
1393 _sapp.framebuffer_width = 2 * _sapp.window_width;
1394 _sapp.framebuffer_height = 2 * _sapp.window_height;
1395 }
1396 else {
1397 _sapp.framebuffer_width = _sapp.window_width;
1398 _sapp.framebuffer_height = _sapp.window_height;
1399 }
1400 _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width;
1401 #if defined(SOKOL_METAL)
1402 _sapp_mtl_device_obj = MTLCreateSystemDefaultDevice();
1403 _sapp_ios_mtk_view_dlg_obj = [[_sapp_ios_mtk_view_dlg alloc] init];
1404 _sapp_view_obj = [[_sapp_ios_view alloc] init];
1405 _sapp_view_obj.preferredFramesPerSecond = 60 / _sapp.swap_interval;
1406 _sapp_view_obj.delegate = _sapp_ios_mtk_view_dlg_obj;
1407 _sapp_view_obj.device = _sapp_mtl_device_obj;
1408 _sapp_view_obj.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
1409 _sapp_view_obj.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
1410 _sapp_view_obj.sampleCount = _sapp.sample_count;
1411 if (_sapp.desc.high_dpi) {
1412 _sapp_view_obj.contentScaleFactor = 2.0;
1413 }
1414 else {
1415 _sapp_view_obj.contentScaleFactor = 1.0;
1416 }
1417 _sapp_view_obj.userInteractionEnabled = YES;
1418 _sapp_view_obj.multipleTouchEnabled = YES;
1419 [_sapp_ios_window_obj addSubview:_sapp_view_obj];
1420 _sapp_ios_view_ctrl_obj = [[UIViewController<MTKViewDelegate> alloc] init];
1421 _sapp_ios_view_ctrl_obj.view = _sapp_view_obj;
1422 _sapp_ios_window_obj.rootViewController = _sapp_ios_view_ctrl_obj;
1423 #else
1424 if (_sapp.desc.gl_force_gles2) {
1425 _sapp_ios_eagl_ctx_obj = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
1426 _sapp.gles2_fallback = true;
1427 }
1428 else {
1429 _sapp_ios_eagl_ctx_obj = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
1430 if (_sapp_ios_eagl_ctx_obj == nil) {
1431 _sapp_ios_eagl_ctx_obj = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
1432 _sapp.gles2_fallback = true;
1433 }
1434 }
1435 _sapp_ios_glk_view_dlg_obj = [[_sapp_ios_glk_view_dlg alloc] init];
1436 _sapp_view_obj = [[_sapp_ios_view alloc] initWithFrame:screen_rect];
1437 _sapp_view_obj.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
1438 _sapp_view_obj.drawableDepthFormat = GLKViewDrawableDepthFormat24;
1439 _sapp_view_obj.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
1440 _sapp_view_obj.drawableMultisample = GLKViewDrawableMultisampleNone; /* FIXME */
1441 _sapp_view_obj.context = _sapp_ios_eagl_ctx_obj;
1442 _sapp_view_obj.delegate = _sapp_ios_glk_view_dlg_obj;
1443 _sapp_view_obj.enableSetNeedsDisplay = NO;
1444 _sapp_view_obj.userInteractionEnabled = YES;
1445 _sapp_view_obj.multipleTouchEnabled = YES;
1446 if (_sapp.desc.high_dpi) {
1447 _sapp_view_obj.contentScaleFactor = 2.0;
1448 }
1449 else {
1450 _sapp_view_obj.contentScaleFactor = 1.0;
1451 }
1452 [_sapp_ios_window_obj addSubview:_sapp_view_obj];
1453 _sapp_ios_view_ctrl_obj = [[GLKViewController alloc] init];
1454 _sapp_ios_view_ctrl_obj.view = _sapp_view_obj;
1455 _sapp_ios_view_ctrl_obj.preferredFramesPerSecond = 60 / _sapp.swap_interval;
1456 _sapp_ios_window_obj.rootViewController = _sapp_ios_view_ctrl_obj;
1457 #endif
1458 [_sapp_ios_window_obj makeKeyAndVisible];
1459
1460 _sapp.valid = true;
1461 return YES;
1462}
1463
1464- (void)applicationWillResignActive:(UIApplication *)application {
1465 if (!_sapp_ios_suspended) {
1466 _sapp_ios_suspended = true;
1467 _sapp_ios_app_event(SAPP_EVENTTYPE_SUSPENDED);
1468 }
1469}
1470
1471- (void)applicationDidBecomeActive:(UIApplication *)application {
1472 if (_sapp_ios_suspended) {
1473 _sapp_ios_suspended = false;
1474 _sapp_ios_app_event(SAPP_EVENTTYPE_RESUMED);
1475 }
1476}
1477@end
1478
1479@implementation _sapp_textfield_dlg
1480- (void)keyboardWasShown:(NSNotification*)notif {
1481 _sapp.onscreen_keyboard_shown = true;
1482 /* query the keyboard's size, and modify the content view's size */
1483 if (_sapp.desc.ios_keyboard_resizes_canvas) {
1484 NSDictionary* info = notif.userInfo;
1485 CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
1486 CGRect view_frame = UIScreen.mainScreen.bounds;
1487 view_frame.size.height -= kbd_h;
1488 _sapp_view_obj.frame = view_frame;
1489 }
1490}
1491- (void)keyboardWillBeHidden:(NSNotification*)notif {
1492 _sapp.onscreen_keyboard_shown = false;
1493 if (_sapp.desc.ios_keyboard_resizes_canvas) {
1494 _sapp_view_obj.frame = UIScreen.mainScreen.bounds;
1495 }
1496}
1497- (void)keyboardDidChangeFrame:(NSNotification*)notif {
1498 /* this is for the case when the screen rotation changes while the keyboard is open */
1499 if (_sapp.onscreen_keyboard_shown && _sapp.desc.ios_keyboard_resizes_canvas) {
1500 NSDictionary* info = notif.userInfo;
1501 CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
1502 CGRect view_frame = UIScreen.mainScreen.bounds;
1503 view_frame.size.height -= kbd_h;
1504 _sapp_view_obj.frame = view_frame;
1505 }
1506}
1507- (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string {
1508 if (_sapp_events_enabled()) {
1509 const NSUInteger len = string.length;
1510 if (len > 0) {
1511 for (NSUInteger i = 0; i < len; i++) {
1512 unichar c = [string characterAtIndex:i];
1513 if (c >= 32) {
1514 /* ignore surrogates for now */
1515 if ((c < 0xD800) || (c > 0xDFFF)) {
1516 _sapp_init_event(SAPP_EVENTTYPE_CHAR);
1517 _sapp.event.char_code = c;
1518 _sapp.desc.event_cb(&_sapp.event);
1519 }
1520 }
1521 if (c <= 32) {
1522 sapp_keycode k = SAPP_KEYCODE_INVALID;
1523 switch (c) {
1524 case 10: k = SAPP_KEYCODE_ENTER; break;
1525 case 32: k = SAPP_KEYCODE_SPACE; break;
1526 default: break;
1527 }
1528 if (k != SAPP_KEYCODE_INVALID) {
1529 _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN);
1530 _sapp.event.key_code = k;
1531 _sapp.desc.event_cb(&_sapp.event);
1532 _sapp_init_event(SAPP_EVENTTYPE_KEY_UP);
1533 _sapp.event.key_code = k;
1534 _sapp.desc.event_cb(&_sapp.event);
1535 }
1536 }
1537 }
1538 }
1539 else {
1540 /* this was a backspace */
1541 _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN);
1542 _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE;
1543 _sapp.desc.event_cb(&_sapp.event);
1544 _sapp_init_event(SAPP_EVENTTYPE_KEY_UP);
1545 _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE;
1546 _sapp.desc.event_cb(&_sapp.event);
1547 }
1548 }
1549 return NO;
1550}
1551@end
1552
1553#if defined(SOKOL_METAL)
1554@implementation _sapp_ios_mtk_view_dlg
1555- (void)drawInMTKView:(MTKView*)view {
1556 @autoreleasepool {
1557 _sapp_ios_frame();
1558 }
1559}
1560
1561- (void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size {
1562 /* this is required by the protocol, but we can't do anything useful here */
1563}
1564@end
1565#else
1566@implementation _sapp_ios_glk_view_dlg
1567- (void)glkView:(GLKView*)view drawInRect:(CGRect)rect {
1568 @autoreleasepool {
1569 _sapp_ios_frame();
1570 }
1571}
1572@end
1573#endif
1574
1575_SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet<UITouch *>* touches, UIEvent* event) {
1576 if (_sapp_events_enabled()) {
1577 _sapp_init_event(type);
1578 NSEnumerator* enumerator = event.allTouches.objectEnumerator;
1579 UITouch* ios_touch;
1580 while ((ios_touch = [enumerator nextObject])) {
1581 if ((_sapp.event.num_touches + 1) < SAPP_MAX_TOUCHPOINTS) {
1582 CGPoint ios_pos = [ios_touch locationInView:_sapp_view_obj];
1583 sapp_touchpoint* cur_point = &_sapp.event.touches[_sapp.event.num_touches++];
1584 cur_point->identifier = (uintptr_t) ios_touch;
1585 cur_point->pos_x = ios_pos.x * _sapp.dpi_scale;
1586 cur_point->pos_y = ios_pos.y * _sapp.dpi_scale;
1587 cur_point->changed = [touches containsObject:ios_touch];
1588 }
1589 }
1590 if (_sapp.event.num_touches > 0) {
1591 _sapp.desc.event_cb(&_sapp.event);
1592 }
1593 }
1594}
1595
1596@implementation _sapp_ios_view
1597- (BOOL) isOpaque {
1598 return YES;
1599}
1600- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
1601 _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_BEGAN, touches, event);
1602}
1603- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
1604 _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_MOVED, touches, event);
1605}
1606- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
1607 _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_ENDED, touches, event);
1608}
1609- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
1610 _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_CANCELLED, touches, event);
1611}
1612@end
1613#endif /* TARGET_OS_IPHONE */
1614
1615#endif /* __APPLE__ */
1616
1617/*== EMSCRIPTEN ==============================================================*/
1618#if defined(__EMSCRIPTEN__)
1619#if defined(SOKOL_GLES3)
1620#include <GLES3/gl3.h>
1621#else
1622#ifndef GL_EXT_PROTOTYPES
1623#define GL_GLEXT_PROTOTYPES
1624#endif
1625#include <GLES2/gl2.h>
1626#include <GLES2/gl2ext.h>
1627#endif
1628#include <emscripten/emscripten.h>
1629#include <emscripten/html5.h>
1630
1631static bool _sapp_emsc_input_created;
1632static bool _sapp_emsc_wants_show_keyboard;
1633static bool _sapp_emsc_wants_hide_keyboard;
1634
1635/* this function is called from a JS event handler when the user hides
1636 the onscreen keyboard pressing the 'dismiss keyboard key'
1637*/
1638EMSCRIPTEN_KEEPALIVE void _sapp_emsc_notify_keyboard_hidden(void) {
1639 _sapp.onscreen_keyboard_shown = false;
1640}
1641
1642/* Javascript helper functions for mobile virtual keyboard input */
1643EM_JS(void, _sapp_js_create_textfield, (), {
1644 var inp = document.createElement("input");
1645 inp.type = "text";
1646 inp.id = "_sokol_app_input_element";
1647 inp.autocapitalize = "none";
1648 inp.addEventListener("focusout", function(e) {
1649 __sapp_emsc_notify_keyboard_hidden()
1650
1651 });
1652 document.body.append(x);
1653});
1654
1655EM_JS(void, _sapp_js_focus_textfield, (), {
1656 document.getElementById("_sokol_app_input_element").focus();
1657});
1658
1659EM_JS(void, _sapp_js_unfocus_textfield, (), {
1660 document.getElementById("_sokol_app_input_element").blur();
1661});
1662
1663/* called from the emscripten event handler to update the keyboard visibility
1664 state, this must happen from an JS input event handler, otherwise
1665 the request will be ignored by the browser
1666*/
1667_SOKOL_PRIVATE void _sapp_emsc_update_keyboard_state(void) {
1668 if (_sapp_emsc_wants_show_keyboard) {
1669 /* create input text field on demand */
1670 if (!_sapp_emsc_input_created) {
1671 _sapp_emsc_input_created = true;
1672 _sapp_js_create_textfield();
1673 }
1674 /* focus the text input field, this will bring up the keyboard */
1675 _sapp.onscreen_keyboard_shown = true;
1676 _sapp_emsc_wants_show_keyboard = false;
1677 _sapp_js_focus_textfield();
1678 }
1679 if (_sapp_emsc_wants_hide_keyboard) {
1680 /* unfocus the text input field */
1681 if (_sapp_emsc_input_created) {
1682 _sapp.onscreen_keyboard_shown = false;
1683 _sapp_emsc_wants_hide_keyboard = false;
1684 _sapp_js_unfocus_textfield();
1685 }
1686 }
1687}
1688
1689/* actually showing the onscreen keyboard must be initiated from a JS
1690 input event handler, so we'll just keep track of the desired
1691 state, and the actual state change will happen with the next input event
1692*/
1693_SOKOL_PRIVATE void _sapp_emsc_show_keyboard(bool show) {
1694 if (show) {
1695 _sapp_emsc_wants_show_keyboard = true;
1696 }
1697 else {
1698 _sapp_emsc_wants_hide_keyboard = true;
1699 }
1700}
1701
1702_SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenUiEvent* ui_event, void* user_data) {
1703 double w, h;
1704 emscripten_get_element_css_size(_sapp.html5_canvas_name, &w, &h);
1705 /* The above method might report zero when toggling HTML5 fullscreen,
1706 in that case use the window's inner width reported by the
1707 emscripten event. This works ok when toggling *into* fullscreen
1708 but doesn't properly restore the previous canvas size when switching
1709 back from fullscreen.
1710
1711 In general, due to the HTML5's fullscreen API's flaky nature it is
1712 recommended to use 'soft fullscreen' (stretching the WebGL canvas
1713 over the browser window's client rect) with a CSS definition like this:
1714
1715 position: absolute;
1716 top: 0px;
1717 left: 0px;
1718 margin: 0px;
1719 border: 0;
1720 width: 100%;
1721 height: 100%;
1722 overflow: hidden;
1723 display: block;
1724 */
1725 if (w < 1.0) {
1726 w = ui_event->windowInnerWidth;
1727 }
1728 else {
1729 _sapp.window_width = (int) w;
1730 }
1731 if (h < 1.0) {
1732 h = ui_event->windowInnerHeight;
1733 }
1734 else {
1735 _sapp.window_height = (int) h;
1736 }
1737 if (_sapp.desc.high_dpi) {
1738 _sapp.dpi_scale = emscripten_get_device_pixel_ratio();
1739 w *= _sapp.dpi_scale;
1740 h *= _sapp.dpi_scale;
1741 }
1742 _sapp.framebuffer_width = (int) w;
1743 _sapp.framebuffer_height = (int) h;
1744 SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0));
1745 emscripten_set_canvas_element_size(_sapp.html5_canvas_name, w, h);
1746 if (_sapp_events_enabled()) {
1747 _sapp_init_event(SAPP_EVENTTYPE_RESIZED);
1748 _sapp.desc.event_cb(&_sapp.event);
1749 }
1750 return true;
1751}
1752
1753_SOKOL_PRIVATE void _sapp_emsc_frame(void) {
1754 if (_sapp.first_frame) {
1755 emscripten_set_main_loop_timing(EM_TIMING_RAF, _sapp.swap_interval);
1756 }
1757 _sapp_frame();
1758}
1759
1760_SOKOL_PRIVATE EM_BOOL _sapp_emsc_context_cb(int emsc_type, const void* reserved, void* user_data) {
1761 sapp_event_type type;
1762 switch (emsc_type) {
1763 case EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST: type = SAPP_EVENTTYPE_SUSPENDED; break;
1764 case EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED: type = SAPP_EVENTTYPE_RESUMED; break;
1765 default: type = SAPP_EVENTTYPE_INVALID; break;
1766 }
1767 if (_sapp_events_enabled() && (SAPP_EVENTTYPE_INVALID != type)) {
1768 _sapp_init_event(type);
1769 _sapp.desc.event_cb(&_sapp.event);
1770 }
1771 return true;
1772}
1773
1774_SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseEvent* emsc_event, void* user_data) {
1775 _sapp.mouse_x = (emsc_event->canvasX * _sapp.dpi_scale);
1776 _sapp.mouse_y = (emsc_event->canvasY * _sapp.dpi_scale);
1777 if (_sapp_events_enabled() && (emsc_event->button >= 0) && (emsc_event->button < SAPP_MAX_MOUSEBUTTONS)) {
1778 sapp_event_type type;
1779 bool is_button_event = false;
1780 switch (emsc_type) {
1781 case EMSCRIPTEN_EVENT_MOUSEDOWN:
1782 type = SAPP_EVENTTYPE_MOUSE_DOWN;
1783 is_button_event = true;
1784 break;
1785 case EMSCRIPTEN_EVENT_MOUSEUP:
1786 type = SAPP_EVENTTYPE_MOUSE_UP;
1787 is_button_event = true;
1788 break;
1789 case EMSCRIPTEN_EVENT_MOUSEMOVE:
1790 type = SAPP_EVENTTYPE_MOUSE_MOVE;
1791 break;
1792 case EMSCRIPTEN_EVENT_MOUSEENTER:
1793 type = SAPP_EVENTTYPE_MOUSE_ENTER;
1794 break;
1795 case EMSCRIPTEN_EVENT_MOUSELEAVE:
1796 type = SAPP_EVENTTYPE_MOUSE_LEAVE;
1797 break;
1798 default:
1799 type = SAPP_EVENTTYPE_INVALID;
1800 break;
1801 }
1802 if (type != SAPP_EVENTTYPE_INVALID) {
1803 _sapp_init_event(type);
1804 if (emsc_event->ctrlKey) {
1805 _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
1806 }
1807 if (emsc_event->shiftKey) {
1808 _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
1809 }
1810 if (emsc_event->altKey) {
1811 _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
1812 }
1813 if (emsc_event->metaKey) {
1814 _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
1815 }
1816 if (is_button_event) {
1817 switch (emsc_event->button) {
1818 case 0: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_LEFT; break;
1819 case 1: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_MIDDLE; break;
1820 case 2: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_RIGHT; break;
1821 default: _sapp.event.mouse_button = emsc_event->button; break;
1822 }
1823 }
1824 else {
1825 _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID;
1826 }
1827 _sapp.event.mouse_x = _sapp.mouse_x;
1828 _sapp.event.mouse_y = _sapp.mouse_y;
1829 _sapp.desc.event_cb(&_sapp.event);
1830 }
1831 }
1832 _sapp_emsc_update_keyboard_state();
1833 return true;
1834}
1835
1836_SOKOL_PRIVATE EM_BOOL _sapp_emsc_wheel_cb(int emsc_type, const EmscriptenWheelEvent* emsc_event, void* user_data) {
1837 if (_sapp_events_enabled()) {
1838 _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
1839 if (emsc_event->mouse.ctrlKey) {
1840 _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
1841 }
1842 if (emsc_event->mouse.shiftKey) {
1843 _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
1844 }
1845 if (emsc_event->mouse.altKey) {
1846 _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
1847 }
1848 if (emsc_event->mouse.metaKey) {
1849 _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
1850 }
1851 _sapp.event.scroll_x = -0.1 * (float)emsc_event->deltaX;
1852 _sapp.event.scroll_y = -0.1 * (float)emsc_event->deltaY;
1853 _sapp.desc.event_cb(&_sapp.event);
1854 }
1855 _sapp_emsc_update_keyboard_state();
1856 return true;
1857}
1858
1859_SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboardEvent* emsc_event, void* user_data) {
1860 bool retval = true;
1861 if (_sapp_events_enabled()) {
1862 sapp_event_type type;
1863 switch (emsc_type) {
1864 case EMSCRIPTEN_EVENT_KEYDOWN:
1865 type = SAPP_EVENTTYPE_KEY_DOWN;
1866 break;
1867 case EMSCRIPTEN_EVENT_KEYUP:
1868 type = SAPP_EVENTTYPE_KEY_UP;
1869 break;
1870 case EMSCRIPTEN_EVENT_KEYPRESS:
1871 type = SAPP_EVENTTYPE_CHAR;
1872 break;
1873 default:
1874 type = SAPP_EVENTTYPE_INVALID;
1875 break;
1876 }
1877 if (type != SAPP_EVENTTYPE_INVALID) {
1878 _sapp_init_event(type);
1879 if (emsc_event->ctrlKey) {
1880 _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
1881 }
1882 if (emsc_event->shiftKey) {
1883 _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
1884 }
1885 if (emsc_event->altKey) {
1886 _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
1887 }
1888 if (emsc_event->metaKey) {
1889 _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
1890 }
1891 if (type == SAPP_EVENTTYPE_CHAR) {
1892 _sapp.event.char_code = emsc_event->charCode;
1893 }
1894 else {
1895 _sapp.event.key_code = _sapp_translate_key(emsc_event->keyCode);
1896 /* only forward a certain key ranges to the browser */
1897 switch (_sapp.event.key_code) {
1898 case SAPP_KEYCODE_WORLD_1:
1899 case SAPP_KEYCODE_WORLD_2:
1900 case SAPP_KEYCODE_ESCAPE:
1901 case SAPP_KEYCODE_ENTER:
1902 case SAPP_KEYCODE_TAB:
1903 case SAPP_KEYCODE_BACKSPACE:
1904 case SAPP_KEYCODE_INSERT:
1905 case SAPP_KEYCODE_DELETE:
1906 case SAPP_KEYCODE_RIGHT:
1907 case SAPP_KEYCODE_LEFT:
1908 case SAPP_KEYCODE_DOWN:
1909 case SAPP_KEYCODE_UP:
1910 case SAPP_KEYCODE_PAGE_UP:
1911 case SAPP_KEYCODE_PAGE_DOWN:
1912 case SAPP_KEYCODE_HOME:
1913 case SAPP_KEYCODE_END:
1914 case SAPP_KEYCODE_CAPS_LOCK:
1915 case SAPP_KEYCODE_SCROLL_LOCK:
1916 case SAPP_KEYCODE_NUM_LOCK:
1917 case SAPP_KEYCODE_PRINT_SCREEN:
1918 case SAPP_KEYCODE_PAUSE:
1919 case SAPP_KEYCODE_F1:
1920 case SAPP_KEYCODE_F2:
1921 case SAPP_KEYCODE_F3:
1922 case SAPP_KEYCODE_F4:
1923 case SAPP_KEYCODE_F5:
1924 case SAPP_KEYCODE_F6:
1925 case SAPP_KEYCODE_F7:
1926 case SAPP_KEYCODE_F8:
1927 case SAPP_KEYCODE_F9:
1928 case SAPP_KEYCODE_F10:
1929 case SAPP_KEYCODE_F11:
1930 case SAPP_KEYCODE_F12:
1931 case SAPP_KEYCODE_F13:
1932 case SAPP_KEYCODE_F14:
1933 case SAPP_KEYCODE_F15:
1934 case SAPP_KEYCODE_F16:
1935 case SAPP_KEYCODE_F17:
1936 case SAPP_KEYCODE_F18:
1937 case SAPP_KEYCODE_F19:
1938 case SAPP_KEYCODE_F20:
1939 case SAPP_KEYCODE_F21:
1940 case SAPP_KEYCODE_F22:
1941 case SAPP_KEYCODE_F23:
1942 case SAPP_KEYCODE_F24:
1943 case SAPP_KEYCODE_F25:
1944 case SAPP_KEYCODE_LEFT_SHIFT:
1945 case SAPP_KEYCODE_LEFT_CONTROL:
1946 case SAPP_KEYCODE_LEFT_ALT:
1947 case SAPP_KEYCODE_LEFT_SUPER:
1948 case SAPP_KEYCODE_RIGHT_SHIFT:
1949 case SAPP_KEYCODE_RIGHT_CONTROL:
1950 case SAPP_KEYCODE_RIGHT_ALT:
1951 case SAPP_KEYCODE_RIGHT_SUPER:
1952 case SAPP_KEYCODE_MENU:
1953 /* consume the event */
1954 break;
1955 default:
1956 /* forward key to browser */
1957 retval = false;
1958 break;
1959 }
1960 }
1961 _sapp.desc.event_cb(&_sapp.event);
1962 }
1963 }
1964 _sapp_emsc_update_keyboard_state();
1965 return retval;
1966}
1967
1968_SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchEvent* emsc_event, void* user_data) {
1969 bool retval = true;
1970 if (_sapp_events_enabled()) {
1971 sapp_event_type type;
1972 switch (emsc_type) {
1973 case EMSCRIPTEN_EVENT_TOUCHSTART:
1974 type = SAPP_EVENTTYPE_TOUCHES_BEGAN;
1975 break;
1976 case EMSCRIPTEN_EVENT_TOUCHMOVE:
1977 type = SAPP_EVENTTYPE_TOUCHES_MOVED;
1978 break;
1979 case EMSCRIPTEN_EVENT_TOUCHEND:
1980 type = SAPP_EVENTTYPE_TOUCHES_ENDED;
1981 break;
1982 case EMSCRIPTEN_EVENT_TOUCHCANCEL:
1983 type = SAPP_EVENTTYPE_TOUCHES_CANCELLED;
1984 break;
1985 default:
1986 type = SAPP_EVENTTYPE_INVALID;
1987 retval = false;
1988 break;
1989 }
1990 if (type != SAPP_EVENTTYPE_INVALID) {
1991 _sapp_init_event(type);
1992 if (emsc_event->ctrlKey) {
1993 _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
1994 }
1995 if (emsc_event->shiftKey) {
1996 _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
1997 }
1998 if (emsc_event->altKey) {
1999 _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
2000 }
2001 if (emsc_event->metaKey) {
2002 _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
2003 }
2004 _sapp.event.num_touches = emsc_event->numTouches;
2005 if (_sapp.event.num_touches > SAPP_MAX_TOUCHPOINTS) {
2006 _sapp.event.num_touches = SAPP_MAX_TOUCHPOINTS;
2007 }
2008 for (int i = 0; i < _sapp.event.num_touches; i++) {
2009 const EmscriptenTouchPoint* src = &emsc_event->touches[i];
2010 sapp_touchpoint* dst = &_sapp.event.touches[i];
2011 dst->identifier = src->identifier;
2012 dst->pos_x = src->canvasX * _sapp.dpi_scale;
2013 dst->pos_y = src->canvasY * _sapp.dpi_scale;
2014 dst->changed = src->isChanged;
2015 }
2016 _sapp.desc.event_cb(&_sapp.event);
2017 }
2018 }
2019 _sapp_emsc_update_keyboard_state();
2020 return retval;
2021}
2022
2023_SOKOL_PRIVATE void _sapp_emsc_init_keytable(void) {
2024 _sapp.keycodes[8] = SAPP_KEYCODE_BACKSPACE;
2025 _sapp.keycodes[9] = SAPP_KEYCODE_TAB;
2026 _sapp.keycodes[13] = SAPP_KEYCODE_ENTER;
2027 _sapp.keycodes[16] = SAPP_KEYCODE_LEFT_SHIFT;
2028 _sapp.keycodes[17] = SAPP_KEYCODE_LEFT_CONTROL;
2029 _sapp.keycodes[18] = SAPP_KEYCODE_LEFT_ALT;
2030 _sapp.keycodes[19] = SAPP_KEYCODE_PAUSE;
2031 _sapp.keycodes[27] = SAPP_KEYCODE_ESCAPE;
2032 _sapp.keycodes[32] = SAPP_KEYCODE_SPACE;
2033 _sapp.keycodes[33] = SAPP_KEYCODE_PAGE_UP;
2034 _sapp.keycodes[34] = SAPP_KEYCODE_PAGE_DOWN;
2035 _sapp.keycodes[35] = SAPP_KEYCODE_END;
2036 _sapp.keycodes[36] = SAPP_KEYCODE_HOME;
2037 _sapp.keycodes[37] = SAPP_KEYCODE_LEFT;
2038 _sapp.keycodes[38] = SAPP_KEYCODE_UP;
2039 _sapp.keycodes[39] = SAPP_KEYCODE_RIGHT;
2040 _sapp.keycodes[40] = SAPP_KEYCODE_DOWN;
2041 _sapp.keycodes[45] = SAPP_KEYCODE_INSERT;
2042 _sapp.keycodes[46] = SAPP_KEYCODE_DELETE;
2043 _sapp.keycodes[48] = SAPP_KEYCODE_0;
2044 _sapp.keycodes[49] = SAPP_KEYCODE_1;
2045 _sapp.keycodes[50] = SAPP_KEYCODE_2;
2046 _sapp.keycodes[51] = SAPP_KEYCODE_3;
2047 _sapp.keycodes[52] = SAPP_KEYCODE_4;
2048 _sapp.keycodes[53] = SAPP_KEYCODE_5;
2049 _sapp.keycodes[54] = SAPP_KEYCODE_6;
2050 _sapp.keycodes[55] = SAPP_KEYCODE_7;
2051 _sapp.keycodes[56] = SAPP_KEYCODE_8;
2052 _sapp.keycodes[57] = SAPP_KEYCODE_9;
2053 _sapp.keycodes[59] = SAPP_KEYCODE_SEMICOLON;
2054 _sapp.keycodes[64] = SAPP_KEYCODE_EQUAL;
2055 _sapp.keycodes[65] = SAPP_KEYCODE_A;
2056 _sapp.keycodes[66] = SAPP_KEYCODE_B;
2057 _sapp.keycodes[67] = SAPP_KEYCODE_C;
2058 _sapp.keycodes[68] = SAPP_KEYCODE_D;
2059 _sapp.keycodes[69] = SAPP_KEYCODE_E;
2060 _sapp.keycodes[70] = SAPP_KEYCODE_F;
2061 _sapp.keycodes[71] = SAPP_KEYCODE_G;
2062 _sapp.keycodes[72] = SAPP_KEYCODE_H;
2063 _sapp.keycodes[73] = SAPP_KEYCODE_I;
2064 _sapp.keycodes[74] = SAPP_KEYCODE_J;
2065 _sapp.keycodes[75] = SAPP_KEYCODE_K;
2066 _sapp.keycodes[76] = SAPP_KEYCODE_L;
2067 _sapp.keycodes[77] = SAPP_KEYCODE_M;
2068 _sapp.keycodes[78] = SAPP_KEYCODE_N;
2069 _sapp.keycodes[79] = SAPP_KEYCODE_O;
2070 _sapp.keycodes[80] = SAPP_KEYCODE_P;
2071 _sapp.keycodes[81] = SAPP_KEYCODE_Q;
2072 _sapp.keycodes[82] = SAPP_KEYCODE_R;
2073 _sapp.keycodes[83] = SAPP_KEYCODE_S;
2074 _sapp.keycodes[84] = SAPP_KEYCODE_T;
2075 _sapp.keycodes[85] = SAPP_KEYCODE_U;
2076 _sapp.keycodes[86] = SAPP_KEYCODE_V;
2077 _sapp.keycodes[87] = SAPP_KEYCODE_W;
2078 _sapp.keycodes[88] = SAPP_KEYCODE_X;
2079 _sapp.keycodes[89] = SAPP_KEYCODE_Y;
2080 _sapp.keycodes[90] = SAPP_KEYCODE_Z;
2081 _sapp.keycodes[91] = SAPP_KEYCODE_LEFT_SUPER;
2082 _sapp.keycodes[93] = SAPP_KEYCODE_MENU;
2083 _sapp.keycodes[96] = SAPP_KEYCODE_KP_0;
2084 _sapp.keycodes[97] = SAPP_KEYCODE_KP_1;
2085 _sapp.keycodes[98] = SAPP_KEYCODE_KP_2;
2086 _sapp.keycodes[99] = SAPP_KEYCODE_KP_3;
2087 _sapp.keycodes[100] = SAPP_KEYCODE_KP_4;
2088 _sapp.keycodes[101] = SAPP_KEYCODE_KP_5;
2089 _sapp.keycodes[102] = SAPP_KEYCODE_KP_6;
2090 _sapp.keycodes[103] = SAPP_KEYCODE_KP_7;
2091 _sapp.keycodes[104] = SAPP_KEYCODE_KP_8;
2092 _sapp.keycodes[105] = SAPP_KEYCODE_KP_9;
2093 _sapp.keycodes[106] = SAPP_KEYCODE_KP_MULTIPLY;
2094 _sapp.keycodes[107] = SAPP_KEYCODE_KP_ADD;
2095 _sapp.keycodes[109] = SAPP_KEYCODE_KP_SUBTRACT;
2096 _sapp.keycodes[110] = SAPP_KEYCODE_KP_DECIMAL;
2097 _sapp.keycodes[111] = SAPP_KEYCODE_KP_DIVIDE;
2098 _sapp.keycodes[112] = SAPP_KEYCODE_F1;
2099 _sapp.keycodes[113] = SAPP_KEYCODE_F2;
2100 _sapp.keycodes[114] = SAPP_KEYCODE_F3;
2101 _sapp.keycodes[115] = SAPP_KEYCODE_F4;
2102 _sapp.keycodes[116] = SAPP_KEYCODE_F5;
2103 _sapp.keycodes[117] = SAPP_KEYCODE_F6;
2104 _sapp.keycodes[118] = SAPP_KEYCODE_F7;
2105 _sapp.keycodes[119] = SAPP_KEYCODE_F8;
2106 _sapp.keycodes[120] = SAPP_KEYCODE_F9;
2107 _sapp.keycodes[121] = SAPP_KEYCODE_F10;
2108 _sapp.keycodes[122] = SAPP_KEYCODE_F11;
2109 _sapp.keycodes[123] = SAPP_KEYCODE_F12;
2110 _sapp.keycodes[144] = SAPP_KEYCODE_NUM_LOCK;
2111 _sapp.keycodes[145] = SAPP_KEYCODE_SCROLL_LOCK;
2112 _sapp.keycodes[173] = SAPP_KEYCODE_MINUS;
2113 _sapp.keycodes[186] = SAPP_KEYCODE_SEMICOLON;
2114 _sapp.keycodes[187] = SAPP_KEYCODE_EQUAL;
2115 _sapp.keycodes[188] = SAPP_KEYCODE_COMMA;
2116 _sapp.keycodes[189] = SAPP_KEYCODE_MINUS;
2117 _sapp.keycodes[190] = SAPP_KEYCODE_PERIOD;
2118 _sapp.keycodes[191] = SAPP_KEYCODE_SLASH;
2119 _sapp.keycodes[192] = SAPP_KEYCODE_GRAVE_ACCENT;
2120 _sapp.keycodes[219] = SAPP_KEYCODE_LEFT_BRACKET;
2121 _sapp.keycodes[220] = SAPP_KEYCODE_BACKSLASH;
2122 _sapp.keycodes[221] = SAPP_KEYCODE_RIGHT_BRACKET;
2123 _sapp.keycodes[222] = SAPP_KEYCODE_APOSTROPHE;
2124 _sapp.keycodes[224] = SAPP_KEYCODE_LEFT_SUPER;
2125}
2126
2127int main(int argc, char* argv[]) {
2128 sapp_desc desc = sokol_main(argc, argv);
2129 _sapp_init_state(&desc, 0, 0);
2130 _sapp_emsc_init_keytable();
2131 double w, h;
2132 if (_sapp.html5_canvas_resize) {
2133 w = (double) desc.width;
2134 h = (double) desc.height;
2135 }
2136 else {
2137 emscripten_get_element_css_size(_sapp.html5_canvas_name, &w, &h);
2138 emscripten_set_resize_callback(0, 0, false, _sapp_emsc_size_changed);
2139 }
2140 if (_sapp.desc.high_dpi) {
2141 _sapp.dpi_scale = emscripten_get_device_pixel_ratio();
2142 w *= _sapp.dpi_scale;
2143 h *= _sapp.dpi_scale;
2144 }
2145 emscripten_set_canvas_element_size(_sapp.html5_canvas_name, w, h);
2146 _sapp.framebuffer_width = (int) w;
2147 _sapp.framebuffer_height = (int) h;
2148 EmscriptenWebGLContextAttributes attrs;
2149 emscripten_webgl_init_context_attributes(&attrs);
2150 attrs.alpha = _sapp.desc.alpha;
2151 attrs.depth = true;
2152 attrs.stencil = true;
2153 attrs.antialias = _sapp.sample_count > 1;
2154 attrs.premultipliedAlpha = _sapp.desc.premultiplied_alpha;
2155 attrs.preserveDrawingBuffer = _sapp.desc.preserve_drawing_buffer;
2156 attrs.enableExtensionsByDefault = true;
2157 #if defined(SOKOL_GLES3)
2158 if (desc.gl_force_gles2) {
2159 attrs.majorVersion = 1;
2160 _sapp.gles2_fallback = true;
2161 }
2162 else {
2163 attrs.majorVersion = 2;
2164 }
2165 #endif
2166 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(0, &attrs);
2167 if (!ctx) {
2168 attrs.majorVersion = 1;
2169 ctx = emscripten_webgl_create_context(0, &attrs);
2170 _sapp.gles2_fallback = true;
2171 }
2172 emscripten_webgl_make_context_current(ctx);
2173 _sapp.valid = true;
2174 emscripten_set_mousedown_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
2175 emscripten_set_mouseup_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
2176 emscripten_set_mousemove_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
2177 emscripten_set_mouseenter_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
2178 emscripten_set_mouseleave_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
2179 emscripten_set_wheel_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_wheel_cb);
2180 emscripten_set_keydown_callback(0, 0, true, _sapp_emsc_key_cb);
2181 emscripten_set_keyup_callback(0, 0, true, _sapp_emsc_key_cb);
2182 emscripten_set_keypress_callback(0, 0, true, _sapp_emsc_key_cb);
2183 emscripten_set_touchstart_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
2184 emscripten_set_touchmove_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
2185 emscripten_set_touchend_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
2186 emscripten_set_touchcancel_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
2187 emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_context_cb);
2188 emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_context_cb);
2189 emscripten_set_main_loop(_sapp_emsc_frame, 0, 1);
2190 return 0;
2191}
2192#endif /* __EMSCRIPTEN__ */
2193
2194/*== MISC GL SUPPORT FUNCTIONS ================================================*/
2195#if defined(SOKOL_GLCORE33)
2196typedef struct {
2197 int red_bits;
2198 int green_bits;
2199 int blue_bits;
2200 int alpha_bits;
2201 int depth_bits;
2202 int stencil_bits;
2203 int samples;
2204 bool doublebuffer;
2205 uintptr_t handle;
2206} _sapp_gl_fbconfig;
2207
2208_SOKOL_PRIVATE void _sapp_gl_init_fbconfig(_sapp_gl_fbconfig* fbconfig) {
2209 memset(fbconfig, 0, sizeof(_sapp_gl_fbconfig));
2210 /* -1 means "don't care" */
2211 fbconfig->red_bits = -1;
2212 fbconfig->green_bits = -1;
2213 fbconfig->blue_bits = -1;
2214 fbconfig->alpha_bits = -1;
2215 fbconfig->depth_bits = -1;
2216 fbconfig->stencil_bits = -1;
2217 fbconfig->samples = -1;
2218}
2219
2220_SOKOL_PRIVATE const _sapp_gl_fbconfig* _sapp_gl_choose_fbconfig(const _sapp_gl_fbconfig* desired, const _sapp_gl_fbconfig* alternatives, unsigned int count) {
2221 unsigned int i;
2222 unsigned int missing, least_missing = 1000000;
2223 unsigned int color_diff, least_color_diff = 10000000;
2224 unsigned int extra_diff, least_extra_diff = 10000000;
2225 const _sapp_gl_fbconfig* current;
2226 const _sapp_gl_fbconfig* closest = NULL;
2227 for (i = 0; i < count; i++) {
2228 current = alternatives + i;
2229 if (desired->doublebuffer != current->doublebuffer) {
2230 continue;
2231 }
2232 missing = 0;
2233 if (desired->alpha_bits > 0 && current->alpha_bits == 0) {
2234 missing++;
2235 }
2236 if (desired->depth_bits > 0 && current->depth_bits == 0) {
2237 missing++;
2238 }
2239 if (desired->stencil_bits > 0 && current->stencil_bits == 0) {
2240 missing++;
2241 }
2242 if (desired->samples > 0 && current->samples == 0) {
2243 /* Technically, several multisampling buffers could be
2244 involved, but that's a lower level implementation detail and
2245 not important to us here, so we count them as one
2246 */
2247 missing++;
2248 }
2249
2250 /* These polynomials make many small channel size differences matter
2251 less than one large channel size difference
2252 Calculate color channel size difference value
2253 */
2254 color_diff = 0;
2255 if (desired->red_bits != -1) {
2256 color_diff += (desired->red_bits - current->red_bits) * (desired->red_bits - current->red_bits);
2257 }
2258 if (desired->green_bits != -1) {
2259 color_diff += (desired->green_bits - current->green_bits) * (desired->green_bits - current->green_bits);
2260 }
2261 if (desired->blue_bits != -1) {
2262 color_diff += (desired->blue_bits - current->blue_bits) * (desired->blue_bits - current->blue_bits);
2263 }
2264
2265 /* Calculate non-color channel size difference value */
2266 extra_diff = 0;
2267 if (desired->alpha_bits != -1) {
2268 extra_diff += (desired->alpha_bits - current->alpha_bits) * (desired->alpha_bits - current->alpha_bits);
2269 }
2270 if (desired->depth_bits != -1) {
2271 extra_diff += (desired->depth_bits - current->depth_bits) * (desired->depth_bits - current->depth_bits);
2272 }
2273 if (desired->stencil_bits != -1) {
2274 extra_diff += (desired->stencil_bits - current->stencil_bits) * (desired->stencil_bits - current->stencil_bits);
2275 }
2276 if (desired->samples != -1) {
2277 extra_diff += (desired->samples - current->samples) * (desired->samples - current->samples);
2278 }
2279
2280 /* Figure out if the current one is better than the best one found so far
2281 Least number of missing buffers is the most important heuristic,
2282 then color buffer size match and lastly size match for other buffers
2283 */
2284 if (missing < least_missing) {
2285 closest = current;
2286 }
2287 else if (missing == least_missing) {
2288 if ((color_diff < least_color_diff) ||
2289 (color_diff == least_color_diff && extra_diff < least_extra_diff))
2290 {
2291 closest = current;
2292 }
2293 }
2294 if (current == closest) {
2295 least_missing = missing;
2296 least_color_diff = color_diff;
2297 least_extra_diff = extra_diff;
2298 }
2299 }
2300 return closest;
2301}
2302#endif
2303
2304/*== WINDOWS ==================================================================*/
2305#if defined(_WIN32)
2306#ifndef WIN32_LEAN_AND_MEAN
2307#define WIN32_LEAN_AND_MEAN
2308#endif
2309#include <windows.h>
2310#include <windowsx.h>
2311
2312#if defined(SOKOL_D3D11)
2313#ifndef D3D11_NO_HELPERS
2314#define D3D11_NO_HELPERS
2315#endif
2316#ifndef CINTERFACE
2317#define CINTERFACE
2318#endif
2319#ifndef COBJMACROS
2320#define COBJMACROS
2321#endif
2322#include <windows.h>
2323#include <d3d11.h>
2324#include <dxgi.h>
2325#if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
2326#pragma comment (lib, "WindowsApp.lib")
2327#else
2328#pragma comment (lib, "user32.lib")
2329#pragma comment (lib, "dxgi.lib")
2330#pragma comment (lib, "d3d11.lib")
2331#pragma comment (lib, "dxguid.lib")
2332#endif
2333#endif
2334
2335#ifndef DPI_ENUMS_DECLARED
2336typedef enum PROCESS_DPI_AWARENESS
2337{
2338 PROCESS_DPI_UNAWARE = 0,
2339 PROCESS_SYSTEM_DPI_AWARE = 1,
2340 PROCESS_PER_MONITOR_DPI_AWARE = 2
2341} PROCESS_DPI_AWARENESS;
2342typedef enum MONITOR_DPI_TYPE {
2343 MDT_EFFECTIVE_DPI = 0,
2344 MDT_ANGULAR_DPI = 1,
2345 MDT_RAW_DPI = 2,
2346 MDT_DEFAULT = MDT_EFFECTIVE_DPI
2347} MONITOR_DPI_TYPE;
2348#endif /*DPI_ENUMS_DECLARED*/
2349
2350static HWND _sapp_win32_hwnd;
2351static HDC _sapp_win32_dc;
2352static bool _sapp_win32_in_create_window;
2353static bool _sapp_win32_dpi_aware;
2354static int _sapp_win32_content_scale;
2355static int _sapp_win32_window_scale;
2356static float _sapp_win32_mouse_scale;
2357static bool _sapp_win32_iconified;
2358typedef BOOL(WINAPI * SETPROCESSDPIAWARE_T)(void);
2359typedef HRESULT(WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS);
2360typedef HRESULT(WINAPI * GETDPIFORMONITOR_T)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);
2361static SETPROCESSDPIAWARE_T _sapp_win32_setprocessdpiaware;
2362static SETPROCESSDPIAWARENESS_T _sapp_win32_setprocessdpiawareness;
2363static GETDPIFORMONITOR_T _sapp_win32_getdpiformonitor;
2364#if defined(SOKOL_D3D11)
2365static ID3D11Device* _sapp_d3d11_device;
2366static ID3D11DeviceContext* _sapp_d3d11_device_context;
2367static DXGI_SWAP_CHAIN_DESC _sapp_dxgi_swap_chain_desc;
2368static IDXGISwapChain* _sapp_dxgi_swap_chain;
2369static ID3D11Texture2D* _sapp_d3d11_rt;
2370static ID3D11RenderTargetView* _sapp_d3d11_rtv;
2371static ID3D11Texture2D* _sapp_d3d11_ds;
2372static ID3D11DepthStencilView* _sapp_d3d11_dsv;
2373#endif
2374#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
2375#define WGL_SUPPORT_OPENGL_ARB 0x2010
2376#define WGL_DRAW_TO_WINDOW_ARB 0x2001
2377#define WGL_PIXEL_TYPE_ARB 0x2013
2378#define WGL_TYPE_RGBA_ARB 0x202b
2379#define WGL_ACCELERATION_ARB 0x2003
2380#define WGL_NO_ACCELERATION_ARB 0x2025
2381#define WGL_RED_BITS_ARB 0x2015
2382#define WGL_RED_SHIFT_ARB 0x2016
2383#define WGL_GREEN_BITS_ARB 0x2017
2384#define WGL_GREEN_SHIFT_ARB 0x2018
2385#define WGL_BLUE_BITS_ARB 0x2019
2386#define WGL_BLUE_SHIFT_ARB 0x201a
2387#define WGL_ALPHA_BITS_ARB 0x201b
2388#define WGL_ALPHA_SHIFT_ARB 0x201c
2389#define WGL_ACCUM_BITS_ARB 0x201d
2390#define WGL_ACCUM_RED_BITS_ARB 0x201e
2391#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
2392#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
2393#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
2394#define WGL_DEPTH_BITS_ARB 0x2022
2395#define WGL_STENCIL_BITS_ARB 0x2023
2396#define WGL_AUX_BUFFERS_ARB 0x2024
2397#define WGL_STEREO_ARB 0x2012
2398#define WGL_DOUBLE_BUFFER_ARB 0x2011
2399#define WGL_SAMPLES_ARB 0x2042
2400#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
2401#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
2402#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
2403#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
2404#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
2405#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
2406#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
2407#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
2408#define WGL_CONTEXT_FLAGS_ARB 0x2094
2409#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
2410#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
2411#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
2412#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
2413#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
2414#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
2415#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
2416#define WGL_COLORSPACE_EXT 0x309d
2417#define WGL_COLORSPACE_SRGB_EXT 0x3089
2418#define ERROR_INVALID_VERSION_ARB 0x2095
2419#define ERROR_INVALID_PROFILE_ARB 0x2096
2420#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
2421typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
2422typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
2423typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
2424typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
2425typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*);
2426typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC);
2427typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC);
2428typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR);
2429typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void);
2430typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC);
2431static HINSTANCE _sapp_opengl32;
2432static HGLRC _sapp_gl_ctx;
2433static PFN_wglCreateContext _sapp_wglCreateContext;
2434static PFN_wglDeleteContext _sapp_wglDeleteContext;
2435static PFN_wglGetProcAddress _sapp_wglGetProcAddress;
2436static PFN_wglGetCurrentDC _sapp_wglGetCurrentDC;
2437static PFN_wglMakeCurrent _sapp_wglMakeCurrent;
2438static PFNWGLSWAPINTERVALEXTPROC _sapp_SwapIntervalEXT;
2439static PFNWGLGETPIXELFORMATATTRIBIVARBPROC _sapp_GetPixelFormatAttribivARB;
2440static PFNWGLGETEXTENSIONSSTRINGEXTPROC _sapp_GetExtensionsStringEXT;
2441static PFNWGLGETEXTENSIONSSTRINGARBPROC _sapp_GetExtensionsStringARB;
2442static PFNWGLCREATECONTEXTATTRIBSARBPROC _sapp_CreateContextAttribsARB;
2443static bool _sapp_ext_swap_control;
2444static bool _sapp_arb_multisample;
2445static bool _sapp_arb_pixel_format;
2446static bool _sapp_arb_create_context;
2447static bool _sapp_arb_create_context_profile;
2448static HWND _sapp_win32_msg_hwnd;
2449static HDC _sapp_win32_msg_dc;
2450
2451/* NOTE: the optional GL loader only contains the GL constants and functions required for sokol_gfx.h, if you need
2452more, you'll need to use you own gl header-generator/loader
2453*/
2454#if !defined(SOKOL_WIN32_NO_GL_LOADER)
2455#if defined(SOKOL_GLCORE33)
2456#define __gl_h_ 1
2457#define __gl32_h_ 1
2458#define __gl31_h_ 1
2459#define __GL_H__ 1
2460#define __glext_h_ 1
2461#define __GLEXT_H_ 1
2462#define __gltypes_h_ 1
2463#define __glcorearb_h_ 1
2464#define __gl_glcorearb_h_ 1
2465#define GL_APIENTRY APIENTRY
2466
2467typedef unsigned int GLenum;
2468typedef unsigned int GLuint;
2469typedef int GLsizei;
2470typedef char GLchar;
2471typedef ptrdiff_t GLintptr;
2472typedef ptrdiff_t GLsizeiptr;
2473typedef double GLclampd;
2474typedef unsigned short GLushort;
2475typedef unsigned char GLubyte;
2476typedef unsigned char GLboolean;
2477typedef uint64_t GLuint64;
2478typedef double GLdouble;
2479typedef unsigned short GLhalf;
2480typedef float GLclampf;
2481typedef unsigned int GLbitfield;
2482typedef signed char GLbyte;
2483typedef short GLshort;
2484typedef void GLvoid;
2485typedef int64_t GLint64;
2486typedef float GLfloat;
2487typedef struct __GLsync * GLsync;
2488typedef int GLint;
2489#define GL_INT_2_10_10_10_REV 0x8D9F
2490#define GL_R32F 0x822E
2491#define GL_PROGRAM_POINT_SIZE 0x8642
2492#define GL_STENCIL_ATTACHMENT 0x8D20
2493#define GL_DEPTH_ATTACHMENT 0x8D00
2494#define GL_COLOR_ATTACHMENT2 0x8CE2
2495#define GL_COLOR_ATTACHMENT0 0x8CE0
2496#define GL_R16F 0x822D
2497#define GL_COLOR_ATTACHMENT22 0x8CF6
2498#define GL_DRAW_FRAMEBUFFER 0x8CA9
2499#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
2500#define GL_NUM_EXTENSIONS 0x821D
2501#define GL_INFO_LOG_LENGTH 0x8B84
2502#define GL_VERTEX_SHADER 0x8B31
2503#define GL_INCR 0x1E02
2504#define GL_DYNAMIC_DRAW 0x88E8
2505#define GL_STATIC_DRAW 0x88E4
2506#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
2507#define GL_TEXTURE_CUBE_MAP 0x8513
2508#define GL_FUNC_SUBTRACT 0x800A
2509#define GL_FUNC_REVERSE_SUBTRACT 0x800B
2510#define GL_CONSTANT_COLOR 0x8001
2511#define GL_DECR_WRAP 0x8508
2512#define GL_R8 0x8229
2513#define GL_LINEAR_MIPMAP_LINEAR 0x2703
2514#define GL_ELEMENT_ARRAY_BUFFER 0x8893
2515#define GL_SHORT 0x1402
2516#define GL_DEPTH_TEST 0x0B71
2517#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
2518#define GL_LINK_STATUS 0x8B82
2519#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
2520#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
2521#define GL_RGBA16F 0x881A
2522#define GL_CONSTANT_ALPHA 0x8003
2523#define GL_READ_FRAMEBUFFER 0x8CA8
2524#define GL_TEXTURE0 0x84C0
2525#define GL_TEXTURE_MIN_LOD 0x813A
2526#define GL_CLAMP_TO_EDGE 0x812F
2527#define GL_UNSIGNED_SHORT_5_6_5 0x8363
2528#define GL_TEXTURE_WRAP_R 0x8072
2529#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
2530#define GL_NEAREST_MIPMAP_NEAREST 0x2700
2531#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
2532#define GL_SRC_ALPHA_SATURATE 0x0308
2533#define GL_STREAM_DRAW 0x88E0
2534#define GL_ONE 1
2535#define GL_NEAREST_MIPMAP_LINEAR 0x2702
2536#define GL_RGB10_A2 0x8059
2537#define GL_RGBA8 0x8058
2538#define GL_COLOR_ATTACHMENT1 0x8CE1
2539#define GL_RGBA4 0x8056
2540#define GL_RGB8 0x8051
2541#define GL_ARRAY_BUFFER 0x8892
2542#define GL_STENCIL 0x1802
2543#define GL_TEXTURE_2D 0x0DE1
2544#define GL_DEPTH 0x1801
2545#define GL_FRONT 0x0404
2546#define GL_STENCIL_BUFFER_BIT 0x00000400
2547#define GL_REPEAT 0x2901
2548#define GL_RGBA 0x1908
2549#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
2550#define GL_DECR 0x1E03
2551#define GL_FRAGMENT_SHADER 0x8B30
2552#define GL_FLOAT 0x1406
2553#define GL_TEXTURE_MAX_LOD 0x813B
2554#define GL_DEPTH_COMPONENT 0x1902
2555#define GL_ONE_MINUS_DST_ALPHA 0x0305
2556#define GL_COLOR 0x1800
2557#define GL_TEXTURE_2D_ARRAY 0x8C1A
2558#define GL_TRIANGLES 0x0004
2559#define GL_UNSIGNED_BYTE 0x1401
2560#define GL_TEXTURE_MAG_FILTER 0x2800
2561#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
2562#define GL_NONE 0
2563#define GL_SRC_COLOR 0x0300
2564#define GL_BYTE 0x1400
2565#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
2566#define GL_LINE_STRIP 0x0003
2567#define GL_TEXTURE_3D 0x806F
2568#define GL_CW 0x0900
2569#define GL_LINEAR 0x2601
2570#define GL_RENDERBUFFER 0x8D41
2571#define GL_GEQUAL 0x0206
2572#define GL_COLOR_BUFFER_BIT 0x00004000
2573#define GL_RGBA32F 0x8814
2574#define GL_BLEND 0x0BE2
2575#define GL_ONE_MINUS_SRC_ALPHA 0x0303
2576#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
2577#define GL_TEXTURE_WRAP_T 0x2803
2578#define GL_TEXTURE_WRAP_S 0x2802
2579#define GL_TEXTURE_MIN_FILTER 0x2801
2580#define GL_LINEAR_MIPMAP_NEAREST 0x2701
2581#define GL_EXTENSIONS 0x1F03
2582#define GL_NO_ERROR 0
2583#define GL_REPLACE 0x1E01
2584#define GL_KEEP 0x1E00
2585#define GL_CCW 0x0901
2586#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
2587#define GL_RGB 0x1907
2588#define GL_TRIANGLE_STRIP 0x0005
2589#define GL_FALSE 0
2590#define GL_ZERO 0
2591#define GL_CULL_FACE 0x0B44
2592#define GL_INVERT 0x150A
2593#define GL_UNSIGNED_INT 0x1405
2594#define GL_UNSIGNED_SHORT 0x1403
2595#define GL_NEAREST 0x2600
2596#define GL_SCISSOR_TEST 0x0C11
2597#define GL_LEQUAL 0x0203
2598#define GL_STENCIL_TEST 0x0B90
2599#define GL_DITHER 0x0BD0
2600#define GL_DEPTH_COMPONENT16 0x81A5
2601#define GL_EQUAL 0x0202
2602#define GL_FRAMEBUFFER 0x8D40
2603#define GL_RGB5 0x8050
2604#define GL_LINES 0x0001
2605#define GL_DEPTH_BUFFER_BIT 0x00000100
2606#define GL_SRC_ALPHA 0x0302
2607#define GL_INCR_WRAP 0x8507
2608#define GL_LESS 0x0201
2609#define GL_MULTISAMPLE 0x809D
2610#define GL_FRAMEBUFFER_BINDING 0x8CA6
2611#define GL_BACK 0x0405
2612#define GL_ALWAYS 0x0207
2613#define GL_FUNC_ADD 0x8006
2614#define GL_ONE_MINUS_DST_COLOR 0x0307
2615#define GL_NOTEQUAL 0x0205
2616#define GL_DST_COLOR 0x0306
2617#define GL_COMPILE_STATUS 0x8B81
2618#define GL_RED 0x1903
2619#define GL_COLOR_ATTACHMENT3 0x8CE3
2620#define GL_DST_ALPHA 0x0304
2621#define GL_RGB5_A1 0x8057
2622#define GL_GREATER 0x0204
2623#define GL_POLYGON_OFFSET_FILL 0x8037
2624#define GL_TRUE 1
2625#define GL_NEVER 0x0200
2626#define GL_POINTS 0x0000
2627#define GL_ONE_MINUS_SRC_COLOR 0x0301
2628#define GL_MIRRORED_REPEAT 0x8370
2629
2630typedef void (GL_APIENTRY *PFN_glBindVertexArray)(GLuint array);
2631static PFN_glBindVertexArray _sapp_glBindVertexArray;
2632typedef void (GL_APIENTRY *PFN_glFramebufferTextureLayer)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
2633static PFN_glFramebufferTextureLayer _sapp_glFramebufferTextureLayer;
2634typedef void (GL_APIENTRY *PFN_glGenFramebuffers)(GLsizei n, GLuint * framebuffers);
2635static PFN_glGenFramebuffers _sapp_glGenFramebuffers;
2636typedef void (GL_APIENTRY *PFN_glBindFramebuffer)(GLenum target, GLuint framebuffer);
2637static PFN_glBindFramebuffer _sapp_glBindFramebuffer;
2638typedef void (GL_APIENTRY *PFN_glBindRenderbuffer)(GLenum target, GLuint renderbuffer);
2639static PFN_glBindRenderbuffer _sapp_glBindRenderbuffer;
2640typedef const GLubyte * (GL_APIENTRY *PFN_glGetStringi)(GLenum name, GLuint index);
2641static PFN_glGetStringi _sapp_glGetStringi;
2642typedef void (GL_APIENTRY *PFN_glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
2643static PFN_glClearBufferfi _sapp_glClearBufferfi;
2644typedef void (GL_APIENTRY *PFN_glClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat * value);
2645static PFN_glClearBufferfv _sapp_glClearBufferfv;
2646typedef void (GL_APIENTRY *PFN_glClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint * value);
2647static PFN_glClearBufferuiv _sapp_glClearBufferuiv;
2648typedef void (GL_APIENTRY *PFN_glDeleteRenderbuffers)(GLsizei n, const GLuint * renderbuffers);
2649static PFN_glDeleteRenderbuffers _sapp_glDeleteRenderbuffers;
2650typedef void (GL_APIENTRY *PFN_glUniform4fv)(GLint location, GLsizei count, const GLfloat * value);
2651static PFN_glUniform4fv _sapp_glUniform4fv;
2652typedef void (GL_APIENTRY *PFN_glUniform2fv)(GLint location, GLsizei count, const GLfloat * value);
2653static PFN_glUniform2fv _sapp_glUniform2fv;
2654typedef void (GL_APIENTRY *PFN_glUseProgram)(GLuint program);
2655static PFN_glUseProgram _sapp_glUseProgram;
2656typedef void (GL_APIENTRY *PFN_glShaderSource)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);
2657static PFN_glShaderSource _sapp_glShaderSource;
2658typedef void (GL_APIENTRY *PFN_glLinkProgram)(GLuint program);
2659static PFN_glLinkProgram _sapp_glLinkProgram;
2660typedef GLint (GL_APIENTRY *PFN_glGetUniformLocation)(GLuint program, const GLchar * name);
2661static PFN_glGetUniformLocation _sapp_glGetUniformLocation;
2662typedef void (GL_APIENTRY *PFN_glGetShaderiv)(GLuint shader, GLenum pname, GLint * params);
2663static PFN_glGetShaderiv _sapp_glGetShaderiv;
2664typedef void (GL_APIENTRY *PFN_glGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
2665static PFN_glGetProgramInfoLog _sapp_glGetProgramInfoLog;
2666typedef GLint (GL_APIENTRY *PFN_glGetAttribLocation)(GLuint program, const GLchar * name);
2667static PFN_glGetAttribLocation _sapp_glGetAttribLocation;
2668typedef void (GL_APIENTRY *PFN_glDisableVertexAttribArray)(GLuint index);
2669static PFN_glDisableVertexAttribArray _sapp_glDisableVertexAttribArray;
2670typedef void (GL_APIENTRY *PFN_glDeleteShader)(GLuint shader);
2671static PFN_glDeleteShader _sapp_glDeleteShader;
2672typedef void (GL_APIENTRY *PFN_glDeleteProgram)(GLuint program);
2673static PFN_glDeleteProgram _sapp_glDeleteProgram;
2674typedef void (GL_APIENTRY *PFN_glCompileShader)(GLuint shader);
2675static PFN_glCompileShader _sapp_glCompileShader;
2676typedef void (GL_APIENTRY *PFN_glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask);
2677static PFN_glStencilFuncSeparate _sapp_glStencilFuncSeparate;
2678typedef void (GL_APIENTRY *PFN_glStencilOpSeparate)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
2679static PFN_glStencilOpSeparate _sapp_glStencilOpSeparate;
2680typedef void (GL_APIENTRY *PFN_glRenderbufferStorageMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
2681static PFN_glRenderbufferStorageMultisample _sapp_glRenderbufferStorageMultisample;
2682typedef void (GL_APIENTRY *PFN_glDrawBuffers)(GLsizei n, const GLenum * bufs);
2683static PFN_glDrawBuffers _sapp_glDrawBuffers;
2684typedef void (GL_APIENTRY *PFN_glVertexAttribDivisor)(GLuint index, GLuint divisor);
2685static PFN_glVertexAttribDivisor _sapp_glVertexAttribDivisor;
2686typedef void (GL_APIENTRY *PFN_glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data);
2687static PFN_glBufferSubData _sapp_glBufferSubData;
2688typedef void (GL_APIENTRY *PFN_glGenBuffers)(GLsizei n, GLuint * buffers);
2689static PFN_glGenBuffers _sapp_glGenBuffers;
2690typedef GLenum (GL_APIENTRY *PFN_glCheckFramebufferStatus)(GLenum target);
2691static PFN_glCheckFramebufferStatus _sapp_glCheckFramebufferStatus;
2692typedef void (GL_APIENTRY *PFN_glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
2693static PFN_glFramebufferRenderbuffer _sapp_glFramebufferRenderbuffer;
2694typedef void (GL_APIENTRY *PFN_glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data);
2695static PFN_glCompressedTexImage2D _sapp_glCompressedTexImage2D;
2696typedef void (GL_APIENTRY *PFN_glCompressedTexImage3D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data);
2697static PFN_glCompressedTexImage3D _sapp_glCompressedTexImage3D;
2698typedef void (GL_APIENTRY *PFN_glActiveTexture)(GLenum texture);
2699static PFN_glActiveTexture _sapp_glActiveTexture;
2700typedef void (GL_APIENTRY *PFN_glTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels);
2701static PFN_glTexSubImage3D _sapp_glTexSubImage3D;
2702typedef void (GL_APIENTRY *PFN_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
2703static PFN_glUniformMatrix4fv _sapp_glUniformMatrix4fv;
2704typedef void (GL_APIENTRY *PFN_glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
2705static PFN_glRenderbufferStorage _sapp_glRenderbufferStorage;
2706typedef void (GL_APIENTRY *PFN_glGenTextures)(GLsizei n, GLuint * textures);
2707static PFN_glGenTextures _sapp_glGenTextures;
2708typedef void (GL_APIENTRY *PFN_glPolygonOffset)(GLfloat factor, GLfloat units);
2709static PFN_glPolygonOffset _sapp_glPolygonOffset;
2710typedef void (GL_APIENTRY *PFN_glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void * indices);
2711static PFN_glDrawElements _sapp_glDrawElements;
2712typedef void (GL_APIENTRY *PFN_glDeleteFramebuffers)(GLsizei n, const GLuint * framebuffers);
2713static PFN_glDeleteFramebuffers _sapp_glDeleteFramebuffers;
2714typedef void (GL_APIENTRY *PFN_glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha);
2715static PFN_glBlendEquationSeparate _sapp_glBlendEquationSeparate;
2716typedef void (GL_APIENTRY *PFN_glDeleteTextures)(GLsizei n, const GLuint * textures);
2717static PFN_glDeleteTextures _sapp_glDeleteTextures;
2718typedef void (GL_APIENTRY *PFN_glGetProgramiv)(GLuint program, GLenum pname, GLint * params);
2719static PFN_glGetProgramiv _sapp_glGetProgramiv;
2720typedef void (GL_APIENTRY *PFN_glBindTexture)(GLenum target, GLuint texture);
2721static PFN_glBindTexture _sapp_glBindTexture;
2722typedef void (GL_APIENTRY *PFN_glTexImage3D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels);
2723static PFN_glTexImage3D _sapp_glTexImage3D;
2724typedef GLuint (GL_APIENTRY *PFN_glCreateShader)(GLenum type);
2725static PFN_glCreateShader _sapp_glCreateShader;
2726typedef void (GL_APIENTRY *PFN_glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);
2727static PFN_glTexSubImage2D _sapp_glTexSubImage2D;
2728typedef void (GL_APIENTRY *PFN_glClearDepth)(GLdouble depth);
2729static PFN_glClearDepth _sapp_glClearDepth;
2730typedef void (GL_APIENTRY *PFN_glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
2731static PFN_glFramebufferTexture2D _sapp_glFramebufferTexture2D;
2732typedef GLuint (GL_APIENTRY *PFN_glCreateProgram)();
2733static PFN_glCreateProgram _sapp_glCreateProgram;
2734typedef void (GL_APIENTRY *PFN_glViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
2735static PFN_glViewport _sapp_glViewport;
2736typedef void (GL_APIENTRY *PFN_glDeleteBuffers)(GLsizei n, const GLuint * buffers);
2737static PFN_glDeleteBuffers _sapp_glDeleteBuffers;
2738typedef void (GL_APIENTRY *PFN_glDrawArrays)(GLenum mode, GLint first, GLsizei count);
2739static PFN_glDrawArrays _sapp_glDrawArrays;
2740typedef void (GL_APIENTRY *PFN_glDrawElementsInstanced)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount);
2741static PFN_glDrawElementsInstanced _sapp_glDrawElementsInstanced;
2742typedef void (GL_APIENTRY *PFN_glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer);
2743static PFN_glVertexAttribPointer _sapp_glVertexAttribPointer;
2744typedef void (GL_APIENTRY *PFN_glUniform1i)(GLint location, GLint v0);
2745static PFN_glUniform1i _sapp_glUniform1i;
2746typedef void (GL_APIENTRY *PFN_glDisable)(GLenum cap);
2747static PFN_glDisable _sapp_glDisable;
2748typedef void (GL_APIENTRY *PFN_glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
2749static PFN_glColorMask _sapp_glColorMask;
2750typedef void (GL_APIENTRY *PFN_glBindBuffer)(GLenum target, GLuint buffer);
2751static PFN_glBindBuffer _sapp_glBindBuffer;
2752typedef void (GL_APIENTRY *PFN_glDeleteVertexArrays)(GLsizei n, const GLuint * arrays);
2753static PFN_glDeleteVertexArrays _sapp_glDeleteVertexArrays;
2754typedef void (GL_APIENTRY *PFN_glDepthMask)(GLboolean flag);
2755static PFN_glDepthMask _sapp_glDepthMask;
2756typedef void (GL_APIENTRY *PFN_glDrawArraysInstanced)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
2757static PFN_glDrawArraysInstanced _sapp_glDrawArraysInstanced;
2758typedef void (GL_APIENTRY *PFN_glClearStencil)(GLint s);
2759static PFN_glClearStencil _sapp_glClearStencil;
2760typedef void (GL_APIENTRY *PFN_glScissor)(GLint x, GLint y, GLsizei width, GLsizei height);
2761static PFN_glScissor _sapp_glScissor;
2762typedef void (GL_APIENTRY *PFN_glUniform3fv)(GLint location, GLsizei count, const GLfloat * value);
2763static PFN_glUniform3fv _sapp_glUniform3fv;
2764typedef void (GL_APIENTRY *PFN_glGenRenderbuffers)(GLsizei n, GLuint * renderbuffers);
2765static PFN_glGenRenderbuffers _sapp_glGenRenderbuffers;
2766typedef void (GL_APIENTRY *PFN_glBufferData)(GLenum target, GLsizeiptr size, const void * data, GLenum usage);
2767static PFN_glBufferData _sapp_glBufferData;
2768typedef void (GL_APIENTRY *PFN_glBlendFuncSeparate)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
2769static PFN_glBlendFuncSeparate _sapp_glBlendFuncSeparate;
2770typedef void (GL_APIENTRY *PFN_glTexParameteri)(GLenum target, GLenum pname, GLint param);
2771static PFN_glTexParameteri _sapp_glTexParameteri;
2772typedef void (GL_APIENTRY *PFN_glGetIntegerv)(GLenum pname, GLint * data);
2773static PFN_glGetIntegerv _sapp_glGetIntegerv;
2774typedef void (GL_APIENTRY *PFN_glEnable)(GLenum cap);
2775static PFN_glEnable _sapp_glEnable;
2776typedef void (GL_APIENTRY *PFN_glBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
2777static PFN_glBlitFramebuffer _sapp_glBlitFramebuffer;
2778typedef void (GL_APIENTRY *PFN_glStencilMask)(GLuint mask);
2779static PFN_glStencilMask _sapp_glStencilMask;
2780typedef void (GL_APIENTRY *PFN_glAttachShader)(GLuint program, GLuint shader);
2781static PFN_glAttachShader _sapp_glAttachShader;
2782typedef GLenum (GL_APIENTRY *PFN_glGetError)();
2783static PFN_glGetError _sapp_glGetError;
2784typedef void (GL_APIENTRY *PFN_glClearColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
2785static PFN_glClearColor _sapp_glClearColor;
2786typedef void (GL_APIENTRY *PFN_glBlendColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
2787static PFN_glBlendColor _sapp_glBlendColor;
2788typedef void (GL_APIENTRY *PFN_glTexParameterf)(GLenum target, GLenum pname, GLfloat param);
2789static PFN_glTexParameterf _sapp_glTexParameterf;
2790typedef void (GL_APIENTRY *PFN_glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
2791static PFN_glGetShaderInfoLog _sapp_glGetShaderInfoLog;
2792typedef void (GL_APIENTRY *PFN_glDepthFunc)(GLenum func);
2793static PFN_glDepthFunc _sapp_glDepthFunc;
2794typedef void (GL_APIENTRY *PFN_glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass);
2795static PFN_glStencilOp _sapp_glStencilOp;
2796typedef void (GL_APIENTRY *PFN_glStencilFunc)(GLenum func, GLint ref, GLuint mask);
2797static PFN_glStencilFunc _sapp_glStencilFunc;
2798typedef void (GL_APIENTRY *PFN_glEnableVertexAttribArray)(GLuint index);
2799static PFN_glEnableVertexAttribArray _sapp_glEnableVertexAttribArray;
2800typedef void (GL_APIENTRY *PFN_glBlendFunc)(GLenum sfactor, GLenum dfactor);
2801static PFN_glBlendFunc _sapp_glBlendFunc;
2802typedef void (GL_APIENTRY *PFN_glUniform1fv)(GLint location, GLsizei count, const GLfloat * value);
2803static PFN_glUniform1fv _sapp_glUniform1fv;
2804typedef void (GL_APIENTRY *PFN_glReadBuffer)(GLenum src);
2805static PFN_glReadBuffer _sapp_glReadBuffer;
2806typedef void (GL_APIENTRY *PFN_glClear)(GLbitfield mask);
2807static PFN_glClear _sapp_glClear;
2808typedef void (GL_APIENTRY *PFN_glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels);
2809static PFN_glTexImage2D _sapp_glTexImage2D;
2810typedef void (GL_APIENTRY *PFN_glGenVertexArrays)(GLsizei n, GLuint * arrays);
2811static PFN_glGenVertexArrays _sapp_glGenVertexArrays;
2812typedef void (GL_APIENTRY *PFN_glFrontFace)(GLenum mode);
2813static PFN_glFrontFace _sapp_glFrontFace;
2814typedef void (GL_APIENTRY *PFN_glCullFace)(GLenum mode);
2815static PFN_glCullFace _sapp_glCullFace;
2816
2817_SOKOL_PRIVATE void* _sapp_win32_glgetprocaddr(const char* name) {
2818 void* proc_addr = (void*) _sapp_wglGetProcAddress(name);
2819 if (0 == proc_addr) {
2820 proc_addr = (void*) GetProcAddress(_sapp_opengl32, name);
2821 }
2822 SOKOL_ASSERT(proc_addr);
2823 return proc_addr;
2824}
2825
2826#define _SAPP_GLPROC(name) _sapp_ ## name = (PFN_ ## name) _sapp_win32_glgetprocaddr(#name)
2827
2828_SOKOL_PRIVATE void _sapp_win32_gl_loadfuncs(void) {
2829 SOKOL_ASSERT(_sapp_wglGetProcAddress);
2830 SOKOL_ASSERT(_sapp_opengl32);
2831 _SAPP_GLPROC(glBindVertexArray);
2832 _SAPP_GLPROC(glFramebufferTextureLayer);
2833 _SAPP_GLPROC(glGenFramebuffers);
2834 _SAPP_GLPROC(glBindFramebuffer);
2835 _SAPP_GLPROC(glBindRenderbuffer);
2836 _SAPP_GLPROC(glGetStringi);
2837 _SAPP_GLPROC(glClearBufferfi);
2838 _SAPP_GLPROC(glClearBufferfv);
2839 _SAPP_GLPROC(glClearBufferuiv);
2840 _SAPP_GLPROC(glDeleteRenderbuffers);
2841 _SAPP_GLPROC(glUniform4fv);
2842 _SAPP_GLPROC(glUniform2fv);
2843 _SAPP_GLPROC(glUseProgram);
2844 _SAPP_GLPROC(glShaderSource);
2845 _SAPP_GLPROC(glLinkProgram);
2846 _SAPP_GLPROC(glGetUniformLocation);
2847 _SAPP_GLPROC(glGetShaderiv);
2848 _SAPP_GLPROC(glGetProgramInfoLog);
2849 _SAPP_GLPROC(glGetAttribLocation);
2850 _SAPP_GLPROC(glDisableVertexAttribArray);
2851 _SAPP_GLPROC(glDeleteShader);
2852 _SAPP_GLPROC(glDeleteProgram);
2853 _SAPP_GLPROC(glCompileShader);
2854 _SAPP_GLPROC(glStencilFuncSeparate);
2855 _SAPP_GLPROC(glStencilOpSeparate);
2856 _SAPP_GLPROC(glRenderbufferStorageMultisample);
2857 _SAPP_GLPROC(glDrawBuffers);
2858 _SAPP_GLPROC(glVertexAttribDivisor);
2859 _SAPP_GLPROC(glBufferSubData);
2860 _SAPP_GLPROC(glGenBuffers);
2861 _SAPP_GLPROC(glCheckFramebufferStatus);
2862 _SAPP_GLPROC(glFramebufferRenderbuffer);
2863 _SAPP_GLPROC(glCompressedTexImage2D);
2864 _SAPP_GLPROC(glCompressedTexImage3D);
2865 _SAPP_GLPROC(glActiveTexture);
2866 _SAPP_GLPROC(glTexSubImage3D);
2867 _SAPP_GLPROC(glUniformMatrix4fv);
2868 _SAPP_GLPROC(glRenderbufferStorage);
2869 _SAPP_GLPROC(glGenTextures);
2870 _SAPP_GLPROC(glPolygonOffset);
2871 _SAPP_GLPROC(glDrawElements);
2872 _SAPP_GLPROC(glDeleteFramebuffers);
2873 _SAPP_GLPROC(glBlendEquationSeparate);
2874 _SAPP_GLPROC(glDeleteTextures);
2875 _SAPP_GLPROC(glGetProgramiv);
2876 _SAPP_GLPROC(glBindTexture);
2877 _SAPP_GLPROC(glTexImage3D);
2878 _SAPP_GLPROC(glCreateShader);
2879 _SAPP_GLPROC(glTexSubImage2D);
2880 _SAPP_GLPROC(glClearDepth);
2881 _SAPP_GLPROC(glFramebufferTexture2D);
2882 _SAPP_GLPROC(glCreateProgram);
2883 _SAPP_GLPROC(glViewport);
2884 _SAPP_GLPROC(glDeleteBuffers);
2885 _SAPP_GLPROC(glDrawArrays);
2886 _SAPP_GLPROC(glDrawElementsInstanced);
2887 _SAPP_GLPROC(glVertexAttribPointer);
2888 _SAPP_GLPROC(glUniform1i);
2889 _SAPP_GLPROC(glDisable);
2890 _SAPP_GLPROC(glColorMask);
2891 _SAPP_GLPROC(glBindBuffer);
2892 _SAPP_GLPROC(glDeleteVertexArrays);
2893 _SAPP_GLPROC(glDepthMask);
2894 _SAPP_GLPROC(glDrawArraysInstanced);
2895 _SAPP_GLPROC(glClearStencil);
2896 _SAPP_GLPROC(glScissor);
2897 _SAPP_GLPROC(glUniform3fv);
2898 _SAPP_GLPROC(glGenRenderbuffers);
2899 _SAPP_GLPROC(glBufferData);
2900 _SAPP_GLPROC(glBlendFuncSeparate);
2901 _SAPP_GLPROC(glTexParameteri);
2902 _SAPP_GLPROC(glGetIntegerv);
2903 _SAPP_GLPROC(glEnable);
2904 _SAPP_GLPROC(glBlitFramebuffer);
2905 _SAPP_GLPROC(glStencilMask);
2906 _SAPP_GLPROC(glAttachShader);
2907 _SAPP_GLPROC(glGetError);
2908 _SAPP_GLPROC(glClearColor);
2909 _SAPP_GLPROC(glBlendColor);
2910 _SAPP_GLPROC(glTexParameterf);
2911 _SAPP_GLPROC(glGetShaderInfoLog);
2912 _SAPP_GLPROC(glDepthFunc);
2913 _SAPP_GLPROC(glStencilOp);
2914 _SAPP_GLPROC(glStencilFunc);
2915 _SAPP_GLPROC(glEnableVertexAttribArray);
2916 _SAPP_GLPROC(glBlendFunc);
2917 _SAPP_GLPROC(glUniform1fv);
2918 _SAPP_GLPROC(glReadBuffer);
2919 _SAPP_GLPROC(glClear);
2920 _SAPP_GLPROC(glTexImage2D);
2921 _SAPP_GLPROC(glGenVertexArrays);
2922 _SAPP_GLPROC(glFrontFace);
2923 _SAPP_GLPROC(glCullFace);
2924}
2925#define glBindVertexArray _sapp_glBindVertexArray
2926#define glFramebufferTextureLayer _sapp_glFramebufferTextureLayer
2927#define glGenFramebuffers _sapp_glGenFramebuffers
2928#define glBindFramebuffer _sapp_glBindFramebuffer
2929#define glBindRenderbuffer _sapp_glBindRenderbuffer
2930#define glGetStringi _sapp_glGetStringi
2931#define glClearBufferfi _sapp_glClearBufferfi
2932#define glClearBufferfv _sapp_glClearBufferfv
2933#define glClearBufferuiv _sapp_glClearBufferuiv
2934#define glDeleteRenderbuffers _sapp_glDeleteRenderbuffers
2935#define glUniform4fv _sapp_glUniform4fv
2936#define glUniform2fv _sapp_glUniform2fv
2937#define glUseProgram _sapp_glUseProgram
2938#define glShaderSource _sapp_glShaderSource
2939#define glLinkProgram _sapp_glLinkProgram
2940#define glGetUniformLocation _sapp_glGetUniformLocation
2941#define glGetShaderiv _sapp_glGetShaderiv
2942#define glGetProgramInfoLog _sapp_glGetProgramInfoLog
2943#define glGetAttribLocation _sapp_glGetAttribLocation
2944#define glDisableVertexAttribArray _sapp_glDisableVertexAttribArray
2945#define glDeleteShader _sapp_glDeleteShader
2946#define glDeleteProgram _sapp_glDeleteProgram
2947#define glCompileShader _sapp_glCompileShader
2948#define glStencilFuncSeparate _sapp_glStencilFuncSeparate
2949#define glStencilOpSeparate _sapp_glStencilOpSeparate
2950#define glRenderbufferStorageMultisample _sapp_glRenderbufferStorageMultisample
2951#define glDrawBuffers _sapp_glDrawBuffers
2952#define glVertexAttribDivisor _sapp_glVertexAttribDivisor
2953#define glBufferSubData _sapp_glBufferSubData
2954#define glGenBuffers _sapp_glGenBuffers
2955#define glCheckFramebufferStatus _sapp_glCheckFramebufferStatus
2956#define glFramebufferRenderbuffer _sapp_glFramebufferRenderbuffer
2957#define glCompressedTexImage2D _sapp_glCompressedTexImage2D
2958#define glCompressedTexImage3D _sapp_glCompressedTexImage3D
2959#define glActiveTexture _sapp_glActiveTexture
2960#define glTexSubImage3D _sapp_glTexSubImage3D
2961#define glUniformMatrix4fv _sapp_glUniformMatrix4fv
2962#define glRenderbufferStorage _sapp_glRenderbufferStorage
2963#define glGenTextures _sapp_glGenTextures
2964#define glPolygonOffset _sapp_glPolygonOffset
2965#define glDrawElements _sapp_glDrawElements
2966#define glDeleteFramebuffers _sapp_glDeleteFramebuffers
2967#define glBlendEquationSeparate _sapp_glBlendEquationSeparate
2968#define glDeleteTextures _sapp_glDeleteTextures
2969#define glGetProgramiv _sapp_glGetProgramiv
2970#define glBindTexture _sapp_glBindTexture
2971#define glTexImage3D _sapp_glTexImage3D
2972#define glCreateShader _sapp_glCreateShader
2973#define glTexSubImage2D _sapp_glTexSubImage2D
2974#define glClearDepth _sapp_glClearDepth
2975#define glFramebufferTexture2D _sapp_glFramebufferTexture2D
2976#define glCreateProgram _sapp_glCreateProgram
2977#define glViewport _sapp_glViewport
2978#define glDeleteBuffers _sapp_glDeleteBuffers
2979#define glDrawArrays _sapp_glDrawArrays
2980#define glDrawElementsInstanced _sapp_glDrawElementsInstanced
2981#define glVertexAttribPointer _sapp_glVertexAttribPointer
2982#define glUniform1i _sapp_glUniform1i
2983#define glDisable _sapp_glDisable
2984#define glColorMask _sapp_glColorMask
2985#define glBindBuffer _sapp_glBindBuffer
2986#define glDeleteVertexArrays _sapp_glDeleteVertexArrays
2987#define glDepthMask _sapp_glDepthMask
2988#define glDrawArraysInstanced _sapp_glDrawArraysInstanced
2989#define glClearStencil _sapp_glClearStencil
2990#define glScissor _sapp_glScissor
2991#define glUniform3fv _sapp_glUniform3fv
2992#define glGenRenderbuffers _sapp_glGenRenderbuffers
2993#define glBufferData _sapp_glBufferData
2994#define glBlendFuncSeparate _sapp_glBlendFuncSeparate
2995#define glTexParameteri _sapp_glTexParameteri
2996#define glGetIntegerv _sapp_glGetIntegerv
2997#define glEnable _sapp_glEnable
2998#define glBlitFramebuffer _sapp_glBlitFramebuffer
2999#define glStencilMask _sapp_glStencilMask
3000#define glAttachShader _sapp_glAttachShader
3001#define glGetError _sapp_glGetError
3002#define glClearColor _sapp_glClearColor
3003#define glBlendColor _sapp_glBlendColor
3004#define glTexParameterf _sapp_glTexParameterf
3005#define glGetShaderInfoLog _sapp_glGetShaderInfoLog
3006#define glDepthFunc _sapp_glDepthFunc
3007#define glStencilOp _sapp_glStencilOp
3008#define glStencilFunc _sapp_glStencilFunc
3009#define glEnableVertexAttribArray _sapp_glEnableVertexAttribArray
3010#define glBlendFunc _sapp_glBlendFunc
3011#define glUniform1fv _sapp_glUniform1fv
3012#define glReadBuffer _sapp_glReadBuffer
3013#define glClear _sapp_glClear
3014#define glTexImage2D _sapp_glTexImage2D
3015#define glGenVertexArrays _sapp_glGenVertexArrays
3016#define glFrontFace _sapp_glFrontFace
3017#define glCullFace _sapp_glCullFace
3018
3019#endif /* SOKOL_WIN32_NO_GL_LOADER */
3020
3021#endif /* SOKOL_GLCORE33 */
3022
3023#if defined(SOKOL_D3D11)
3024#define _SAPP_SAFE_RELEASE(class, obj) if (obj) { class##_Release(obj); obj=0; }
3025_SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) {
3026 DXGI_SWAP_CHAIN_DESC* sc_desc = &_sapp_dxgi_swap_chain_desc;
3027 sc_desc->BufferDesc.Width = _sapp.framebuffer_width;
3028 sc_desc->BufferDesc.Height = _sapp.framebuffer_height;
3029 sc_desc->BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
3030 sc_desc->BufferDesc.RefreshRate.Numerator = 60;
3031 sc_desc->BufferDesc.RefreshRate.Denominator = 1;
3032 sc_desc->OutputWindow = _sapp_win32_hwnd;
3033 sc_desc->Windowed = true;
3034 sc_desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
3035 sc_desc->BufferCount = 1;
3036 sc_desc->SampleDesc.Count = _sapp.sample_count;
3037 sc_desc->SampleDesc.Quality = _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0;
3038 sc_desc->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3039 int create_flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
3040 #if defined(SOKOL_DEBUG)
3041 create_flags |= D3D11_CREATE_DEVICE_DEBUG;
3042 #endif
3043 D3D_FEATURE_LEVEL feature_level;
3044 HRESULT hr = D3D11CreateDeviceAndSwapChain(
3045 NULL, /* pAdapter (use default) */
3046 D3D_DRIVER_TYPE_HARDWARE, /* DriverType */
3047 NULL, /* Software */
3048 create_flags, /* Flags */
3049 NULL, /* pFeatureLevels */
3050 0, /* FeatureLevels */
3051 D3D11_SDK_VERSION, /* SDKVersion */
3052 sc_desc, /* pSwapChainDesc */
3053 &_sapp_dxgi_swap_chain, /* ppSwapChain */
3054 &_sapp_d3d11_device, /* ppDevice */
3055 &feature_level, /* pFeatureLevel */
3056 &_sapp_d3d11_device_context); /* ppImmediateContext */
3057 _SOKOL_UNUSED(hr);
3058 SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_dxgi_swap_chain && _sapp_d3d11_device && _sapp_d3d11_device_context);
3059}
3060
3061_SOKOL_PRIVATE void _sapp_d3d11_destroy_device_and_swapchain(void) {
3062 _SAPP_SAFE_RELEASE(IDXGISwapChain, _sapp_dxgi_swap_chain);
3063 _SAPP_SAFE_RELEASE(ID3D11DeviceContext, _sapp_d3d11_device_context);
3064 _SAPP_SAFE_RELEASE(ID3D11Device, _sapp_d3d11_device);
3065}
3066
3067_SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(void) {
3068 HRESULT hr;
3069 #ifdef __cplusplus
3070 hr = IDXGISwapChain_GetBuffer(_sapp_dxgi_swap_chain, 0, IID_ID3D11Texture2D, (void**)&_sapp_d3d11_rt);
3071 #else
3072 hr = IDXGISwapChain_GetBuffer(_sapp_dxgi_swap_chain, 0, &IID_ID3D11Texture2D, (void**)&_sapp_d3d11_rt);
3073 #endif
3074 SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_rt);
3075 hr = ID3D11Device_CreateRenderTargetView(_sapp_d3d11_device, (ID3D11Resource*)_sapp_d3d11_rt, NULL, &_sapp_d3d11_rtv);
3076 SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_rtv);
3077 D3D11_TEXTURE2D_DESC ds_desc;
3078 memset(&ds_desc, 0, sizeof(ds_desc));
3079 ds_desc.Width = _sapp.framebuffer_width;
3080 ds_desc.Height = _sapp.framebuffer_height;
3081 ds_desc.MipLevels = 1;
3082 ds_desc.ArraySize = 1;
3083 ds_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
3084 ds_desc.SampleDesc = _sapp_dxgi_swap_chain_desc.SampleDesc;
3085 ds_desc.Usage = D3D11_USAGE_DEFAULT;
3086 ds_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
3087 hr = ID3D11Device_CreateTexture2D(_sapp_d3d11_device, &ds_desc, NULL, &_sapp_d3d11_ds);
3088 SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_ds);
3089 D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc;
3090 memset(&dsv_desc, 0, sizeof(dsv_desc));
3091 dsv_desc.Format = ds_desc.Format;
3092 dsv_desc.ViewDimension = _sapp.sample_count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
3093 hr = ID3D11Device_CreateDepthStencilView(_sapp_d3d11_device, (ID3D11Resource*)_sapp_d3d11_ds, &dsv_desc, &_sapp_d3d11_dsv);
3094 SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_dsv);
3095}
3096
3097_SOKOL_PRIVATE void _sapp_d3d11_destroy_default_render_target(void) {
3098 _SAPP_SAFE_RELEASE(ID3D11Texture2D, _sapp_d3d11_rt);
3099 _SAPP_SAFE_RELEASE(ID3D11RenderTargetView, _sapp_d3d11_rtv);
3100 _SAPP_SAFE_RELEASE(ID3D11Texture2D, _sapp_d3d11_ds);
3101 _SAPP_SAFE_RELEASE(ID3D11DepthStencilView, _sapp_d3d11_dsv);
3102}
3103
3104_SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(void) {
3105 if (_sapp_dxgi_swap_chain) {
3106 _sapp_d3d11_destroy_default_render_target();
3107 IDXGISwapChain_ResizeBuffers(_sapp_dxgi_swap_chain, 1, _sapp.framebuffer_width, _sapp.framebuffer_height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
3108 _sapp_d3d11_create_default_render_target();
3109 }
3110}
3111#endif
3112
3113#if defined(SOKOL_GLCORE33)
3114_SOKOL_PRIVATE void _sapp_wgl_init(void) {
3115 _sapp_opengl32 = LoadLibraryA("opengl32.dll");
3116 if (!_sapp_opengl32) {
3117 _sapp_fail("Failed to load opengl32.dll\n");
3118 }
3119 SOKOL_ASSERT(_sapp_opengl32);
3120 _sapp_wglCreateContext = (PFN_wglCreateContext) GetProcAddress(_sapp_opengl32, "wglCreateContext");
3121 SOKOL_ASSERT(_sapp_wglCreateContext);
3122 _sapp_wglDeleteContext = (PFN_wglDeleteContext) GetProcAddress(_sapp_opengl32, "wglDeleteContext");
3123 SOKOL_ASSERT(_sapp_wglDeleteContext);
3124 _sapp_wglGetProcAddress = (PFN_wglGetProcAddress) GetProcAddress(_sapp_opengl32, "wglGetProcAddress");
3125 SOKOL_ASSERT(_sapp_wglGetProcAddress);
3126 _sapp_wglGetCurrentDC = (PFN_wglGetCurrentDC) GetProcAddress(_sapp_opengl32, "wglGetCurrentDC");
3127 SOKOL_ASSERT(_sapp_wglGetCurrentDC);
3128 _sapp_wglMakeCurrent = (PFN_wglMakeCurrent) GetProcAddress(_sapp_opengl32, "wglMakeCurrent");
3129 SOKOL_ASSERT(_sapp_wglMakeCurrent);
3130
3131 _sapp_win32_msg_hwnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
3132 L"SOKOLAPP",
3133 L"sokol-app message window",
3134 WS_CLIPSIBLINGS|WS_CLIPCHILDREN,
3135 0, 0, 1, 1,
3136 NULL, NULL,
3137 GetModuleHandleW(NULL),
3138 NULL);
3139 if (!_sapp_win32_msg_hwnd) {
3140 _sapp_fail("Win32: failed to create helper window!\n");
3141 }
3142 ShowWindow(_sapp_win32_msg_hwnd, SW_HIDE);
3143 MSG msg;
3144 while (PeekMessageW(&msg, _sapp_win32_msg_hwnd, 0, 0, PM_REMOVE)) {
3145 TranslateMessage(&msg);
3146 DispatchMessageW(&msg);
3147 }
3148 _sapp_win32_msg_dc = GetDC(_sapp_win32_msg_hwnd);
3149 if (!_sapp_win32_msg_dc) {
3150 _sapp_fail("Win32: failed to obtain helper window DC!\n");
3151 }
3152}
3153
3154_SOKOL_PRIVATE void _sapp_wgl_shutdown(void) {
3155 SOKOL_ASSERT(_sapp_opengl32 && _sapp_win32_msg_hwnd);
3156 DestroyWindow(_sapp_win32_msg_hwnd); _sapp_win32_msg_hwnd = 0;
3157 FreeLibrary(_sapp_opengl32); _sapp_opengl32 = 0;
3158}
3159
3160_SOKOL_PRIVATE bool _sapp_wgl_has_ext(const char* ext, const char* extensions) {
3161 SOKOL_ASSERT(ext && extensions);
3162 const char* start = extensions;
3163 while (true) {
3164 const char* where = strstr(start, ext);
3165 if (!where) {
3166 return false;
3167 }
3168 const char* terminator = where + strlen(ext);
3169 if ((where == start) || (*(where - 1) == ' ')) {
3170 if (*terminator == ' ' || *terminator == '\0') {
3171 break;
3172 }
3173 }
3174 start = terminator;
3175 }
3176 return true;
3177}
3178
3179_SOKOL_PRIVATE bool _sapp_wgl_ext_supported(const char* ext) {
3180 SOKOL_ASSERT(ext);
3181 if (_sapp_GetExtensionsStringEXT) {
3182 const char* extensions = _sapp_GetExtensionsStringEXT();
3183 if (extensions) {
3184 if (_sapp_wgl_has_ext(ext, extensions)) {
3185 return true;
3186 }
3187 }
3188 }
3189 if (_sapp_GetExtensionsStringARB) {
3190 const char* extensions = _sapp_GetExtensionsStringARB(_sapp_wglGetCurrentDC());
3191 if (extensions) {
3192 if (_sapp_wgl_has_ext(ext, extensions)) {
3193 return true;
3194 }
3195 }
3196 }
3197 return false;
3198}
3199
3200_SOKOL_PRIVATE void _sapp_wgl_load_extensions(void) {
3201 SOKOL_ASSERT(_sapp_win32_msg_dc);
3202 PIXELFORMATDESCRIPTOR pfd;
3203 memset(&pfd, 0, sizeof(pfd));
3204 pfd.nSize = sizeof(pfd);
3205 pfd.nVersion = 1;
3206 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
3207 pfd.iPixelType = PFD_TYPE_RGBA;
3208 pfd.cColorBits = 24;
3209 if (!SetPixelFormat(_sapp_win32_msg_dc, ChoosePixelFormat(_sapp_win32_msg_dc, &pfd), &pfd)) {
3210 _sapp_fail("WGL: failed to set pixel format for dummy context\n");
3211 }
3212 HGLRC rc = _sapp_wglCreateContext(_sapp_win32_msg_dc);
3213 if (!rc) {
3214 _sapp_fail("WGL: Failed to create dummy context\n");
3215 }
3216 if (!_sapp_wglMakeCurrent(_sapp_win32_msg_dc, rc)) {
3217 _sapp_fail("WGL: Failed to make context current\n");
3218 }
3219 _sapp_GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) _sapp_wglGetProcAddress("wglGetExtensionsStringEXT");
3220 _sapp_GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) _sapp_wglGetProcAddress("wglGetExtensionsStringARB");
3221 _sapp_CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) _sapp_wglGetProcAddress("wglCreateContextAttribsARB");
3222 _sapp_SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) _sapp_wglGetProcAddress("wglSwapIntervalEXT");
3223 _sapp_GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) _sapp_wglGetProcAddress("wglGetPixelFormatAttribivARB");
3224 _sapp_arb_multisample = _sapp_wgl_ext_supported("WGL_ARB_multisample");
3225 _sapp_arb_create_context = _sapp_wgl_ext_supported("WGL_ARB_create_context");
3226 _sapp_arb_create_context_profile = _sapp_wgl_ext_supported("WGL_ARB_create_context_profile");
3227 _sapp_ext_swap_control = _sapp_wgl_ext_supported("WGL_EXT_swap_control");
3228 _sapp_arb_pixel_format = _sapp_wgl_ext_supported("WGL_ARB_pixel_format");
3229 _sapp_wglMakeCurrent(_sapp_win32_msg_dc, 0);
3230 _sapp_wglDeleteContext(rc);
3231}
3232
3233_SOKOL_PRIVATE int _sapp_wgl_attrib(int pixel_format, int attrib) {
3234 SOKOL_ASSERT(_sapp_arb_pixel_format);
3235 int value = 0;
3236 if (!_sapp_GetPixelFormatAttribivARB(_sapp_win32_dc, pixel_format, 0, 1, &attrib, &value)) {
3237 _sapp_fail("WGL: Failed to retrieve pixel format attribute\n");
3238 }
3239 return value;
3240}
3241
3242_SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) {
3243 SOKOL_ASSERT(_sapp_win32_dc);
3244 SOKOL_ASSERT(_sapp_arb_pixel_format);
3245 const _sapp_gl_fbconfig* closest;
3246
3247 int native_count = _sapp_wgl_attrib(1, WGL_NUMBER_PIXEL_FORMATS_ARB);
3248 _sapp_gl_fbconfig* usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC(native_count, sizeof(_sapp_gl_fbconfig));
3249 int usable_count = 0;
3250 for (int i = 0; i < native_count; i++) {
3251 const int n = i + 1;
3252 _sapp_gl_fbconfig* u = usable_configs + usable_count;
3253 _sapp_gl_init_fbconfig(u);
3254 if (!_sapp_wgl_attrib(n, WGL_SUPPORT_OPENGL_ARB) || !_sapp_wgl_attrib(n, WGL_DRAW_TO_WINDOW_ARB)) {
3255 continue;
3256 }
3257 if (_sapp_wgl_attrib(n, WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) {
3258 continue;
3259 }
3260 if (_sapp_wgl_attrib(n, WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) {
3261 continue;
3262 }
3263 u->red_bits = _sapp_wgl_attrib(n, WGL_RED_BITS_ARB);
3264 u->green_bits = _sapp_wgl_attrib(n, WGL_GREEN_BITS_ARB);
3265 u->blue_bits = _sapp_wgl_attrib(n, WGL_BLUE_BITS_ARB);
3266 u->alpha_bits = _sapp_wgl_attrib(n, WGL_ALPHA_BITS_ARB);
3267 u->depth_bits = _sapp_wgl_attrib(n, WGL_DEPTH_BITS_ARB);
3268 u->stencil_bits = _sapp_wgl_attrib(n, WGL_STENCIL_BITS_ARB);
3269 if (_sapp_wgl_attrib(n, WGL_DOUBLE_BUFFER_ARB)) {
3270 u->doublebuffer = true;
3271 }
3272 if (_sapp_arb_multisample) {
3273 u->samples = _sapp_wgl_attrib(n, WGL_SAMPLES_ARB);
3274 }
3275 u->handle = n;
3276 usable_count++;
3277 }
3278 SOKOL_ASSERT(usable_count > 0);
3279 _sapp_gl_fbconfig desired;
3280 _sapp_gl_init_fbconfig(&desired);
3281 desired.red_bits = 8;
3282 desired.green_bits = 8;
3283 desired.blue_bits = 8;
3284 desired.alpha_bits = 8;
3285 desired.depth_bits = 24;
3286 desired.stencil_bits = 8;
3287 desired.doublebuffer = true;
3288 desired.samples = _sapp.sample_count > 1 ? _sapp.sample_count : 0;
3289 closest = _sapp_gl_choose_fbconfig(&desired, usable_configs, usable_count);
3290 int pixel_format = 0;
3291 if (closest) {
3292 pixel_format = (int) closest->handle;
3293 }
3294 SOKOL_FREE(usable_configs);
3295 return pixel_format;
3296}
3297
3298_SOKOL_PRIVATE void _sapp_wgl_create_context(void) {
3299 int pixel_format = _sapp_wgl_find_pixel_format();
3300 if (0 == pixel_format) {
3301 _sapp_fail("WGL: Didn't find matching pixel format.\n");
3302 }
3303 PIXELFORMATDESCRIPTOR pfd;
3304 if (!DescribePixelFormat(_sapp_win32_dc, pixel_format, sizeof(pfd), &pfd)) {
3305 _sapp_fail("WGL: Failed to retrieve PFD for selected pixel format!\n");
3306 }
3307 if (!SetPixelFormat(_sapp_win32_dc, pixel_format, &pfd)) {
3308 _sapp_fail("WGL: Failed to set selected pixel format!\n");
3309 }
3310 if (!_sapp_arb_create_context) {
3311 _sapp_fail("WGL: ARB_create_context required!\n");
3312 }
3313 if (!_sapp_arb_create_context_profile) {
3314 _sapp_fail("WGL: ARB_create_context_profile required!\n");
3315 }
3316 const int attrs[] = {
3317 WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
3318 WGL_CONTEXT_MINOR_VERSION_ARB, 3,
3319 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
3320 WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
3321 0, 0
3322 };
3323 _sapp_gl_ctx = _sapp_CreateContextAttribsARB(_sapp_win32_dc, 0, attrs);
3324 if (!_sapp_gl_ctx) {
3325 const DWORD err = GetLastError();
3326 if (err == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) {
3327 _sapp_fail("WGL: Driver does not support OpenGL version 3.3\n");
3328 }
3329 else if (err == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) {
3330 _sapp_fail("WGL: Driver does not support the requested OpenGL profile");
3331 }
3332 else if (err == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) {
3333 _sapp_fail("WGL: The share context is not compatible with the requested context");
3334 }
3335 else {
3336 _sapp_fail("WGL: Failed to create OpenGL context");
3337 }
3338 }
3339 _sapp_wglMakeCurrent(_sapp_win32_dc, _sapp_gl_ctx);
3340 if (_sapp_ext_swap_control) {
3341 /* FIXME: DwmIsCompositionEnabled() (see GLFW) */
3342 _sapp_SwapIntervalEXT(_sapp.swap_interval);
3343 }
3344}
3345
3346_SOKOL_PRIVATE void _sapp_wgl_destroy_context(void) {
3347 SOKOL_ASSERT(_sapp_gl_ctx);
3348 _sapp_wglDeleteContext(_sapp_gl_ctx);
3349 _sapp_gl_ctx = 0;
3350}
3351
3352_SOKOL_PRIVATE void _sapp_wgl_swap_buffers(void) {
3353 SOKOL_ASSERT(_sapp_win32_dc);
3354 /* FIXME: DwmIsCompositionEnabled? (see GLFW) */
3355 SwapBuffers(_sapp_win32_dc);
3356}
3357#endif
3358
3359_SOKOL_PRIVATE bool _sapp_win32_utf8_to_wide(const char* src, wchar_t* dst, int dst_num_bytes) {
3360 SOKOL_ASSERT(src && dst && (dst_num_bytes > 1));
3361 memset(dst, 0, dst_num_bytes);
3362 const int dst_chars = dst_num_bytes / sizeof(wchar_t);
3363 const int dst_needed = MultiByteToWideChar(CP_UTF8, 0, src, -1, 0, 0);
3364 if ((dst_needed > 0) && (dst_needed < dst_chars)) {
3365 MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst_chars);
3366 return true;
3367 }
3368 else {
3369 /* input string doesn't fit into destination buffer */
3370 return false;
3371 }
3372}
3373
3374_SOKOL_PRIVATE void _sapp_win32_init_keytable(void) {
3375 /* same as GLFW */
3376 _sapp.keycodes[0x00B] = SAPP_KEYCODE_0;
3377 _sapp.keycodes[0x002] = SAPP_KEYCODE_1;
3378 _sapp.keycodes[0x003] = SAPP_KEYCODE_2;
3379 _sapp.keycodes[0x004] = SAPP_KEYCODE_3;
3380 _sapp.keycodes[0x005] = SAPP_KEYCODE_4;
3381 _sapp.keycodes[0x006] = SAPP_KEYCODE_5;
3382 _sapp.keycodes[0x007] = SAPP_KEYCODE_6;
3383 _sapp.keycodes[0x008] = SAPP_KEYCODE_7;
3384 _sapp.keycodes[0x009] = SAPP_KEYCODE_8;
3385 _sapp.keycodes[0x00A] = SAPP_KEYCODE_9;
3386 _sapp.keycodes[0x01E] = SAPP_KEYCODE_A;
3387 _sapp.keycodes[0x030] = SAPP_KEYCODE_B;
3388 _sapp.keycodes[0x02E] = SAPP_KEYCODE_C;
3389 _sapp.keycodes[0x020] = SAPP_KEYCODE_D;
3390 _sapp.keycodes[0x012] = SAPP_KEYCODE_E;
3391 _sapp.keycodes[0x021] = SAPP_KEYCODE_F;
3392 _sapp.keycodes[0x022] = SAPP_KEYCODE_G;
3393 _sapp.keycodes[0x023] = SAPP_KEYCODE_H;
3394 _sapp.keycodes[0x017] = SAPP_KEYCODE_I;
3395 _sapp.keycodes[0x024] = SAPP_KEYCODE_J;
3396 _sapp.keycodes[0x025] = SAPP_KEYCODE_K;
3397 _sapp.keycodes[0x026] = SAPP_KEYCODE_L;
3398 _sapp.keycodes[0x032] = SAPP_KEYCODE_M;
3399 _sapp.keycodes[0x031] = SAPP_KEYCODE_N;
3400 _sapp.keycodes[0x018] = SAPP_KEYCODE_O;
3401 _sapp.keycodes[0x019] = SAPP_KEYCODE_P;
3402 _sapp.keycodes[0x010] = SAPP_KEYCODE_Q;
3403 _sapp.keycodes[0x013] = SAPP_KEYCODE_R;
3404 _sapp.keycodes[0x01F] = SAPP_KEYCODE_S;
3405 _sapp.keycodes[0x014] = SAPP_KEYCODE_T;
3406 _sapp.keycodes[0x016] = SAPP_KEYCODE_U;
3407 _sapp.keycodes[0x02F] = SAPP_KEYCODE_V;
3408 _sapp.keycodes[0x011] = SAPP_KEYCODE_W;
3409 _sapp.keycodes[0x02D] = SAPP_KEYCODE_X;
3410 _sapp.keycodes[0x015] = SAPP_KEYCODE_Y;
3411 _sapp.keycodes[0x02C] = SAPP_KEYCODE_Z;
3412 _sapp.keycodes[0x028] = SAPP_KEYCODE_APOSTROPHE;
3413 _sapp.keycodes[0x02B] = SAPP_KEYCODE_BACKSLASH;
3414 _sapp.keycodes[0x033] = SAPP_KEYCODE_COMMA;
3415 _sapp.keycodes[0x00D] = SAPP_KEYCODE_EQUAL;
3416 _sapp.keycodes[0x029] = SAPP_KEYCODE_GRAVE_ACCENT;
3417 _sapp.keycodes[0x01A] = SAPP_KEYCODE_LEFT_BRACKET;
3418 _sapp.keycodes[0x00C] = SAPP_KEYCODE_MINUS;
3419 _sapp.keycodes[0x034] = SAPP_KEYCODE_PERIOD;
3420 _sapp.keycodes[0x01B] = SAPP_KEYCODE_RIGHT_BRACKET;
3421 _sapp.keycodes[0x027] = SAPP_KEYCODE_SEMICOLON;
3422 _sapp.keycodes[0x035] = SAPP_KEYCODE_SLASH;
3423 _sapp.keycodes[0x056] = SAPP_KEYCODE_WORLD_2;
3424 _sapp.keycodes[0x00E] = SAPP_KEYCODE_BACKSPACE;
3425 _sapp.keycodes[0x153] = SAPP_KEYCODE_DELETE;
3426 _sapp.keycodes[0x14F] = SAPP_KEYCODE_END;
3427 _sapp.keycodes[0x01C] = SAPP_KEYCODE_ENTER;
3428 _sapp.keycodes[0x001] = SAPP_KEYCODE_ESCAPE;
3429 _sapp.keycodes[0x147] = SAPP_KEYCODE_HOME;
3430 _sapp.keycodes[0x152] = SAPP_KEYCODE_INSERT;
3431 _sapp.keycodes[0x15D] = SAPP_KEYCODE_MENU;
3432 _sapp.keycodes[0x151] = SAPP_KEYCODE_PAGE_DOWN;
3433 _sapp.keycodes[0x149] = SAPP_KEYCODE_PAGE_UP;
3434 _sapp.keycodes[0x045] = SAPP_KEYCODE_PAUSE;
3435 _sapp.keycodes[0x146] = SAPP_KEYCODE_PAUSE;
3436 _sapp.keycodes[0x039] = SAPP_KEYCODE_SPACE;
3437 _sapp.keycodes[0x00F] = SAPP_KEYCODE_TAB;
3438 _sapp.keycodes[0x03A] = SAPP_KEYCODE_CAPS_LOCK;
3439 _sapp.keycodes[0x145] = SAPP_KEYCODE_NUM_LOCK;
3440 _sapp.keycodes[0x046] = SAPP_KEYCODE_SCROLL_LOCK;
3441 _sapp.keycodes[0x03B] = SAPP_KEYCODE_F1;
3442 _sapp.keycodes[0x03C] = SAPP_KEYCODE_F2;
3443 _sapp.keycodes[0x03D] = SAPP_KEYCODE_F3;
3444 _sapp.keycodes[0x03E] = SAPP_KEYCODE_F4;
3445 _sapp.keycodes[0x03F] = SAPP_KEYCODE_F5;
3446 _sapp.keycodes[0x040] = SAPP_KEYCODE_F6;
3447 _sapp.keycodes[0x041] = SAPP_KEYCODE_F7;
3448 _sapp.keycodes[0x042] = SAPP_KEYCODE_F8;
3449 _sapp.keycodes[0x043] = SAPP_KEYCODE_F9;
3450 _sapp.keycodes[0x044] = SAPP_KEYCODE_F10;
3451 _sapp.keycodes[0x057] = SAPP_KEYCODE_F11;
3452 _sapp.keycodes[0x058] = SAPP_KEYCODE_F12;
3453 _sapp.keycodes[0x064] = SAPP_KEYCODE_F13;
3454 _sapp.keycodes[0x065] = SAPP_KEYCODE_F14;
3455 _sapp.keycodes[0x066] = SAPP_KEYCODE_F15;
3456 _sapp.keycodes[0x067] = SAPP_KEYCODE_F16;
3457 _sapp.keycodes[0x068] = SAPP_KEYCODE_F17;
3458 _sapp.keycodes[0x069] = SAPP_KEYCODE_F18;
3459 _sapp.keycodes[0x06A] = SAPP_KEYCODE_F19;
3460 _sapp.keycodes[0x06B] = SAPP_KEYCODE_F20;
3461 _sapp.keycodes[0x06C] = SAPP_KEYCODE_F21;
3462 _sapp.keycodes[0x06D] = SAPP_KEYCODE_F22;
3463 _sapp.keycodes[0x06E] = SAPP_KEYCODE_F23;
3464 _sapp.keycodes[0x076] = SAPP_KEYCODE_F24;
3465 _sapp.keycodes[0x038] = SAPP_KEYCODE_LEFT_ALT;
3466 _sapp.keycodes[0x01D] = SAPP_KEYCODE_LEFT_CONTROL;
3467 _sapp.keycodes[0x02A] = SAPP_KEYCODE_LEFT_SHIFT;
3468 _sapp.keycodes[0x15B] = SAPP_KEYCODE_LEFT_SUPER;
3469 _sapp.keycodes[0x137] = SAPP_KEYCODE_PRINT_SCREEN;
3470 _sapp.keycodes[0x138] = SAPP_KEYCODE_RIGHT_ALT;
3471 _sapp.keycodes[0x11D] = SAPP_KEYCODE_RIGHT_CONTROL;
3472 _sapp.keycodes[0x036] = SAPP_KEYCODE_RIGHT_SHIFT;
3473 _sapp.keycodes[0x15C] = SAPP_KEYCODE_RIGHT_SUPER;
3474 _sapp.keycodes[0x150] = SAPP_KEYCODE_DOWN;
3475 _sapp.keycodes[0x14B] = SAPP_KEYCODE_LEFT;
3476 _sapp.keycodes[0x14D] = SAPP_KEYCODE_RIGHT;
3477 _sapp.keycodes[0x148] = SAPP_KEYCODE_UP;
3478 _sapp.keycodes[0x052] = SAPP_KEYCODE_KP_0;
3479 _sapp.keycodes[0x04F] = SAPP_KEYCODE_KP_1;
3480 _sapp.keycodes[0x050] = SAPP_KEYCODE_KP_2;
3481 _sapp.keycodes[0x051] = SAPP_KEYCODE_KP_3;
3482 _sapp.keycodes[0x04B] = SAPP_KEYCODE_KP_4;
3483 _sapp.keycodes[0x04C] = SAPP_KEYCODE_KP_5;
3484 _sapp.keycodes[0x04D] = SAPP_KEYCODE_KP_6;
3485 _sapp.keycodes[0x047] = SAPP_KEYCODE_KP_7;
3486 _sapp.keycodes[0x048] = SAPP_KEYCODE_KP_8;
3487 _sapp.keycodes[0x049] = SAPP_KEYCODE_KP_9;
3488 _sapp.keycodes[0x04E] = SAPP_KEYCODE_KP_ADD;
3489 _sapp.keycodes[0x053] = SAPP_KEYCODE_KP_DECIMAL;
3490 _sapp.keycodes[0x135] = SAPP_KEYCODE_KP_DIVIDE;
3491 _sapp.keycodes[0x11C] = SAPP_KEYCODE_KP_ENTER;
3492 _sapp.keycodes[0x037] = SAPP_KEYCODE_KP_MULTIPLY;
3493 _sapp.keycodes[0x04A] = SAPP_KEYCODE_KP_SUBTRACT;
3494}
3495
3496/* updates current window and framebuffer size from the window's client rect, returns true if size has changed */
3497_SOKOL_PRIVATE bool _sapp_win32_update_dimensions(void) {
3498 RECT rect;
3499 if (GetClientRect(_sapp_win32_hwnd, &rect)) {
3500 const int cur_width = (rect.right - rect.left) / _sapp_win32_window_scale;
3501 const int cur_height = (rect.bottom - rect.top) / _sapp_win32_window_scale;
3502 if ((cur_width != _sapp.window_width) || (cur_height != _sapp.window_height)) {
3503 _sapp.window_width = cur_width;
3504 _sapp.window_height = cur_height;
3505 _sapp.framebuffer_width = _sapp.window_width * _sapp_win32_content_scale;
3506 _sapp.framebuffer_height = _sapp.window_height * _sapp_win32_content_scale;
3507 /* prevent a framebuffer size of 0 when window is minimized */
3508 if (_sapp.framebuffer_width == 0) {
3509 _sapp.framebuffer_width = 1;
3510 }
3511 if (_sapp.framebuffer_height == 0) {
3512 _sapp.framebuffer_height = 1;
3513 }
3514 return true;
3515 }
3516 }
3517 else {
3518 _sapp.window_width = _sapp.window_height = 1;
3519 _sapp.framebuffer_width = _sapp.framebuffer_height = 1;
3520 }
3521 return false;
3522}
3523
3524_SOKOL_PRIVATE uint32_t _sapp_win32_mods(void) {
3525 uint32_t mods = 0;
3526 if (GetKeyState(VK_SHIFT) & (1<<31)) {
3527 mods |= SAPP_MODIFIER_SHIFT;
3528 }
3529 if (GetKeyState(VK_CONTROL) & (1<<31)) {
3530 mods |= SAPP_MODIFIER_CTRL;
3531 }
3532 if (GetKeyState(VK_MENU) & (1<<31)) {
3533 mods |= SAPP_MODIFIER_ALT;
3534 }
3535 if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1<<31)) {
3536 mods |= SAPP_MODIFIER_SUPER;
3537 }
3538 return mods;
3539}
3540
3541_SOKOL_PRIVATE void _sapp_win32_mouse_event(sapp_event_type type, sapp_mousebutton btn) {
3542 if (_sapp_events_enabled()) {
3543 _sapp_init_event(type);
3544 _sapp.event.modifiers = _sapp_win32_mods();
3545 _sapp.event.mouse_button = btn;
3546 _sapp.event.mouse_x = _sapp.mouse_x;
3547 _sapp.event.mouse_y = _sapp.mouse_y;
3548 _sapp.desc.event_cb(&_sapp.event);
3549 }
3550}
3551
3552_SOKOL_PRIVATE void _sapp_win32_scroll_event(float x, float y) {
3553 if (_sapp_events_enabled()) {
3554 _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
3555 _sapp.event.modifiers = _sapp_win32_mods();
3556 _sapp.event.scroll_x = -x / 30.0f;
3557 _sapp.event.scroll_y = y / 30.0f;
3558 _sapp.desc.event_cb(&_sapp.event);
3559 }
3560}
3561
3562_SOKOL_PRIVATE void _sapp_win32_key_event(sapp_event_type type, int vk) {
3563 if (_sapp_events_enabled() && (vk < SAPP_MAX_KEYCODES)) {
3564 _sapp_init_event(type);
3565 _sapp.event.modifiers = _sapp_win32_mods();
3566 _sapp.event.key_code = _sapp.keycodes[vk];
3567 _sapp.desc.event_cb(&_sapp.event);
3568 }
3569}
3570
3571_SOKOL_PRIVATE void _sapp_win32_char_event(uint32_t c) {
3572 if (_sapp_events_enabled() && (c >= 32)) {
3573 _sapp_init_event(SAPP_EVENTTYPE_CHAR);
3574 _sapp.event.modifiers = _sapp_win32_mods();
3575 _sapp.event.char_code = c;
3576 _sapp.desc.event_cb(&_sapp.event);
3577 }
3578}
3579
3580_SOKOL_PRIVATE void _sapp_win32_app_event(sapp_event_type type) {
3581 if (_sapp_events_enabled()) {
3582 _sapp_init_event(type);
3583 _sapp.desc.event_cb(&_sapp.event);
3584 }
3585}
3586
3587_SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3588 /* FIXME: refresh rendering during resize with a WM_TIMER event */
3589 if (!_sapp_win32_in_create_window) {
3590 switch (uMsg) {
3591 case WM_CLOSE:
3592 PostQuitMessage(0);
3593 return 0;
3594 case WM_SYSCOMMAND:
3595 switch (wParam & 0xFFF0) {
3596 case SC_SCREENSAVE:
3597 case SC_MONITORPOWER:
3598 if (_sapp.desc.fullscreen) {
3599 /* disable screen saver and blanking in fullscreen mode */
3600 return 0;
3601 }
3602 break;
3603 case SC_KEYMENU:
3604 /* user trying to access menu via ALT */
3605 return 0;
3606 }
3607 break;
3608 case WM_ERASEBKGND:
3609 return 1;
3610 case WM_SIZE:
3611 {
3612 const bool iconified = wParam == SIZE_MINIMIZED;
3613 if (iconified != _sapp_win32_iconified) {
3614 _sapp_win32_iconified = iconified;
3615 if (iconified) {
3616 _sapp_win32_app_event(SAPP_EVENTTYPE_ICONIFIED);
3617 }
3618 else {
3619 _sapp_win32_app_event(SAPP_EVENTTYPE_RESTORED);
3620 }
3621 }
3622 if (_sapp_win32_update_dimensions()) {
3623 #if defined(SOKOL_D3D11)
3624 _sapp_d3d11_resize_default_render_target();
3625 #endif
3626 _sapp_win32_app_event(SAPP_EVENTTYPE_RESIZED);
3627 }
3628 }
3629 break;
3630 case WM_SETCURSOR:
3631 if (_sapp.desc.user_cursor) {
3632 if (LOWORD(lParam) == HTCLIENT) {
3633 _sapp_win32_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR);
3634 return 1;
3635 }
3636 }
3637 break;
3638 case WM_LBUTTONDOWN:
3639 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT);
3640 break;
3641 case WM_RBUTTONDOWN:
3642 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_RIGHT);
3643 break;
3644 case WM_MBUTTONDOWN:
3645 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_MIDDLE);
3646 break;
3647 case WM_LBUTTONUP:
3648 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_LEFT);
3649 break;
3650 case WM_RBUTTONUP:
3651 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_RIGHT);
3652 break;
3653 case WM_MBUTTONUP:
3654 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_MIDDLE);
3655 break;
3656 case WM_MOUSEMOVE:
3657 _sapp.mouse_x = (float)GET_X_LPARAM(lParam) * _sapp_win32_mouse_scale;
3658 _sapp.mouse_y = (float)GET_Y_LPARAM(lParam) * _sapp_win32_mouse_scale;
3659 if (!_sapp.win32_mouse_tracked) {
3660 _sapp.win32_mouse_tracked = true;
3661 TRACKMOUSEEVENT tme;
3662 memset(&tme, 0, sizeof(tme));
3663 tme.cbSize = sizeof(tme);
3664 tme.dwFlags = TME_LEAVE;
3665 tme.hwndTrack = _sapp_win32_hwnd;
3666 TrackMouseEvent(&tme);
3667 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID);
3668 }
3669 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID);
3670 break;
3671 case WM_MOUSELEAVE:
3672 _sapp.win32_mouse_tracked = false;
3673 _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID);
3674 break;
3675 case WM_MOUSEWHEEL:
3676 _sapp_win32_scroll_event(0.0f, (float)((SHORT)HIWORD(wParam)));
3677 break;
3678 case WM_MOUSEHWHEEL:
3679 _sapp_win32_scroll_event((float)((SHORT)HIWORD(wParam)), 0.0f);
3680 break;
3681 case WM_CHAR:
3682 _sapp_win32_char_event((uint32_t)wParam);
3683 break;
3684 case WM_KEYDOWN:
3685 case WM_SYSKEYDOWN:
3686 _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_DOWN, (int)(HIWORD(lParam)&0x1FF));
3687 break;
3688 case WM_KEYUP:
3689 case WM_SYSKEYUP:
3690 _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_UP, (int)(HIWORD(lParam)&0x1FF));
3691 break;
3692 default:
3693 break;
3694 }
3695 }
3696 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
3697}
3698
3699_SOKOL_PRIVATE void _sapp_win32_create_window(void) {
3700 WNDCLASSW wndclassw;
3701 memset(&wndclassw, 0, sizeof(wndclassw));
3702 wndclassw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
3703 wndclassw.lpfnWndProc = (WNDPROC) _sapp_win32_wndproc;
3704 wndclassw.hInstance = GetModuleHandleW(NULL);
3705 wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW);
3706 wndclassw.hIcon = LoadIcon(NULL, IDI_WINLOGO);
3707 wndclassw.lpszClassName = L"SOKOLAPP";
3708 RegisterClassW(&wndclassw);
3709
3710 DWORD win_style;
3711 const DWORD win_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
3712 RECT rect = { 0, 0, 0, 0 };
3713 if (_sapp.desc.fullscreen) {
3714 win_style = WS_POPUP | WS_SYSMENU | WS_VISIBLE;
3715 rect.right = GetSystemMetrics(SM_CXSCREEN);
3716 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
3717 }
3718 else {
3719 win_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX;
3720 rect.right = (int) (_sapp.window_width * _sapp_win32_window_scale);
3721 rect.bottom = (int) (_sapp.window_height * _sapp_win32_window_scale);
3722 }
3723 AdjustWindowRectEx(&rect, win_style, FALSE, win_ex_style);
3724 const int win_width = rect.right - rect.left;
3725 const int win_height = rect.bottom - rect.top;
3726 _sapp_win32_in_create_window = true;
3727 _sapp_win32_hwnd = CreateWindowExW(
3728 win_ex_style, /* dwExStyle */
3729 L"SOKOLAPP", /* lpClassName */
3730 _sapp.window_title_wide, /* lpWindowName */
3731 win_style, /* dwStyle */
3732 CW_USEDEFAULT, /* X */
3733 CW_USEDEFAULT, /* Y */
3734 win_width, /* nWidth */
3735 win_height, /* nHeight */
3736 NULL, /* hWndParent */
3737 NULL, /* hMenu */
3738 GetModuleHandle(NULL), /* hInstance */
3739 NULL); /* lParam */
3740 ShowWindow(_sapp_win32_hwnd, SW_SHOW);
3741 _sapp_win32_in_create_window = false;
3742 _sapp_win32_dc = GetDC(_sapp_win32_hwnd);
3743 SOKOL_ASSERT(_sapp_win32_dc);
3744 _sapp_win32_update_dimensions();
3745}
3746
3747_SOKOL_PRIVATE void _sapp_win32_destroy_window(void) {
3748 DestroyWindow(_sapp_win32_hwnd); _sapp_win32_hwnd = 0;
3749 UnregisterClassW(L"SOKOLAPP", GetModuleHandleW(NULL));
3750}
3751
3752_SOKOL_PRIVATE void _sapp_win32_init_dpi(void) {
3753 SOKOL_ASSERT(0 == _sapp_win32_setprocessdpiaware);
3754 SOKOL_ASSERT(0 == _sapp_win32_setprocessdpiawareness);
3755 SOKOL_ASSERT(0 == _sapp_win32_getdpiformonitor);
3756 HINSTANCE user32 = LoadLibraryA("user32.dll");
3757 if (user32) {
3758 _sapp_win32_setprocessdpiaware = (SETPROCESSDPIAWARE_T) GetProcAddress(user32, "SetProcessDPIAware");
3759 }
3760 HINSTANCE shcore = LoadLibraryA("shcore.dll");
3761 if (shcore) {
3762 _sapp_win32_setprocessdpiawareness = (SETPROCESSDPIAWARENESS_T) GetProcAddress(shcore, "SetProcessDpiAwareness");
3763 _sapp_win32_getdpiformonitor = (GETDPIFORMONITOR_T) GetProcAddress(shcore, "GetDpiForMonitor");
3764 }
3765 if (_sapp_win32_setprocessdpiawareness) {
3766 /* if the app didn't request HighDPI rendering, let Windows do the upscaling */
3767 PROCESS_DPI_AWARENESS process_dpi_awareness = PROCESS_SYSTEM_DPI_AWARE;
3768 _sapp_win32_dpi_aware = true;
3769 if (!_sapp.desc.high_dpi) {
3770 process_dpi_awareness = PROCESS_DPI_UNAWARE;
3771 _sapp_win32_dpi_aware = false;
3772 }
3773 _sapp_win32_setprocessdpiawareness(process_dpi_awareness);
3774 }
3775 else if (_sapp_win32_setprocessdpiaware) {
3776 _sapp_win32_setprocessdpiaware();
3777 _sapp_win32_dpi_aware = true;
3778 }
3779 /* get dpi scale factor for main monitor */
3780 if (_sapp_win32_getdpiformonitor && _sapp_win32_dpi_aware) {
3781 POINT pt = { 1, 1 };
3782 HMONITOR hm = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
3783 UINT dpix, dpiy;
3784 HRESULT hr = _sapp_win32_getdpiformonitor(hm, MDT_EFFECTIVE_DPI, &dpix, &dpiy);
3785 _SOKOL_UNUSED(hr);
3786 SOKOL_ASSERT(SUCCEEDED(hr));
3787 /* clamp window scale to an integer factor */
3788 _sapp_win32_window_scale = (int)((float)dpix / 96.0f);
3789 }
3790 else {
3791 _sapp_win32_window_scale = 1;
3792 }
3793 if (_sapp.desc.high_dpi) {
3794 _sapp_win32_content_scale = _sapp_win32_window_scale;
3795 _sapp_win32_mouse_scale = 1.0f;
3796 }
3797 else {
3798 _sapp_win32_content_scale = 1;
3799 _sapp_win32_mouse_scale = 1.0f / _sapp_win32_window_scale;
3800 }
3801 _sapp.dpi_scale = (float) _sapp_win32_content_scale;
3802 if (user32) {
3803 FreeLibrary(user32);
3804 }
3805 if (shcore) {
3806 FreeLibrary(shcore);
3807 }
3808}
3809
3810#if defined(SOKOL_WIN32_FORCE_MAIN)
3811int main(int argc, char** argv) {
3812#else
3813int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) {
3814 _SOKOL_UNUSED(hInstance);
3815 _SOKOL_UNUSED(hPrevInstance);
3816 _SOKOL_UNUSED(lpCmdLine);
3817 _SOKOL_UNUSED(nCmdShow);
3818 int argc = __argc;
3819 char** argv = __argv;
3820#endif
3821 sapp_desc desc = sokol_main(argc, argv);
3822 _sapp_init_state(&desc, argc, argv);
3823 _sapp_win32_init_keytable();
3824 _sapp_win32_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide));
3825 _sapp_win32_init_dpi();
3826 _sapp_win32_create_window();
3827 #if defined(SOKOL_D3D11)
3828 _sapp_d3d11_create_device_and_swapchain();
3829 _sapp_d3d11_create_default_render_target();
3830 #endif
3831 #if defined(SOKOL_GLCORE33)
3832 _sapp_wgl_init();
3833 _sapp_wgl_load_extensions();
3834 _sapp_wgl_create_context();
3835 #if !defined(SOKOL_WIN32_NO_GL_LOADER)
3836 _sapp_win32_gl_loadfuncs();
3837 #endif
3838 #endif
3839 _sapp.valid = true;
3840
3841 bool done = false;
3842 while (!done) {
3843 MSG msg;
3844 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
3845 if (WM_QUIT == msg.message) {
3846 done = true;
3847 }
3848 else {
3849 TranslateMessage(&msg);
3850 DispatchMessage(&msg);
3851 }
3852 }
3853 _sapp_frame();
3854 #if defined(SOKOL_D3D11)
3855 IDXGISwapChain_Present(_sapp_dxgi_swap_chain, _sapp.swap_interval, 0);
3856 #endif
3857 #if defined(SOKOL_GLCORE33)
3858 _sapp_wgl_swap_buffers();
3859 #endif
3860 }
3861 _sapp.desc.cleanup_cb();
3862
3863 #if defined(SOKOL_D3D11)
3864 _sapp_d3d11_destroy_default_render_target();
3865 _sapp_d3d11_destroy_device_and_swapchain();
3866 #else
3867 _sapp_wgl_destroy_context();
3868 _sapp_wgl_shutdown();
3869 #endif
3870 _sapp_win32_destroy_window();
3871 return 0;
3872}
3873
3874#undef _SAPP_SAFE_RELEASE
3875#endif /* WINDOWS */
3876
3877/*== LINUX ==================================================================*/
3878#if defined(linux)
3879#define GL_GLEXT_PROTOTYPES
3880#include <X11/X.h>
3881#include <X11/Xlib.h>
3882#include <X11/Xresource.h>
3883#include <X11/extensions/Xrandr.h>
3884#include <X11/Xmd.h> /* CARD32 */
3885#include <GL/gl.h>
3886#include <dlfcn.h> /* dlopen, dlsym, dlclose */
3887#include <limits.h> /* LONG_MAX */
3888
3889#define GLX_VENDOR 1
3890#define GLX_RGBA_BIT 0x00000001
3891#define GLX_WINDOW_BIT 0x00000001
3892#define GLX_DRAWABLE_TYPE 0x8010
3893#define GLX_RENDER_TYPE 0x8011
3894#define GLX_RGBA_TYPE 0x8014
3895#define GLX_DOUBLEBUFFER 5
3896#define GLX_STEREO 6
3897#define GLX_AUX_BUFFERS 7
3898#define GLX_RED_SIZE 8
3899#define GLX_GREEN_SIZE 9
3900#define GLX_BLUE_SIZE 10
3901#define GLX_ALPHA_SIZE 11
3902#define GLX_DEPTH_SIZE 12
3903#define GLX_STENCIL_SIZE 13
3904#define GLX_ACCUM_RED_SIZE 14
3905#define GLX_ACCUM_GREEN_SIZE 15
3906#define GLX_ACCUM_BLUE_SIZE 16
3907#define GLX_ACCUM_ALPHA_SIZE 17
3908#define GLX_SAMPLES 0x186a1
3909#define GLX_VISUAL_ID 0x800b
3910
3911#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2
3912#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
3913#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
3914#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
3915#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
3916#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
3917#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
3918#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
3919#define GLX_CONTEXT_FLAGS_ARB 0x2094
3920#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
3921#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
3922#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
3923#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
3924#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
3925#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
3926#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
3927
3928typedef XID GLXWindow;
3929typedef XID GLXDrawable;
3930typedef struct __GLXFBConfig* GLXFBConfig;
3931typedef struct __GLXcontext* GLXContext;
3932typedef void (*__GLXextproc)(void);
3933
3934typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
3935typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
3936typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
3937typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
3938typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext);
3939typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext);
3940typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable);
3941typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int);
3942typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*);
3943typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool);
3944typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName);
3945typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
3946typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig);
3947typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*);
3948typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow);
3949
3950typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
3951typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*);
3952
3953static bool _sapp_x11_quit_requested;
3954static Display* _sapp_x11_display;
3955static int _sapp_x11_screen;
3956static Window _sapp_x11_root;
3957static Colormap _sapp_x11_colormap;
3958static Window _sapp_x11_window;
3959static float _sapp_x11_dpi;
3960static int _sapp_x11_window_state;
3961static unsigned char _sapp_x11_error_code;
3962static void* _sapp_glx_libgl;
3963static int _sapp_glx_major;
3964static int _sapp_glx_minor;
3965static int _sapp_glx_eventbase;
3966static int _sapp_glx_errorbase;
3967static GLXContext _sapp_glx_ctx;
3968static GLXWindow _sapp_glx_window;
3969static Atom _sapp_x11_UTF8_STRING;
3970static Atom _sapp_x11_WM_PROTOCOLS;
3971static Atom _sapp_x11_WM_DELETE_WINDOW;
3972static Atom _sapp_x11_WM_STATE;
3973static Atom _sapp_x11_NET_WM_NAME;
3974static Atom _sapp_x11_NET_WM_ICON_NAME;
3975// GLX 1.3 functions
3976static PFNGLXGETFBCONFIGSPROC _sapp_glx_GetFBConfigs;
3977static PFNGLXGETFBCONFIGATTRIBPROC _sapp_glx_GetFBConfigAttrib;
3978static PFNGLXGETCLIENTSTRINGPROC _sapp_glx_GetClientString;
3979static PFNGLXQUERYEXTENSIONPROC _sapp_glx_QueryExtension;
3980static PFNGLXQUERYVERSIONPROC _sapp_glx_QueryVersion;
3981static PFNGLXDESTROYCONTEXTPROC _sapp_glx_DestroyContext;
3982static PFNGLXMAKECURRENTPROC _sapp_glx_MakeCurrent;
3983static PFNGLXSWAPBUFFERSPROC _sapp_glx_SwapBuffers;
3984static PFNGLXQUERYEXTENSIONSSTRINGPROC _sapp_glx_QueryExtensionsString;
3985static PFNGLXCREATENEWCONTEXTPROC _sapp_glx_CreateNewContext;
3986static PFNGLXGETVISUALFROMFBCONFIGPROC _sapp_glx_GetVisualFromFBConfig;
3987static PFNGLXCREATEWINDOWPROC _sapp_glx_CreateWindow;
3988static PFNGLXDESTROYWINDOWPROC _sapp_glx_DestroyWindow;
3989
3990// GLX 1.4 and extension functions
3991static PFNGLXGETPROCADDRESSPROC _sapp_glx_GetProcAddress;
3992static PFNGLXGETPROCADDRESSPROC _sapp_glx_GetProcAddressARB;
3993static PFNGLXSWAPINTERVALEXTPROC _sapp_glx_SwapIntervalEXT;
3994static PFNGLXSWAPINTERVALMESAPROC _sapp_glx_SwapIntervalMESA;
3995static PFNGLXCREATECONTEXTATTRIBSARBPROC _sapp_glx_CreateContextAttribsARB;
3996static bool _sapp_glx_EXT_swap_control;
3997static bool _sapp_glx_MESA_swap_control;
3998static bool _sapp_glx_ARB_multisample;
3999static bool _sapp_glx_ARB_framebuffer_sRGB;
4000static bool _sapp_glx_EXT_framebuffer_sRGB;
4001static bool _sapp_glx_ARB_create_context;
4002static bool _sapp_glx_ARB_create_context_profile;
4003
4004/* see GLFW's xkb_unicode.c */
4005static const struct _sapp_x11_codepair {
4006 uint16_t keysym;
4007 uint16_t ucs;
4008} _sapp_x11_keysymtab[] = {
4009 { 0x01a1, 0x0104 },
4010 { 0x01a2, 0x02d8 },
4011 { 0x01a3, 0x0141 },
4012 { 0x01a5, 0x013d },
4013 { 0x01a6, 0x015a },
4014 { 0x01a9, 0x0160 },
4015 { 0x01aa, 0x015e },
4016 { 0x01ab, 0x0164 },
4017 { 0x01ac, 0x0179 },
4018 { 0x01ae, 0x017d },
4019 { 0x01af, 0x017b },
4020 { 0x01b1, 0x0105 },
4021 { 0x01b2, 0x02db },
4022 { 0x01b3, 0x0142 },
4023 { 0x01b5, 0x013e },
4024 { 0x01b6, 0x015b },
4025 { 0x01b7, 0x02c7 },
4026 { 0x01b9, 0x0161 },
4027 { 0x01ba, 0x015f },
4028 { 0x01bb, 0x0165 },
4029 { 0x01bc, 0x017a },
4030 { 0x01bd, 0x02dd },
4031 { 0x01be, 0x017e },
4032 { 0x01bf, 0x017c },
4033 { 0x01c0, 0x0154 },
4034 { 0x01c3, 0x0102 },
4035 { 0x01c5, 0x0139 },
4036 { 0x01c6, 0x0106 },
4037 { 0x01c8, 0x010c },
4038 { 0x01ca, 0x0118 },
4039 { 0x01cc, 0x011a },
4040 { 0x01cf, 0x010e },
4041 { 0x01d0, 0x0110 },
4042 { 0x01d1, 0x0143 },
4043 { 0x01d2, 0x0147 },
4044 { 0x01d5, 0x0150 },
4045 { 0x01d8, 0x0158 },
4046 { 0x01d9, 0x016e },
4047 { 0x01db, 0x0170 },
4048 { 0x01de, 0x0162 },
4049 { 0x01e0, 0x0155 },
4050 { 0x01e3, 0x0103 },
4051 { 0x01e5, 0x013a },
4052 { 0x01e6, 0x0107 },
4053 { 0x01e8, 0x010d },
4054 { 0x01ea, 0x0119 },
4055 { 0x01ec, 0x011b },
4056 { 0x01ef, 0x010f },
4057 { 0x01f0, 0x0111 },
4058 { 0x01f1, 0x0144 },
4059 { 0x01f2, 0x0148 },
4060 { 0x01f5, 0x0151 },
4061 { 0x01f8, 0x0159 },
4062 { 0x01f9, 0x016f },
4063 { 0x01fb, 0x0171 },
4064 { 0x01fe, 0x0163 },
4065 { 0x01ff, 0x02d9 },
4066 { 0x02a1, 0x0126 },
4067 { 0x02a6, 0x0124 },
4068 { 0x02a9, 0x0130 },
4069 { 0x02ab, 0x011e },
4070 { 0x02ac, 0x0134 },
4071 { 0x02b1, 0x0127 },
4072 { 0x02b6, 0x0125 },
4073 { 0x02b9, 0x0131 },
4074 { 0x02bb, 0x011f },
4075 { 0x02bc, 0x0135 },
4076 { 0x02c5, 0x010a },
4077 { 0x02c6, 0x0108 },
4078 { 0x02d5, 0x0120 },
4079 { 0x02d8, 0x011c },
4080 { 0x02dd, 0x016c },
4081 { 0x02de, 0x015c },
4082 { 0x02e5, 0x010b },
4083 { 0x02e6, 0x0109 },
4084 { 0x02f5, 0x0121 },
4085 { 0x02f8, 0x011d },
4086 { 0x02fd, 0x016d },
4087 { 0x02fe, 0x015d },
4088 { 0x03a2, 0x0138 },
4089 { 0x03a3, 0x0156 },
4090 { 0x03a5, 0x0128 },
4091 { 0x03a6, 0x013b },
4092 { 0x03aa, 0x0112 },
4093 { 0x03ab, 0x0122 },
4094 { 0x03ac, 0x0166 },
4095 { 0x03b3, 0x0157 },
4096 { 0x03b5, 0x0129 },
4097 { 0x03b6, 0x013c },
4098 { 0x03ba, 0x0113 },
4099 { 0x03bb, 0x0123 },
4100 { 0x03bc, 0x0167 },
4101 { 0x03bd, 0x014a },
4102 { 0x03bf, 0x014b },
4103 { 0x03c0, 0x0100 },
4104 { 0x03c7, 0x012e },
4105 { 0x03cc, 0x0116 },
4106 { 0x03cf, 0x012a },
4107 { 0x03d1, 0x0145 },
4108 { 0x03d2, 0x014c },
4109 { 0x03d3, 0x0136 },
4110 { 0x03d9, 0x0172 },
4111 { 0x03dd, 0x0168 },
4112 { 0x03de, 0x016a },
4113 { 0x03e0, 0x0101 },
4114 { 0x03e7, 0x012f },
4115 { 0x03ec, 0x0117 },
4116 { 0x03ef, 0x012b },
4117 { 0x03f1, 0x0146 },
4118 { 0x03f2, 0x014d },
4119 { 0x03f3, 0x0137 },
4120 { 0x03f9, 0x0173 },
4121 { 0x03fd, 0x0169 },
4122 { 0x03fe, 0x016b },
4123 { 0x047e, 0x203e },
4124 { 0x04a1, 0x3002 },
4125 { 0x04a2, 0x300c },
4126 { 0x04a3, 0x300d },
4127 { 0x04a4, 0x3001 },
4128 { 0x04a5, 0x30fb },
4129 { 0x04a6, 0x30f2 },
4130 { 0x04a7, 0x30a1 },
4131 { 0x04a8, 0x30a3 },
4132 { 0x04a9, 0x30a5 },
4133 { 0x04aa, 0x30a7 },
4134 { 0x04ab, 0x30a9 },
4135 { 0x04ac, 0x30e3 },
4136 { 0x04ad, 0x30e5 },
4137 { 0x04ae, 0x30e7 },
4138 { 0x04af, 0x30c3 },
4139 { 0x04b0, 0x30fc },
4140 { 0x04b1, 0x30a2 },
4141 { 0x04b2, 0x30a4 },
4142 { 0x04b3, 0x30a6 },
4143 { 0x04b4, 0x30a8 },
4144 { 0x04b5, 0x30aa },
4145 { 0x04b6, 0x30ab },
4146 { 0x04b7, 0x30ad },
4147 { 0x04b8, 0x30af },
4148 { 0x04b9, 0x30b1 },
4149 { 0x04ba, 0x30b3 },
4150 { 0x04bb, 0x30b5 },
4151 { 0x04bc, 0x30b7 },
4152 { 0x04bd, 0x30b9 },
4153 { 0x04be, 0x30bb },
4154 { 0x04bf, 0x30bd },
4155 { 0x04c0, 0x30bf },
4156 { 0x04c1, 0x30c1 },
4157 { 0x04c2, 0x30c4 },
4158 { 0x04c3, 0x30c6 },
4159 { 0x04c4, 0x30c8 },
4160 { 0x04c5, 0x30ca },
4161 { 0x04c6, 0x30cb },
4162 { 0x04c7, 0x30cc },
4163 { 0x04c8, 0x30cd },
4164 { 0x04c9, 0x30ce },
4165 { 0x04ca, 0x30cf },
4166 { 0x04cb, 0x30d2 },
4167 { 0x04cc, 0x30d5 },
4168 { 0x04cd, 0x30d8 },
4169 { 0x04ce, 0x30db },
4170 { 0x04cf, 0x30de },
4171 { 0x04d0, 0x30df },
4172 { 0x04d1, 0x30e0 },
4173 { 0x04d2, 0x30e1 },
4174 { 0x04d3, 0x30e2 },
4175 { 0x04d4, 0x30e4 },
4176 { 0x04d5, 0x30e6 },
4177 { 0x04d6, 0x30e8 },
4178 { 0x04d7, 0x30e9 },
4179 { 0x04d8, 0x30ea },
4180 { 0x04d9, 0x30eb },
4181 { 0x04da, 0x30ec },
4182 { 0x04db, 0x30ed },
4183 { 0x04dc, 0x30ef },
4184 { 0x04dd, 0x30f3 },
4185 { 0x04de, 0x309b },
4186 { 0x04df, 0x309c },
4187 { 0x05ac, 0x060c },
4188 { 0x05bb, 0x061b },
4189 { 0x05bf, 0x061f },
4190 { 0x05c1, 0x0621 },
4191 { 0x05c2, 0x0622 },
4192 { 0x05c3, 0x0623 },
4193 { 0x05c4, 0x0624 },
4194 { 0x05c5, 0x0625 },
4195 { 0x05c6, 0x0626 },
4196 { 0x05c7, 0x0627 },
4197 { 0x05c8, 0x0628 },
4198 { 0x05c9, 0x0629 },
4199 { 0x05ca, 0x062a },
4200 { 0x05cb, 0x062b },
4201 { 0x05cc, 0x062c },
4202 { 0x05cd, 0x062d },
4203 { 0x05ce, 0x062e },
4204 { 0x05cf, 0x062f },
4205 { 0x05d0, 0x0630 },
4206 { 0x05d1, 0x0631 },
4207 { 0x05d2, 0x0632 },
4208 { 0x05d3, 0x0633 },
4209 { 0x05d4, 0x0634 },
4210 { 0x05d5, 0x0635 },
4211 { 0x05d6, 0x0636 },
4212 { 0x05d7, 0x0637 },
4213 { 0x05d8, 0x0638 },
4214 { 0x05d9, 0x0639 },
4215 { 0x05da, 0x063a },
4216 { 0x05e0, 0x0640 },
4217 { 0x05e1, 0x0641 },
4218 { 0x05e2, 0x0642 },
4219 { 0x05e3, 0x0643 },
4220 { 0x05e4, 0x0644 },
4221 { 0x05e5, 0x0645 },
4222 { 0x05e6, 0x0646 },
4223 { 0x05e7, 0x0647 },
4224 { 0x05e8, 0x0648 },
4225 { 0x05e9, 0x0649 },
4226 { 0x05ea, 0x064a },
4227 { 0x05eb, 0x064b },
4228 { 0x05ec, 0x064c },
4229 { 0x05ed, 0x064d },
4230 { 0x05ee, 0x064e },
4231 { 0x05ef, 0x064f },
4232 { 0x05f0, 0x0650 },
4233 { 0x05f1, 0x0651 },
4234 { 0x05f2, 0x0652 },
4235 { 0x06a1, 0x0452 },
4236 { 0x06a2, 0x0453 },
4237 { 0x06a3, 0x0451 },
4238 { 0x06a4, 0x0454 },
4239 { 0x06a5, 0x0455 },
4240 { 0x06a6, 0x0456 },
4241 { 0x06a7, 0x0457 },
4242 { 0x06a8, 0x0458 },
4243 { 0x06a9, 0x0459 },
4244 { 0x06aa, 0x045a },
4245 { 0x06ab, 0x045b },
4246 { 0x06ac, 0x045c },
4247 { 0x06ae, 0x045e },
4248 { 0x06af, 0x045f },
4249 { 0x06b0, 0x2116 },
4250 { 0x06b1, 0x0402 },
4251 { 0x06b2, 0x0403 },
4252 { 0x06b3, 0x0401 },
4253 { 0x06b4, 0x0404 },
4254 { 0x06b5, 0x0405 },
4255 { 0x06b6, 0x0406 },
4256 { 0x06b7, 0x0407 },
4257 { 0x06b8, 0x0408 },
4258 { 0x06b9, 0x0409 },
4259 { 0x06ba, 0x040a },
4260 { 0x06bb, 0x040b },
4261 { 0x06bc, 0x040c },
4262 { 0x06be, 0x040e },
4263 { 0x06bf, 0x040f },
4264 { 0x06c0, 0x044e },
4265 { 0x06c1, 0x0430 },
4266 { 0x06c2, 0x0431 },
4267 { 0x06c3, 0x0446 },
4268 { 0x06c4, 0x0434 },
4269 { 0x06c5, 0x0435 },
4270 { 0x06c6, 0x0444 },
4271 { 0x06c7, 0x0433 },
4272 { 0x06c8, 0x0445 },
4273 { 0x06c9, 0x0438 },
4274 { 0x06ca, 0x0439 },
4275 { 0x06cb, 0x043a },
4276 { 0x06cc, 0x043b },
4277 { 0x06cd, 0x043c },
4278 { 0x06ce, 0x043d },
4279 { 0x06cf, 0x043e },
4280 { 0x06d0, 0x043f },
4281 { 0x06d1, 0x044f },
4282 { 0x06d2, 0x0440 },
4283 { 0x06d3, 0x0441 },
4284 { 0x06d4, 0x0442 },
4285 { 0x06d5, 0x0443 },
4286 { 0x06d6, 0x0436 },
4287 { 0x06d7, 0x0432 },
4288 { 0x06d8, 0x044c },
4289 { 0x06d9, 0x044b },
4290 { 0x06da, 0x0437 },
4291 { 0x06db, 0x0448 },
4292 { 0x06dc, 0x044d },
4293 { 0x06dd, 0x0449 },
4294 { 0x06de, 0x0447 },
4295 { 0x06df, 0x044a },
4296 { 0x06e0, 0x042e },
4297 { 0x06e1, 0x0410 },
4298 { 0x06e2, 0x0411 },
4299 { 0x06e3, 0x0426 },
4300 { 0x06e4, 0x0414 },
4301 { 0x06e5, 0x0415 },
4302 { 0x06e6, 0x0424 },
4303 { 0x06e7, 0x0413 },
4304 { 0x06e8, 0x0425 },
4305 { 0x06e9, 0x0418 },
4306 { 0x06ea, 0x0419 },
4307 { 0x06eb, 0x041a },
4308 { 0x06ec, 0x041b },
4309 { 0x06ed, 0x041c },
4310 { 0x06ee, 0x041d },
4311 { 0x06ef, 0x041e },
4312 { 0x06f0, 0x041f },
4313 { 0x06f1, 0x042f },
4314 { 0x06f2, 0x0420 },
4315 { 0x06f3, 0x0421 },
4316 { 0x06f4, 0x0422 },
4317 { 0x06f5, 0x0423 },
4318 { 0x06f6, 0x0416 },
4319 { 0x06f7, 0x0412 },
4320 { 0x06f8, 0x042c },
4321 { 0x06f9, 0x042b },
4322 { 0x06fa, 0x0417 },
4323 { 0x06fb, 0x0428 },
4324 { 0x06fc, 0x042d },
4325 { 0x06fd, 0x0429 },
4326 { 0x06fe, 0x0427 },
4327 { 0x06ff, 0x042a },
4328 { 0x07a1, 0x0386 },
4329 { 0x07a2, 0x0388 },
4330 { 0x07a3, 0x0389 },
4331 { 0x07a4, 0x038a },
4332 { 0x07a5, 0x03aa },
4333 { 0x07a7, 0x038c },
4334 { 0x07a8, 0x038e },
4335 { 0x07a9, 0x03ab },
4336 { 0x07ab, 0x038f },
4337 { 0x07ae, 0x0385 },
4338 { 0x07af, 0x2015 },
4339 { 0x07b1, 0x03ac },
4340 { 0x07b2, 0x03ad },
4341 { 0x07b3, 0x03ae },
4342 { 0x07b4, 0x03af },
4343 { 0x07b5, 0x03ca },
4344 { 0x07b6, 0x0390 },
4345 { 0x07b7, 0x03cc },
4346 { 0x07b8, 0x03cd },
4347 { 0x07b9, 0x03cb },
4348 { 0x07ba, 0x03b0 },
4349 { 0x07bb, 0x03ce },
4350 { 0x07c1, 0x0391 },
4351 { 0x07c2, 0x0392 },
4352 { 0x07c3, 0x0393 },
4353 { 0x07c4, 0x0394 },
4354 { 0x07c5, 0x0395 },
4355 { 0x07c6, 0x0396 },
4356 { 0x07c7, 0x0397 },
4357 { 0x07c8, 0x0398 },
4358 { 0x07c9, 0x0399 },
4359 { 0x07ca, 0x039a },
4360 { 0x07cb, 0x039b },
4361 { 0x07cc, 0x039c },
4362 { 0x07cd, 0x039d },
4363 { 0x07ce, 0x039e },
4364 { 0x07cf, 0x039f },
4365 { 0x07d0, 0x03a0 },
4366 { 0x07d1, 0x03a1 },
4367 { 0x07d2, 0x03a3 },
4368 { 0x07d4, 0x03a4 },
4369 { 0x07d5, 0x03a5 },
4370 { 0x07d6, 0x03a6 },
4371 { 0x07d7, 0x03a7 },
4372 { 0x07d8, 0x03a8 },
4373 { 0x07d9, 0x03a9 },
4374 { 0x07e1, 0x03b1 },
4375 { 0x07e2, 0x03b2 },
4376 { 0x07e3, 0x03b3 },
4377 { 0x07e4, 0x03b4 },
4378 { 0x07e5, 0x03b5 },
4379 { 0x07e6, 0x03b6 },
4380 { 0x07e7, 0x03b7 },
4381 { 0x07e8, 0x03b8 },
4382 { 0x07e9, 0x03b9 },
4383 { 0x07ea, 0x03ba },
4384 { 0x07eb, 0x03bb },
4385 { 0x07ec, 0x03bc },
4386 { 0x07ed, 0x03bd },
4387 { 0x07ee, 0x03be },
4388 { 0x07ef, 0x03bf },
4389 { 0x07f0, 0x03c0 },
4390 { 0x07f1, 0x03c1 },
4391 { 0x07f2, 0x03c3 },
4392 { 0x07f3, 0x03c2 },
4393 { 0x07f4, 0x03c4 },
4394 { 0x07f5, 0x03c5 },
4395 { 0x07f6, 0x03c6 },
4396 { 0x07f7, 0x03c7 },
4397 { 0x07f8, 0x03c8 },
4398 { 0x07f9, 0x03c9 },
4399 { 0x08a1, 0x23b7 },
4400 { 0x08a2, 0x250c },
4401 { 0x08a3, 0x2500 },
4402 { 0x08a4, 0x2320 },
4403 { 0x08a5, 0x2321 },
4404 { 0x08a6, 0x2502 },
4405 { 0x08a7, 0x23a1 },
4406 { 0x08a8, 0x23a3 },
4407 { 0x08a9, 0x23a4 },
4408 { 0x08aa, 0x23a6 },
4409 { 0x08ab, 0x239b },
4410 { 0x08ac, 0x239d },
4411 { 0x08ad, 0x239e },
4412 { 0x08ae, 0x23a0 },
4413 { 0x08af, 0x23a8 },
4414 { 0x08b0, 0x23ac },
4415 { 0x08bc, 0x2264 },
4416 { 0x08bd, 0x2260 },
4417 { 0x08be, 0x2265 },
4418 { 0x08bf, 0x222b },
4419 { 0x08c0, 0x2234 },
4420 { 0x08c1, 0x221d },
4421 { 0x08c2, 0x221e },
4422 { 0x08c5, 0x2207 },
4423 { 0x08c8, 0x223c },
4424 { 0x08c9, 0x2243 },
4425 { 0x08cd, 0x21d4 },
4426 { 0x08ce, 0x21d2 },
4427 { 0x08cf, 0x2261 },
4428 { 0x08d6, 0x221a },
4429 { 0x08da, 0x2282 },
4430 { 0x08db, 0x2283 },
4431 { 0x08dc, 0x2229 },
4432 { 0x08dd, 0x222a },
4433 { 0x08de, 0x2227 },
4434 { 0x08df, 0x2228 },
4435 { 0x08ef, 0x2202 },
4436 { 0x08f6, 0x0192 },
4437 { 0x08fb, 0x2190 },
4438 { 0x08fc, 0x2191 },
4439 { 0x08fd, 0x2192 },
4440 { 0x08fe, 0x2193 },
4441 { 0x09e0, 0x25c6 },
4442 { 0x09e1, 0x2592 },
4443 { 0x09e2, 0x2409 },
4444 { 0x09e3, 0x240c },
4445 { 0x09e4, 0x240d },
4446 { 0x09e5, 0x240a },
4447 { 0x09e8, 0x2424 },
4448 { 0x09e9, 0x240b },
4449 { 0x09ea, 0x2518 },
4450 { 0x09eb, 0x2510 },
4451 { 0x09ec, 0x250c },
4452 { 0x09ed, 0x2514 },
4453 { 0x09ee, 0x253c },
4454 { 0x09ef, 0x23ba },
4455 { 0x09f0, 0x23bb },
4456 { 0x09f1, 0x2500 },
4457 { 0x09f2, 0x23bc },
4458 { 0x09f3, 0x23bd },
4459 { 0x09f4, 0x251c },
4460 { 0x09f5, 0x2524 },
4461 { 0x09f6, 0x2534 },
4462 { 0x09f7, 0x252c },
4463 { 0x09f8, 0x2502 },
4464 { 0x0aa1, 0x2003 },
4465 { 0x0aa2, 0x2002 },
4466 { 0x0aa3, 0x2004 },
4467 { 0x0aa4, 0x2005 },
4468 { 0x0aa5, 0x2007 },
4469 { 0x0aa6, 0x2008 },
4470 { 0x0aa7, 0x2009 },
4471 { 0x0aa8, 0x200a },
4472 { 0x0aa9, 0x2014 },
4473 { 0x0aaa, 0x2013 },
4474 { 0x0aae, 0x2026 },
4475 { 0x0aaf, 0x2025 },
4476 { 0x0ab0, 0x2153 },
4477 { 0x0ab1, 0x2154 },
4478 { 0x0ab2, 0x2155 },
4479 { 0x0ab3, 0x2156 },
4480 { 0x0ab4, 0x2157 },
4481 { 0x0ab5, 0x2158 },
4482 { 0x0ab6, 0x2159 },
4483 { 0x0ab7, 0x215a },
4484 { 0x0ab8, 0x2105 },
4485 { 0x0abb, 0x2012 },
4486 { 0x0abc, 0x2329 },
4487 { 0x0abe, 0x232a },
4488 { 0x0ac3, 0x215b },
4489 { 0x0ac4, 0x215c },
4490 { 0x0ac5, 0x215d },
4491 { 0x0ac6, 0x215e },
4492 { 0x0ac9, 0x2122 },
4493 { 0x0aca, 0x2613 },
4494 { 0x0acc, 0x25c1 },
4495 { 0x0acd, 0x25b7 },
4496 { 0x0ace, 0x25cb },
4497 { 0x0acf, 0x25af },
4498 { 0x0ad0, 0x2018 },
4499 { 0x0ad1, 0x2019 },
4500 { 0x0ad2, 0x201c },
4501 { 0x0ad3, 0x201d },
4502 { 0x0ad4, 0x211e },
4503 { 0x0ad6, 0x2032 },
4504 { 0x0ad7, 0x2033 },
4505 { 0x0ad9, 0x271d },
4506 { 0x0adb, 0x25ac },
4507 { 0x0adc, 0x25c0 },
4508 { 0x0add, 0x25b6 },
4509 { 0x0ade, 0x25cf },
4510 { 0x0adf, 0x25ae },
4511 { 0x0ae0, 0x25e6 },
4512 { 0x0ae1, 0x25ab },
4513 { 0x0ae2, 0x25ad },
4514 { 0x0ae3, 0x25b3 },
4515 { 0x0ae4, 0x25bd },
4516 { 0x0ae5, 0x2606 },
4517 { 0x0ae6, 0x2022 },
4518 { 0x0ae7, 0x25aa },
4519 { 0x0ae8, 0x25b2 },
4520 { 0x0ae9, 0x25bc },
4521 { 0x0aea, 0x261c },
4522 { 0x0aeb, 0x261e },
4523 { 0x0aec, 0x2663 },
4524 { 0x0aed, 0x2666 },
4525 { 0x0aee, 0x2665 },
4526 { 0x0af0, 0x2720 },
4527 { 0x0af1, 0x2020 },
4528 { 0x0af2, 0x2021 },
4529 { 0x0af3, 0x2713 },
4530 { 0x0af4, 0x2717 },
4531 { 0x0af5, 0x266f },
4532 { 0x0af6, 0x266d },
4533 { 0x0af7, 0x2642 },
4534 { 0x0af8, 0x2640 },
4535 { 0x0af9, 0x260e },
4536 { 0x0afa, 0x2315 },
4537 { 0x0afb, 0x2117 },
4538 { 0x0afc, 0x2038 },
4539 { 0x0afd, 0x201a },
4540 { 0x0afe, 0x201e },
4541 { 0x0ba3, 0x003c },
4542 { 0x0ba6, 0x003e },
4543 { 0x0ba8, 0x2228 },
4544 { 0x0ba9, 0x2227 },
4545 { 0x0bc0, 0x00af },
4546 { 0x0bc2, 0x22a5 },
4547 { 0x0bc3, 0x2229 },
4548 { 0x0bc4, 0x230a },
4549 { 0x0bc6, 0x005f },
4550 { 0x0bca, 0x2218 },
4551 { 0x0bcc, 0x2395 },
4552 { 0x0bce, 0x22a4 },
4553 { 0x0bcf, 0x25cb },
4554 { 0x0bd3, 0x2308 },
4555 { 0x0bd6, 0x222a },
4556 { 0x0bd8, 0x2283 },
4557 { 0x0bda, 0x2282 },
4558 { 0x0bdc, 0x22a2 },
4559 { 0x0bfc, 0x22a3 },
4560 { 0x0cdf, 0x2017 },
4561 { 0x0ce0, 0x05d0 },
4562 { 0x0ce1, 0x05d1 },
4563 { 0x0ce2, 0x05d2 },
4564 { 0x0ce3, 0x05d3 },
4565 { 0x0ce4, 0x05d4 },
4566 { 0x0ce5, 0x05d5 },
4567 { 0x0ce6, 0x05d6 },
4568 { 0x0ce7, 0x05d7 },
4569 { 0x0ce8, 0x05d8 },
4570 { 0x0ce9, 0x05d9 },
4571 { 0x0cea, 0x05da },
4572 { 0x0ceb, 0x05db },
4573 { 0x0cec, 0x05dc },
4574 { 0x0ced, 0x05dd },
4575 { 0x0cee, 0x05de },
4576 { 0x0cef, 0x05df },
4577 { 0x0cf0, 0x05e0 },
4578 { 0x0cf1, 0x05e1 },
4579 { 0x0cf2, 0x05e2 },
4580 { 0x0cf3, 0x05e3 },
4581 { 0x0cf4, 0x05e4 },
4582 { 0x0cf5, 0x05e5 },
4583 { 0x0cf6, 0x05e6 },
4584 { 0x0cf7, 0x05e7 },
4585 { 0x0cf8, 0x05e8 },
4586 { 0x0cf9, 0x05e9 },
4587 { 0x0cfa, 0x05ea },
4588 { 0x0da1, 0x0e01 },
4589 { 0x0da2, 0x0e02 },
4590 { 0x0da3, 0x0e03 },
4591 { 0x0da4, 0x0e04 },
4592 { 0x0da5, 0x0e05 },
4593 { 0x0da6, 0x0e06 },
4594 { 0x0da7, 0x0e07 },
4595 { 0x0da8, 0x0e08 },
4596 { 0x0da9, 0x0e09 },
4597 { 0x0daa, 0x0e0a },
4598 { 0x0dab, 0x0e0b },
4599 { 0x0dac, 0x0e0c },
4600 { 0x0dad, 0x0e0d },
4601 { 0x0dae, 0x0e0e },
4602 { 0x0daf, 0x0e0f },
4603 { 0x0db0, 0x0e10 },
4604 { 0x0db1, 0x0e11 },
4605 { 0x0db2, 0x0e12 },
4606 { 0x0db3, 0x0e13 },
4607 { 0x0db4, 0x0e14 },
4608 { 0x0db5, 0x0e15 },
4609 { 0x0db6, 0x0e16 },
4610 { 0x0db7, 0x0e17 },
4611 { 0x0db8, 0x0e18 },
4612 { 0x0db9, 0x0e19 },
4613 { 0x0dba, 0x0e1a },
4614 { 0x0dbb, 0x0e1b },
4615 { 0x0dbc, 0x0e1c },
4616 { 0x0dbd, 0x0e1d },
4617 { 0x0dbe, 0x0e1e },
4618 { 0x0dbf, 0x0e1f },
4619 { 0x0dc0, 0x0e20 },
4620 { 0x0dc1, 0x0e21 },
4621 { 0x0dc2, 0x0e22 },
4622 { 0x0dc3, 0x0e23 },
4623 { 0x0dc4, 0x0e24 },
4624 { 0x0dc5, 0x0e25 },
4625 { 0x0dc6, 0x0e26 },
4626 { 0x0dc7, 0x0e27 },
4627 { 0x0dc8, 0x0e28 },
4628 { 0x0dc9, 0x0e29 },
4629 { 0x0dca, 0x0e2a },
4630 { 0x0dcb, 0x0e2b },
4631 { 0x0dcc, 0x0e2c },
4632 { 0x0dcd, 0x0e2d },
4633 { 0x0dce, 0x0e2e },
4634 { 0x0dcf, 0x0e2f },
4635 { 0x0dd0, 0x0e30 },
4636 { 0x0dd1, 0x0e31 },
4637 { 0x0dd2, 0x0e32 },
4638 { 0x0dd3, 0x0e33 },
4639 { 0x0dd4, 0x0e34 },
4640 { 0x0dd5, 0x0e35 },
4641 { 0x0dd6, 0x0e36 },
4642 { 0x0dd7, 0x0e37 },
4643 { 0x0dd8, 0x0e38 },
4644 { 0x0dd9, 0x0e39 },
4645 { 0x0dda, 0x0e3a },
4646 { 0x0ddf, 0x0e3f },
4647 { 0x0de0, 0x0e40 },
4648 { 0x0de1, 0x0e41 },
4649 { 0x0de2, 0x0e42 },
4650 { 0x0de3, 0x0e43 },
4651 { 0x0de4, 0x0e44 },
4652 { 0x0de5, 0x0e45 },
4653 { 0x0de6, 0x0e46 },
4654 { 0x0de7, 0x0e47 },
4655 { 0x0de8, 0x0e48 },
4656 { 0x0de9, 0x0e49 },
4657 { 0x0dea, 0x0e4a },
4658 { 0x0deb, 0x0e4b },
4659 { 0x0dec, 0x0e4c },
4660 { 0x0ded, 0x0e4d },
4661 { 0x0df0, 0x0e50 },
4662 { 0x0df1, 0x0e51 },
4663 { 0x0df2, 0x0e52 },
4664 { 0x0df3, 0x0e53 },
4665 { 0x0df4, 0x0e54 },
4666 { 0x0df5, 0x0e55 },
4667 { 0x0df6, 0x0e56 },
4668 { 0x0df7, 0x0e57 },
4669 { 0x0df8, 0x0e58 },
4670 { 0x0df9, 0x0e59 },
4671 { 0x0ea1, 0x3131 },
4672 { 0x0ea2, 0x3132 },
4673 { 0x0ea3, 0x3133 },
4674 { 0x0ea4, 0x3134 },
4675 { 0x0ea5, 0x3135 },
4676 { 0x0ea6, 0x3136 },
4677 { 0x0ea7, 0x3137 },
4678 { 0x0ea8, 0x3138 },
4679 { 0x0ea9, 0x3139 },
4680 { 0x0eaa, 0x313a },
4681 { 0x0eab, 0x313b },
4682 { 0x0eac, 0x313c },
4683 { 0x0ead, 0x313d },
4684 { 0x0eae, 0x313e },
4685 { 0x0eaf, 0x313f },
4686 { 0x0eb0, 0x3140 },
4687 { 0x0eb1, 0x3141 },
4688 { 0x0eb2, 0x3142 },
4689 { 0x0eb3, 0x3143 },
4690 { 0x0eb4, 0x3144 },
4691 { 0x0eb5, 0x3145 },
4692 { 0x0eb6, 0x3146 },
4693 { 0x0eb7, 0x3147 },
4694 { 0x0eb8, 0x3148 },
4695 { 0x0eb9, 0x3149 },
4696 { 0x0eba, 0x314a },
4697 { 0x0ebb, 0x314b },
4698 { 0x0ebc, 0x314c },
4699 { 0x0ebd, 0x314d },
4700 { 0x0ebe, 0x314e },
4701 { 0x0ebf, 0x314f },
4702 { 0x0ec0, 0x3150 },
4703 { 0x0ec1, 0x3151 },
4704 { 0x0ec2, 0x3152 },
4705 { 0x0ec3, 0x3153 },
4706 { 0x0ec4, 0x3154 },
4707 { 0x0ec5, 0x3155 },
4708 { 0x0ec6, 0x3156 },
4709 { 0x0ec7, 0x3157 },
4710 { 0x0ec8, 0x3158 },
4711 { 0x0ec9, 0x3159 },
4712 { 0x0eca, 0x315a },
4713 { 0x0ecb, 0x315b },
4714 { 0x0ecc, 0x315c },
4715 { 0x0ecd, 0x315d },
4716 { 0x0ece, 0x315e },
4717 { 0x0ecf, 0x315f },
4718 { 0x0ed0, 0x3160 },
4719 { 0x0ed1, 0x3161 },
4720 { 0x0ed2, 0x3162 },
4721 { 0x0ed3, 0x3163 },
4722 { 0x0ed4, 0x11a8 },
4723 { 0x0ed5, 0x11a9 },
4724 { 0x0ed6, 0x11aa },
4725 { 0x0ed7, 0x11ab },
4726 { 0x0ed8, 0x11ac },
4727 { 0x0ed9, 0x11ad },
4728 { 0x0eda, 0x11ae },
4729 { 0x0edb, 0x11af },
4730 { 0x0edc, 0x11b0 },
4731 { 0x0edd, 0x11b1 },
4732 { 0x0ede, 0x11b2 },
4733 { 0x0edf, 0x11b3 },
4734 { 0x0ee0, 0x11b4 },
4735 { 0x0ee1, 0x11b5 },
4736 { 0x0ee2, 0x11b6 },
4737 { 0x0ee3, 0x11b7 },
4738 { 0x0ee4, 0x11b8 },
4739 { 0x0ee5, 0x11b9 },
4740 { 0x0ee6, 0x11ba },
4741 { 0x0ee7, 0x11bb },
4742 { 0x0ee8, 0x11bc },
4743 { 0x0ee9, 0x11bd },
4744 { 0x0eea, 0x11be },
4745 { 0x0eeb, 0x11bf },
4746 { 0x0eec, 0x11c0 },
4747 { 0x0eed, 0x11c1 },
4748 { 0x0eee, 0x11c2 },
4749 { 0x0eef, 0x316d },
4750 { 0x0ef0, 0x3171 },
4751 { 0x0ef1, 0x3178 },
4752 { 0x0ef2, 0x317f },
4753 { 0x0ef3, 0x3181 },
4754 { 0x0ef4, 0x3184 },
4755 { 0x0ef5, 0x3186 },
4756 { 0x0ef6, 0x318d },
4757 { 0x0ef7, 0x318e },
4758 { 0x0ef8, 0x11eb },
4759 { 0x0ef9, 0x11f0 },
4760 { 0x0efa, 0x11f9 },
4761 { 0x0eff, 0x20a9 },
4762 { 0x13a4, 0x20ac },
4763 { 0x13bc, 0x0152 },
4764 { 0x13bd, 0x0153 },
4765 { 0x13be, 0x0178 },
4766 { 0x20ac, 0x20ac },
4767 { 0xfe50, '`' },
4768 { 0xfe51, 0x00b4 },
4769 { 0xfe52, '^' },
4770 { 0xfe53, '~' },
4771 { 0xfe54, 0x00af },
4772 { 0xfe55, 0x02d8 },
4773 { 0xfe56, 0x02d9 },
4774 { 0xfe57, 0x00a8 },
4775 { 0xfe58, 0x02da },
4776 { 0xfe59, 0x02dd },
4777 { 0xfe5a, 0x02c7 },
4778 { 0xfe5b, 0x00b8 },
4779 { 0xfe5c, 0x02db },
4780 { 0xfe5d, 0x037a },
4781 { 0xfe5e, 0x309b },
4782 { 0xfe5f, 0x309c },
4783 { 0xfe63, '/' },
4784 { 0xfe64, 0x02bc },
4785 { 0xfe65, 0x02bd },
4786 { 0xfe66, 0x02f5 },
4787 { 0xfe67, 0x02f3 },
4788 { 0xfe68, 0x02cd },
4789 { 0xfe69, 0xa788 },
4790 { 0xfe6a, 0x02f7 },
4791 { 0xfe6e, ',' },
4792 { 0xfe6f, 0x00a4 },
4793 { 0xfe80, 'a' }, /* XK_dead_a */
4794 { 0xfe81, 'A' }, /* XK_dead_A */
4795 { 0xfe82, 'e' }, /* XK_dead_e */
4796 { 0xfe83, 'E' }, /* XK_dead_E */
4797 { 0xfe84, 'i' }, /* XK_dead_i */
4798 { 0xfe85, 'I' }, /* XK_dead_I */
4799 { 0xfe86, 'o' }, /* XK_dead_o */
4800 { 0xfe87, 'O' }, /* XK_dead_O */
4801 { 0xfe88, 'u' }, /* XK_dead_u */
4802 { 0xfe89, 'U' }, /* XK_dead_U */
4803 { 0xfe8a, 0x0259 },
4804 { 0xfe8b, 0x018f },
4805 { 0xfe8c, 0x00b5 },
4806 { 0xfe90, '_' },
4807 { 0xfe91, 0x02c8 },
4808 { 0xfe92, 0x02cc },
4809 { 0xff80 /*XKB_KEY_KP_Space*/, ' ' },
4810 { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 },
4811 { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 },
4812 { 0xff97 /*XKB_KEY_KP_8*/, 0x0038 },
4813 { 0xff98 /*XKB_KEY_KP_6*/, 0x0036 },
4814 { 0xff99 /*XKB_KEY_KP_2*/, 0x0032 },
4815 { 0xff9a /*XKB_KEY_KP_9*/, 0x0039 },
4816 { 0xff9b /*XKB_KEY_KP_3*/, 0x0033 },
4817 { 0xff9c /*XKB_KEY_KP_1*/, 0x0031 },
4818 { 0xff9d /*XKB_KEY_KP_5*/, 0x0035 },
4819 { 0xff9e /*XKB_KEY_KP_0*/, 0x0030 },
4820 { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' },
4821 { 0xffab /*XKB_KEY_KP_Add*/, '+' },
4822 { 0xffac /*XKB_KEY_KP_Separator*/, ',' },
4823 { 0xffad /*XKB_KEY_KP_Subtract*/, '-' },
4824 { 0xffae /*XKB_KEY_KP_Decimal*/, '.' },
4825 { 0xffaf /*XKB_KEY_KP_Divide*/, '/' },
4826 { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 },
4827 { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 },
4828 { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 },
4829 { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 },
4830 { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 },
4831 { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 },
4832 { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 },
4833 { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 },
4834 { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 },
4835 { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 },
4836 { 0xffbd /*XKB_KEY_KP_Equal*/, '=' }
4837};
4838
4839_SOKOL_PRIVATE int _sapp_x11_error_handler(Display* display, XErrorEvent* event) {
4840 _sapp_x11_error_code = event->error_code;
4841 return 0;
4842}
4843
4844_SOKOL_PRIVATE void _sapp_x11_grab_error_handler(void) {
4845 _sapp_x11_error_code = Success;
4846 XSetErrorHandler(_sapp_x11_error_handler);
4847}
4848
4849_SOKOL_PRIVATE void _sapp_x11_release_error_handler(void) {
4850 XSync(_sapp_x11_display, False);
4851 XSetErrorHandler(NULL);
4852}
4853
4854_SOKOL_PRIVATE void _sapp_x11_init_extensions(void) {
4855 _sapp_x11_UTF8_STRING = XInternAtom(_sapp_x11_display, "UTF8_STRING", False);
4856 _sapp_x11_WM_PROTOCOLS = XInternAtom(_sapp_x11_display, "WM_PROTOCOLS", False);
4857 _sapp_x11_WM_DELETE_WINDOW = XInternAtom(_sapp_x11_display, "WM_DELETE_WINDOW", False);
4858 _sapp_x11_WM_STATE = XInternAtom(_sapp_x11_display, "WM_STATE", False);
4859 _sapp_x11_NET_WM_NAME = XInternAtom(_sapp_x11_display, "_NET_WM_NAME", False);
4860 _sapp_x11_NET_WM_ICON_NAME = XInternAtom(_sapp_x11_display, "_NET_WM_ICON_NAME", False);
4861}
4862
4863_SOKOL_PRIVATE void _sapp_x11_query_system_dpi(void) {
4864 /* from GLFW:
4865
4866 NOTE: Default to the display-wide DPI as we don't currently have a policy
4867 for which monitor a window is considered to be on
4868 _sapp_x11_dpi = DisplayWidth(_sapp_x11_display, _sapp_x11_screen) *
4869 25.4f / DisplayWidthMM(_sapp_x11_display, _sapp_x11_screen);
4870
4871 NOTE: Basing the scale on Xft.dpi where available should provide the most
4872 consistent user experience (matches Qt, Gtk, etc), although not
4873 always the most accurate one
4874 */
4875 char* rms = XResourceManagerString(_sapp_x11_display);
4876 if (rms) {
4877 XrmDatabase db = XrmGetStringDatabase(rms);
4878 if (db) {
4879 XrmValue value;
4880 char* type = NULL;
4881 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) {
4882 if (type && strcmp(type, "String") == 0) {
4883 _sapp_x11_dpi = atof(value.addr);
4884 }
4885 }
4886 XrmDestroyDatabase(db);
4887 }
4888 }
4889}
4890
4891_SOKOL_PRIVATE bool _sapp_glx_has_ext(const char* ext, const char* extensions) {
4892 SOKOL_ASSERT(ext);
4893 const char* start = extensions;
4894 while (true) {
4895 const char* where = strstr(start, ext);
4896 if (!where) {
4897 return false;
4898 }
4899 const char* terminator = where + strlen(ext);
4900 if ((where == start) || (*(where - 1) == ' ')) {
4901 if (*terminator == ' ' || *terminator == '\0') {
4902 break;
4903 }
4904 }
4905 start = terminator;
4906 }
4907 return true;
4908}
4909
4910_SOKOL_PRIVATE bool _sapp_glx_extsupported(const char* ext, const char* extensions) {
4911 if (extensions) {
4912 return _sapp_glx_has_ext(ext, extensions);
4913 }
4914 else {
4915 return false;
4916 }
4917}
4918
4919_SOKOL_PRIVATE void* _sapp_glx_getprocaddr(const char* procname)
4920{
4921 if (_sapp_glx_GetProcAddress) {
4922 return _sapp_glx_GetProcAddress((const GLubyte*) procname);
4923 }
4924 else if (_sapp_glx_GetProcAddressARB) {
4925 return _sapp_glx_GetProcAddressARB((const GLubyte*) procname);
4926 }
4927 else {
4928 return dlsym(_sapp_glx_libgl, procname);
4929 }
4930}
4931
4932_SOKOL_PRIVATE void _sapp_glx_init() {
4933 const char* sonames[] = { "libGL.so.1", "libGL.so", 0 };
4934 for (int i = 0; sonames[i]; i++) {
4935 _sapp_glx_libgl = dlopen(sonames[i], RTLD_LAZY|RTLD_GLOBAL);
4936 if (_sapp_glx_libgl) {
4937 break;
4938 }
4939 }
4940 if (!_sapp_glx_libgl) {
4941 _sapp_fail("GLX: failed to load libGL");
4942 }
4943 _sapp_glx_GetFBConfigs = dlsym(_sapp_glx_libgl, "glXGetFBConfigs");
4944 _sapp_glx_GetFBConfigAttrib = dlsym(_sapp_glx_libgl, "glXGetFBConfigAttrib");
4945 _sapp_glx_GetClientString = dlsym(_sapp_glx_libgl, "glXGetClientString");
4946 _sapp_glx_QueryExtension = dlsym(_sapp_glx_libgl, "glXQueryExtension");
4947 _sapp_glx_QueryVersion = dlsym(_sapp_glx_libgl, "glXQueryVersion");
4948 _sapp_glx_DestroyContext = dlsym(_sapp_glx_libgl, "glXDestroyContext");
4949 _sapp_glx_MakeCurrent = dlsym(_sapp_glx_libgl, "glXMakeCurrent");
4950 _sapp_glx_SwapBuffers = dlsym(_sapp_glx_libgl, "glXSwapBuffers");
4951 _sapp_glx_QueryExtensionsString = dlsym(_sapp_glx_libgl, "glXQueryExtensionsString");
4952 _sapp_glx_CreateNewContext = dlsym(_sapp_glx_libgl, "glXCreateNewContext");
4953 _sapp_glx_CreateWindow = dlsym(_sapp_glx_libgl, "glXCreateWindow");
4954 _sapp_glx_DestroyWindow = dlsym(_sapp_glx_libgl, "glXDestroyWindow");
4955 _sapp_glx_GetProcAddress = dlsym(_sapp_glx_libgl, "glXGetProcAddress");
4956 _sapp_glx_GetProcAddressARB = dlsym(_sapp_glx_libgl, "glXGetProcAddressARB");
4957 _sapp_glx_GetVisualFromFBConfig = dlsym(_sapp_glx_libgl, "glXGetVisualFromFBConfig");
4958 if (!_sapp_glx_GetFBConfigs ||
4959 !_sapp_glx_GetFBConfigAttrib ||
4960 !_sapp_glx_GetClientString ||
4961 !_sapp_glx_QueryExtension ||
4962 !_sapp_glx_QueryVersion ||
4963 !_sapp_glx_DestroyContext ||
4964 !_sapp_glx_MakeCurrent ||
4965 !_sapp_glx_SwapBuffers ||
4966 !_sapp_glx_QueryExtensionsString ||
4967 !_sapp_glx_CreateNewContext ||
4968 !_sapp_glx_CreateWindow ||
4969 !_sapp_glx_DestroyWindow ||
4970 !_sapp_glx_GetProcAddress ||
4971 !_sapp_glx_GetProcAddressARB ||
4972 !_sapp_glx_GetVisualFromFBConfig)
4973 {
4974 _sapp_fail("GLX: failed to load required entry points");
4975 }
4976
4977 if (!_sapp_glx_QueryExtension(_sapp_x11_display,
4978 &_sapp_glx_errorbase,
4979 &_sapp_glx_eventbase))
4980 {
4981 _sapp_fail("GLX: GLX extension not found");
4982 }
4983 if (!_sapp_glx_QueryVersion(_sapp_x11_display, &_sapp_glx_major, &_sapp_glx_minor)) {
4984 _sapp_fail("GLX: Failed to query GLX version");
4985 }
4986 if (_sapp_glx_major == 1 && _sapp_glx_minor < 3) {
4987 _sapp_fail("GLX: GLX version 1.3 is required");
4988 }
4989 const char* exts = _sapp_glx_QueryExtensionsString(_sapp_x11_display, _sapp_x11_screen);
4990 if (_sapp_glx_extsupported("GLX_EXT_swap_control", exts)) {
4991 _sapp_glx_SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) _sapp_glx_getprocaddr("glXSwapIntervalEXT");
4992 _sapp_glx_EXT_swap_control = 0 != _sapp_glx_SwapIntervalEXT;
4993 }
4994 if (_sapp_glx_extsupported("GLX_MESA_swap_control", exts)) {
4995 _sapp_glx_SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) _sapp_glx_getprocaddr("glXSwapIntervalMESA");
4996 _sapp_glx_MESA_swap_control = 0 != _sapp_glx_SwapIntervalMESA;
4997 }
4998 _sapp_glx_ARB_multisample = _sapp_glx_extsupported("GLX_ARB_multisample", exts);
4999 _sapp_glx_ARB_framebuffer_sRGB = _sapp_glx_extsupported("GLX_ARB_framebuffer_sRGB", exts);
5000 _sapp_glx_EXT_framebuffer_sRGB = _sapp_glx_extsupported("GLX_EXT_framebuffer_sRGB", exts);
5001 if (_sapp_glx_extsupported("GLX_ARB_create_context", exts)) {
5002 _sapp_glx_CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) _sapp_glx_getprocaddr("glXCreateContextAttribsARB");
5003 _sapp_glx_ARB_create_context = 0 != _sapp_glx_CreateContextAttribsARB;
5004 }
5005 _sapp_glx_ARB_create_context_profile = _sapp_glx_extsupported("GLX_ARB_create_context_profile", exts);
5006}
5007
5008_SOKOL_PRIVATE int _sapp_glx_attrib(GLXFBConfig fbconfig, int attrib) {
5009 int value;
5010 _sapp_glx_GetFBConfigAttrib(_sapp_x11_display, fbconfig, attrib, &value);
5011 return value;
5012}
5013
5014_SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig() {
5015 GLXFBConfig* native_configs;
5016 _sapp_gl_fbconfig* usable_configs;
5017 const _sapp_gl_fbconfig* closest;
5018 int i, native_count, usable_count;
5019 const char* vendor;
5020 bool trust_window_bit = true;
5021
5022 /* HACK: This is a (hopefully temporary) workaround for Chromium
5023 (VirtualBox GL) not setting the window bit on any GLXFBConfigs
5024 */
5025 vendor = _sapp_glx_GetClientString(_sapp_x11_display, GLX_VENDOR);
5026 if (vendor && strcmp(vendor, "Chromium") == 0) {
5027 trust_window_bit = false;
5028 }
5029
5030 native_configs = _sapp_glx_GetFBConfigs(_sapp_x11_display, _sapp_x11_screen, &native_count);
5031 if (!native_configs || !native_count) {
5032 _sapp_fail("GLX: No GLXFBConfigs returned");
5033 }
5034
5035 usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC(native_count, sizeof(_sapp_gl_fbconfig));
5036 usable_count = 0;
5037 for (i = 0; i < native_count; i++) {
5038 const GLXFBConfig n = native_configs[i];
5039 _sapp_gl_fbconfig* u = usable_configs + usable_count;
5040 _sapp_gl_init_fbconfig(u);
5041
5042 /* Only consider RGBA GLXFBConfigs */
5043 if (!_sapp_glx_attrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT) {
5044 continue;
5045 }
5046 /* Only consider window GLXFBConfigs */
5047 if (!_sapp_glx_attrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT) {
5048 if (trust_window_bit) {
5049 continue;
5050 }
5051 }
5052 u->red_bits = _sapp_glx_attrib(n, GLX_RED_SIZE);
5053 u->green_bits = _sapp_glx_attrib(n, GLX_GREEN_SIZE);
5054 u->blue_bits = _sapp_glx_attrib(n, GLX_BLUE_SIZE);
5055 u->alpha_bits = _sapp_glx_attrib(n, GLX_ALPHA_SIZE);
5056 u->depth_bits = _sapp_glx_attrib(n, GLX_DEPTH_SIZE);
5057 u->stencil_bits = _sapp_glx_attrib(n, GLX_STENCIL_SIZE);
5058 if (_sapp_glx_attrib(n, GLX_DOUBLEBUFFER)) {
5059 u->doublebuffer = true;
5060 }
5061 if (_sapp_glx_ARB_multisample) {
5062 u->samples = _sapp_glx_attrib(n, GLX_SAMPLES);
5063 }
5064 u->handle = (uintptr_t) n;
5065 usable_count++;
5066 }
5067 _sapp_gl_fbconfig desired;
5068 _sapp_gl_init_fbconfig(&desired);
5069 desired.red_bits = 8;
5070 desired.green_bits = 8;
5071 desired.blue_bits = 8;
5072 desired.alpha_bits = 8;
5073 desired.depth_bits = 24;
5074 desired.stencil_bits = 8;
5075 desired.doublebuffer = true;
5076 desired.samples = _sapp.sample_count > 1 ? _sapp.sample_count : 0;
5077 closest = _sapp_gl_choose_fbconfig(&desired, usable_configs, usable_count);
5078 GLXFBConfig result = 0;
5079 if (closest) {
5080 result = (GLXFBConfig) closest->handle;
5081 }
5082 XFree(native_configs);
5083 SOKOL_FREE(usable_configs);
5084 return result;
5085}
5086
5087_SOKOL_PRIVATE void _sapp_glx_choose_visual(Visual** visual, int* depth) {
5088 GLXFBConfig native = _sapp_glx_choosefbconfig();
5089 if (0 == native) {
5090 _sapp_fail("GLX: Failed to find a suitable GLXFBConfig");
5091 }
5092 XVisualInfo* result = _sapp_glx_GetVisualFromFBConfig(_sapp_x11_display, native);
5093 if (!result) {
5094 _sapp_fail("GLX: Failed to retrieve Visual for GLXFBConfig");
5095 }
5096 *visual = result->visual;
5097 *depth = result->depth;
5098 XFree(result);
5099}
5100
5101_SOKOL_PRIVATE void _sapp_glx_create_context(void) {
5102 GLXFBConfig native = _sapp_glx_choosefbconfig();
5103 if (0 == native){
5104 _sapp_fail("GLX: Failed to find a suitable GLXFBConfig (2)");
5105 }
5106 if (!(_sapp_glx_ARB_create_context && _sapp_glx_ARB_create_context_profile)) {
5107 _sapp_fail("GLX: ARB_create_context and ARB_create_context_profile required");
5108 }
5109 _sapp_x11_grab_error_handler();
5110 const int attribs[] = {
5111 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
5112 GLX_CONTEXT_MINOR_VERSION_ARB, 3,
5113 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
5114 GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
5115 0, 0
5116 };
5117 _sapp_glx_ctx = _sapp_glx_CreateContextAttribsARB(_sapp_x11_display, native, NULL, True, attribs);
5118 if (!_sapp_glx_ctx) {
5119 _sapp_fail("GLX: failed to create GL context");
5120 }
5121 _sapp_x11_release_error_handler();
5122 _sapp_glx_window = _sapp_glx_CreateWindow(_sapp_x11_display, native, _sapp_x11_window, NULL);
5123 if (!_sapp_glx_window) {
5124 _sapp_fail("GLX: failed to create window");
5125 }
5126}
5127
5128_SOKOL_PRIVATE void _sapp_glx_destroy_context(void) {
5129 if (_sapp_glx_window) {
5130 _sapp_glx_DestroyWindow(_sapp_x11_display, _sapp_glx_window);
5131 _sapp_glx_window = 0;
5132 }
5133 if (_sapp_glx_ctx) {
5134 _sapp_glx_DestroyContext(_sapp_x11_display, _sapp_glx_ctx);
5135 _sapp_glx_ctx = 0;
5136 }
5137}
5138
5139_SOKOL_PRIVATE void _sapp_glx_make_current(void) {
5140 _sapp_glx_MakeCurrent(_sapp_x11_display, _sapp_glx_window, _sapp_glx_ctx);
5141}
5142
5143_SOKOL_PRIVATE void _sapp_glx_swap_buffers(void) {
5144 _sapp_glx_SwapBuffers(_sapp_x11_display, _sapp_glx_window);
5145}
5146
5147_SOKOL_PRIVATE void _sapp_glx_swapinterval(int interval) {
5148 _sapp_glx_make_current();
5149 if (_sapp_glx_EXT_swap_control) {
5150 _sapp_glx_SwapIntervalEXT(_sapp_x11_display, _sapp_glx_window, interval);
5151 }
5152 else if (_sapp_glx_MESA_swap_control) {
5153 _sapp_glx_SwapIntervalMESA(interval);
5154 }
5155}
5156
5157_SOKOL_PRIVATE void _sapp_x11_update_window_title(void) {
5158 Xutf8SetWMProperties(_sapp_x11_display,
5159 _sapp_x11_window,
5160 _sapp.window_title, _sapp.window_title,
5161 NULL, 0, NULL, NULL, NULL);
5162 XChangeProperty(_sapp_x11_display, _sapp_x11_window,
5163 _sapp_x11_NET_WM_NAME, _sapp_x11_UTF8_STRING, 8,
5164 PropModeReplace,
5165 (unsigned char*)_sapp.window_title,
5166 strlen(_sapp.window_title));
5167 XChangeProperty(_sapp_x11_display, _sapp_x11_window,
5168 _sapp_x11_NET_WM_ICON_NAME, _sapp_x11_UTF8_STRING, 8,
5169 PropModeReplace,
5170 (unsigned char*)_sapp.window_title,
5171 strlen(_sapp.window_title));
5172 XFlush(_sapp_x11_display);
5173}
5174
5175_SOKOL_PRIVATE void _sapp_x11_query_window_size(void) {
5176 XWindowAttributes attribs;
5177 XGetWindowAttributes(_sapp_x11_display, _sapp_x11_window, &attribs);
5178 _sapp.window_width = attribs.width;
5179 _sapp.window_height = attribs.height;
5180 _sapp.framebuffer_width = _sapp.window_width;
5181 _sapp.framebuffer_height = _sapp.framebuffer_height;
5182}
5183
5184_SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) {
5185 _sapp_x11_colormap = XCreateColormap(_sapp_x11_display, _sapp_x11_root, visual, AllocNone);
5186 XSetWindowAttributes wa;
5187 memset(&wa, 0, sizeof(wa));
5188 const uint32_t wamask = CWBorderPixel | CWColormap | CWEventMask;
5189 wa.colormap = _sapp_x11_colormap;
5190 wa.border_pixel = 0;
5191 wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
5192 PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
5193 ExposureMask | FocusChangeMask | VisibilityChangeMask |
5194 EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
5195 _sapp_x11_grab_error_handler();
5196 _sapp_x11_window = XCreateWindow(_sapp_x11_display,
5197 _sapp_x11_root,
5198 0, 0,
5199 _sapp.window_width,
5200 _sapp.window_height,
5201 0, /* border width */
5202 depth, /* color depth */
5203 InputOutput,
5204 visual,
5205 wamask,
5206 &wa);
5207 _sapp_x11_release_error_handler();
5208 if (!_sapp_x11_window) {
5209 _sapp_fail("X11: Failed to create window");
5210 }
5211
5212 Atom protocols[] = {
5213 _sapp_x11_WM_DELETE_WINDOW
5214 };
5215 XSetWMProtocols(_sapp_x11_display, _sapp_x11_window, protocols, 1);
5216
5217 XSizeHints* hints = XAllocSizeHints();
5218 hints->flags |= PWinGravity;
5219 hints->win_gravity = StaticGravity;
5220 XSetWMNormalHints(_sapp_x11_display, _sapp_x11_window, hints);
5221 XFree(hints);
5222
5223 _sapp_x11_update_window_title();
5224 _sapp_x11_query_window_size();
5225}
5226
5227_SOKOL_PRIVATE void _sapp_x11_destroy_window(void) {
5228 if (_sapp_x11_window) {
5229 XUnmapWindow(_sapp_x11_display, _sapp_x11_window);
5230 XDestroyWindow(_sapp_x11_display, _sapp_x11_window);
5231 _sapp_x11_window = 0;
5232 }
5233 if (_sapp_x11_colormap) {
5234 XFreeColormap(_sapp_x11_display, _sapp_x11_colormap);
5235 _sapp_x11_colormap = 0;
5236 }
5237 XFlush(_sapp_x11_display);
5238}
5239
5240_SOKOL_PRIVATE bool _sapp_x11_window_visible(void) {
5241 XWindowAttributes wa;
5242 XGetWindowAttributes(_sapp_x11_display, _sapp_x11_window, &wa);
5243 return wa.map_state == IsViewable;
5244}
5245
5246_SOKOL_PRIVATE void _sapp_x11_show_window(void) {
5247 if (!_sapp_x11_window_visible()) {
5248 XMapWindow(_sapp_x11_display, _sapp_x11_window);
5249 XRaiseWindow(_sapp_x11_display, _sapp_x11_window);
5250 XFlush(_sapp_x11_display);
5251 }
5252}
5253
5254_SOKOL_PRIVATE void _sapp_x11_hide_window(void) {
5255 XUnmapWindow(_sapp_x11_display, _sapp_x11_window);
5256 XFlush(_sapp_x11_display);
5257}
5258
5259_SOKOL_PRIVATE unsigned long _sapp_x11_get_window_property(Atom property, Atom type, unsigned char** value) {
5260 Atom actualType;
5261 int actualFormat;
5262 unsigned long itemCount, bytesAfter;
5263 XGetWindowProperty(_sapp_x11_display,
5264 _sapp_x11_window,
5265 property,
5266 0,
5267 LONG_MAX,
5268 False,
5269 type,
5270 &actualType,
5271 &actualFormat,
5272 &itemCount,
5273 &bytesAfter,
5274 value);
5275 return itemCount;
5276}
5277
5278_SOKOL_PRIVATE int _sapp_x11_get_window_state(void) {
5279 int result = WithdrawnState;
5280 struct {
5281 CARD32 state;
5282 Window icon;
5283 } *state = NULL;
5284
5285 if (_sapp_x11_get_window_property(_sapp_x11_WM_STATE, _sapp_x11_WM_STATE, (unsigned char**)&state) >= 2) {
5286 result = state->state;
5287 }
5288 if (state) {
5289 XFree(state);
5290 }
5291 return result;
5292}
5293
5294_SOKOL_PRIVATE uint32_t _sapp_x11_mod(int x11_mods) {
5295 uint32_t mods = 0;
5296 if (x11_mods & ShiftMask) {
5297 mods |= SAPP_MODIFIER_SHIFT;
5298 }
5299 if (x11_mods & ControlMask) {
5300 mods |= SAPP_MODIFIER_CTRL;
5301 }
5302 if (x11_mods & Mod1Mask) {
5303 mods |= SAPP_MODIFIER_ALT;
5304 }
5305 if (x11_mods & Mod4Mask) {
5306 mods |= SAPP_MODIFIER_SUPER;
5307 }
5308 return mods;
5309}
5310
5311_SOKOL_PRIVATE void _sapp_x11_app_event(sapp_event_type type) {
5312 if (_sapp_events_enabled()) {
5313 _sapp_init_event(type);
5314 _sapp.desc.event_cb(&_sapp.event);
5315 }
5316}
5317
5318_SOKOL_PRIVATE sapp_mousebutton _sapp_x11_translate_button(const XEvent* event) {
5319 switch (event->xbutton.button) {
5320 case Button1: return SAPP_MOUSEBUTTON_LEFT;
5321 case Button2: return SAPP_MOUSEBUTTON_MIDDLE;
5322 case Button3: return SAPP_MOUSEBUTTON_RIGHT;
5323 default: return SAPP_MOUSEBUTTON_INVALID;
5324 }
5325}
5326
5327_SOKOL_PRIVATE void _sapp_x11_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mods) {
5328 if (_sapp_events_enabled()) {
5329 _sapp_init_event(type);
5330 _sapp.event.mouse_button = btn;
5331 _sapp.event.modifiers = mods;
5332 _sapp.event.mouse_x = _sapp.mouse_x;
5333 _sapp.event.mouse_y = _sapp.mouse_y;
5334 _sapp.desc.event_cb(&_sapp.event);
5335 }
5336}
5337
5338_SOKOL_PRIVATE void _sapp_x11_scroll_event(float x, float y, uint32_t mods) {
5339 if (_sapp_events_enabled()) {
5340 _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
5341 _sapp.event.modifiers = mods;
5342 _sapp.event.scroll_x = x;
5343 _sapp.event.scroll_y = y;
5344 _sapp.desc.event_cb(&_sapp.event);
5345 }
5346}
5347
5348_SOKOL_PRIVATE void _sapp_x11_key_event(sapp_event_type type, sapp_keycode key, uint32_t mods) {
5349 if (_sapp_events_enabled()) {
5350 _sapp_init_event(type);
5351 _sapp.event.key_code = key;
5352 _sapp.event.modifiers = mods;
5353 _sapp.desc.event_cb(&_sapp.event);
5354 }
5355}
5356
5357_SOKOL_PRIVATE void _sapp_x11_char_event(uint32_t chr, uint32_t mods) {
5358 if (_sapp_events_enabled()) {
5359 _sapp_init_event(SAPP_EVENTTYPE_CHAR);
5360 _sapp.event.char_code = chr;
5361 _sapp.event.modifiers = mods;
5362 _sapp.desc.event_cb(&_sapp.event);
5363 }
5364}
5365
5366_SOKOL_PRIVATE sapp_keycode _sapp_x11_translate_key(int scancode) {
5367 int dummy;
5368 KeySym* keysyms = XGetKeyboardMapping(_sapp_x11_display, scancode, 1, &dummy);
5369 SOKOL_ASSERT(keysyms);
5370 KeySym keysym = keysyms[0];
5371 XFree(keysyms);
5372 switch (keysym) {
5373 case XK_Escape: return SAPP_KEYCODE_ESCAPE;
5374 case XK_Tab: return SAPP_KEYCODE_TAB;
5375 case XK_Shift_L: return SAPP_KEYCODE_LEFT_SHIFT;
5376 case XK_Shift_R: return SAPP_KEYCODE_RIGHT_SHIFT;
5377 case XK_Control_L: return SAPP_KEYCODE_LEFT_CONTROL;
5378 case XK_Control_R: return SAPP_KEYCODE_RIGHT_CONTROL;
5379 case XK_Meta_L:
5380 case XK_Alt_L: return SAPP_KEYCODE_LEFT_ALT;
5381 case XK_Mode_switch: /* Mapped to Alt_R on many keyboards */
5382 case XK_ISO_Level3_Shift: /* AltGr on at least some machines */
5383 case XK_Meta_R:
5384 case XK_Alt_R: return SAPP_KEYCODE_RIGHT_ALT;
5385 case XK_Super_L: return SAPP_KEYCODE_LEFT_SUPER;
5386 case XK_Super_R: return SAPP_KEYCODE_RIGHT_SUPER;
5387 case XK_Menu: return SAPP_KEYCODE_MENU;
5388 case XK_Num_Lock: return SAPP_KEYCODE_NUM_LOCK;
5389 case XK_Caps_Lock: return SAPP_KEYCODE_CAPS_LOCK;
5390 case XK_Print: return SAPP_KEYCODE_PRINT_SCREEN;
5391 case XK_Scroll_Lock: return SAPP_KEYCODE_SCROLL_LOCK;
5392 case XK_Pause: return SAPP_KEYCODE_PAUSE;
5393 case XK_Delete: return SAPP_KEYCODE_DELETE;
5394 case XK_BackSpace: return SAPP_KEYCODE_BACKSPACE;
5395 case XK_Return: return SAPP_KEYCODE_ENTER;
5396 case XK_Home: return SAPP_KEYCODE_HOME;
5397 case XK_End: return SAPP_KEYCODE_END;
5398 case XK_Page_Up: return SAPP_KEYCODE_PAGE_UP;
5399 case XK_Page_Down: return SAPP_KEYCODE_PAGE_DOWN;
5400 case XK_Insert: return SAPP_KEYCODE_INSERT;
5401 case XK_Left: return SAPP_KEYCODE_LEFT;
5402 case XK_Right: return SAPP_KEYCODE_RIGHT;
5403 case XK_Down: return SAPP_KEYCODE_DOWN;
5404 case XK_Up: return SAPP_KEYCODE_UP;
5405 case XK_F1: return SAPP_KEYCODE_F1;
5406 case XK_F2: return SAPP_KEYCODE_F2;
5407 case XK_F3: return SAPP_KEYCODE_F3;
5408 case XK_F4: return SAPP_KEYCODE_F4;
5409 case XK_F5: return SAPP_KEYCODE_F5;
5410 case XK_F6: return SAPP_KEYCODE_F6;
5411 case XK_F7: return SAPP_KEYCODE_F7;
5412 case XK_F8: return SAPP_KEYCODE_F8;
5413 case XK_F9: return SAPP_KEYCODE_F9;
5414 case XK_F10: return SAPP_KEYCODE_F10;
5415 case XK_F11: return SAPP_KEYCODE_F11;
5416 case XK_F12: return SAPP_KEYCODE_F12;
5417 case XK_F13: return SAPP_KEYCODE_F13;
5418 case XK_F14: return SAPP_KEYCODE_F14;
5419 case XK_F15: return SAPP_KEYCODE_F15;
5420 case XK_F16: return SAPP_KEYCODE_F16;
5421 case XK_F17: return SAPP_KEYCODE_F17;
5422 case XK_F18: return SAPP_KEYCODE_F18;
5423 case XK_F19: return SAPP_KEYCODE_F19;
5424 case XK_F20: return SAPP_KEYCODE_F20;
5425 case XK_F21: return SAPP_KEYCODE_F21;
5426 case XK_F22: return SAPP_KEYCODE_F22;
5427 case XK_F23: return SAPP_KEYCODE_F23;
5428 case XK_F24: return SAPP_KEYCODE_F24;
5429 case XK_F25: return SAPP_KEYCODE_F25;
5430
5431 case XK_KP_Divide: return SAPP_KEYCODE_KP_DIVIDE;
5432 case XK_KP_Multiply: return SAPP_KEYCODE_KP_MULTIPLY;
5433 case XK_KP_Subtract: return SAPP_KEYCODE_KP_SUBTRACT;
5434 case XK_KP_Add: return SAPP_KEYCODE_KP_ADD;
5435
5436 case XK_KP_Insert: return SAPP_KEYCODE_KP_0;
5437 case XK_KP_End: return SAPP_KEYCODE_KP_1;
5438 case XK_KP_Down: return SAPP_KEYCODE_KP_2;
5439 case XK_KP_Page_Down: return SAPP_KEYCODE_KP_3;
5440 case XK_KP_Left: return SAPP_KEYCODE_KP_4;
5441 case XK_KP_Right: return SAPP_KEYCODE_KP_6;
5442 case XK_KP_Home: return SAPP_KEYCODE_KP_7;
5443 case XK_KP_Up: return SAPP_KEYCODE_KP_8;
5444 case XK_KP_Page_Up: return SAPP_KEYCODE_KP_9;
5445 case XK_KP_Delete: return SAPP_KEYCODE_KP_DECIMAL;
5446 case XK_KP_Equal: return SAPP_KEYCODE_KP_EQUAL;
5447 case XK_KP_Enter: return SAPP_KEYCODE_KP_ENTER;
5448
5449 case XK_a: return SAPP_KEYCODE_A;
5450 case XK_b: return SAPP_KEYCODE_B;
5451 case XK_c: return SAPP_KEYCODE_C;
5452 case XK_d: return SAPP_KEYCODE_D;
5453 case XK_e: return SAPP_KEYCODE_E;
5454 case XK_f: return SAPP_KEYCODE_F;
5455 case XK_g: return SAPP_KEYCODE_G;
5456 case XK_h: return SAPP_KEYCODE_H;
5457 case XK_i: return SAPP_KEYCODE_I;
5458 case XK_j: return SAPP_KEYCODE_J;
5459 case XK_k: return SAPP_KEYCODE_K;
5460 case XK_l: return SAPP_KEYCODE_L;
5461 case XK_m: return SAPP_KEYCODE_M;
5462 case XK_n: return SAPP_KEYCODE_N;
5463 case XK_o: return SAPP_KEYCODE_O;
5464 case XK_p: return SAPP_KEYCODE_P;
5465 case XK_q: return SAPP_KEYCODE_Q;
5466 case XK_r: return SAPP_KEYCODE_R;
5467 case XK_s: return SAPP_KEYCODE_S;
5468 case XK_t: return SAPP_KEYCODE_T;
5469 case XK_u: return SAPP_KEYCODE_U;
5470 case XK_v: return SAPP_KEYCODE_V;
5471 case XK_w: return SAPP_KEYCODE_W;
5472 case XK_x: return SAPP_KEYCODE_X;
5473 case XK_y: return SAPP_KEYCODE_Y;
5474 case XK_z: return SAPP_KEYCODE_Z;
5475 case XK_1: return SAPP_KEYCODE_1;
5476 case XK_2: return SAPP_KEYCODE_2;
5477 case XK_3: return SAPP_KEYCODE_3;
5478 case XK_4: return SAPP_KEYCODE_4;
5479 case XK_5: return SAPP_KEYCODE_5;
5480 case XK_6: return SAPP_KEYCODE_6;
5481 case XK_7: return SAPP_KEYCODE_7;
5482 case XK_8: return SAPP_KEYCODE_8;
5483 case XK_9: return SAPP_KEYCODE_9;
5484 case XK_0: return SAPP_KEYCODE_0;
5485 case XK_space: return SAPP_KEYCODE_SPACE;
5486 case XK_minus: return SAPP_KEYCODE_MINUS;
5487 case XK_equal: return SAPP_KEYCODE_EQUAL;
5488 case XK_bracketleft: return SAPP_KEYCODE_LEFT_BRACKET;
5489 case XK_bracketright: return SAPP_KEYCODE_RIGHT_BRACKET;
5490 case XK_backslash: return SAPP_KEYCODE_BACKSLASH;
5491 case XK_semicolon: return SAPP_KEYCODE_SEMICOLON;
5492 case XK_apostrophe: return SAPP_KEYCODE_APOSTROPHE;
5493 case XK_grave: return SAPP_KEYCODE_GRAVE_ACCENT;
5494 case XK_comma: return SAPP_KEYCODE_COMMA;
5495 case XK_period: return SAPP_KEYCODE_PERIOD;
5496 case XK_slash: return SAPP_KEYCODE_SLASH;
5497 case XK_less: return SAPP_KEYCODE_WORLD_1; /* At least in some layouts... */
5498 default: return SAPP_KEYCODE_INVALID;
5499 }
5500}
5501
5502_SOKOL_PRIVATE int32_t _sapp_x11_keysym_to_unicode(KeySym keysym) {
5503 int min = 0;
5504 int max = sizeof(_sapp_x11_keysymtab) / sizeof(struct _sapp_x11_codepair) - 1;
5505 int mid;
5506
5507 /* First check for Latin-1 characters (1:1 mapping) */
5508 if ((keysym >= 0x0020 && keysym <= 0x007e) ||
5509 (keysym >= 0x00a0 && keysym <= 0x00ff))
5510 {
5511 return keysym;
5512 }
5513
5514 /* Also check for directly encoded 24-bit UCS characters */
5515 if ((keysym & 0xff000000) == 0x01000000) {
5516 return keysym & 0x00ffffff;
5517 }
5518
5519 /* Binary search in table */
5520 while (max >= min) {
5521 mid = (min + max) / 2;
5522 if (_sapp_x11_keysymtab[mid].keysym < keysym) {
5523 min = mid + 1;
5524 }
5525 else if (_sapp_x11_keysymtab[mid].keysym > keysym) {
5526 max = mid - 1;
5527 }
5528 else {
5529 return _sapp_x11_keysymtab[mid].ucs;
5530 }
5531 }
5532
5533 /* No matching Unicode value found */
5534 return -1;
5535}
5536
5537_SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) {
5538 switch (event->type) {
5539 case KeyPress:
5540 {
5541 const sapp_keycode key = _sapp_x11_translate_key(event->xkey.keycode);
5542 const uint32_t mods = _sapp_x11_mod(event->xkey.state);
5543 if (key != SAPP_KEYCODE_INVALID) {
5544 _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_DOWN, key, mods);
5545 }
5546 KeySym keysym;
5547 XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
5548 int32_t chr = _sapp_x11_keysym_to_unicode(keysym);
5549 if (chr > 0) {
5550 _sapp_x11_char_event((uint32_t)chr, mods);
5551 }
5552 }
5553 break;
5554 case KeyRelease:
5555 {
5556 const sapp_keycode key = _sapp_x11_translate_key(event->xkey.keycode);
5557 if (key != SAPP_KEYCODE_INVALID) {
5558 const uint32_t mods = _sapp_x11_mod(event->xkey.state);
5559 _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_UP, key, mods);
5560 }
5561 }
5562 break;
5563 case ButtonPress:
5564 {
5565 const sapp_mousebutton btn = _sapp_x11_translate_button(event);
5566 const uint32_t mods = _sapp_x11_mod(event->xbutton.state);
5567 if (btn != SAPP_MOUSEBUTTON_INVALID) {
5568 _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, btn, mods);
5569 }
5570 else {
5571 /* might be a scroll event */
5572 switch (event->xbutton.button) {
5573 case 4: _sapp_x11_scroll_event(0.0f, 1.0f, mods); break;
5574 case 5: _sapp_x11_scroll_event(0.0f, -1.0f, mods); break;
5575 case 6: _sapp_x11_scroll_event(1.0f, 0.0f, mods); break;
5576 case 7: _sapp_x11_scroll_event(-1.0f, 0.0f, mods); break;
5577 }
5578 }
5579 }
5580 break;
5581 case ButtonRelease:
5582 {
5583 const sapp_mousebutton btn = _sapp_x11_translate_button(event);
5584 if (btn != SAPP_MOUSEBUTTON_INVALID) {
5585 _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, btn, _sapp_x11_mod(event->xbutton.state));
5586 }
5587 }
5588 break;
5589 case EnterNotify:
5590 _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state));
5591 break;
5592 case LeaveNotify:
5593 _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state));
5594 break;
5595 case MotionNotify:
5596 _sapp.mouse_x = event->xmotion.x;
5597 _sapp.mouse_y = event->xmotion.y;
5598 _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xmotion.state));
5599 break;
5600 case ConfigureNotify:
5601 if ((event->xconfigure.width != _sapp.window_width) || (event->xconfigure.height != _sapp.window_height)) {
5602 _sapp.window_width = event->xconfigure.width;
5603 _sapp.window_height = event->xconfigure.height;
5604 _sapp.framebuffer_width = _sapp.window_width;
5605 _sapp.framebuffer_height = _sapp.window_height;
5606 _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED);
5607 }
5608 break;
5609 case PropertyNotify:
5610 if (event->xproperty.state == PropertyNewValue) {
5611 if (event->xproperty.atom == _sapp_x11_WM_STATE) {
5612 const int state = _sapp_x11_get_window_state();
5613 if (state != _sapp_x11_window_state) {
5614 _sapp_x11_window_state = state;
5615 if (state == IconicState) {
5616 _sapp_x11_app_event(SAPP_EVENTTYPE_ICONIFIED);
5617 }
5618 else if (state == NormalState) {
5619 _sapp_x11_app_event(SAPP_EVENTTYPE_RESTORED);
5620 }
5621 }
5622 }
5623 }
5624 break;
5625 case ClientMessage:
5626 if (event->xclient.message_type == _sapp_x11_WM_PROTOCOLS) {
5627 const Atom protocol = event->xclient.data.l[0];
5628 if (protocol == _sapp_x11_WM_DELETE_WINDOW) {
5629 _sapp_x11_quit_requested = true;
5630 }
5631 }
5632 break;
5633 case DestroyNotify:
5634 break;
5635 }
5636}
5637
5638int main(int argc, char* argv[]) {
5639 sapp_desc desc = sokol_main(argc, argv);
5640 _sapp_init_state(&desc, argc, argv);
5641 _sapp_x11_quit_requested = false;
5642 _sapp_x11_window_state = NormalState;
5643
5644 XInitThreads();
5645 XrmInitialize();
5646 _sapp_x11_display = XOpenDisplay(NULL);
5647 if (!_sapp_x11_display) {
5648 _sapp_fail("XOpenDisplay() failed!\n");
5649 }
5650 _sapp_x11_screen = DefaultScreen(_sapp_x11_display);
5651 _sapp_x11_root = DefaultRootWindow(_sapp_x11_display);
5652 _sapp_x11_query_system_dpi();
5653 _sapp.dpi_scale = _sapp_x11_dpi / 96.0f;
5654 _sapp_x11_init_extensions();
5655 _sapp_glx_init();
5656 Visual* visual = 0;
5657 int depth = 0;
5658 _sapp_glx_choose_visual(&visual, &depth);
5659 _sapp_x11_create_window(visual, depth);
5660 _sapp_glx_create_context();
5661 _sapp.valid = true;
5662 _sapp_x11_show_window();
5663 _sapp_glx_swapinterval(_sapp.swap_interval);
5664 XFlush(_sapp_x11_display);
5665 while (!_sapp_x11_quit_requested) {
5666 _sapp_glx_make_current();
5667 int count = XPending(_sapp_x11_display);
5668 while (count--) {
5669 XEvent event;
5670 XNextEvent(_sapp_x11_display, &event);
5671 _sapp_x11_process_event(&event);
5672 }
5673 _sapp_frame();
5674 _sapp_glx_swap_buffers();
5675 XFlush(_sapp_x11_display);
5676 }
5677 _sapp.desc.cleanup_cb();
5678 _sapp_glx_destroy_context();
5679 _sapp_x11_destroy_window();
5680 XCloseDisplay(_sapp_x11_display);
5681 return 0;
5682}
5683
5684#endif /* LINUX */
5685
5686/*== PUBLIC API FUNCTIONS ====================================================*/
5687SOKOL_API_IMPL bool sapp_isvalid(void) {
5688 return _sapp.valid;
5689}
5690
5691SOKOL_API_IMPL int sapp_width(void) {
5692 return (_sapp.framebuffer_width > 0) ? _sapp.framebuffer_width : 1;
5693}
5694
5695SOKOL_API_IMPL int sapp_height(void) {
5696 return (_sapp.framebuffer_height > 0) ? _sapp.framebuffer_height : 1;
5697}
5698
5699SOKOL_API_IMPL bool sapp_high_dpi(void) {
5700 return _sapp.desc.high_dpi && (_sapp.dpi_scale > 1.5f);
5701}
5702
5703SOKOL_API_IMPL float sapp_dpi_scale(void) {
5704 return _sapp.dpi_scale;
5705}
5706
5707SOKOL_API_IMPL bool sapp_gles2(void) {
5708 return _sapp.gles2_fallback;
5709}
5710
5711SOKOL_API_IMPL void sapp_show_keyboard(bool shown) {
5712 #if TARGET_OS_IPHONE
5713 _sapp_ios_show_keyboard(shown);
5714 #elif __EMSCRIPTEN__
5715 _sapp_emsc_show_keyboard(shown);
5716 #else
5717 _SOKOL_UNUSED(shown);
5718 #endif
5719}
5720
5721SOKOL_API_IMPL bool sapp_keyboard_shown(void) {
5722 return _sapp.onscreen_keyboard_shown;
5723}
5724
5725SOKOL_API_IMPL const void* sapp_metal_get_device(void) {
5726 SOKOL_ASSERT(_sapp.valid);
5727 #if defined(SOKOL_METAL)
5728 const void* obj = (__bridge const void*) _sapp_mtl_device_obj;
5729 SOKOL_ASSERT(obj);
5730 return obj;
5731 #else
5732 return 0;
5733 #endif
5734}
5735
5736SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) {
5737 SOKOL_ASSERT(_sapp.valid);
5738 #if defined(SOKOL_METAL)
5739 const void* obj = (__bridge const void*) [_sapp_view_obj currentRenderPassDescriptor];
5740 SOKOL_ASSERT(obj);
5741 return obj;
5742 #else
5743 return 0;
5744 #endif
5745}
5746
5747SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) {
5748 SOKOL_ASSERT(_sapp.valid);
5749 #if defined(SOKOL_METAL)
5750 const void* obj = (__bridge const void*) [_sapp_view_obj currentDrawable];
5751 SOKOL_ASSERT(obj);
5752 return obj;
5753 #else
5754 return 0;
5755 #endif
5756}
5757
5758SOKOL_API_IMPL const void* sapp_macos_get_window(void) {
5759 #if defined(__APPLE__) && !TARGET_OS_IPHONE
5760 const void* obj = (__bridge const void*) _sapp_macos_window_obj;
5761 SOKOL_ASSERT(obj);
5762 return obj;
5763 #else
5764 return 0;
5765 #endif
5766}
5767
5768SOKOL_API_IMPL const void* sapp_ios_get_window(void) {
5769 #if defined(__APPLE__) && TARGET_OS_IPHONE
5770 const void* obj = (__bridge const void*) _sapp_ios_window_obj;
5771 SOKOL_ASSERT(obj);
5772 return obj;
5773 #else
5774 return 0;
5775 #endif
5776
5777}
5778
5779SOKOL_API_IMPL const void* sapp_d3d11_get_device(void) {
5780 SOKOL_ASSERT(_sapp.valid);
5781 #if defined(SOKOL_D3D11)
5782 return _sapp_d3d11_device;
5783 #else
5784 return 0;
5785 #endif
5786}
5787
5788SOKOL_API_IMPL const void* sapp_d3d11_get_device_context(void) {
5789 SOKOL_ASSERT(_sapp.valid);
5790 #if defined(SOKOL_D3D11)
5791 return _sapp_d3d11_device_context;
5792 #else
5793 return 0;
5794 #endif
5795}
5796
5797SOKOL_API_IMPL const void* sapp_d3d11_get_render_target_view(void) {
5798 SOKOL_ASSERT(_sapp.valid);
5799 #if defined(SOKOL_D3D11)
5800 return _sapp_d3d11_rtv;
5801 #else
5802 return 0;
5803 #endif
5804}
5805
5806SOKOL_API_IMPL const void* sapp_d3d11_get_depth_stencil_view(void) {
5807 SOKOL_ASSERT(_sapp.valid);
5808 #if defined(SOKOL_D3D11)
5809 return _sapp_d3d11_dsv;
5810 #else
5811 return 0;
5812 #endif
5813}
5814
5815SOKOL_API_IMPL const void* sapp_win32_get_hwnd(void) {
5816 SOKOL_ASSERT(_sapp.valid);
5817 #if defined(_WIN32)
5818 return _sapp_win32_hwnd;
5819 #else
5820 return 0;
5821 #endif
5822}
5823
5824#undef _sapp_def
5825
5826#ifdef _MSC_VER
5827#pragma warning(pop)
5828#endif
5829
5830#endif /* SOKOL_IMPL */
5831