Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libglfw.js
6171 views
1
/**
2
* @license
3
* Copyright 2013 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
/*
8
* EMSCRIPTEN GLFW 2.x-3.x emulation.
9
* It tries to emulate the behavior described in
10
* http://www.glfw.org/docs/latest/
11
*
12
* This also implements parts of GLFW 2.x on top of GLFW 3.x.
13
*
14
* What it does:
15
* - Creates a GL context.
16
* - Manage keyboard and mouse events.
17
* - GL Extensions support.
18
*
19
* What it does not but should probably do:
20
* - Transmit events when glfwPollEvents, glfwWaitEvents or glfwSwapBuffers is
21
* called. Events callbacks are called as soon as events are received.
22
* - Input modes.
23
* - Gamma ramps.
24
* - Video modes.
25
* - Monitors.
26
* - Clipboard (not possible from javascript?).
27
* - Multiple windows.
28
* - Error codes && messages through callback.
29
* - Thread emulation. (removed in GLFW3).
30
* - Image/Texture I/O support (removed in GLFW 3).
31
*
32
* Authors:
33
* - Jari Vetoniemi <[email protected]>
34
* - Éloi Rivard <[email protected]>
35
* - Thomas Borsos <[email protected]>
36
*/
37
38
var LibraryGLFW = {
39
$GLFW_Window__docs: '/** @constructor */',
40
$GLFW_Window: function(id, width, height, framebufferWidth, framebufferHeight, title, monitor, share) {
41
this.id = id;
42
this.x = 0;
43
this.y = 0;
44
this.fullscreen = false; // Used to determine if app is in fullscreen mode
45
this.storedX = 0; // Used to store X before fullscreen
46
this.storedY = 0; // Used to store Y before fullscreen
47
this.width = width;
48
this.height = height;
49
this.framebufferWidth = framebufferWidth;
50
this.framebufferHeight = framebufferHeight;
51
this.storedWidth = width; // Used to store width before fullscreen
52
this.storedHeight = height; // Used to store height before fullscreen
53
this.title = title;
54
this.monitor = monitor;
55
this.share = share;
56
this.attributes = {...GLFW.hints};
57
this.inputModes = {
58
0x00033001:0x00034001, // GLFW_CURSOR (GLFW_CURSOR_NORMAL)
59
0x00033002:0, // GLFW_STICKY_KEYS
60
0x00033003:0, // GLFW_STICKY_MOUSE_BUTTONS
61
};
62
this.buttons = 0;
63
this.keys = new Array();
64
this.domKeys = new Array();
65
this.shouldClose = 0;
66
this.title = null;
67
this.windowPosFunc = 0; // GLFWwindowposfun
68
this.windowSizeFunc = 0; // GLFWwindowsizefun
69
this.windowCloseFunc = 0; // GLFWwindowclosefun
70
this.windowRefreshFunc = 0; // GLFWwindowrefreshfun
71
this.windowFocusFunc = 0; // GLFWwindowfocusfun
72
this.windowIconifyFunc = 0; // GLFWwindowiconifyfun
73
this.windowMaximizeFunc = 0; // GLFWwindowmaximizefun
74
this.framebufferSizeFunc = 0; // GLFWframebuffersizefun
75
this.windowContentScaleFunc = 0; // GLFWwindowcontentscalefun
76
this.mouseButtonFunc = 0; // GLFWmousebuttonfun
77
this.cursorPosFunc = 0; // GLFWcursorposfun
78
this.cursorEnterFunc = 0; // GLFWcursorenterfun
79
this.scrollFunc = 0; // GLFWscrollfun
80
this.dropFunc = 0; // GLFWdropfun
81
this.keyFunc = 0; // GLFWkeyfun
82
this.charFunc = 0; // GLFWcharfun
83
this.userptr = 0;
84
},
85
86
$GLFW__deps: ['emscripten_get_now', '$GL', '$Browser', '$GLFW_Window',
87
'malloc', 'free',
88
'$MainLoop',
89
'$stringToNewUTF8',
90
'$getFullscreenElement',
91
'emscripten_set_window_title',
92
#if FILESYSTEM
93
'$FS',
94
#endif
95
],
96
$GLFW: {
97
WindowFromId: (id) => {
98
if (id <= 0 || !GLFW.windows) return null;
99
return GLFW.windows[id - 1];
100
},
101
102
joystickFunc: 0, // GLFWjoystickfun
103
errorFunc: 0, // GLFWerrorfun
104
monitorFunc: 0, // GLFWmonitorfun
105
active: null, // active window
106
scale: null,
107
windows: null,
108
monitors: null,
109
monitorString: null,
110
versionString: null,
111
initialTime: null,
112
extensions: null,
113
devicePixelRatioMQL: null, // MediaQueryList from window.matchMedia
114
hints: null,
115
primaryTouchId: null,
116
defaultHints: {
117
0x00020001:0, // GLFW_FOCUSED
118
0x00020002:0, // GLFW_ICONIFIED
119
0x00020003:1, // GLFW_RESIZABLE
120
0x00020004:1, // GLFW_VISIBLE
121
0x00020005:1, // GLFW_DECORATED
122
0x0002000A:0, // GLFW_TRANSPARENT_FRAMEBUFFER
123
0x0002200C:0, // GLFW_SCALE_TO_MONITOR
124
125
0x00021001:8, // GLFW_RED_BITS
126
0x00021002:8, // GLFW_GREEN_BITS
127
0x00021003:8, // GLFW_BLUE_BITS
128
0x00021004:8, // GLFW_ALPHA_BITS
129
0x00021005:24, // GLFW_DEPTH_BITS
130
0x00021006:8, // GLFW_STENCIL_BITS
131
0x00021007:0, // GLFW_ACCUM_RED_BITS
132
0x00021008:0, // GLFW_ACCUM_GREEN_BITS
133
0x00021009:0, // GLFW_ACCUM_BLUE_BITS
134
0x0002100A:0, // GLFW_ACCUM_ALPHA_BITS
135
0x0002100B:0, // GLFW_AUX_BUFFERS
136
0x0002100C:0, // GLFW_STEREO
137
0x0002100D:0, // GLFW_SAMPLES
138
0x0002100E:0, // GLFW_SRGB_CAPABLE
139
0x0002100F:0, // GLFW_REFRESH_RATE
140
141
0x00022001:0x00030001, // GLFW_CLIENT_API (GLFW_OPENGL_API)
142
0x00022002:1, // GLFW_CONTEXT_VERSION_MAJOR
143
0x00022003:0, // GLFW_CONTEXT_VERSION_MINOR
144
0x00022004:0, // GLFW_CONTEXT_REVISION
145
0x00022005:0, // GLFW_CONTEXT_ROBUSTNESS
146
0x00022006:0, // GLFW_OPENGL_FORWARD_COMPAT
147
0x00022007:0, // GLFW_OPENGL_DEBUG_CONTEXT
148
0x00022008:0, // GLFW_OPENGL_PROFILE
149
},
150
151
/*******************************************************************************
152
* DOM EVENT CALLBACKS
153
******************************************************************************/
154
155
/* https://developer.mozilla.org/en/Document_Object_Model_%28DOM%29/KeyboardEvent and GLFW/glfw3.h */
156
DOMToGLFWKeyCode: (keycode) => {
157
switch (keycode) {
158
// these keycodes are only defined for GLFW3, assume they are the same for GLFW2
159
case 0x20:return 32; // DOM_VK_SPACE -> GLFW_KEY_SPACE
160
case 0xDE:return 39; // DOM_VK_QUOTE -> GLFW_KEY_APOSTROPHE
161
case 0xBC:return 44; // DOM_VK_COMMA -> GLFW_KEY_COMMA
162
case 0xAD:return 45; // DOM_VK_HYPHEN_MINUS -> GLFW_KEY_MINUS
163
case 0xBD:return 45; // DOM_VK_MINUS -> GLFW_KEY_MINUS
164
case 0xBE:return 46; // DOM_VK_PERIOD -> GLFW_KEY_PERIOD
165
case 0xBF:return 47; // DOM_VK_SLASH -> GLFW_KEY_SLASH
166
case 0x30:return 48; // DOM_VK_0 -> GLFW_KEY_0
167
case 0x31:return 49; // DOM_VK_1 -> GLFW_KEY_1
168
case 0x32:return 50; // DOM_VK_2 -> GLFW_KEY_2
169
case 0x33:return 51; // DOM_VK_3 -> GLFW_KEY_3
170
case 0x34:return 52; // DOM_VK_4 -> GLFW_KEY_4
171
case 0x35:return 53; // DOM_VK_5 -> GLFW_KEY_5
172
case 0x36:return 54; // DOM_VK_6 -> GLFW_KEY_6
173
case 0x37:return 55; // DOM_VK_7 -> GLFW_KEY_7
174
case 0x38:return 56; // DOM_VK_8 -> GLFW_KEY_8
175
case 0x39:return 57; // DOM_VK_9 -> GLFW_KEY_9
176
case 0x3B:return 59; // DOM_VK_SEMICOLON -> GLFW_KEY_SEMICOLON
177
case 0x3D:return 61; // DOM_VK_EQUALS -> GLFW_KEY_EQUAL
178
case 0xBB:return 61; // DOM_VK_EQUALS -> GLFW_KEY_EQUAL
179
case 0x41:return 65; // DOM_VK_A -> GLFW_KEY_A
180
case 0x42:return 66; // DOM_VK_B -> GLFW_KEY_B
181
case 0x43:return 67; // DOM_VK_C -> GLFW_KEY_C
182
case 0x44:return 68; // DOM_VK_D -> GLFW_KEY_D
183
case 0x45:return 69; // DOM_VK_E -> GLFW_KEY_E
184
case 0x46:return 70; // DOM_VK_F -> GLFW_KEY_F
185
case 0x47:return 71; // DOM_VK_G -> GLFW_KEY_G
186
case 0x48:return 72; // DOM_VK_H -> GLFW_KEY_H
187
case 0x49:return 73; // DOM_VK_I -> GLFW_KEY_I
188
case 0x4A:return 74; // DOM_VK_J -> GLFW_KEY_J
189
case 0x4B:return 75; // DOM_VK_K -> GLFW_KEY_K
190
case 0x4C:return 76; // DOM_VK_L -> GLFW_KEY_L
191
case 0x4D:return 77; // DOM_VK_M -> GLFW_KEY_M
192
case 0x4E:return 78; // DOM_VK_N -> GLFW_KEY_N
193
case 0x4F:return 79; // DOM_VK_O -> GLFW_KEY_O
194
case 0x50:return 80; // DOM_VK_P -> GLFW_KEY_P
195
case 0x51:return 81; // DOM_VK_Q -> GLFW_KEY_Q
196
case 0x52:return 82; // DOM_VK_R -> GLFW_KEY_R
197
case 0x53:return 83; // DOM_VK_S -> GLFW_KEY_S
198
case 0x54:return 84; // DOM_VK_T -> GLFW_KEY_T
199
case 0x55:return 85; // DOM_VK_U -> GLFW_KEY_U
200
case 0x56:return 86; // DOM_VK_V -> GLFW_KEY_V
201
case 0x57:return 87; // DOM_VK_W -> GLFW_KEY_W
202
case 0x58:return 88; // DOM_VK_X -> GLFW_KEY_X
203
case 0x59:return 89; // DOM_VK_Y -> GLFW_KEY_Y
204
case 0x5a:return 90; // DOM_VK_Z -> GLFW_KEY_Z
205
case 0xDB:return 91; // DOM_VK_OPEN_BRACKET -> GLFW_KEY_LEFT_BRACKET
206
case 0xDC:return 92; // DOM_VK_BACKSLASH -> GLFW_KEY_BACKSLASH
207
case 0xDD:return 93; // DOM_VK_CLOSE_BRACKET -> GLFW_KEY_RIGHT_BRACKET
208
case 0xC0:return 96; // DOM_VK_BACK_QUOTE -> GLFW_KEY_GRAVE_ACCENT
209
210
#if USE_GLFW == 2
211
//#define GLFW_KEY_SPECIAL 256
212
case 0x1B:return (256+1); // DOM_VK_ESCAPE -> GLFW_KEY_ESC
213
case 0x70:return (256+2); // DOM_VK_F1 -> GLFW_KEY_F1
214
case 0x71:return (256+3); // DOM_VK_F2 -> GLFW_KEY_F2
215
case 0x72:return (256+4); // DOM_VK_F3 -> GLFW_KEY_F3
216
case 0x73:return (256+5); // DOM_VK_F4 -> GLFW_KEY_F4
217
case 0x74:return (256+6); // DOM_VK_F5 -> GLFW_KEY_F5
218
case 0x75:return (256+7); // DOM_VK_F6 -> GLFW_KEY_F6
219
case 0x76:return (256+8); // DOM_VK_F7 -> GLFW_KEY_F7
220
case 0x77:return (256+9); // DOM_VK_F8 -> GLFW_KEY_F8
221
case 0x78:return (256+10); // DOM_VK_F9 -> GLFW_KEY_F9
222
case 0x79:return (256+11); // DOM_VK_F10 -> GLFW_KEY_F10
223
case 0x7A:return (256+12); // DOM_VK_F11 -> GLFW_KEY_F11
224
case 0x7B:return (256+13); // DOM_VK_F12 -> GLFW_KEY_F12
225
case 0x7C:return (256+14); // DOM_VK_F13 -> GLFW_KEY_F13
226
case 0x7D:return (256+15); // DOM_VK_F14 -> GLFW_KEY_F14
227
case 0x7E:return (256+16); // DOM_VK_F15 -> GLFW_KEY_F15
228
case 0x7F:return (256+17); // DOM_VK_F16 -> GLFW_KEY_F16
229
case 0x80:return (256+18); // DOM_VK_F17 -> GLFW_KEY_F17
230
case 0x81:return (256+19); // DOM_VK_F18 -> GLFW_KEY_F18
231
case 0x82:return (256+20); // DOM_VK_F19 -> GLFW_KEY_F19
232
case 0x83:return (256+21); // DOM_VK_F20 -> GLFW_KEY_F20
233
case 0x84:return (256+22); // DOM_VK_F21 -> GLFW_KEY_F21
234
case 0x85:return (256+23); // DOM_VK_F22 -> GLFW_KEY_F22
235
case 0x86:return (256+24); // DOM_VK_F23 -> GLFW_KEY_F23
236
case 0x87:return (256+25); // DOM_VK_F24 -> GLFW_KEY_F24
237
case 0x88:return (256+26); // 0x88 (not used?) -> GLFW_KEY_F25
238
case 0x27:return (256+30); // DOM_VK_RIGHT -> GLFW_KEY_RIGHT
239
case 0x25:return (256+29); // DOM_VK_LEFT -> GLFW_KEY_LEFT
240
case 0x28:return (256+28); // DOM_VK_DOWN -> GLFW_KEY_DOWN
241
case 0x26:return (256+27); // DOM_VK_UP -> GLFW_KEY_UP
242
case 0x10:return (256+31); // DOM_VK_SHIFT -> GLFW_KEY_LSHIFT
243
// #define GLFW_KEY_RSHIFT (GLFW_KEY_SPECIAL+32)
244
case 0x11:return (256+33); // DOM_VK_CONTROL -> GLFW_KEY_LCTRL
245
// #define GLFW_KEY_RCTRL (GLFW_KEY_SPECIAL+34)
246
case 0x12:return (256+35); // DOM_VK_ALT -> GLFW_KEY_LALT
247
// #define GLFW_KEY_RALT (GLFW_KEY_SPECIAL+36)
248
case 0x09:return (256+37); // DOM_VK_TAB -> GLFW_KEY_TAB
249
case 0x0D:return (256+38); // DOM_VK_RETURN -> GLFW_KEY_ENTER
250
case 0x08:return (256+39); // DOM_VK_BACK -> GLFW_KEY_BACKSPACE
251
case 0x2D:return (256+40); // DOM_VK_INSERT -> GLFW_KEY_INSERT
252
case 0x2E:return (256+41); // DOM_VK_DELETE -> GLFW_KEY_DEL
253
case 0x21:return (256+42); // DOM_VK_PAGE_UP -> GLFW_KEY_PAGEUP
254
case 0x22:return (256+43); // DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGEDOWN
255
case 0x24:return (256+44); // DOM_VK_HOME -> GLFW_KEY_HOME
256
case 0x23:return (256+45); // DOM_VK_END -> GLFW_KEY_END
257
case 0x60:return (256+46); // DOM_VK_NUMPAD0 -> GLFW_KEY_KP_0
258
case 0x61:return (256+47); // DOM_VK_NUMPAD1 -> GLFW_KEY_KP_1
259
case 0x62:return (256+48); // DOM_VK_NUMPAD2 -> GLFW_KEY_KP_2
260
case 0x63:return (256+49); // DOM_VK_NUMPAD3 -> GLFW_KEY_KP_3
261
case 0x64:return (256+50); // DOM_VK_NUMPAD4 -> GLFW_KEY_KP_4
262
case 0x65:return (256+51); // DOM_VK_NUMPAD5 -> GLFW_KEY_KP_5
263
case 0x66:return (256+52); // DOM_VK_NUMPAD6 -> GLFW_KEY_KP_6
264
case 0x67:return (256+53); // DOM_VK_NUMPAD7 -> GLFW_KEY_KP_7
265
case 0x68:return (256+54); // DOM_VK_NUMPAD8 -> GLFW_KEY_KP_8
266
case 0x69:return (256+55); // DOM_VK_NUMPAD9 -> GLFW_KEY_KP_9
267
case 0x6F:return (256+56); // DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE
268
case 0x6A:return (256+57); // DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY
269
case 0x6D:return (256+58); // DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT
270
case 0x6B:return (256+59); // DOM_VK_ADD -> GLFW_KEY_KP_ADD
271
case 0x6E:return (256+60); // DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL
272
// #define GLFW_KEY_KP_EQUAL (GLFW_KEY_SPECIAL+61)
273
// #define GLFW_KEY_KP_ENTER (GLFW_KEY_SPECIAL+62)
274
case 0x90:return (256+63); // DOM_VK_NUM_LOCK -> GLFW_KEY_KP_NUM_LOCK
275
case 0x14:return (256+64); // DOM_VK_CAPS_LOCK -> GLFW_KEY_CAPS_LOCK
276
case 0x91:return (256+65); // DOM_VK_SCROLL_LOCK -> GLFW_KEY_SCROLL_LOCK
277
case 0x13:return (256+66); // DOM_VK_PAUSE -> GLFW_KEY_PAUSE
278
case 0x5B:return (256+67); // DOM_VK_WIN -> GLFW_KEY_LSUPER
279
// #define GLFW_KEY_RSUPER (GLFW_KEY_SPECIAL+68)
280
case 0x5D:return (256+69); // DOM_VK_CONTEXT_MENU -> GLFW_KEY_MENU
281
#endif
282
283
#if USE_GLFW == 3
284
case 0x1B:return 256; // DOM_VK_ESCAPE -> GLFW_KEY_ESCAPE
285
case 0x0D:return 257; // DOM_VK_RETURN -> GLFW_KEY_ENTER
286
case 0x09:return 258; // DOM_VK_TAB -> GLFW_KEY_TAB
287
case 0x08:return 259; // DOM_VK_BACK -> GLFW_KEY_BACKSPACE
288
case 0x2D:return 260; // DOM_VK_INSERT -> GLFW_KEY_INSERT
289
case 0x2E:return 261; // DOM_VK_DELETE -> GLFW_KEY_DELETE
290
case 0x27:return 262; // DOM_VK_RIGHT -> GLFW_KEY_RIGHT
291
case 0x25:return 263; // DOM_VK_LEFT -> GLFW_KEY_LEFT
292
case 0x28:return 264; // DOM_VK_DOWN -> GLFW_KEY_DOWN
293
case 0x26:return 265; // DOM_VK_UP -> GLFW_KEY_UP
294
case 0x21:return 266; // DOM_VK_PAGE_UP -> GLFW_KEY_PAGE_UP
295
case 0x22:return 267; // DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGE_DOWN
296
case 0x24:return 268; // DOM_VK_HOME -> GLFW_KEY_HOME
297
case 0x23:return 269; // DOM_VK_END -> GLFW_KEY_END
298
case 0x14:return 280; // DOM_VK_CAPS_LOCK -> GLFW_KEY_CAPS_LOCK
299
case 0x91:return 281; // DOM_VK_SCROLL_LOCK -> GLFW_KEY_SCROLL_LOCK
300
case 0x90:return 282; // DOM_VK_NUM_LOCK -> GLFW_KEY_NUM_LOCK
301
case 0x2C:return 283; // DOM_VK_SNAPSHOT -> GLFW_KEY_PRINT_SCREEN
302
case 0x13:return 284; // DOM_VK_PAUSE -> GLFW_KEY_PAUSE
303
case 0x70:return 290; // DOM_VK_F1 -> GLFW_KEY_F1
304
case 0x71:return 291; // DOM_VK_F2 -> GLFW_KEY_F2
305
case 0x72:return 292; // DOM_VK_F3 -> GLFW_KEY_F3
306
case 0x73:return 293; // DOM_VK_F4 -> GLFW_KEY_F4
307
case 0x74:return 294; // DOM_VK_F5 -> GLFW_KEY_F5
308
case 0x75:return 295; // DOM_VK_F6 -> GLFW_KEY_F6
309
case 0x76:return 296; // DOM_VK_F7 -> GLFW_KEY_F7
310
case 0x77:return 297; // DOM_VK_F8 -> GLFW_KEY_F8
311
case 0x78:return 298; // DOM_VK_F9 -> GLFW_KEY_F9
312
case 0x79:return 299; // DOM_VK_F10 -> GLFW_KEY_F10
313
case 0x7A:return 300; // DOM_VK_F11 -> GLFW_KEY_F11
314
case 0x7B:return 301; // DOM_VK_F12 -> GLFW_KEY_F12
315
case 0x7C:return 302; // DOM_VK_F13 -> GLFW_KEY_F13
316
case 0x7D:return 303; // DOM_VK_F14 -> GLFW_KEY_F14
317
case 0x7E:return 304; // DOM_VK_F15 -> GLFW_KEY_F15
318
case 0x7F:return 305; // DOM_VK_F16 -> GLFW_KEY_F16
319
case 0x80:return 306; // DOM_VK_F17 -> GLFW_KEY_F17
320
case 0x81:return 307; // DOM_VK_F18 -> GLFW_KEY_F18
321
case 0x82:return 308; // DOM_VK_F19 -> GLFW_KEY_F19
322
case 0x83:return 309; // DOM_VK_F20 -> GLFW_KEY_F20
323
case 0x84:return 310; // DOM_VK_F21 -> GLFW_KEY_F21
324
case 0x85:return 311; // DOM_VK_F22 -> GLFW_KEY_F22
325
case 0x86:return 312; // DOM_VK_F23 -> GLFW_KEY_F23
326
case 0x87:return 313; // DOM_VK_F24 -> GLFW_KEY_F24
327
case 0x88:return 314; // 0x88 (not used?) -> GLFW_KEY_F25
328
case 0x60:return 320; // DOM_VK_NUMPAD0 -> GLFW_KEY_KP_0
329
case 0x61:return 321; // DOM_VK_NUMPAD1 -> GLFW_KEY_KP_1
330
case 0x62:return 322; // DOM_VK_NUMPAD2 -> GLFW_KEY_KP_2
331
case 0x63:return 323; // DOM_VK_NUMPAD3 -> GLFW_KEY_KP_3
332
case 0x64:return 324; // DOM_VK_NUMPAD4 -> GLFW_KEY_KP_4
333
case 0x65:return 325; // DOM_VK_NUMPAD5 -> GLFW_KEY_KP_5
334
case 0x66:return 326; // DOM_VK_NUMPAD6 -> GLFW_KEY_KP_6
335
case 0x67:return 327; // DOM_VK_NUMPAD7 -> GLFW_KEY_KP_7
336
case 0x68:return 328; // DOM_VK_NUMPAD8 -> GLFW_KEY_KP_8
337
case 0x69:return 329; // DOM_VK_NUMPAD9 -> GLFW_KEY_KP_9
338
case 0x6E:return 330; // DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL
339
case 0x6F:return 331; // DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE
340
case 0x6A:return 332; // DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY
341
case 0x6D:return 333; // DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT
342
case 0x6B:return 334; // DOM_VK_ADD -> GLFW_KEY_KP_ADD
343
// case 0x0D:return 335; // DOM_VK_RETURN -> GLFW_KEY_KP_ENTER (DOM_KEY_LOCATION_RIGHT)
344
// case 0x61:return 336; // DOM_VK_EQUALS -> GLFW_KEY_KP_EQUAL (DOM_KEY_LOCATION_RIGHT)
345
case 0x10:return 340; // DOM_VK_SHIFT -> GLFW_KEY_LEFT_SHIFT
346
case 0x11:return 341; // DOM_VK_CONTROL -> GLFW_KEY_LEFT_CONTROL
347
case 0x12:return 342; // DOM_VK_ALT -> GLFW_KEY_LEFT_ALT
348
case 0x5B:return 343; // DOM_VK_WIN -> GLFW_KEY_LEFT_SUPER
349
case 0xE0:return 343; // DOM_VK_META -> GLFW_KEY_LEFT_SUPER
350
// case 0x10:return 344; // DOM_VK_SHIFT -> GLFW_KEY_RIGHT_SHIFT (DOM_KEY_LOCATION_RIGHT)
351
// case 0x11:return 345; // DOM_VK_CONTROL -> GLFW_KEY_RIGHT_CONTROL (DOM_KEY_LOCATION_RIGHT)
352
// case 0x12:return 346; // DOM_VK_ALT -> GLFW_KEY_RIGHT_ALT (DOM_KEY_LOCATION_RIGHT)
353
// case 0x5B:return 347; // DOM_VK_WIN -> GLFW_KEY_RIGHT_SUPER (DOM_KEY_LOCATION_RIGHT)
354
case 0x5D:return 348; // DOM_VK_CONTEXT_MENU -> GLFW_KEY_MENU
355
// XXX: GLFW_KEY_WORLD_1, GLFW_KEY_WORLD_2 what are these?
356
#endif
357
default:return -1; // GLFW_KEY_UNKNOWN
358
};
359
},
360
361
getModBits: (win) => {
362
var mod = 0;
363
if (win.keys[340]) mod |= 0x0001; // GLFW_MOD_SHIFT
364
if (win.keys[341]) mod |= 0x0002; // GLFW_MOD_CONTROL
365
if (win.keys[342]) mod |= 0x0004; // GLFW_MOD_ALT
366
if (win.keys[343] || win.keys[348]) mod |= 0x0008; // GLFW_MOD_SUPER
367
// add caps and num lock keys? only if lock_key_mod is set
368
return mod;
369
},
370
371
onKeyPress: (event) => {
372
if (!GLFW.active || !GLFW.active.charFunc) return;
373
if (event.ctrlKey || event.metaKey) return;
374
375
// correct unicode charCode is only available with onKeyPress event
376
var charCode = event.charCode;
377
if (charCode == 0 || (charCode >= 0x00 && charCode <= 0x1F)) return;
378
379
#if USE_GLFW == 2
380
{{{ makeDynCall('vii', 'GLFW.active.charFunc') }}}(charCode, 1);
381
#endif
382
#if USE_GLFW == 3
383
{{{ makeDynCall('vpi', 'GLFW.active.charFunc') }}}(GLFW.active.id, charCode);
384
#endif
385
},
386
387
onKeyChanged: (keyCode, status) => {
388
if (!GLFW.active) return;
389
390
var key = GLFW.DOMToGLFWKeyCode(keyCode);
391
if (key == -1) return;
392
393
#if USE_GLFW == 3
394
var repeat = status && GLFW.active.keys[key];
395
#endif
396
GLFW.active.keys[key] = status;
397
GLFW.active.domKeys[keyCode] = status;
398
399
if (GLFW.active.keyFunc) {
400
#if USE_GLFW == 2
401
{{{ makeDynCall('vii', 'GLFW.active.keyFunc') }}}(key, status);
402
#endif
403
#if USE_GLFW == 3
404
if (repeat) status = 2; // GLFW_REPEAT
405
{{{ makeDynCall('vpiiii', 'GLFW.active.keyFunc') }}}(GLFW.active.id, key, keyCode, status, GLFW.getModBits(GLFW.active));
406
#endif
407
}
408
},
409
410
onGamepadConnected: (event) => {
411
GLFW.refreshJoysticks();
412
},
413
414
onGamepadDisconnected: (event) => {
415
GLFW.refreshJoysticks();
416
},
417
418
onKeydown: (event) => {
419
GLFW.onKeyChanged(event.keyCode, 1); // GLFW_PRESS or GLFW_REPEAT
420
421
// This logic comes directly from the sdl implementation. We cannot
422
// call preventDefault on all keydown events otherwise onKeyPress will
423
// not get called
424
if (event.key == 'Backspace' || event.key == 'Tab') {
425
event.preventDefault();
426
}
427
},
428
429
onKeyup: (event) => {
430
GLFW.onKeyChanged(event.keyCode, 0); // GLFW_RELEASE
431
},
432
433
onBlur: (event) => {
434
if (!GLFW.active) return;
435
436
for (var i = 0; i < GLFW.active.domKeys.length; ++i) {
437
if (GLFW.active.domKeys[i]) {
438
GLFW.onKeyChanged(i, 0); // GLFW_RELEASE
439
}
440
}
441
},
442
443
onMousemove: (event) => {
444
if (!GLFW.active) return;
445
446
if (event.type === 'touchmove') {
447
// Handling for touch events that are being converted to mouse input.
448
449
// Don't let the browser fire a duplicate mouse event.
450
event.preventDefault();
451
452
let primaryChanged = false;
453
for (let i of event.changedTouches) {
454
// If our chosen primary touch moved, update Browser mouse coords
455
if (GLFW.primaryTouchId === i.identifier) {
456
Browser.setMouseCoords(i.pageX, i.pageY);
457
primaryChanged = true;
458
break;
459
}
460
}
461
462
if (!primaryChanged) {
463
// Do not send mouse events if some touch other than the primary triggered this.
464
return;
465
}
466
467
} else {
468
// Handling for non-touch mouse input events.
469
Browser.calculateMouseEvent(event);
470
}
471
472
if (event.target != Browser.getCanvas() || !GLFW.active.cursorPosFunc) return;
473
474
if (GLFW.active.cursorPosFunc) {
475
#if USE_GLFW == 2
476
{{{ makeDynCall('vii', 'GLFW.active.cursorPosFunc') }}}(Browser.mouseX, Browser.mouseY);
477
#endif
478
#if USE_GLFW == 3
479
{{{ makeDynCall('vpdd', 'GLFW.active.cursorPosFunc') }}}(GLFW.active.id, Browser.mouseX, Browser.mouseY);
480
#endif
481
}
482
},
483
484
DOMToGLFWMouseButton: (event) => {
485
// DOM and glfw have different button codes.
486
// See http://www.w3schools.com/jsref/event_button.asp.
487
var eventButton = event['button'];
488
if (eventButton > 0) {
489
if (eventButton == 1) {
490
eventButton = 2;
491
} else {
492
eventButton = 1;
493
}
494
}
495
return eventButton;
496
},
497
498
onMouseenter: (event) => {
499
if (!GLFW.active) return;
500
501
if (event.target != Browser.getCanvas()) return;
502
503
#if USE_GLFW == 3
504
if (GLFW.active.cursorEnterFunc) {
505
{{{ makeDynCall('vpi', 'GLFW.active.cursorEnterFunc') }}}(GLFW.active.id, 1);
506
}
507
#endif
508
},
509
510
onMouseleave: (event) => {
511
if (!GLFW.active) return;
512
513
if (event.target != Browser.getCanvas()) return;
514
515
#if USE_GLFW == 3
516
if (GLFW.active.cursorEnterFunc) {
517
{{{ makeDynCall('vpi', 'GLFW.active.cursorEnterFunc') }}}(GLFW.active.id, 0);
518
}
519
#endif
520
},
521
522
onMouseButtonChanged: (event, status) => {
523
if (!GLFW.active) return;
524
525
if (event.target != Browser.getCanvas()) return;
526
527
// Is this from a touch event?
528
const isTouchType = event.type === 'touchstart' || event.type === 'touchend' || event.type === 'touchcancel';
529
530
// Only emulating mouse left-click behavior for touches.
531
let eventButton = 0;
532
if (isTouchType) {
533
// Handling for touch events that are being converted to mouse input.
534
535
// Don't let the browser fire a duplicate mouse event.
536
event.preventDefault();
537
538
let primaryChanged = false;
539
540
// Set a primary touch if we have none.
541
if (GLFW.primaryTouchId === null && event.type === 'touchstart' && event.targetTouches.length > 0) {
542
// Pick the first touch that started in the canvas and treat it as primary.
543
const chosenTouch = event.targetTouches[0];
544
GLFW.primaryTouchId = chosenTouch.identifier;
545
546
Browser.setMouseCoords(chosenTouch.pageX, chosenTouch.pageY);
547
primaryChanged = true;
548
} else if (event.type === 'touchend' || event.type === 'touchcancel') {
549
// Clear the primary touch if it ended.
550
for (let i of event.changedTouches) {
551
// If our chosen primary touch ended, remove it.
552
if (GLFW.primaryTouchId === i.identifier) {
553
GLFW.primaryTouchId = null;
554
primaryChanged = true;
555
break;
556
}
557
}
558
}
559
560
if (!primaryChanged) {
561
// Do not send mouse events if some touch other than the primary triggered this.
562
return;
563
}
564
565
} else {
566
// Handling for non-touch mouse input events.
567
Browser.calculateMouseEvent(event);
568
eventButton = GLFW.DOMToGLFWMouseButton(event);
569
}
570
571
if (status == 1) { // GLFW_PRESS
572
GLFW.active.buttons |= (1 << eventButton);
573
try {
574
event.target.setCapture();
575
} catch (e) {}
576
} else { // GLFW_RELEASE
577
GLFW.active.buttons &= ~(1 << eventButton);
578
}
579
580
// Send mouse event to GLFW.
581
if (GLFW.active.mouseButtonFunc) {
582
#if USE_GLFW == 2
583
{{{ makeDynCall('vii', 'GLFW.active.mouseButtonFunc') }}}(eventButton, status);
584
#endif
585
#if USE_GLFW == 3
586
{{{ makeDynCall('vpiii', 'GLFW.active.mouseButtonFunc') }}}(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active));
587
#endif
588
}
589
},
590
591
onMouseButtonDown: (event) => {
592
if (!GLFW.active) return;
593
GLFW.onMouseButtonChanged(event, 1); // GLFW_PRESS
594
},
595
596
onMouseButtonUp: (event) => {
597
if (!GLFW.active) return;
598
GLFW.onMouseButtonChanged(event, 0); // GLFW_RELEASE
599
},
600
601
onMouseWheel: (event) => {
602
// Note the minus sign that flips browser wheel direction (positive direction scrolls page down) to native wheel direction (positive direction is mouse wheel up)
603
var delta = -Browser.getMouseWheelDelta(event);
604
delta = (delta == 0) ? 0 : (delta > 0 ? Math.max(delta, 1) : Math.min(delta, -1)); // Quantize to integer so that minimum scroll is at least +/- 1.
605
GLFW.wheelPos += delta;
606
607
if (!GLFW.active || !GLFW.active.scrollFunc || event.target != Browser.getCanvas()) return;
608
#if USE_GLFW == 2
609
{{{ makeDynCall('vi', 'GLFW.active.scrollFunc') }}}(GLFW.wheelPos);
610
#endif
611
#if USE_GLFW == 3
612
var sx = 0;
613
var sy = delta;
614
if (event.type == 'mousewheel') {
615
sx = event.wheelDeltaX;
616
} else {
617
sx = event.deltaX;
618
}
619
620
{{{ makeDynCall('vpdd', 'GLFW.active.scrollFunc') }}}(GLFW.active.id, sx, sy);
621
#endif
622
623
event.preventDefault();
624
},
625
626
// width/height are the dimensions in screen coordinates the user interact with (ex: drawing, mouse coordinates...)
627
// framebufferWidth/framebufferHeight are the dimensions in pixel coordinates used for rendering
628
// in a HiDPI scenario framebufferWidth = devicePixelRatio * width
629
onCanvasResize: (width, height, framebufferWidth, framebufferHeight) => {
630
if (!GLFW.active) return;
631
632
var resizeNeeded = false;
633
634
// If the client is requesting fullscreen mode
635
if (getFullscreenElement()) {
636
if (!GLFW.active.fullscreen) {
637
resizeNeeded = width != screen.width || height != screen.height;
638
GLFW.active.storedX = GLFW.active.x;
639
GLFW.active.storedY = GLFW.active.y;
640
GLFW.active.storedWidth = GLFW.active.width;
641
GLFW.active.storedHeight = GLFW.active.height;
642
GLFW.active.x = GLFW.active.y = 0;
643
GLFW.active.width = screen.width;
644
GLFW.active.height = screen.height;
645
GLFW.active.fullscreen = true;
646
}
647
// If the client is reverting from fullscreen mode
648
} else if (GLFW.active.fullscreen == true) {
649
resizeNeeded = width != GLFW.active.storedWidth || height != GLFW.active.storedHeight;
650
GLFW.active.x = GLFW.active.storedX;
651
GLFW.active.y = GLFW.active.storedY;
652
GLFW.active.width = GLFW.active.storedWidth;
653
GLFW.active.height = GLFW.active.storedHeight;
654
GLFW.active.fullscreen = false;
655
}
656
657
if (resizeNeeded) {
658
// width or height is changed (fullscreen / exit fullscreen) which will call this listener back
659
// with proper framebufferWidth/framebufferHeight
660
Browser.setCanvasSize(GLFW.active.width, GLFW.active.height);
661
} else if (GLFW.active.width != width ||
662
GLFW.active.height != height ||
663
GLFW.active.framebufferWidth != framebufferWidth ||
664
GLFW.active.framebufferHeight != framebufferHeight) {
665
GLFW.active.width = width;
666
GLFW.active.height = height;
667
GLFW.active.framebufferWidth = framebufferWidth;
668
GLFW.active.framebufferHeight = framebufferHeight;
669
GLFW.onWindowSizeChanged();
670
GLFW.onFramebufferSizeChanged();
671
}
672
},
673
674
onWindowSizeChanged: () => {
675
if (!GLFW.active) return;
676
677
if (GLFW.active.windowSizeFunc) {
678
#if USE_GLFW == 2
679
{{{ makeDynCall('vii', 'GLFW.active.windowSizeFunc') }}}(GLFW.active.width, GLFW.active.height);
680
#endif
681
#if USE_GLFW == 3
682
{{{ makeDynCall('vpii', 'GLFW.active.windowSizeFunc') }}}(GLFW.active.id, GLFW.active.width, GLFW.active.height);
683
#endif
684
}
685
},
686
687
onFramebufferSizeChanged: () => {
688
if (!GLFW.active) return;
689
690
#if USE_GLFW == 3
691
if (GLFW.active.framebufferSizeFunc) {
692
{{{ makeDynCall('vpii', 'GLFW.active.framebufferSizeFunc') }}}(GLFW.active.id, GLFW.active.framebufferWidth, GLFW.active.framebufferHeight);
693
}
694
#endif
695
},
696
697
onWindowContentScaleChanged: (scale) => {
698
GLFW.scale = scale;
699
if (!GLFW.active) return;
700
701
#if USE_GLFW == 3
702
if (GLFW.active.windowContentScaleFunc) {
703
{{{ makeDynCall('vpff', 'GLFW.active.windowContentScaleFunc') }}}(GLFW.active.id, GLFW.scale, GLFW.scale);
704
}
705
#endif
706
},
707
708
getTime: () => _emscripten_get_now() / 1000,
709
710
/* GLFW2 wrapping */
711
712
setWindowTitle: (winid, title) => {
713
var win = GLFW.WindowFromId(winid);
714
if (!win) return;
715
716
win.title = title;
717
if (GLFW.active.id == win.id) {
718
_emscripten_set_window_title(title);
719
}
720
},
721
722
setJoystickCallback: (cbfun) => {
723
var prevcbfun = GLFW.joystickFunc;
724
GLFW.joystickFunc = cbfun;
725
GLFW.refreshJoysticks();
726
return prevcbfun;
727
},
728
729
joys: {}, // glfw joystick data
730
lastGamepadState: [],
731
lastGamepadStateFrame: null, // The integer value of MainLoop.currentFrameNumber of when the last gamepad state was produced.
732
733
refreshJoysticks: () => {
734
// Produce a new Gamepad API sample if we are ticking a new game frame, or if not using emscripten_set_main_loop() at all to drive animation.
735
if (MainLoop.currentFrameNumber !== GLFW.lastGamepadStateFrame || !MainLoop.currentFrameNumber) {
736
GLFW.lastGamepadState = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads || []);
737
GLFW.lastGamepadStateFrame = MainLoop.currentFrameNumber;
738
739
for (var joy = 0; joy < GLFW.lastGamepadState.length; ++joy) {
740
var gamepad = GLFW.lastGamepadState[joy];
741
742
if (gamepad) {
743
if (!GLFW.joys[joy]) {
744
out('glfw joystick connected:',joy);
745
GLFW.joys[joy] = {
746
id: stringToNewUTF8(gamepad.id),
747
buttonsCount: gamepad.buttons.length,
748
axesCount: gamepad.axes.length,
749
buttons: _malloc(gamepad.buttons.length),
750
axes: _malloc(gamepad.axes.length*4),
751
};
752
753
if (GLFW.joystickFunc) {
754
{{{ makeDynCall('vii', 'GLFW.joystickFunc') }}}(joy, 0x00040001); // GLFW_CONNECTED
755
}
756
}
757
758
var data = GLFW.joys[joy];
759
760
for (var i = 0; i < gamepad.buttons.length; ++i) {
761
{{{ makeSetValue('data.buttons + i', '0', 'gamepad.buttons[i].pressed', 'i8') }}};
762
}
763
764
for (var i = 0; i < gamepad.axes.length; ++i) {
765
{{{ makeSetValue('data.axes + i*4', '0', 'gamepad.axes[i]', 'float') }}};
766
}
767
} else {
768
if (GLFW.joys[joy]) {
769
out('glfw joystick disconnected',joy);
770
771
if (GLFW.joystickFunc) {
772
{{{ makeDynCall('vii', 'GLFW.joystickFunc') }}}(joy, 0x00040002); // GLFW_DISCONNECTED
773
}
774
775
_free(GLFW.joys[joy].id);
776
_free(GLFW.joys[joy].buttons);
777
_free(GLFW.joys[joy].axes);
778
779
delete GLFW.joys[joy];
780
}
781
}
782
}
783
}
784
},
785
786
setKeyCallback: (winid, cbfun) => {
787
var win = GLFW.WindowFromId(winid);
788
if (!win) return null;
789
var prevcbfun = win.keyFunc;
790
win.keyFunc = cbfun;
791
return prevcbfun;
792
},
793
794
setCharCallback: (winid, cbfun) => {
795
var win = GLFW.WindowFromId(winid);
796
if (!win) return null;
797
var prevcbfun = win.charFunc;
798
win.charFunc = cbfun;
799
return prevcbfun;
800
},
801
802
setMouseButtonCallback: (winid, cbfun) => {
803
var win = GLFW.WindowFromId(winid);
804
if (!win) return null;
805
var prevcbfun = win.mouseButtonFunc;
806
win.mouseButtonFunc = cbfun;
807
return prevcbfun;
808
},
809
810
setCursorPosCallback: (winid, cbfun) => {
811
var win = GLFW.WindowFromId(winid);
812
if (!win) return null;
813
var prevcbfun = win.cursorPosFunc;
814
win.cursorPosFunc = cbfun;
815
return prevcbfun;
816
},
817
818
setScrollCallback: (winid, cbfun) => {
819
var win = GLFW.WindowFromId(winid);
820
if (!win) return null;
821
var prevcbfun = win.scrollFunc;
822
win.scrollFunc = cbfun;
823
return prevcbfun;
824
},
825
826
setDropCallback: (winid, cbfun) => {
827
var win = GLFW.WindowFromId(winid);
828
if (!win) return null;
829
var prevcbfun = win.dropFunc;
830
win.dropFunc = cbfun;
831
return prevcbfun;
832
},
833
834
onDrop: (event) => {
835
if (!GLFW.active || !GLFW.active.dropFunc) return;
836
if (!event.dataTransfer || !event.dataTransfer.files || event.dataTransfer.files.length == 0) return;
837
838
event.preventDefault();
839
840
#if FILESYSTEM
841
var drop_dir = '.glfw_dropped_files';
842
var filenames = _malloc(event.dataTransfer.files.length * {{{ POINTER_SIZE }}});
843
var filenamesArray = [];
844
for (var i = 0; i < event.dataTransfer.files.length; ++i) {
845
var path = `/${drop_dir}/${event.dataTransfer.files[i].name.replace(/\//g, "_")}`;
846
var filename = stringToNewUTF8(path);
847
filenamesArray.push(filename);
848
{{{ makeSetValue('filenames', `i*${POINTER_SIZE}` , 'filename', '*') }}};
849
}
850
851
// Read and save the files to emscripten's FS
852
var written = 0;
853
FS.createPath('/', drop_dir);
854
855
function save(file, in_path, numfiles) {
856
var path = '/' + drop_dir + in_path + '/' + file.name.replace(/\//g, '_');
857
var reader = new FileReader();
858
reader.onloadend = (e) => {
859
if (reader.readyState != 2) { // not DONE
860
++written;
861
err(`failed to read dropped file: ${in_path}/${file.name}: ${reader.error}`);
862
return;
863
}
864
865
var data = e.target.result;
866
FS.writeFile(path, new Uint8Array(data));
867
if (++written === numfiles) {
868
{{{ makeDynCall('vpip', 'GLFW.active.dropFunc') }}}(GLFW.active.id, filenamesArray.length, filenames);
869
870
for (var i = 0; i < filenamesArray.length; ++i) {
871
_free(filenamesArray[i]);
872
}
873
_free(filenames);
874
}
875
};
876
reader.readAsArrayBuffer(file);
877
}
878
879
let filesQ = [];
880
function finalize() {
881
var count = filesQ.length;
882
for (var i = 0; i < count; ++i) {
883
save(filesQ[i].file, filesQ[i].path, count);
884
}
885
}
886
887
if (DataTransferItem.prototype.webkitGetAsEntry) {
888
let entriesTree = {};
889
function markDone(fullpath, recursive) {
890
if (entriesTree[fullpath].subpaths.length != 0) return;
891
delete entriesTree[fullpath];
892
let parentpath = fullpath.substring(0, fullpath.lastIndexOf('/'));
893
if (!entriesTree.hasOwnProperty(parentpath)) {
894
if (Object.keys(entriesTree).length == 0) finalize();
895
return;
896
}
897
const fpIndex = entriesTree[parentpath].subpaths.indexOf(fullpath);
898
if (fpIndex > -1) entriesTree[parentpath].subpaths.splice(fpIndex, 1);
899
if (recursive) markDone(parentpath, true);
900
if (Object.keys(entriesTree).length == 0) finalize();
901
}
902
function processEntry(entry) {
903
let fp = entry.fullPath;
904
let pp = fp.substring(0, fp.lastIndexOf('/'));
905
entriesTree[fp] = { subpaths: [] };
906
if (entry.isFile) {
907
entry.file((f) => { filesQ.push({ file: f, path: pp }); markDone(fp, false); })
908
} else if (entry.isDirectory) {
909
if (entriesTree.hasOwnProperty(pp)) entriesTree[pp].subpaths.push(fp);
910
FS.createPath("/" + drop_dir + pp, entry.name);
911
var reader = entry.createReader();
912
var rRead = function (dirEntries) {
913
if (dirEntries.length == 0) {
914
markDone(fp, true);
915
return;
916
}
917
for (const ent of dirEntries) processEntry(ent);
918
reader.readEntries(rRead);
919
};
920
reader.readEntries(rRead);
921
}
922
}
923
for (const item of event.dataTransfer.items) {
924
processEntry(item.webkitGetAsEntry());
925
}
926
} else {
927
// fallback for browsers that does not support webkitGetAsEntry
928
for (const file of event.dataTransfer.files) {
929
filesQ.push({ file: file, path: "" });
930
}
931
finalize();
932
}
933
#endif // FILESYSTEM
934
935
return false;
936
},
937
938
onDragover: (event) => {
939
if (!GLFW.active || !GLFW.active.dropFunc) return;
940
941
event.preventDefault();
942
return false;
943
},
944
945
setWindowSizeCallback: (winid, cbfun) => {
946
var win = GLFW.WindowFromId(winid);
947
if (!win) return null;
948
var prevcbfun = win.windowSizeFunc;
949
win.windowSizeFunc = cbfun;
950
951
#if USE_GLFW == 2
952
// As documented in GLFW2 API (http://www.glfw.org/GLFWReference27.pdf#page=22), when size
953
// callback function is set, it will be called with the current window size before this
954
// function returns.
955
// GLFW3 on the other hand doesn't have this behavior (https://github.com/glfw/glfw/issues/62).
956
if (!win.windowSizeFunc) return null;
957
{{{ makeDynCall('vii', 'win.windowSizeFunc') }}}(win.width, win.height);
958
#endif
959
960
return prevcbfun;
961
},
962
963
setWindowCloseCallback: (winid, cbfun) => {
964
var win = GLFW.WindowFromId(winid);
965
if (!win) return null;
966
var prevcbfun = win.windowCloseFunc;
967
win.windowCloseFunc = cbfun;
968
return prevcbfun;
969
},
970
971
setWindowRefreshCallback: (winid, cbfun) => {
972
var win = GLFW.WindowFromId(winid);
973
if (!win) return null;
974
var prevcbfun = win.windowRefreshFunc;
975
win.windowRefreshFunc = cbfun;
976
return prevcbfun;
977
},
978
979
onClickRequestPointerLock: (e) => {
980
var canvas = Browser.getCanvas();
981
if (!Browser.pointerLock && canvas.requestPointerLock) {
982
canvas.requestPointerLock();
983
e.preventDefault();
984
}
985
},
986
987
setInputMode: (winid, mode, value) => {
988
var win = GLFW.WindowFromId(winid);
989
if (!win) return;
990
991
switch (mode) {
992
case 0x00033001: { // GLFW_CURSOR
993
var canvas = Browser.getCanvas();
994
switch (value) {
995
case 0x00034001: { // GLFW_CURSOR_NORMAL
996
win.inputModes[mode] = value;
997
canvas.removeEventListener('click', GLFW.onClickRequestPointerLock, true);
998
document.exitPointerLock();
999
break;
1000
}
1001
case 0x00034002: { // GLFW_CURSOR_HIDDEN
1002
err('glfwSetInputMode called with GLFW_CURSOR_HIDDEN value not implemented');
1003
break;
1004
}
1005
case 0x00034003: { // GLFW_CURSOR_DISABLED
1006
win.inputModes[mode] = value;
1007
canvas.addEventListener('click', GLFW.onClickRequestPointerLock, true);
1008
canvas.requestPointerLock();
1009
break;
1010
}
1011
default: {
1012
err(`glfwSetInputMode called with unknown value parameter value: ${value}`);
1013
break;
1014
}
1015
}
1016
break;
1017
}
1018
case 0x00033002: { // GLFW_STICKY_KEYS
1019
err('glfwSetInputMode called with GLFW_STICKY_KEYS mode not implemented');
1020
break;
1021
}
1022
case 0x00033003: { // GLFW_STICKY_MOUSE_BUTTONS
1023
err('glfwSetInputMode called with GLFW_STICKY_MOUSE_BUTTONS mode not implemented');
1024
break;
1025
}
1026
case 0x00033004: { // GLFW_LOCK_KEY_MODS
1027
err('glfwSetInputMode called with GLFW_LOCK_KEY_MODS mode not implemented');
1028
break;
1029
}
1030
case 0x00033005: { // GLFW_RAW_MOUSE_MOTION
1031
err('glfwSetInputMode called with GLFW_RAW_MOUSE_MOTION mode not implemented');
1032
break;
1033
}
1034
default: {
1035
err(`glfwSetInputMode called with unknown mode parameter value: ${mode}`);
1036
break;
1037
}
1038
}
1039
},
1040
1041
getKey: (winid, key) => {
1042
var win = GLFW.WindowFromId(winid);
1043
if (!win) return 0;
1044
return win.keys[key];
1045
},
1046
1047
getMouseButton: (winid, button) => {
1048
var win = GLFW.WindowFromId(winid);
1049
if (!win) return 0;
1050
return (win.buttons & (1 << button)) > 0;
1051
},
1052
1053
getCursorPos: (winid, x, y) => {
1054
{{{ makeSetValue('x', '0', 'Browser.mouseX', 'double') }}};
1055
{{{ makeSetValue('y', '0', 'Browser.mouseY', 'double') }}};
1056
},
1057
1058
getMousePos: (winid, x, y) => {
1059
{{{ makeSetValue('x', '0', 'Browser.mouseX', 'i32') }}};
1060
{{{ makeSetValue('y', '0', 'Browser.mouseY', 'i32') }}};
1061
},
1062
1063
setCursorPos: (winid, x, y) => {
1064
},
1065
1066
getWindowPos: (winid, x, y) => {
1067
var wx = 0;
1068
var wy = 0;
1069
1070
var win = GLFW.WindowFromId(winid);
1071
if (win) {
1072
wx = win.x;
1073
wy = win.y;
1074
}
1075
1076
if (x) {
1077
{{{ makeSetValue('x', '0', 'wx', 'i32') }}};
1078
}
1079
1080
if (y) {
1081
{{{ makeSetValue('y', '0', 'wy', 'i32') }}};
1082
}
1083
},
1084
1085
setWindowPos: (winid, x, y) => {
1086
var win = GLFW.WindowFromId(winid);
1087
if (!win) return;
1088
win.x = x;
1089
win.y = y;
1090
},
1091
1092
getWindowSize: (winid, width, height) => {
1093
var ww = 0;
1094
var wh = 0;
1095
1096
var win = GLFW.WindowFromId(winid);
1097
if (win) {
1098
ww = win.width;
1099
wh = win.height;
1100
}
1101
1102
if (width) {
1103
{{{ makeSetValue('width', '0', 'ww', 'i32') }}};
1104
}
1105
1106
if (height) {
1107
{{{ makeSetValue('height', '0', 'wh', 'i32') }}};
1108
}
1109
},
1110
1111
setWindowSize: (winid, width, height) => {
1112
var win = GLFW.WindowFromId(winid);
1113
if (!win) return;
1114
1115
if (GLFW.active.id == win.id) {
1116
Browser.setCanvasSize(width, height); // triggers the listener (onCanvasResize) + windowSizeFunc
1117
}
1118
},
1119
1120
defaultWindowHints: () => {
1121
GLFW.hints = {...GLFW.defaultHints};
1122
},
1123
1124
createWindow: (width, height, title, monitor, share) => {
1125
var i, id;
1126
for (i = 0; i < GLFW.windows.length && GLFW.windows[i] !== null; i++) {
1127
// no-op
1128
}
1129
if (i > 0) abort("glfwCreateWindow only supports one window at time currently");
1130
1131
// id for window
1132
id = i + 1;
1133
1134
// not valid
1135
if (width <= 0 || height <= 0) return 0;
1136
1137
if (monitor) {
1138
Browser.requestFullscreen();
1139
} else {
1140
Browser.setCanvasSize(width, height);
1141
}
1142
1143
// Create context when there are no existing alive windows
1144
for (i = 0; i < GLFW.windows.length && GLFW.windows[i] == null; i++) {
1145
// no-op
1146
}
1147
1148
const canvas = Browser.getCanvas();
1149
1150
var useWebGL = GLFW.hints[0x00022001] > 0; // Use WebGL when we are told to based on GLFW_CLIENT_API
1151
if (i == GLFW.windows.length) {
1152
if (useWebGL) {
1153
var contextAttributes = {
1154
antialias: (GLFW.hints[0x0002100D] > 1), // GLFW_SAMPLES
1155
depth: (GLFW.hints[0x00021005] > 0), // GLFW_DEPTH_BITS
1156
stencil: (GLFW.hints[0x00021006] > 0), // GLFW_STENCIL_BITS
1157
alpha: (GLFW.hints[0x00021004] > 0) // GLFW_ALPHA_BITS
1158
}
1159
#if OFFSCREEN_FRAMEBUFFER
1160
// TODO: Make GLFW explicitly aware of whether it is being proxied or not, and set these to true only when proxying is being performed.
1161
GL.enableOffscreenFramebufferAttributes(contextAttributes);
1162
#endif
1163
Browser.createContext(canvas, /*useWebGL=*/true, /*setInModule=*/true, contextAttributes);
1164
} else {
1165
Browser.init();
1166
}
1167
}
1168
1169
// If context creation failed, do not return a valid window
1170
if (!Module['ctx'] && useWebGL) return 0;
1171
1172
// Initializes the framebuffer size from the canvas
1173
var win = new GLFW_Window(id, width, height, canvas.width, canvas.height, title, monitor, share);
1174
1175
// Set window to array
1176
if (id - 1 == GLFW.windows.length) {
1177
GLFW.windows.push(win);
1178
} else {
1179
GLFW.windows[id - 1] = win;
1180
}
1181
1182
GLFW.active = win;
1183
GLFW.adjustCanvasDimensions();
1184
return win.id;
1185
},
1186
1187
destroyWindow: (winid) => {
1188
var win = GLFW.WindowFromId(winid);
1189
if (!win) return;
1190
1191
#if USE_GLFW == 3
1192
if (win.windowCloseFunc) {
1193
{{{ makeDynCall('vp', 'win.windowCloseFunc') }}}(win.id);
1194
}
1195
#endif
1196
1197
GLFW.windows[win.id - 1] = null;
1198
if (GLFW.active.id == win.id) {
1199
GLFW.active = null;
1200
}
1201
1202
// Destroy context when no alive windows
1203
for (win of GLFW.windows) {
1204
if (win !== null) return;
1205
}
1206
1207
delete Module['ctx'];
1208
},
1209
1210
swapBuffers: (winid) => {
1211
},
1212
1213
// Overrides Browser.requestFullscreen to notify listeners even if Browser.resizeCanvas is false
1214
requestFullscreen(lockPointer, resizeCanvas) {
1215
Browser.lockPointer = lockPointer;
1216
Browser.resizeCanvas = resizeCanvas;
1217
if (typeof Browser.lockPointer == 'undefined') Browser.lockPointer = true;
1218
if (typeof Browser.resizeCanvas == 'undefined') Browser.resizeCanvas = false;
1219
1220
var canvas = Browser.getCanvas();
1221
function fullscreenChange() {
1222
Browser.isFullscreen = false;
1223
var canvasContainer = canvas.parentNode;
1224
if (getFullscreenElement() === canvasContainer) {
1225
canvas.exitFullscreen = Browser.exitFullscreen;
1226
if (Browser.lockPointer) canvas.requestPointerLock();
1227
Browser.isFullscreen = true;
1228
if (Browser.resizeCanvas) {
1229
Browser.setFullscreenCanvasSize();
1230
} else {
1231
Browser.updateCanvasDimensions(canvas);
1232
Browser.updateResizeListeners();
1233
}
1234
} else {
1235
// remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
1236
canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
1237
canvasContainer.parentNode.removeChild(canvasContainer);
1238
1239
if (Browser.resizeCanvas) {
1240
Browser.setWindowedCanvasSize();
1241
} else {
1242
Browser.updateCanvasDimensions(canvas);
1243
Browser.updateResizeListeners();
1244
}
1245
}
1246
Module['onFullScreen']?.(Browser.isFullscreen);
1247
Module['onFullscreen']?.(Browser.isFullscreen);
1248
}
1249
1250
if (!Browser.fullscreenHandlersInstalled) {
1251
Browser.fullscreenHandlersInstalled = true;
1252
document.addEventListener('fullscreenchange', fullscreenChange, false);
1253
document.addEventListener('mozfullscreenchange', fullscreenChange, false);
1254
document.addEventListener('webkitfullscreenchange', fullscreenChange, false);
1255
document.addEventListener('MSFullscreenChange', fullscreenChange, false);
1256
}
1257
1258
// create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
1259
var canvasContainer = document.createElement("div");
1260
canvas.parentNode.insertBefore(canvasContainer, canvas);
1261
canvasContainer.appendChild(canvas);
1262
1263
// use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
1264
canvasContainer.requestFullscreen = canvasContainer['requestFullscreen'] ||
1265
canvasContainer['mozRequestFullScreen'] ||
1266
canvasContainer['msRequestFullscreen'] ||
1267
(canvasContainer['webkitRequestFullscreen'] ? () => canvasContainer['webkitRequestFullscreen'](Element['ALLOW_KEYBOARD_INPUT']) : null) ||
1268
(canvasContainer['webkitRequestFullScreen'] ? () => canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) : null);
1269
1270
canvasContainer.requestFullscreen();
1271
},
1272
1273
// Overrides Browser.updateCanvasDimensions to account for hi dpi scaling
1274
updateCanvasDimensions(canvas, wNative, hNative) {
1275
const scale = GLFW.getHiDPIScale();
1276
1277
if (wNative && hNative) {
1278
canvas.widthNative = wNative;
1279
canvas.heightNative = hNative;
1280
} else {
1281
wNative = canvas.widthNative;
1282
hNative = canvas.heightNative;
1283
}
1284
var w = wNative;
1285
var h = hNative;
1286
if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
1287
if (w/h < Module['forcedAspectRatio']) {
1288
w = Math.round(h * Module['forcedAspectRatio']);
1289
} else {
1290
h = Math.round(w / Module['forcedAspectRatio']);
1291
}
1292
}
1293
if ((getFullscreenElement() === canvas.parentNode) && (typeof screen != 'undefined')) {
1294
var factor = Math.min(screen.width / w, screen.height / h);
1295
w = Math.round(w * factor);
1296
h = Math.round(h * factor);
1297
}
1298
if (Browser.resizeCanvas) {
1299
wNative = w;
1300
hNative = h;
1301
}
1302
const wNativeScaled = Math.floor(wNative * scale);
1303
const hNativeScaled = Math.floor(hNative * scale);
1304
if (canvas.width != wNativeScaled) canvas.width = wNativeScaled;
1305
if (canvas.height != hNativeScaled) canvas.height = hNativeScaled;
1306
if (typeof canvas.style != 'undefined') {
1307
if (!GLFW.isCSSScalingEnabled()) {
1308
canvas.style.setProperty( "width", wNative + "px", "important");
1309
canvas.style.setProperty("height", hNative + "px", "important");
1310
} else {
1311
canvas.style.removeProperty( "width");
1312
canvas.style.removeProperty("height");
1313
}
1314
}
1315
},
1316
1317
// Overrides Browser.calculateMouseCoords to account for HiDPI scaling and CSS scaling
1318
calculateMouseCoords(pageX, pageY) {
1319
// Calculate the movement based on the changes
1320
// in the coordinates.
1321
const rect = Browser.getCanvas().getBoundingClientRect();
1322
1323
// Neither .scrollX or .pageXOffset are defined in a spec, but
1324
// we prefer .scrollX because it is currently in a spec draft.
1325
// (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
1326
var scrollX = ((typeof window.scrollX != 'undefined') ? window.scrollX : window.pageXOffset);
1327
var scrollY = ((typeof window.scrollY != 'undefined') ? window.scrollY : window.pageYOffset);
1328
#if ASSERTIONS
1329
// If this assert lands, it's likely because the browser doesn't support scrollX or pageXOffset
1330
// and we have no viable fallback.
1331
assert((typeof scrollX != 'undefined') && (typeof scrollY != 'undefined'), 'Unable to retrieve scroll position, mouse positions likely broken.');
1332
#endif
1333
var adjustedX = pageX - (scrollX + rect.left);
1334
var adjustedY = pageY - (scrollY + rect.top);
1335
1336
// getBoundingClientRect() returns dimension affected by CSS, so as a result:
1337
// - when CSS scaling is enabled, this will fix the mouse coordinates to match the width/height of the window
1338
// - otherwise the CSS width/height are forced to the width/height of the GLFW window (see updateCanvasDimensions),
1339
// so there is no need to adjust the position
1340
if (GLFW.isCSSScalingEnabled() && GLFW.active) {
1341
adjustedX = adjustedX * (GLFW.active.width / rect.width);
1342
adjustedY = adjustedY * (GLFW.active.height / rect.height);
1343
}
1344
1345
return { x: adjustedX, y: adjustedY };
1346
},
1347
1348
setWindowAttrib: (winid, attrib, value) => {
1349
var win = GLFW.WindowFromId(winid);
1350
if (!win) return;
1351
const isHiDPIAware = GLFW.isHiDPIAware();
1352
win.attributes[attrib] = value;
1353
if (isHiDPIAware !== GLFW.isHiDPIAware())
1354
GLFW.adjustCanvasDimensions();
1355
},
1356
1357
getDevicePixelRatio() {
1358
return (typeof devicePixelRatio == 'number' && devicePixelRatio) || 1.0;
1359
},
1360
1361
isHiDPIAware() {
1362
if (GLFW.active)
1363
return GLFW.active.attributes[0x0002200C] > 0; // GLFW_SCALE_TO_MONITOR
1364
else
1365
return false;
1366
},
1367
1368
/**
1369
* CSS Scaling is a feature that is NOT part of the GLFW API, but for historical reasons, it is available
1370
* in Emscripten.
1371
* It is automatically disabled when using Hi DPI (the library overrides CSS sizes). */
1372
isCSSScalingEnabled() {
1373
return !GLFW.isHiDPIAware();
1374
},
1375
1376
adjustCanvasDimensions() {
1377
if (GLFW.active) {
1378
Browser.updateCanvasDimensions(Browser.getCanvas(), GLFW.active.width, GLFW.active.height);
1379
Browser.updateResizeListeners();
1380
}
1381
},
1382
1383
getHiDPIScale() {
1384
return GLFW.isHiDPIAware() ? GLFW.scale : 1.0;
1385
},
1386
1387
onDevicePixelRatioChange() {
1388
GLFW.onWindowContentScaleChanged(GLFW.getDevicePixelRatio());
1389
GLFW.adjustCanvasDimensions();
1390
},
1391
1392
GLFW2ParamToGLFW3Param: (param) => {
1393
var table = {
1394
0x00030001:0, // GLFW_MOUSE_CURSOR
1395
0x00030002:0, // GLFW_STICKY_KEYS
1396
0x00030003:0, // GLFW_STICKY_MOUSE_BUTTONS
1397
0x00030004:0, // GLFW_SYSTEM_KEYS
1398
0x00030005:0, // GLFW_KEY_REPEAT
1399
0x00030006:0, // GLFW_AUTO_POLL_EVENTS
1400
0x00020001:0, // GLFW_OPENED
1401
0x00020002:0, // GLFW_ACTIVE
1402
0x00020003:0, // GLFW_ICONIFIED
1403
0x00020004:0, // GLFW_ACCELERATED
1404
0x00020005:0x00021001, // GLFW_RED_BITS
1405
0x00020006:0x00021002, // GLFW_GREEN_BITS
1406
0x00020007:0x00021003, // GLFW_BLUE_BITS
1407
0x00020008:0x00021004, // GLFW_ALPHA_BITS
1408
0x00020009:0x00021005, // GLFW_DEPTH_BITS
1409
0x0002000A:0x00021006, // GLFW_STENCIL_BITS
1410
0x0002000B:0x0002100F, // GLFW_REFRESH_RATE
1411
0x0002000C:0x00021007, // GLFW_ACCUM_RED_BITS
1412
0x0002000D:0x00021008, // GLFW_ACCUM_GREEN_BITS
1413
0x0002000E:0x00021009, // GLFW_ACCUM_BLUE_BITS
1414
0x0002000F:0x0002100A, // GLFW_ACCUM_ALPHA_BITS
1415
0x00020010:0x0002100B, // GLFW_AUX_BUFFERS
1416
0x00020011:0x0002100C, // GLFW_STEREO
1417
0x00020012:0, // GLFW_WINDOW_NO_RESIZE
1418
0x00020013:0x0002100D, // GLFW_FSAA_SAMPLES
1419
0x00020014:0x00022002, // GLFW_OPENGL_VERSION_MAJOR
1420
0x00020015:0x00022003, // GLFW_OPENGL_VERSION_MINOR
1421
0x00020016:0x00022006, // GLFW_OPENGL_FORWARD_COMPAT
1422
0x00020017:0x00022007, // GLFW_OPENGL_DEBUG_CONTEXT
1423
0x00020018:0x00022008, // GLFW_OPENGL_PROFILE
1424
};
1425
return table[param];
1426
}
1427
},
1428
1429
/*******************************************************************************
1430
* GLFW FUNCTIONS
1431
******************************************************************************/
1432
glfwInit: () => {
1433
if (GLFW.windows) return 1; // GL_TRUE
1434
1435
GLFW.initialTime = GLFW.getTime();
1436
GLFW.defaultWindowHints();
1437
GLFW.windows = new Array()
1438
GLFW.active = null;
1439
GLFW.scale = GLFW.getDevicePixelRatio();
1440
1441
1442
window.addEventListener('gamepadconnected', GLFW.onGamepadConnected, true);
1443
window.addEventListener('gamepaddisconnected', GLFW.onGamepadDisconnected, true);
1444
window.addEventListener('keydown', GLFW.onKeydown, true);
1445
window.addEventListener('keypress', GLFW.onKeyPress, true);
1446
window.addEventListener('keyup', GLFW.onKeyup, true);
1447
window.addEventListener('blur', GLFW.onBlur, true);
1448
1449
// watch for devicePixelRatio changes
1450
GLFW.devicePixelRatioMQL = window.matchMedia('(resolution: ' + GLFW.getDevicePixelRatio() + 'dppx)');
1451
GLFW.devicePixelRatioMQL.addEventListener('change', GLFW.onDevicePixelRatioChange);
1452
1453
var canvas = Browser.getCanvas();
1454
canvas.addEventListener('touchmove', GLFW.onMousemove, true);
1455
canvas.addEventListener('touchstart', GLFW.onMouseButtonDown, true);
1456
canvas.addEventListener('touchcancel', GLFW.onMouseButtonUp, true);
1457
canvas.addEventListener('touchend', GLFW.onMouseButtonUp, true);
1458
canvas.addEventListener('mousemove', GLFW.onMousemove, true);
1459
canvas.addEventListener('mousedown', GLFW.onMouseButtonDown, true);
1460
canvas.addEventListener("mouseup", GLFW.onMouseButtonUp, true);
1461
canvas.addEventListener('wheel', GLFW.onMouseWheel, true);
1462
canvas.addEventListener('mousewheel', GLFW.onMouseWheel, true);
1463
canvas.addEventListener('mouseenter', GLFW.onMouseenter, true);
1464
canvas.addEventListener('mouseleave', GLFW.onMouseleave, true);
1465
canvas.addEventListener('drop', GLFW.onDrop, true);
1466
canvas.addEventListener('dragover', GLFW.onDragover, true);
1467
1468
// Overriding implementation to account for HiDPI
1469
Browser.requestFullscreen = GLFW.requestFullscreen;
1470
Browser.calculateMouseCoords = GLFW.calculateMouseCoords;
1471
Browser.updateCanvasDimensions = GLFW.updateCanvasDimensions;
1472
1473
Browser.resizeListeners.push((width, height) => {
1474
if (GLFW.isHiDPIAware()) {
1475
var canvas = Browser.getCanvas();
1476
GLFW.onCanvasResize(canvas.clientWidth, canvas.clientHeight, width, height);
1477
} else {
1478
GLFW.onCanvasResize(width, height, width, height);
1479
}
1480
});
1481
1482
return 1; // GL_TRUE
1483
},
1484
1485
glfwTerminate: () => {
1486
window.removeEventListener('gamepadconnected', GLFW.onGamepadConnected, true);
1487
window.removeEventListener('gamepaddisconnected', GLFW.onGamepadDisconnected, true);
1488
window.removeEventListener('keydown', GLFW.onKeydown, true);
1489
window.removeEventListener('keypress', GLFW.onKeyPress, true);
1490
window.removeEventListener('keyup', GLFW.onKeyup, true);
1491
window.removeEventListener('blur', GLFW.onBlur, true);
1492
var canvas = Browser.getCanvas();
1493
canvas.removeEventListener('touchmove', GLFW.onMousemove, true);
1494
canvas.removeEventListener('touchstart', GLFW.onMouseButtonDown, true);
1495
canvas.removeEventListener('touchcancel', GLFW.onMouseButtonUp, true);
1496
canvas.removeEventListener('touchend', GLFW.onMouseButtonUp, true);
1497
canvas.removeEventListener('mousemove', GLFW.onMousemove, true);
1498
canvas.removeEventListener('mousedown', GLFW.onMouseButtonDown, true);
1499
canvas.removeEventListener('mouseup', GLFW.onMouseButtonUp, true);
1500
canvas.removeEventListener('wheel', GLFW.onMouseWheel, true);
1501
canvas.removeEventListener('mousewheel', GLFW.onMouseWheel, true);
1502
canvas.removeEventListener('mouseenter', GLFW.onMouseenter, true);
1503
canvas.removeEventListener('mouseleave', GLFW.onMouseleave, true);
1504
canvas.removeEventListener('drop', GLFW.onDrop, true);
1505
canvas.removeEventListener('dragover', GLFW.onDragover, true);
1506
1507
if (GLFW.devicePixelRatioMQL)
1508
GLFW.devicePixelRatioMQL.removeEventListener('change', GLFW.onDevicePixelRatioChange);
1509
1510
canvas.width = canvas.height = 1;
1511
GLFW.windows = null;
1512
GLFW.active = null;
1513
},
1514
1515
glfwGetVersion: (major, minor, rev) => {
1516
#if USE_GLFW == 2
1517
{{{ makeSetValue('major', '0', '2', 'i32') }}};
1518
{{{ makeSetValue('minor', '0', '7', 'i32') }}};
1519
{{{ makeSetValue('rev', '0', '7', 'i32') }}};
1520
#endif
1521
1522
#if USE_GLFW == 3
1523
{{{ makeSetValue('major', '0', '3', 'i32') }}};
1524
{{{ makeSetValue('minor', '0', '2', 'i32') }}};
1525
{{{ makeSetValue('rev', '0', '1', 'i32') }}};
1526
#endif
1527
},
1528
1529
glfwPollEvents: () => 0,
1530
1531
glfwWaitEvents: () => 0,
1532
1533
glfwGetTime: () => GLFW.getTime() - GLFW.initialTime,
1534
1535
glfwSetTime: (time) => {
1536
GLFW.initialTime = GLFW.getTime() - time;
1537
},
1538
1539
glfwExtensionSupported__deps: ['glGetString', '$webglGetExtensions'],
1540
glfwExtensionSupported: (extension) => {
1541
GLFW.extensions ||= webglGetExtensions();
1542
1543
if (GLFW.extensions.includes(extension)) return 1;
1544
1545
// extensions from GLEmulations do not come unprefixed
1546
// so, try with prefix
1547
return (GLFW.extensions.includes("GL_" + extension));
1548
},
1549
1550
glfwSwapInterval__deps: ['emscripten_set_main_loop_timing'],
1551
glfwSwapInterval: (interval) => {
1552
interval = Math.abs(interval); // GLFW uses negative values to enable GLX_EXT_swap_control_tear, which we don't have, so just treat negative and positive the same.
1553
if (interval == 0) _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_SETTIMEOUT }}}, 0);
1554
else _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_RAF }}}, interval);
1555
},
1556
1557
#if USE_GLFW == 3
1558
glfwGetVersionString: () => {
1559
GLFW.versionString ||= stringToNewUTF8("3.2.1 JS WebGL Emscripten");
1560
return GLFW.versionString;
1561
},
1562
1563
glfwSetErrorCallback: (cbfun) => {
1564
var prevcbfun = GLFW.errorFunc;
1565
GLFW.errorFunc = cbfun;
1566
return prevcbfun;
1567
},
1568
1569
glfwWaitEventsTimeout: (timeout) => 0,
1570
1571
glfwPostEmptyEvent: () => 0,
1572
1573
glfwGetMonitors__deps: ['malloc'],
1574
glfwGetMonitors: (count) => {
1575
{{{ makeSetValue('count', '0', '1', 'i32') }}};
1576
if (!GLFW.monitors) {
1577
GLFW.monitors = _malloc({{{ POINTER_SIZE }}});
1578
{{{ makeSetValue('GLFW.monitors', '0', '1', 'i32') }}};
1579
}
1580
return GLFW.monitors;
1581
},
1582
1583
glfwGetPrimaryMonitor: () => 1,
1584
1585
glfwGetMonitorPos: (monitor, x, y) => {
1586
{{{ makeSetValue('x', '0', '0', 'i32') }}};
1587
{{{ makeSetValue('y', '0', '0', 'i32') }}};
1588
},
1589
1590
glfwGetMonitorWorkarea: (monitor, x, y, w, h) => {
1591
{{{ makeSetValue('x', '0', '0', 'i32') }}};
1592
{{{ makeSetValue('y', '0', '0', 'i32') }}};
1593
1594
{{{ makeSetValue('w', '0', 'screen.availWidth', 'i32') }}};
1595
{{{ makeSetValue('h', '0', 'screen.availHeight', 'i32') }}};
1596
},
1597
1598
glfwGetMonitorPhysicalSize: (monitor, width, height) => {
1599
// AFAIK there is no way to do this in javascript
1600
// Maybe with platform specific ccalls?
1601
//
1602
// Let's report 0 now which is as wrong as it can get for end user.
1603
{{{ makeSetValue('width', '0', '0', 'i32') }}};
1604
{{{ makeSetValue('height', '0', '0', 'i32') }}};
1605
},
1606
1607
glfwGetMonitorContentScale: (monitor, x, y) => {
1608
{{{ makeSetValue('x', '0', 'GLFW.scale', 'float') }}};
1609
{{{ makeSetValue('y', '0', 'GLFW.scale', 'float') }}};
1610
},
1611
1612
glfwGetMonitorName: (mon) => {
1613
GLFW.monitorString ||= stringToNewUTF8("HTML5 WebGL Canvas");
1614
return GLFW.monitorString;
1615
},
1616
1617
glfwSetMonitorCallback: (cbfun) => {
1618
var prevcbfun = GLFW.monitorFunc;
1619
GLFW.monitorFunc = cbfun;
1620
return prevcbfun;
1621
},
1622
1623
// TODO: implement
1624
glfwGetVideoModes: (monitor, count) => {
1625
{{{ makeSetValue('count', '0', '0', 'i32') }}};
1626
return 0;
1627
},
1628
1629
// TODO: implement
1630
glfwGetVideoMode: (monitor) => 0,
1631
1632
// TODO: implement
1633
glfwSetGamma: (monitor, gamma) => 0,
1634
1635
glfwGetGammaRamp: (monitor) => abort("glfwGetGammaRamp not implemented."),
1636
1637
glfwSetGammaRamp: (monitor, ramp) => abort("glfwSetGammaRamp not implemented."),
1638
1639
glfwDefaultWindowHints: () => GLFW.defaultWindowHints(),
1640
1641
glfwWindowHint: (target, hint) => {
1642
GLFW.hints[target] = hint;
1643
},
1644
1645
glfwWindowHintString: (hint, value) => {
1646
// from glfw docs -> we just ignore this.
1647
// Some hints are platform specific. These may be set on any platform but they
1648
// will only affect their specific platform. Other platforms will ignore them.
1649
},
1650
1651
glfwCreateWindow: (width, height, title, monitor, share) => GLFW.createWindow(width, height, title, monitor, share),
1652
1653
glfwDestroyWindow: (winid) => GLFW.destroyWindow(winid),
1654
1655
glfwWindowShouldClose: (winid) => {
1656
var win = GLFW.WindowFromId(winid);
1657
if (!win) return 0;
1658
return win.shouldClose;
1659
},
1660
1661
glfwSetWindowShouldClose: (winid, value) => {
1662
var win = GLFW.WindowFromId(winid);
1663
if (!win) return;
1664
win.shouldClose = value;
1665
},
1666
1667
glfwSetWindowTitle: (winid, title) => GLFW.setWindowTitle(winid, title),
1668
1669
glfwGetWindowPos: (winid, x, y) => GLFW.getWindowPos(winid, x, y),
1670
1671
glfwSetWindowPos: (winid, x, y) => GLFW.setWindowPos(winid, x, y),
1672
1673
glfwGetWindowSize: (winid, width, height) => GLFW.getWindowSize(winid, width, height),
1674
1675
glfwSetWindowSize: (winid, width, height) => GLFW.setWindowSize(winid, width, height),
1676
1677
glfwGetFramebufferSize: (winid, width, height) => {
1678
var ww = 0;
1679
var wh = 0;
1680
1681
var win = GLFW.WindowFromId(winid);
1682
if (win) {
1683
ww = win.framebufferWidth;
1684
wh = win.framebufferHeight;
1685
}
1686
1687
if (width) {
1688
{{{ makeSetValue('width', '0', 'ww', 'i32') }}};
1689
}
1690
1691
if (height) {
1692
{{{ makeSetValue('height', '0', 'wh', 'i32') }}};
1693
}
1694
},
1695
1696
glfwGetWindowContentScale: (winid, x, y) => {
1697
// winid doesn't matter. all windows will use same scale anyway.
1698
// hope i used this makeSetValue correctly
1699
{{{ makeSetValue('x', '0', 'GLFW.scale', 'float') }}};
1700
{{{ makeSetValue('y', '0', 'GLFW.scale', 'float') }}};
1701
},
1702
1703
glfwGetWindowOpacity: (winid) => 1.0,
1704
1705
glfwSetWindowOpacity: (winid, opacity) => { /* error */ },
1706
1707
glfwIconifyWindow: (winid) => {
1708
#if ASSERTIONS
1709
warnOnce('glfwIconifyWindow is not implemented');
1710
#endif
1711
},
1712
1713
glfwRestoreWindow: (winid) => {
1714
#if ASSERTIONS
1715
warnOnce('glfwRestoreWindow is not implemented');
1716
#endif
1717
},
1718
1719
glfwShowWindow: (winid) => 0,
1720
1721
glfwHideWindow: (winid) => 0,
1722
1723
glfwGetWindowMonitor: (winid) => {
1724
var win = GLFW.WindowFromId(winid);
1725
if (!win) return 0;
1726
return win.monitor;
1727
},
1728
1729
glfwGetWindowAttrib: (winid, attrib) => {
1730
var win = GLFW.WindowFromId(winid);
1731
if (!win) return 0;
1732
return win.attributes[attrib];
1733
},
1734
1735
glfwSetWindowAttrib: (winid, attrib, value) => GLFW.setWindowAttrib(winid, attrib, value),
1736
1737
glfwSetWindowUserPointer: (winid, ptr) => {
1738
var win = GLFW.WindowFromId(winid);
1739
if (!win) return;
1740
win.userptr = ptr;
1741
},
1742
1743
glfwGetWindowUserPointer: (winid) => {
1744
var win = GLFW.WindowFromId(winid);
1745
if (!win) return 0;
1746
return win.userptr;
1747
},
1748
1749
glfwSetWindowPosCallback: (winid, cbfun) => {
1750
var win = GLFW.WindowFromId(winid);
1751
if (!win) return null;
1752
var prevcbfun = win.windowPosFunc;
1753
win.windowPosFunc = cbfun;
1754
return prevcbfun;
1755
},
1756
1757
glfwSetWindowSizeCallback: (winid, cbfun) => GLFW.setWindowSizeCallback(winid, cbfun),
1758
1759
glfwSetWindowCloseCallback: (winid, cbfun) => GLFW.setWindowCloseCallback(winid, cbfun),
1760
1761
glfwSetWindowRefreshCallback: (winid, cbfun) => GLFW.setWindowRefreshCallback(winid, cbfun),
1762
1763
glfwSetWindowFocusCallback: (winid, cbfun) => {
1764
var win = GLFW.WindowFromId(winid);
1765
if (!win) return null;
1766
var prevcbfun = win.windowFocusFunc;
1767
win.windowFocusFunc = cbfun;
1768
return prevcbfun;
1769
},
1770
1771
glfwSetWindowIconifyCallback: (winid, cbfun) => {
1772
var win = GLFW.WindowFromId(winid);
1773
if (!win) return null;
1774
var prevcbfun = win.windowIconifyFunc;
1775
win.windowIconifyFunc = cbfun;
1776
return prevcbfun;
1777
},
1778
1779
glfwSetWindowMaximizeCallback: (winid, cbfun) => {
1780
var win = GLFW.WindowFromId(winid);
1781
if (!win) return null;
1782
var prevcbfun = win.windowMaximizeFunc;
1783
win.windowMaximizeFunc = cbfun;
1784
return prevcbfun;
1785
},
1786
1787
glfwSetWindowIcon: (winid, count, images) => 0,
1788
1789
glfwSetWindowSizeLimits: (winid, minwidth, minheight, maxwidth, maxheight) => 0,
1790
1791
glfwSetWindowAspectRatio: (winid, numer, denom) => 0,
1792
1793
glfwGetWindowFrameSize: (winid, left, top, right, bottom) => abort("glfwGetWindowFrameSize not implemented."),
1794
1795
glfwMaximizeWindow: (winid) => 0,
1796
1797
glfwFocusWindow: (winid) => 0,
1798
1799
glfwRequestWindowAttention: (winid) => 0, // maybe do window.focus()?
1800
1801
glfwSetWindowMonitor: (winid, monitor, xpos, ypos, width, height, refreshRate) => abort("glfwSetWindowMonitor not implemented."),
1802
1803
glfwCreateCursor: (image, xhot, yhot) => 0,
1804
1805
glfwCreateStandardCursor: (shape) => 0,
1806
1807
glfwDestroyCursor: (cursor) => 0,
1808
1809
glfwSetCursor: (winid, cursor) => 0,
1810
1811
glfwSetFramebufferSizeCallback: (winid, cbfun) => {
1812
var win = GLFW.WindowFromId(winid);
1813
if (!win) return null;
1814
var prevcbfun = win.framebufferSizeFunc;
1815
win.framebufferSizeFunc = cbfun;
1816
return prevcbfun;
1817
},
1818
1819
glfwSetWindowContentScaleCallback: (winid, cbfun) => {
1820
var win = GLFW.WindowFromId(winid);
1821
if (!win) return null;
1822
var prevcbfun = win.windowContentScaleFunc;
1823
win.windowContentScaleFunc = cbfun;
1824
return prevcbfun;
1825
},
1826
1827
glfwGetInputMode: (winid, mode) => {
1828
var win = GLFW.WindowFromId(winid);
1829
if (!win) return;
1830
1831
switch (mode) {
1832
case 0x00033001: { // GLFW_CURSOR
1833
if (Browser.pointerLock) {
1834
win.inputModes[mode] = 0x00034003; // GLFW_CURSOR_DISABLED
1835
} else {
1836
win.inputModes[mode] = 0x00034001; // GLFW_CURSOR_NORMAL
1837
}
1838
}
1839
}
1840
1841
return win.inputModes[mode];
1842
},
1843
1844
glfwSetInputMode: (winid, mode, value) => {
1845
GLFW.setInputMode(winid, mode, value);
1846
},
1847
1848
glfwRawMouseMotionSupported: () => 0,
1849
1850
glfwGetKey: (winid, key) => GLFW.getKey(winid, key),
1851
1852
glfwGetKeyName: (key, scancode) => abort("glfwGetKeyName not implemented."),
1853
1854
glfwGetKeyScancode: (key) => abort("glfwGetKeyScancode not implemented."),
1855
1856
glfwGetMouseButton: (winid, button) => GLFW.getMouseButton(winid, button),
1857
1858
glfwGetCursorPos: (winid, x, y) => GLFW.getCursorPos(winid, x, y),
1859
1860
// I believe it is not possible to move the mouse with JavaScript
1861
glfwSetCursorPos: (winid, x, y) => GLFW.setCursorPos(winid, x, y),
1862
1863
glfwSetKeyCallback: (winid, cbfun) => GLFW.setKeyCallback(winid, cbfun),
1864
1865
glfwSetCharCallback: (winid, cbfun) => GLFW.setCharCallback(winid, cbfun),
1866
1867
glfwSetCharModsCallback: (winid, cbfun) => abort("glfwSetCharModsCallback not implemented."),
1868
1869
glfwSetMouseButtonCallback: (winid, cbfun) => GLFW.setMouseButtonCallback(winid, cbfun),
1870
1871
glfwSetCursorPosCallback: (winid, cbfun) => GLFW.setCursorPosCallback(winid, cbfun),
1872
1873
glfwSetCursorEnterCallback: (winid, cbfun) => {
1874
var win = GLFW.WindowFromId(winid);
1875
if (!win) return null;
1876
var prevcbfun = win.cursorEnterFunc;
1877
win.cursorEnterFunc = cbfun;
1878
return prevcbfun;
1879
},
1880
1881
glfwSetScrollCallback: (winid, cbfun) => GLFW.setScrollCallback(winid, cbfun),
1882
1883
glfwVulkanSupported: () => 0,
1884
1885
glfwSetDropCallback: (winid, cbfun) => GLFW.setDropCallback(winid, cbfun),
1886
1887
glfwGetTimerValue: () => abort("glfwGetTimerValue is not implemented."),
1888
1889
glfwGetTimerFrequency: () => abort("glfwGetTimerFrequency is not implemented."),
1890
1891
glfwGetRequiredInstanceExtensions: (count) => abort("glfwGetRequiredInstanceExtensions is not implemented."),
1892
1893
glfwJoystickPresent: (joy) => {
1894
GLFW.refreshJoysticks();
1895
1896
return GLFW.joys[joy] !== undefined;
1897
},
1898
1899
glfwGetJoystickAxes: (joy, count) => {
1900
GLFW.refreshJoysticks();
1901
1902
var state = GLFW.joys[joy];
1903
if (!state || !state.axes) {
1904
{{{ makeSetValue('count', '0', '0', 'i32') }}};
1905
return;
1906
}
1907
1908
{{{ makeSetValue('count', '0', 'state.axesCount', 'i32') }}};
1909
return state.axes;
1910
},
1911
1912
glfwGetJoystickButtons: (joy, count) => {
1913
GLFW.refreshJoysticks();
1914
1915
var state = GLFW.joys[joy];
1916
if (!state || !state.buttons) {
1917
{{{ makeSetValue('count', '0', '0', 'i32') }}};
1918
return;
1919
}
1920
1921
{{{ makeSetValue('count', '0', 'state.buttonsCount', 'i32') }}};
1922
return state.buttons;
1923
},
1924
1925
glfwGetJoystickHats: (joy, count) => abort("glfwGetJoystickHats is not implemented"),
1926
1927
glfwGetJoystickName: (joy) => {
1928
if (GLFW.joys[joy]) {
1929
return GLFW.joys[joy].id;
1930
}
1931
return 0;
1932
},
1933
1934
glfwGetJoystickGUID: (jid) => abort("glfwGetJoystickGUID not implemented"),
1935
1936
glfwSetJoystickUserPointer: (jid, ptr) => abort("glfwSetJoystickUserPointer not implemented"),
1937
1938
glfwGetJoystickUserPointer: (jid) => abort("glfwGetJoystickUserPointer not implemented"),
1939
1940
glfwJoystickIsGamepad: (jid) => abort("glfwJoystickIsGamepad not implemented"),
1941
1942
glfwSetJoystickCallback: (cbfun) => GLFW.setJoystickCallback(cbfun),
1943
1944
glfwSetClipboardString: (win, string) => 0,
1945
1946
glfwGetClipboardString: (win) => 0,
1947
1948
glfwMakeContextCurrent: (winid) => 0,
1949
1950
glfwGetCurrentContext: () => GLFW.active ? GLFW.active.id : 0,
1951
1952
glfwSwapBuffers: (winid) => GLFW.swapBuffers(winid),
1953
1954
#elif USE_GLFW == 2
1955
glfwOpenWindow: (width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode) => {
1956
GLFW.hints[0x00021001] = redbits; // GLFW_RED_BITS
1957
GLFW.hints[0x00021002] = greenbits; // GLFW_GREEN_BITS
1958
GLFW.hints[0x00021003] = bluebits; // GLFW_BLUE_BITS
1959
GLFW.hints[0x00021004] = alphabits; // GLFW_ALPHA_BITS
1960
GLFW.hints[0x00021005] = depthbits; // GLFW_DEPTH_BITS
1961
GLFW.hints[0x00021006] = stencilbits; // GLFW_STENCIL_BITS
1962
GLFW.createWindow(width, height, "GLFW2 Window", 0, 0);
1963
return 1; // GL_TRUE
1964
},
1965
1966
glfwCloseWindow: () => GLFW.destroyWindow(GLFW.active.id),
1967
1968
glfwOpenWindowHint: (target, hint) => {
1969
target = GLFW.GLFW2ParamToGLFW3Param(target);
1970
GLFW.hints[target] = hint;
1971
},
1972
1973
glfwGetWindowSize_v2: (width, height) => GLFW.getWindowSize(GLFW.active.id, width, height),
1974
1975
glfwSetWindowSize_v2: (width, height) => GLFW.setWindowSize(GLFW.active.id, width, height),
1976
1977
glfwSetWindowPos_v2: (x, y) => GLFW.setWindowPos(GLFW.active.id, x, y),
1978
1979
glfwSetWindowTitle_v2: (title) => GLFW.setWindowTitle(GLFW.active.id, title),
1980
1981
glfwIconifyWindow_v2: () => {
1982
#if ASSERTIONS
1983
warnOnce('glfwIconifyWindow is not implemented');
1984
#endif
1985
},
1986
1987
glfwRestoreWindow_v2: () => {
1988
#if ASSERTIONS
1989
warnOnce('glfwRestoreWindow is not implemented');
1990
#endif
1991
},
1992
1993
glfwSwapBuffers_v2: () => GLFW.swapBuffers(GLFW.active.id),
1994
1995
glfwGetWindowParam: (param) => {
1996
param = GLFW.GLFW2ParamToGLFW3Param(param);
1997
return GLFW.hints[param];
1998
},
1999
2000
glfwSetWindowSizeCallback_v2: (cbfun) => {
2001
GLFW.setWindowSizeCallback(GLFW.active.id, cbfun);
2002
},
2003
2004
glfwSetWindowCloseCallback_v2: (cbfun) => {
2005
GLFW.setWindowCloseCallback(GLFW.active.id, cbfun);
2006
},
2007
2008
glfwSetWindowRefreshCallback_v2: (cbfun) => GLFW.setWindowRefreshCallback(GLFW.active.id, cbfun),
2009
2010
glfwGetKey_v2: (key) => GLFW.getKey(GLFW.active.id, key),
2011
2012
glfwGetMouseButton_v2: (button) => GLFW.getMouseButton(GLFW.active.id, button),
2013
2014
glfwGetMousePos: (x, y) => {
2015
GLFW.getMousePos(GLFW.active.id, x, y);
2016
},
2017
2018
glfwSetMousePos: (x, y) => {
2019
GLFW.setCursorPos(GLFW.active.id, x, y);
2020
},
2021
2022
glfwGetMouseWheel: () => 0,
2023
2024
glfwSetMouseWheel: (pos) => 0,
2025
2026
glfwSetKeyCallback_v2: (cbfun) => {
2027
GLFW.setKeyCallback(GLFW.active.id, cbfun);
2028
},
2029
2030
glfwSetCharCallback_v2: (cbfun) => {
2031
GLFW.setCharCallback(GLFW.active.id, cbfun);
2032
},
2033
2034
glfwSetMouseButtonCallback_v2: (cbfun) => {
2035
GLFW.setMouseButtonCallback(GLFW.active.id, cbfun);
2036
},
2037
2038
glfwSetMousePosCallback: (cbfun) => {
2039
GLFW.setCursorPosCallback(GLFW.active.id, cbfun);
2040
},
2041
2042
glfwSetMouseWheelCallback: (cbfun) => {
2043
GLFW.setScrollCallback(GLFW.active.id, cbfun);
2044
},
2045
2046
glfwGetDesktopMode: (mode) => abort("glfwGetDesktopMode is not implemented."),
2047
2048
glfwSleep__deps: ['sleep'],
2049
glfwSleep: (time) => _sleep(time),
2050
2051
glfwEnable: (target) => {
2052
target = GLFW.GLFW2ParamToGLFW3Param(target);
2053
GLFW.hints[target] = false;
2054
},
2055
2056
glfwDisable: (target) => {
2057
target = GLFW.GLFW2ParamToGLFW3Param(target);
2058
GLFW.hints[target] = true;
2059
},
2060
2061
glfwGetGLVersion: (major, minor, rev) => {
2062
{{{ makeSetValue('major', '0', '0', 'i32') }}};
2063
{{{ makeSetValue('minor', '0', '0', 'i32') }}};
2064
{{{ makeSetValue('rev', '0', '1', 'i32') }}};
2065
},
2066
2067
glfwCreateThread: (fun, arg) => {
2068
{{{ makeDynCall('vp', 'fun') }}}(arg);
2069
// One single thread
2070
return 0;
2071
},
2072
2073
glfwDestroyThread: (ID) => 0,
2074
2075
glfwWaitThread: (ID, waitmode) => 0,
2076
2077
// One single thread
2078
glfwGetThreadID: () => 0,
2079
2080
glfwCreateMutex: () => abort("glfwCreateMutex is not implemented."),
2081
2082
glfwDestroyMutex: (mutex) => abort("glfwDestroyMutex is not implemented."),
2083
2084
glfwLockMutex: (mutex) => abort("glfwLockMutex is not implemented."),
2085
2086
glfwUnlockMutex: (mutex) => abort("glfwUnlockMutex is not implemented."),
2087
2088
glfwCreateCond: () => abort("glfwCreateCond is not implemented."),
2089
2090
glfwDestroyCond: (cond) => abort("glfwDestroyCond is not implemented."),
2091
2092
glfwWaitCond: (cond, mutex, timeout) => abort("glfwWaitCond is not implemented."),
2093
2094
glfwSignalCond: (cond) => abort("glfwSignalCond is not implemented."),
2095
2096
glfwBroadcastCond: (cond) => abort("glfwBroadcastCond is not implemented."),
2097
2098
glfwGetNumberOfProcessors: () => 1, // Threads are disabled anyway…
2099
2100
glfwReadImage: (name, img, flags) => abort("glfwReadImage is not implemented."),
2101
2102
glfwReadMemoryImage: (data, size, img, flags) => abort("glfwReadMemoryImage is not implemented."),
2103
2104
glfwFreeImage: (img) => abort("glfwFreeImage is not implemented."),
2105
2106
glfwLoadTexture2D: (name, flags) => abort("glfwLoadTexture2D is not implemented."),
2107
2108
glfwLoadMemoryTexture2D: (data, size, flags) => abort("glfwLoadMemoryTexture2D is not implemented."),
2109
2110
glfwLoadTextureImage2D: (img, flags) => abort("glfwLoadTextureImage2D is not implemented."),
2111
#endif // GLFW2
2112
};
2113
2114
autoAddDeps(LibraryGLFW, '$GLFW');
2115
addToLibrary(LibraryGLFW);
2116
2117