webruby 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (245) hide show
  1. checksums.yaml +4 -4
  2. data/lib/webruby/config.rb +4 -9
  3. data/lib/webruby/rake/files.rake +2 -2
  4. data/modules/emscripten/AUTHORS +9 -1
  5. data/modules/emscripten/CONTRIBUTING.markdown +5 -0
  6. data/modules/emscripten/ChangeLog +435 -0
  7. data/modules/emscripten/cmake/Modules/FindOpenAL.cmake +26 -0
  8. data/modules/emscripten/cmake/Platform/Emscripten.cmake +9 -2
  9. data/modules/emscripten/em++ +0 -2
  10. data/modules/emscripten/emcc +92 -32
  11. data/modules/emscripten/emlink.py +16 -13
  12. data/modules/emscripten/emmake +1 -1
  13. data/modules/emscripten/emrun +918 -0
  14. data/modules/emscripten/emrun.bat +2 -0
  15. data/modules/emscripten/emscripten.py +545 -20
  16. data/modules/emscripten/src/analyzer.js +6 -1
  17. data/modules/emscripten/src/compiler.js +25 -16
  18. data/modules/emscripten/src/emrun_postjs.js +20 -0
  19. data/modules/emscripten/{tests → src}/hello_world.js +0 -0
  20. data/modules/emscripten/src/intertyper.js +45 -16
  21. data/modules/emscripten/src/jsifier.js +78 -48
  22. data/modules/emscripten/src/library.js +381 -96
  23. data/modules/emscripten/src/library_browser.js +50 -53
  24. data/modules/emscripten/src/library_egl.js +66 -24
  25. data/modules/emscripten/src/library_fs.js +122 -90
  26. data/modules/emscripten/src/library_gl.js +739 -353
  27. data/modules/emscripten/src/library_glfw.js +9 -3
  28. data/modules/emscripten/src/library_glut.js +10 -5
  29. data/modules/emscripten/src/library_idbfs.js +14 -14
  30. data/modules/emscripten/src/library_memfs.js +65 -41
  31. data/modules/emscripten/src/library_nodefs.js +61 -9
  32. data/modules/emscripten/src/library_openal.js +4 -4
  33. data/modules/emscripten/src/library_path.js +9 -13
  34. data/modules/emscripten/src/library_sdl.js +301 -64
  35. data/modules/emscripten/src/library_sockfs.js +7 -5
  36. data/modules/emscripten/src/modules.js +62 -22
  37. data/modules/emscripten/src/parseTools.js +135 -102
  38. data/modules/emscripten/src/postamble.js +3 -4
  39. data/modules/emscripten/src/preamble.js +49 -29
  40. data/modules/emscripten/src/proxyClient.js +1 -1
  41. data/modules/emscripten/src/proxyWorker.js +10 -10
  42. data/modules/emscripten/src/relooper/Relooper.cpp +15 -4
  43. data/modules/emscripten/src/runtime.js +32 -8
  44. data/modules/emscripten/src/settings.js +25 -8
  45. data/modules/emscripten/src/shell.html +6 -3
  46. data/modules/emscripten/src/shell.js +13 -11
  47. data/modules/emscripten/src/simd.js +602 -432
  48. data/modules/emscripten/src/struct_info.json +22 -2
  49. data/modules/emscripten/src/utility.js +32 -17
  50. data/modules/emscripten/system/include/SDL/SDL_events.h +1 -0
  51. data/modules/emscripten/system/include/compat/ctype.h +17 -0
  52. data/modules/emscripten/system/include/compat/wchar.h +23 -0
  53. data/modules/emscripten/system/include/compat/wctype.h +23 -0
  54. data/modules/emscripten/system/include/emscripten/emmintrin.h +87 -0
  55. data/modules/emscripten/system/include/emscripten/emscripten.h +30 -4
  56. data/modules/emscripten/system/include/emscripten/vector.h +29 -1
  57. data/modules/emscripten/system/include/emscripten/xmmintrin.h +131 -0
  58. data/modules/emscripten/system/include/libcxx/CREDITS.TXT +9 -1
  59. data/modules/emscripten/system/include/libcxx/__bit_reference +8 -8
  60. data/modules/emscripten/system/include/libcxx/__config +95 -17
  61. data/modules/emscripten/system/include/libcxx/__debug +25 -4
  62. data/modules/emscripten/system/include/libcxx/__functional_03 +7 -7
  63. data/modules/emscripten/system/include/libcxx/__functional_base +169 -9
  64. data/modules/emscripten/system/include/libcxx/__functional_base_03 +1 -1
  65. data/modules/emscripten/system/include/libcxx/__hash_table +25 -25
  66. data/modules/emscripten/system/include/libcxx/__locale +21 -19
  67. data/modules/emscripten/system/include/libcxx/__mutex_base +2 -33
  68. data/modules/emscripten/system/include/libcxx/__split_buffer +9 -9
  69. data/modules/emscripten/system/include/libcxx/__std_stream +14 -0
  70. data/modules/emscripten/system/include/libcxx/__tree +35 -26
  71. data/modules/emscripten/system/include/libcxx/__tuple +15 -15
  72. data/modules/emscripten/system/include/libcxx/__tuple_03 +2 -2
  73. data/modules/emscripten/system/include/libcxx/__undef_min_max +8 -0
  74. data/modules/emscripten/system/include/libcxx/algorithm +121 -110
  75. data/modules/emscripten/system/include/libcxx/array +15 -15
  76. data/modules/emscripten/system/include/libcxx/bitset +4 -4
  77. data/modules/emscripten/system/include/libcxx/chrono +51 -17
  78. data/modules/emscripten/system/include/libcxx/cmath +25 -23
  79. data/modules/emscripten/system/include/libcxx/codecvt +21 -18
  80. data/modules/emscripten/system/include/libcxx/complex +48 -7
  81. data/modules/emscripten/system/include/libcxx/cstddef +1 -1
  82. data/modules/emscripten/system/include/libcxx/cstdio +8 -1
  83. data/modules/emscripten/system/include/libcxx/cstdlib +1 -1
  84. data/modules/emscripten/system/include/libcxx/cwchar +1 -1
  85. data/modules/emscripten/system/include/libcxx/deque +26 -12
  86. data/modules/emscripten/system/include/libcxx/dynarray +311 -0
  87. data/modules/emscripten/system/include/libcxx/exception +4 -4
  88. data/modules/emscripten/system/include/libcxx/ext/__hash +3 -3
  89. data/modules/emscripten/system/include/libcxx/ext/hash_map +19 -15
  90. data/modules/emscripten/system/include/libcxx/ext/hash_set +7 -3
  91. data/modules/emscripten/system/include/libcxx/forward_list +33 -7
  92. data/modules/emscripten/system/include/libcxx/fstream +4 -4
  93. data/modules/emscripten/system/include/libcxx/functional +200 -170
  94. data/modules/emscripten/system/include/libcxx/future +83 -39
  95. data/modules/emscripten/system/include/libcxx/initializer_list +24 -11
  96. data/modules/emscripten/system/include/libcxx/iomanip +147 -0
  97. data/modules/emscripten/system/include/libcxx/ios +24 -16
  98. data/modules/emscripten/system/include/libcxx/iosfwd +19 -19
  99. data/modules/emscripten/system/include/libcxx/istream +13 -8
  100. data/modules/emscripten/system/include/libcxx/iterator +108 -417
  101. data/modules/emscripten/system/include/libcxx/limits +8 -4
  102. data/modules/emscripten/system/include/libcxx/list +28 -8
  103. data/modules/emscripten/system/include/libcxx/locale +153 -390
  104. data/modules/emscripten/system/include/libcxx/map +280 -100
  105. data/modules/emscripten/system/include/libcxx/memory +49 -97
  106. data/modules/emscripten/system/include/libcxx/mutex +2 -2
  107. data/modules/emscripten/system/include/libcxx/new +43 -14
  108. data/modules/emscripten/system/include/libcxx/numeric +2 -2
  109. data/modules/emscripten/system/include/libcxx/optional +697 -0
  110. data/modules/emscripten/system/include/libcxx/ostream +17 -8
  111. data/modules/emscripten/system/include/libcxx/queue +5 -5
  112. data/modules/emscripten/system/include/libcxx/random +53 -51
  113. data/modules/emscripten/system/include/libcxx/ratio +11 -11
  114. data/modules/emscripten/system/include/libcxx/readme.txt +1 -1
  115. data/modules/emscripten/system/include/libcxx/regex +23 -20
  116. data/modules/emscripten/system/include/libcxx/scoped_allocator +1 -1
  117. data/modules/emscripten/system/include/libcxx/set +166 -2
  118. data/modules/emscripten/system/include/libcxx/shared_mutex +419 -0
  119. data/modules/emscripten/system/include/libcxx/sstream +4 -4
  120. data/modules/emscripten/system/include/libcxx/stack +3 -3
  121. data/modules/emscripten/system/include/libcxx/streambuf +5 -5
  122. data/modules/emscripten/system/include/libcxx/string +372 -324
  123. data/modules/emscripten/system/include/libcxx/support/ibm/limits.h +99 -0
  124. data/modules/emscripten/system/include/libcxx/support/ibm/support.h +54 -0
  125. data/modules/emscripten/system/include/libcxx/support/ibm/xlocale.h +326 -0
  126. data/modules/emscripten/system/include/libcxx/support/win32/limits_win32.h +6 -6
  127. data/modules/emscripten/system/include/libcxx/support/win32/locale_win32.h +15 -15
  128. data/modules/emscripten/system/include/libcxx/support/win32/math_win32.h +2 -0
  129. data/modules/emscripten/system/include/libcxx/support/win32/support.h +6 -1
  130. data/modules/emscripten/system/include/libcxx/system_error +14 -8
  131. data/modules/emscripten/system/include/libcxx/thread +7 -8
  132. data/modules/emscripten/system/include/libcxx/tuple +29 -88
  133. data/modules/emscripten/system/include/libcxx/type_traits +253 -209
  134. data/modules/emscripten/system/include/libcxx/typeindex +3 -3
  135. data/modules/emscripten/system/include/libcxx/unordered_map +162 -101
  136. data/modules/emscripten/system/include/libcxx/unordered_set +79 -2
  137. data/modules/emscripten/system/include/libcxx/utility +20 -20
  138. data/modules/emscripten/system/include/libcxx/valarray +23 -23
  139. data/modules/emscripten/system/include/libcxx/vector +114 -91
  140. data/modules/emscripten/system/lib/libc/musl/src/regex/regcomp.c +3352 -0
  141. data/modules/emscripten/system/lib/libc/musl/src/regex/regerror.c +35 -0
  142. data/modules/emscripten/system/lib/libc/musl/src/regex/regexec.c +1011 -0
  143. data/modules/emscripten/system/lib/libc/musl/src/regex/tre-mem.c +158 -0
  144. data/modules/emscripten/system/lib/libc/musl/src/regex/tre.h +231 -0
  145. data/modules/emscripten/system/lib/libcextra.symbols +7 -0
  146. data/modules/emscripten/system/lib/libcxx/CREDITS.TXT +9 -1
  147. data/modules/emscripten/system/lib/libcxx/algorithm.cpp +1 -0
  148. data/modules/emscripten/system/lib/libcxx/debug.cpp +66 -42
  149. data/modules/emscripten/system/lib/libcxx/exception.cpp +88 -16
  150. data/modules/emscripten/system/lib/libcxx/future.cpp +6 -0
  151. data/modules/emscripten/system/lib/libcxx/ios.cpp +7 -2
  152. data/modules/emscripten/system/lib/libcxx/iostream.cpp +8 -8
  153. data/modules/emscripten/system/lib/libcxx/locale.cpp +38 -11
  154. data/modules/emscripten/system/lib/libcxx/mutex.cpp +3 -0
  155. data/modules/emscripten/system/lib/libcxx/new.cpp +44 -10
  156. data/modules/emscripten/system/lib/libcxx/optional.cpp +25 -0
  157. data/modules/emscripten/system/lib/libcxx/random.cpp +26 -0
  158. data/modules/emscripten/system/lib/libcxx/readme.txt +1 -1
  159. data/modules/emscripten/system/lib/libcxx/shared_mutex.cpp +101 -0
  160. data/modules/emscripten/system/lib/libcxx/stdexcept.cpp +11 -7
  161. data/modules/emscripten/system/lib/libcxx/string.cpp +3 -1
  162. data/modules/emscripten/system/lib/libcxx/strstream.cpp +7 -7
  163. data/modules/emscripten/system/lib/libcxx/support/win32/locale_win32.cpp +12 -13
  164. data/modules/emscripten/system/lib/libcxx/support/win32/support.cpp +33 -36
  165. data/modules/emscripten/system/lib/libcxx/symbols +187 -168
  166. data/modules/emscripten/system/lib/libcxx/system_error.cpp +1 -0
  167. data/modules/emscripten/system/lib/libcxx/thread.cpp +7 -3
  168. data/modules/emscripten/system/lib/libcxx/typeinfo.cpp +9 -6
  169. data/modules/emscripten/system/lib/libcxx/valarray.cpp +2 -0
  170. data/modules/emscripten/third_party/lzma.js/doit.bat +4 -0
  171. data/modules/emscripten/third_party/lzma.js/doit.sh +9 -2
  172. data/modules/emscripten/tools/cache.py +5 -7
  173. data/modules/emscripten/tools/cache.pyc +0 -0
  174. data/modules/emscripten/tools/eliminator/asm-eliminator-test-output.js +7 -0
  175. data/modules/emscripten/tools/eliminator/asm-eliminator-test.js +9 -1
  176. data/modules/emscripten/tools/eliminator/eliminator-test-output.js +3 -0
  177. data/modules/emscripten/tools/eliminator/eliminator-test.js +9 -1
  178. data/modules/emscripten/tools/file_packager.py +93 -50
  179. data/modules/emscripten/tools/js-optimizer.js +98 -48
  180. data/modules/emscripten/tools/js_optimizer.py +4 -4
  181. data/modules/emscripten/tools/js_optimizer.pyc +0 -0
  182. data/modules/emscripten/tools/jsrun.py +1 -1
  183. data/modules/emscripten/tools/jsrun.pyc +0 -0
  184. data/modules/emscripten/tools/response_file.py +6 -0
  185. data/modules/emscripten/tools/response_file.pyc +0 -0
  186. data/modules/emscripten/tools/settings_template_readonly.py +2 -0
  187. data/modules/emscripten/tools/shared.py +88 -34
  188. data/modules/emscripten/tools/shared.pyc +0 -0
  189. data/modules/emscripten/tools/split.py +21 -13
  190. data/modules/mruby/build_config.rb +7 -1
  191. data/modules/mruby/doc/compile/README.md +5 -9
  192. data/modules/mruby/include/mrbconf.h +5 -2
  193. data/modules/mruby/include/mruby/array.h +1 -0
  194. data/modules/mruby/include/mruby/compile.h +2 -4
  195. data/modules/mruby/include/mruby/dump.h +7 -16
  196. data/modules/mruby/include/mruby/hash.h +1 -1
  197. data/modules/mruby/include/mruby/irep.h +14 -2
  198. data/modules/mruby/include/mruby/khash.h +8 -7
  199. data/modules/mruby/include/mruby/string.h +1 -0
  200. data/modules/mruby/include/mruby/value.h +5 -2
  201. data/modules/mruby/include/mruby.h +12 -13
  202. data/modules/mruby/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +16 -6
  203. data/modules/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +18 -30
  204. data/modules/mruby/mrbgems/mruby-fiber/src/fiber.c +21 -0
  205. data/modules/mruby/mrbgems/mruby-math/src/math.c +1 -1
  206. data/modules/mruby/mrbgems/mruby-random/src/random.c +144 -47
  207. data/modules/mruby/mrbgems/mruby-random/test/random.rb +44 -0
  208. data/modules/mruby/mrbgems/mruby-struct/src/struct.c +5 -5
  209. data/modules/mruby/mrblib/numeric.rb +99 -33
  210. data/modules/mruby/src/array.c +11 -4
  211. data/modules/mruby/src/backtrace.c +2 -2
  212. data/modules/mruby/src/class.c +49 -30
  213. data/modules/mruby/src/codegen.c +131 -79
  214. data/modules/mruby/src/debug.c +1 -1
  215. data/modules/mruby/src/dump.c +213 -163
  216. data/modules/mruby/src/error.c +17 -17
  217. data/modules/mruby/src/error.h +1 -1
  218. data/modules/mruby/src/etc.c +10 -0
  219. data/modules/mruby/src/gc.c +35 -17
  220. data/modules/mruby/src/hash.c +5 -5
  221. data/modules/mruby/src/kernel.c +36 -14
  222. data/modules/mruby/src/load.c +238 -296
  223. data/modules/mruby/src/numeric.c +18 -98
  224. data/modules/mruby/src/object.c +3 -5
  225. data/modules/mruby/src/parse.y +63 -56
  226. data/modules/mruby/src/proc.c +8 -5
  227. data/modules/mruby/src/re.h +0 -1
  228. data/modules/mruby/src/state.c +65 -27
  229. data/modules/mruby/src/string.c +3 -31
  230. data/modules/mruby/src/symbol.c +3 -3
  231. data/modules/mruby/src/variable.c +12 -5
  232. data/modules/mruby/src/vm.c +90 -72
  233. data/modules/mruby/tasks/mruby_build.rake +10 -1
  234. data/modules/mruby/tasks/toolchains/gcc.rake +12 -2
  235. data/modules/mruby/tasks/toolchains/{vs2012.rake → visualcpp.rake} +1 -1
  236. data/modules/mruby/test/driver.c +3 -3
  237. data/modules/mruby/test/t/array.rb +5 -5
  238. data/modules/mruby/test/t/class.rb +14 -1
  239. data/modules/mruby/test/t/kernel.rb +4 -0
  240. data/modules/mruby/test/t/module.rb +4 -4
  241. data/modules/mruby/test/t/nameerror.rb +1 -1
  242. data/modules/mruby/tools/mrbc/mrbc.c +23 -17
  243. data/modules/mruby/travis_config.rb +10 -1
  244. metadata +28 -5
  245. data/modules/mruby/tasks/toolchains/vs2010.rake +0 -3
@@ -11,6 +11,7 @@ var LibraryGL = {
11
11
  #endif
12
12
 
13
13
  counter: 1, // 0 is reserved as 'null' in gl
14
+ lastError: 0,
14
15
  buffers: [],
15
16
  programs: [],
16
17
  framebuffers: [],
@@ -40,7 +41,13 @@ var LibraryGL = {
40
41
  8 // GL_DOUBLE
41
42
  ],
42
43
 
43
- uniformTable: {}, // name => uniform ID. the uID must be identical until relinking, cannot create a new uID each call to glGetUniformLocation
44
+ programInfos: {}, // Stores additional information needed for each shader program. Each entry is of form:
45
+ /* { uniforms: {}, // Maps ints back to the opaque WebGLUniformLocation objects.
46
+ maxUniformLength: int, // Cached in order to implement glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH)
47
+ maxAttributeLength: int // Cached in order to implement glGetProgramiv(GL_ACTIVE_ATTRIBUTE_MAX_LENGTH)
48
+ } */
49
+
50
+ stringCache: {},
44
51
 
45
52
  packAlignment: 4, // default alignment is 4 bytes
46
53
  unpackAlignment: 4, // default alignment is 4 bytes
@@ -49,6 +56,13 @@ var LibraryGL = {
49
56
  Browser.moduleContextCreatedCallbacks.push(GL.initExtensions);
50
57
  },
51
58
 
59
+ // Records a GL error condition that occurred, stored until user calls glGetError() to fetch it. As per GLES2 spec, only the first error
60
+ // is remembered, and subsequent errors are discarded until the user has cleared the stored error by a call to glGetError().
61
+ recordError: function recordError(errorCode) {
62
+ if (!GL.lastError) {
63
+ GL.lastError = errorCode;
64
+ }
65
+ },
52
66
  // Get a new ID for a texture/buffer/etc., while keeping the table dense and fast. Creation is farely rare so it is worth optimizing lookups later.
53
67
  getNewId: function(table) {
54
68
  var ret = GL.counter++;
@@ -195,6 +209,114 @@ var LibraryGL = {
195
209
  ((height - 1) * alignedRowSize + plainRowSize);
196
210
  },
197
211
 
212
+ get: function(name_, p, type) {
213
+ // Guard against user passing a null pointer.
214
+ // Note that GLES2 spec does not say anything about how passing a null pointer should be treated.
215
+ // Testing on desktop core GL 3, the application crashes on glGetIntegerv to a null pointer, but
216
+ // better to report an error instead of doing anything random.
217
+ if (!p) {
218
+ #if GL_ASSERTIONS
219
+ Module.printErr('GL_INVALID_VALUE in glGet' + type + 'v(name=' + name_ + ': Function called with null out pointer!');
220
+ #endif
221
+ GL.recordError(0x0501 /* GL_INVALID_VALUE */);
222
+ return;
223
+ }
224
+ var ret = undefined;
225
+ switch(name_) { // Handle a few trivial GLES values
226
+ case 0x8DFA: // GL_SHADER_COMPILER
227
+ ret = 1;
228
+ break;
229
+ case 0x8DF8: // GL_SHADER_BINARY_FORMATS
230
+ if (type !== 'Integer') {
231
+ GL.recordError(0x0500); // GL_INVALID_ENUM
232
+ #if GL_ASSERTIONS
233
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(GL_SHADER_BINARY_FORMATS): Invalid parameter type!');
234
+ #endif
235
+ }
236
+ return; // Do not write anything to the out pointer, since no binary formats are supported.
237
+ case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS
238
+ ret = 0;
239
+ break;
240
+ case 0x86A2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS
241
+ // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be queried for length),
242
+ // so implement it ourselves to allow C++ GLES2 code get the length.
243
+ var formats = Module.ctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/);
244
+ ret = formats.length;
245
+ break;
246
+ case 0x8B9A: // GL_IMPLEMENTATION_COLOR_READ_TYPE
247
+ ret = 0x1401; // GL_UNSIGNED_BYTE
248
+ break;
249
+ case 0x8B9B: // GL_IMPLEMENTATION_COLOR_READ_FORMAT
250
+ ret = 0x1908; // GL_RGBA
251
+ break;
252
+ }
253
+
254
+ if (ret === undefined) {
255
+ var result = Module.ctx.getParameter(name_);
256
+ switch (typeof(result)) {
257
+ case "number":
258
+ ret = result;
259
+ break;
260
+ case "boolean":
261
+ ret = result ? 1 : 0;
262
+ break;
263
+ case "string":
264
+ GL.recordError(0x0500); // GL_INVALID_ENUM
265
+ #if GL_ASSERTIONS
266
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(' + name_ + ') on a name which returns a string!');
267
+ #endif
268
+ return;
269
+ case "object":
270
+ if (result === null) {
271
+ GL.recordError(0x0500); // GL_INVALID_ENUM
272
+ #if GL_ASSERTIONS
273
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(' + name_ + ') and it returns null!');
274
+ #endif
275
+ return;
276
+ } else if (result instanceof Float32Array ||
277
+ result instanceof Uint32Array ||
278
+ result instanceof Int32Array ||
279
+ result instanceof Array) {
280
+ for (var i = 0; i < result.length; ++i) {
281
+ switch (type) {
282
+ case 'Integer': {{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}}; break;
283
+ case 'Float': {{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}}; break;
284
+ case 'Boolean': {{{ makeSetValue('p', 'i', 'result[i] ? 1 : 0', 'i8') }}}; break;
285
+ default: throw 'internal glGet error, bad type: ' + type;
286
+ }
287
+ }
288
+ return;
289
+ } else if (result instanceof WebGLBuffer ||
290
+ result instanceof WebGLProgram ||
291
+ result instanceof WebGLFramebuffer ||
292
+ result instanceof WebGLRenderbuffer ||
293
+ result instanceof WebGLTexture) {
294
+ ret = result.name | 0;
295
+ } else {
296
+ GL.recordError(0x0500); // GL_INVALID_ENUM
297
+ #if GL_ASSERTIONS
298
+ Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v: Unknown object returned from WebGL getParameter(' + name_ + ')!');
299
+ #endif
300
+ return;
301
+ }
302
+ break;
303
+ default:
304
+ GL.recordError(0x0500); // GL_INVALID_ENUM
305
+ #if GL_ASSERTIONS
306
+ Module.printErr('GL_INVALID_ENUM in glGetIntegerv: Native code calling glGet' + type + 'v(' + name_ + ') and it returns ' + result + ' of type ' + typeof(result) + '!');
307
+ #endif
308
+ return;
309
+ }
310
+ }
311
+
312
+ switch (type) {
313
+ case 'Integer': {{{ makeSetValue('p', '0', 'ret', 'i32') }}}; break;
314
+ case 'Float': {{{ makeSetValue('p', '0', 'ret', 'float') }}}; break;
315
+ case 'Boolean': {{{ makeSetValue('p', '0', 'ret ? 1 : 0', 'i8') }}}; break;
316
+ default: throw 'internal glGet error, bad type: ' + type;
317
+ }
318
+ },
319
+
198
320
  getTexPixelData: function(type, format, width, height, pixels, internalFormat) {
199
321
  var sizePerPixel;
200
322
  switch (type) {
@@ -240,7 +362,9 @@ var LibraryGL = {
240
362
  sizePerPixel = 2;
241
363
  break;
242
364
  case 0x1406 /* GL_FLOAT */:
365
+ #if ASSERTIONS
243
366
  assert(GL.floatExt, 'Must have OES_texture_float to use float textures');
367
+ #endif
244
368
  switch (format) {
245
369
  case 0x1907 /* GL_RGB */:
246
370
  sizePerPixel = 3*4;
@@ -272,8 +396,24 @@ var LibraryGL = {
272
396
  }
273
397
  },
274
398
 
399
+ #if GL_FFP_ONLY
400
+ enabledClientAttribIndices: [],
401
+ enableVertexAttribArray: function enableVertexAttribArray(index) {
402
+ if (!GL.enabledClientAttribIndices[index]) {
403
+ GL.enabledClientAttribIndices[index] = true;
404
+ Module.ctx.enableVertexAttribArray(index);
405
+ }
406
+ },
407
+ disableVertexAttribArray: function disableVertexAttribArray(index) {
408
+ if (GL.enabledClientAttribIndices[index]) {
409
+ GL.enabledClientAttribIndices[index] = false;
410
+ Module.ctx.disableVertexAttribArray(index);
411
+ }
412
+ },
413
+ #endif
414
+
275
415
  #if FULL_ES2
276
- calcBufLength: function(size, type, stride, count) {
416
+ calcBufLength: function calcBufLength(size, type, stride, count) {
277
417
  if (stride > 0) {
278
418
  return count * stride; // XXXvlad this is not exactly correct I don't think
279
419
  }
@@ -283,7 +423,7 @@ var LibraryGL = {
283
423
 
284
424
  usedTempBuffers: [],
285
425
 
286
- preDrawHandleClientVertexAttribBindings: function(count) {
426
+ preDrawHandleClientVertexAttribBindings: function preDrawHandleClientVertexAttribBindings(count) {
287
427
  GL.resetBufferBinding = false;
288
428
 
289
429
  var used = GL.usedTempBuffers;
@@ -317,7 +457,7 @@ var LibraryGL = {
317
457
  }
318
458
  },
319
459
 
320
- postDrawHandleClientVertexAttribBindings: function() {
460
+ postDrawHandleClientVertexAttribBindings: function postDrawHandleClientVertexAttribBindings() {
321
461
  if (GL.resetBufferBinding) {
322
462
  Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]);
323
463
  }
@@ -451,15 +591,23 @@ var LibraryGL = {
451
591
  GL.validateGLObjectID(GL.programs, program, 'populateUniformTable', 'program');
452
592
  #endif
453
593
  var p = GL.programs[program];
454
- GL.uniformTable[program] = {};
455
- var ptable = GL.uniformTable[program];
456
- // A program's uniformTable maps the string name of an uniform to an integer location of that uniform.
594
+ GL.programInfos[program] = {
595
+ uniforms: {},
596
+ maxUniformLength: 0, // This is eagerly computed below, since we already enumerate all uniforms anyway.
597
+ maxAttributeLength: -1 // This is lazily computed and cached, computed when/if first asked, "-1" meaning not computed yet.
598
+ };
599
+
600
+ var ptable = GL.programInfos[program];
601
+ var utable = ptable.uniforms;
602
+ // A program's uniform table maps the string name of an uniform to an integer location of that uniform.
457
603
  // The global GL.uniforms map maps integer locations to WebGLUniformLocations.
458
604
  var numUniforms = Module.ctx.getProgramParameter(p, Module.ctx.ACTIVE_UNIFORMS);
459
605
  for (var i = 0; i < numUniforms; ++i) {
460
606
  var u = Module.ctx.getActiveUniform(p, i);
461
607
 
462
608
  var name = u.name;
609
+ ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length+1);
610
+
463
611
  // Strip off any trailing array specifier we might have got, e.g. "[0]".
464
612
  if (name.indexOf(']', name.length-1) !== -1) {
465
613
  var ls = name.lastIndexOf('[');
@@ -467,11 +615,11 @@ var LibraryGL = {
467
615
  }
468
616
 
469
617
  // Optimize memory usage slightly: If we have an array of uniforms, e.g. 'vec3 colors[3];', then
470
- // only store the string 'colors' in ptable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i.
618
+ // only store the string 'colors' in utable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i.
471
619
  // Note that for the GL.uniforms table, we still need to fetch the all WebGLUniformLocations for all the indices.
472
620
  var loc = Module.ctx.getUniformLocation(p, name);
473
621
  var id = GL.getNewId(GL.uniforms);
474
- ptable[name] = [u.size, id];
622
+ utable[name] = [u.size, id];
475
623
  GL.uniforms[id] = loc;
476
624
 
477
625
  for (var j = 1; j < u.size; ++j) {
@@ -497,11 +645,14 @@ var LibraryGL = {
497
645
 
498
646
  glGetString__sig: 'ii',
499
647
  glGetString: function(name_) {
648
+ if (GL.stringCache[name_]) return GL.stringCache[name_];
649
+ var ret;
500
650
  switch(name_) {
501
651
  case 0x1F00 /* GL_VENDOR */:
502
652
  case 0x1F01 /* GL_RENDERER */:
503
653
  case 0x1F02 /* GL_VERSION */:
504
- return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
654
+ ret = allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
655
+ break;
505
656
  case 0x1F03 /* GL_EXTENSIONS */:
506
657
  var exts = Module.ctx.getSupportedExtensions();
507
658
  var gl_exts = [];
@@ -509,151 +660,35 @@ var LibraryGL = {
509
660
  gl_exts.push(exts[i]);
510
661
  gl_exts.push("GL_" + exts[i]);
511
662
  }
512
- return allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL); // XXX this leaks! TODO: Cache all results like this in library_gl.js to be clean and nice and avoid leaking.
663
+ ret = allocate(intArrayFromString(gl_exts.join(' ')), 'i8', ALLOC_NORMAL);
664
+ break;
513
665
  case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */:
514
- return allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL);
666
+ ret = allocate(intArrayFromString('OpenGL ES GLSL 1.00 (WebGL)'), 'i8', ALLOC_NORMAL);
667
+ break;
515
668
  default:
516
- throw 'Failure: Invalid glGetString value: ' + name_;
669
+ GL.recordError(0x0500/*GL_INVALID_ENUM*/);
670
+ #if GL_ASSERTIONS
671
+ Module.printErr('GL_INVALID_ENUM in glGetString: Unknown parameter ' + name_ + '!');
672
+ #endif
673
+ return 0;
517
674
  }
675
+ GL.stringCache[name_] = ret;
676
+ return ret;
518
677
  },
519
678
 
520
679
  glGetIntegerv__sig: 'vii',
521
680
  glGetIntegerv: function(name_, p) {
522
- switch(name_) { // Handle a few trivial GLES values
523
- case 0x8DFA: // GL_SHADER_COMPILER
524
- {{{ makeSetValue('p', '0', '1', 'i32') }}};
525
- return;
526
- case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS
527
- {{{ makeSetValue('p', '0', '0', 'i32') }}};
528
- return;
529
- case 0x86A2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS
530
- // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be queried for length),
531
- // so implement it ourselves to allow C++ GLES2 code get the length.
532
- var formats = Module.ctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/);
533
- {{{ makeSetValue('p', '0', 'formats.length', 'i32') }}};
534
- return;
535
- }
536
- var result = Module.ctx.getParameter(name_);
537
- switch (typeof(result)) {
538
- case "number":
539
- {{{ makeSetValue('p', '0', 'result', 'i32') }}};
540
- break;
541
- case "boolean":
542
- {{{ makeSetValue('p', '0', 'result ? 1 : 0', 'i8') }}};
543
- break;
544
- case "string":
545
- throw 'Native code calling glGetIntegerv(' + name_ + ') on a name which returns a string!';
546
- case "object":
547
- if (result === null) {
548
- {{{ makeSetValue('p', '0', '0', 'i32') }}};
549
- } else if (result instanceof Float32Array ||
550
- result instanceof Uint32Array ||
551
- result instanceof Int32Array ||
552
- result instanceof Array) {
553
- for (var i = 0; i < result.length; ++i) {
554
- {{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}};
555
- }
556
- } else if (result instanceof WebGLBuffer) {
557
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
558
- } else if (result instanceof WebGLProgram) {
559
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
560
- } else if (result instanceof WebGLFramebuffer) {
561
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
562
- } else if (result instanceof WebGLRenderbuffer) {
563
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
564
- } else if (result instanceof WebGLTexture) {
565
- {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
566
- } else {
567
- throw 'Unknown object returned from WebGL getParameter';
568
- }
569
- break;
570
- case "undefined":
571
- throw 'Native code calling glGetIntegerv(' + name_ + ') and it returns undefined';
572
- default:
573
- throw 'Why did we hit the default case?';
574
- }
681
+ return GL.get(name_, p, 'Integer');
575
682
  },
576
683
 
577
684
  glGetFloatv__sig: 'vii',
578
685
  glGetFloatv: function(name_, p) {
579
- var result = Module.ctx.getParameter(name_);
580
- switch (typeof(result)) {
581
- case "number":
582
- {{{ makeSetValue('p', '0', 'result', 'float') }}};
583
- break;
584
- case "boolean":
585
- {{{ makeSetValue('p', '0', 'result ? 1.0 : 0.0', 'float') }}};
586
- break;
587
- case "string":
588
- {{{ makeSetValue('p', '0', '0', 'float') }}};
589
- case "object":
590
- if (result === null) {
591
- throw 'Native code calling glGetFloatv(' + name_ + ') and it returns null';
592
- } else if (result instanceof Float32Array ||
593
- result instanceof Uint32Array ||
594
- result instanceof Int32Array ||
595
- result instanceof Array) {
596
- for (var i = 0; i < result.length; ++i) {
597
- {{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}};
598
- }
599
- } else if (result instanceof WebGLBuffer) {
600
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
601
- } else if (result instanceof WebGLProgram) {
602
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
603
- } else if (result instanceof WebGLFramebuffer) {
604
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
605
- } else if (result instanceof WebGLRenderbuffer) {
606
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
607
- } else if (result instanceof WebGLTexture) {
608
- {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
609
- } else {
610
- throw 'Unknown object returned from WebGL getParameter';
611
- }
612
- break;
613
- case "undefined":
614
- throw 'Native code calling glGetFloatv(' + name_ + ') and it returns undefined';
615
- default:
616
- throw 'Why did we hit the default case?';
617
- }
686
+ return GL.get(name_, p, 'Float');
618
687
  },
619
688
 
620
689
  glGetBooleanv__sig: 'vii',
621
690
  glGetBooleanv: function(name_, p) {
622
- var result = Module.ctx.getParameter(name_);
623
- switch (typeof(result)) {
624
- case "number":
625
- {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}};
626
- break;
627
- case "boolean":
628
- {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}};
629
- break;
630
- case "string":
631
- throw 'Native code calling glGetBooleanv(' + name_ + ') on a name which returns a string!';
632
- case "object":
633
- if (result === null) {
634
- {{{ makeSetValue('p', '0', '0', 'i8') }}};
635
- } else if (result instanceof Float32Array ||
636
- result instanceof Uint32Array ||
637
- result instanceof Int32Array ||
638
- result instanceof Array) {
639
- for (var i = 0; i < result.length; ++i) {
640
- {{{ makeSetValue('p', 'i', 'result[i] != 0', 'i8') }}};
641
- }
642
- } else if (result instanceof WebGLBuffer ||
643
- result instanceof WebGLProgram ||
644
- result instanceof WebGLFramebuffer ||
645
- result instanceof WebGLRenderbuffer ||
646
- result instanceof WebGLTexture) {
647
- {{{ makeSetValue('p', '0', '1', 'i8') }}}; // non-zero ID is always 1!
648
- } else {
649
- throw 'Unknown object returned from WebGL getParameter';
650
- }
651
- break;
652
- case "undefined":
653
- throw 'Unknown object returned from WebGL getParameter';
654
- default:
655
- throw 'Why did we hit the default case?';
656
- }
691
+ return GL.get(name_, p, 'Boolean');
657
692
  },
658
693
 
659
694
  glGenTextures__sig: 'vii',
@@ -680,7 +715,9 @@ var LibraryGL = {
680
715
 
681
716
  glCompressedTexImage2D__sig: 'viiiiiiii',
682
717
  glCompressedTexImage2D: function(target, level, internalFormat, width, height, border, imageSize, data) {
718
+ #if ASSERTIONS
683
719
  assert(GL.compressionExt);
720
+ #endif
684
721
  if (data) {
685
722
  data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}};
686
723
  } else {
@@ -691,7 +728,9 @@ var LibraryGL = {
691
728
 
692
729
  glCompressedTexSubImage2D__sig: 'viiiiiiiii',
693
730
  glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) {
731
+ #if ASSERTIONS
694
732
  assert(GL.compressionExt);
733
+ #endif
695
734
  if (data) {
696
735
  data = {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}};
697
736
  } else {
@@ -725,7 +764,9 @@ var LibraryGL = {
725
764
 
726
765
  glReadPixels__sig: 'viiiiiii',
727
766
  glReadPixels: function(x, y, width, height, format, type, pixels) {
767
+ #if ASSERTIONS
728
768
  assert(type == 0x1401 /* GL_UNSIGNED_BYTE */);
769
+ #endif
729
770
  var sizePerPixel;
730
771
  switch (format) {
731
772
  case 0x1907 /* GL_RGB */:
@@ -734,7 +775,12 @@ var LibraryGL = {
734
775
  case 0x1908 /* GL_RGBA */:
735
776
  sizePerPixel = 4;
736
777
  break;
737
- default: throw 'unsupported glReadPixels format';
778
+ default:
779
+ GL.recordError(0x0500/*GL_INVALID_ENUM*/);
780
+ #if GL_ASSERTIONS
781
+ Module.printErr('GL_INVALID_ENUM in glReadPixels: Unsupported format ' + format + '!');
782
+ #endif
783
+ return;
738
784
  }
739
785
  var totalSize = width*height*sizePerPixel;
740
786
  Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize));
@@ -938,11 +984,12 @@ var LibraryGL = {
938
984
  name = name.slice(0, ls);
939
985
  }
940
986
 
941
- var ptable = GL.uniformTable[program];
987
+ var ptable = GL.programInfos[program];
942
988
  if (!ptable) {
943
989
  return -1;
944
990
  }
945
- var uniformInfo = ptable[name]; // returns pair [ dimension_of_uniform_array, uniform_location ]
991
+ var utable = ptable.uniforms;
992
+ var uniformInfo = utable[name]; // returns pair [ dimension_of_uniform_array, uniform_location ]
946
993
  if (uniformInfo && arrayOffset < uniformInfo[0]) { // Check if user asked for an out-of-bounds element, i.e. for 'vec4 colors[3];' user could ask for 'colors[10]' which should return -1.
947
994
  return uniformInfo[1]+arrayOffset;
948
995
  } else {
@@ -1357,7 +1404,9 @@ var LibraryGL = {
1357
1404
  {{{ makeSetValue('count', '0', 'len', 'i32') }}};
1358
1405
  for (var i = 0; i < len; ++i) {
1359
1406
  var id = GL.shaders.indexOf(result[i]);
1407
+ #if ASSERTIONS
1360
1408
  assert(id !== -1, 'shader not bound to local id');
1409
+ #endif
1361
1410
  {{{ makeSetValue('shaders', 'i*4', 'id', 'i32') }}};
1362
1411
  }
1363
1412
  },
@@ -1428,6 +1477,47 @@ var LibraryGL = {
1428
1477
  #endif
1429
1478
  if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
1430
1479
  {{{ makeSetValue('p', '0', 'Module.ctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}};
1480
+ } else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) {
1481
+ var ptable = GL.programInfos[program];
1482
+ if (ptable) {
1483
+ {{{ makeSetValue('p', '0', 'ptable.maxUniformLength', 'i32') }}};
1484
+ return;
1485
+ } else if (program < GL.counter) {
1486
+ #if GL_ASSERTIONS
1487
+ Module.printErr("A GL object " + program + " that is not a program object was passed to glGetProgramiv!");
1488
+ #endif
1489
+ GL.recordError(0x0502 /* GL_INVALID_OPERATION */);
1490
+ } else {
1491
+ #if GL_ASSERTIONS
1492
+ Module.printErr("A GL object " + program + " that did not come from GL was passed to glGetProgramiv!");
1493
+ #endif
1494
+ GL.recordError(0x0501 /* GL_INVALID_VALUE */);
1495
+ }
1496
+ } else if (pname == 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) {
1497
+ var ptable = GL.programInfos[program];
1498
+ if (ptable) {
1499
+ if (ptable.maxAttributeLength == -1) {
1500
+ var program = GL.programs[program];
1501
+ var numAttribs = Module.ctx.getProgramParameter(program, Module.ctx.ACTIVE_ATTRIBUTES);
1502
+ ptable.maxAttributeLength = 0; // Spec says if there are no active attribs, 0 must be returned.
1503
+ for(var i = 0; i < numAttribs; ++i) {
1504
+ var activeAttrib = Module.ctx.getActiveAttrib(program, i);
1505
+ ptable.maxAttributeLength = Math.max(ptable.maxAttributeLength, activeAttrib.name.length+1);
1506
+ }
1507
+ }
1508
+ {{{ makeSetValue('p', '0', 'ptable.maxAttributeLength', 'i32') }}};
1509
+ return;
1510
+ } else if (program < GL.counter) {
1511
+ #if GL_ASSERTIONS
1512
+ Module.printErr("A GL object " + program + " that is not a program object was passed to glGetProgramiv!");
1513
+ #endif
1514
+ GL.recordError(0x0502 /* GL_INVALID_OPERATION */);
1515
+ } else {
1516
+ #if GL_ASSERTIONS
1517
+ Module.printErr("A GL object " + program + " that did not come from GL was passed to glGetProgramiv!");
1518
+ #endif
1519
+ GL.recordError(0x0501 /* GL_INVALID_VALUE */);
1520
+ }
1431
1521
  } else {
1432
1522
  {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.programs[program], pname)', 'i32') }}};
1433
1523
  }
@@ -1455,7 +1545,7 @@ var LibraryGL = {
1455
1545
  Module.ctx.deleteProgram(program);
1456
1546
  program.name = 0;
1457
1547
  GL.programs[program] = null;
1458
- GL.uniformTable[program] = null;
1548
+ GL.programInfos[program] = null;
1459
1549
  },
1460
1550
 
1461
1551
  glAttachShader__sig: 'vii',
@@ -1491,7 +1581,7 @@ var LibraryGL = {
1491
1581
  GL.validateGLObjectID(GL.programs, program, 'glLinkProgram', 'program');
1492
1582
  #endif
1493
1583
  Module.ctx.linkProgram(GL.programs[program]);
1494
- GL.uniformTable[program] = {}; // uniforms no longer keep the same names after linking
1584
+ GL.programInfos[program] = null; // uniforms no longer keep the same names after linking
1495
1585
  GL.populateUniformTable(program);
1496
1586
  },
1497
1587
 
@@ -1645,7 +1735,7 @@ var LibraryGL = {
1645
1735
 
1646
1736
  // Add some emulation workarounds
1647
1737
  Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work.');
1648
- #if GL_UNSAFE_OPTS == 0
1738
+ #if GL_UNSAFE_OPTS == 1
1649
1739
  Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0');
1650
1740
  #endif
1651
1741
 
@@ -1663,7 +1753,7 @@ var LibraryGL = {
1663
1753
  };
1664
1754
 
1665
1755
  var glEnable = _glEnable;
1666
- _glEnable = function(cap) {
1756
+ _glEnable = function _glEnable(cap) {
1667
1757
  // Clean up the renderer on any change to the rendering state. The optimization of
1668
1758
  // skipping renderer setup is aimed at the case of multiple glDraw* right after each other
1669
1759
  if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
@@ -1685,7 +1775,7 @@ var LibraryGL = {
1685
1775
  };
1686
1776
 
1687
1777
  var glDisable = _glDisable;
1688
- _glDisable = function(cap) {
1778
+ _glDisable = function _glDisable(cap) {
1689
1779
  if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
1690
1780
  if (cap == 0x0B60 /* GL_FOG */) {
1691
1781
  GLEmulation.fogEnabled = false;
@@ -1703,7 +1793,7 @@ var LibraryGL = {
1703
1793
  }
1704
1794
  glDisable(cap);
1705
1795
  };
1706
- _glIsEnabled = function(cap) {
1796
+ _glIsEnabled = function _glIsEnabled(cap) {
1707
1797
  if (cap == 0x0B60 /* GL_FOG */) {
1708
1798
  return GLEmulation.fogEnabled ? 1 : 0;
1709
1799
  } else if (!(cap in validCapabilities)) {
@@ -1713,7 +1803,7 @@ var LibraryGL = {
1713
1803
  };
1714
1804
 
1715
1805
  var glGetBooleanv = _glGetBooleanv;
1716
- _glGetBooleanv = function(pname, p) {
1806
+ _glGetBooleanv = function _glGetBooleanv(pname, p) {
1717
1807
  var attrib = GLEmulation.getAttributeFromCapability(pname);
1718
1808
  if (attrib !== null) {
1719
1809
  var result = GL.immediate.enabledClientAttributes[attrib];
@@ -1724,7 +1814,7 @@ var LibraryGL = {
1724
1814
  };
1725
1815
 
1726
1816
  var glGetIntegerv = _glGetIntegerv;
1727
- _glGetIntegerv = function(pname, params) {
1817
+ _glGetIntegerv = function _glGetIntegerv(pname, params) {
1728
1818
  switch (pname) {
1729
1819
  case 0x84E2: pname = Module.ctx.MAX_TEXTURE_IMAGE_UNITS /* fake it */; break; // GL_MAX_TEXTURE_UNITS
1730
1820
  case 0x8B4A: { // GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB
@@ -1774,17 +1864,17 @@ var LibraryGL = {
1774
1864
  return;
1775
1865
  }
1776
1866
  case 0x8088: { // GL_TEXTURE_COORD_ARRAY_SIZE
1777
- var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
1867
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture];
1778
1868
  {{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
1779
1869
  return;
1780
1870
  }
1781
1871
  case 0x8089: { // GL_TEXTURE_COORD_ARRAY_TYPE
1782
- var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
1872
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture];
1783
1873
  {{{ makeSetValue('params', '0', 'attribute ? attribute.type : 0', 'i32') }}};
1784
1874
  return;
1785
1875
  }
1786
1876
  case 0x808A: { // GL_TEXTURE_COORD_ARRAY_STRIDE
1787
- var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0];
1877
+ var attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture];
1788
1878
  {{{ makeSetValue('params', '0', 'attribute ? attribute.stride : 0', 'i32') }}};
1789
1879
  return;
1790
1880
  }
@@ -1793,14 +1883,17 @@ var LibraryGL = {
1793
1883
  };
1794
1884
 
1795
1885
  var glGetString = _glGetString;
1796
- _glGetString = function(name_) {
1886
+ _glGetString = function _glGetString(name_) {
1887
+ if (GL.stringCache[name_]) return GL.stringCache[name_];
1797
1888
  switch(name_) {
1798
1889
  case 0x1F03 /* GL_EXTENSIONS */: // Add various extensions that we can support
1799
- return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') +
1890
+ var ret = allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') +
1800
1891
  ' GL_EXT_texture_env_combine GL_ARB_texture_env_crossbar GL_ATI_texture_env_combine3 GL_NV_texture_env_combine4 GL_EXT_texture_env_dot3 GL_ARB_multitexture GL_ARB_vertex_buffer_object GL_EXT_framebuffer_object GL_ARB_vertex_program GL_ARB_fragment_program GL_ARB_shading_language_100 GL_ARB_shader_objects GL_ARB_vertex_shader GL_ARB_fragment_shader GL_ARB_texture_cube_map GL_EXT_draw_range_elements' +
1801
1892
  (GL.compressionExt ? ' GL_ARB_texture_compression GL_EXT_texture_compression_s3tc' : '') +
1802
1893
  (GL.anisotropicExt ? ' GL_EXT_texture_filter_anisotropic' : '')
1803
1894
  ), 'i8', ALLOC_NORMAL);
1895
+ GL.stringCache[name_] = ret;
1896
+ return ret;
1804
1897
  }
1805
1898
  return glGetString(name_);
1806
1899
  };
@@ -1814,7 +1907,7 @@ var LibraryGL = {
1814
1907
  GL.shaderOriginalSources = {};
1815
1908
  #endif
1816
1909
  var glCreateShader = _glCreateShader;
1817
- _glCreateShader = function(shaderType) {
1910
+ _glCreateShader = function _glCreateShader(shaderType) {
1818
1911
  var id = glCreateShader(shaderType);
1819
1912
  GL.shaderInfos[id] = {
1820
1913
  type: shaderType,
@@ -1824,7 +1917,7 @@ var LibraryGL = {
1824
1917
  };
1825
1918
 
1826
1919
  var glShaderSource = _glShaderSource;
1827
- _glShaderSource = function(shader, count, string, length) {
1920
+ _glShaderSource = function _glShaderSource(shader, count, string, length) {
1828
1921
  var source = GL.getSource(shader, count, string, length);
1829
1922
  #if GL_DEBUG
1830
1923
  console.log("glShaderSource: Input: \n" + source);
@@ -1937,7 +2030,7 @@ var LibraryGL = {
1937
2030
  };
1938
2031
 
1939
2032
  var glCompileShader = _glCompileShader;
1940
- _glCompileShader = function(shader) {
2033
+ _glCompileShader = function _glCompileShader(shader) {
1941
2034
  Module.ctx.compileShader(GL.shaders[shader]);
1942
2035
  #if GL_DEBUG
1943
2036
  if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) {
@@ -1952,14 +2045,14 @@ var LibraryGL = {
1952
2045
 
1953
2046
  GL.programShaders = {};
1954
2047
  var glAttachShader = _glAttachShader;
1955
- _glAttachShader = function(program, shader) {
2048
+ _glAttachShader = function _glAttachShader(program, shader) {
1956
2049
  if (!GL.programShaders[program]) GL.programShaders[program] = [];
1957
2050
  GL.programShaders[program].push(shader);
1958
2051
  glAttachShader(program, shader);
1959
2052
  };
1960
2053
 
1961
2054
  var glDetachShader = _glDetachShader;
1962
- _glDetachShader = function(program, shader) {
2055
+ _glDetachShader = function _glDetachShader(program, shader) {
1963
2056
  var programShader = GL.programShaders[program];
1964
2057
  if (!programShader) {
1965
2058
  Module.printErr('WARNING: _glDetachShader received invalid program: ' + program);
@@ -1971,7 +2064,7 @@ var LibraryGL = {
1971
2064
  };
1972
2065
 
1973
2066
  var glUseProgram = _glUseProgram;
1974
- _glUseProgram = function(program) {
2067
+ _glUseProgram = function _glUseProgram(program) {
1975
2068
  #if GL_DEBUG
1976
2069
  if (GL.debug) {
1977
2070
  Module.printErr('[using program with shaders]');
@@ -1983,12 +2076,15 @@ var LibraryGL = {
1983
2076
  }
1984
2077
  }
1985
2078
  #endif
1986
- GL.currProgram = program;
2079
+ if (GL.currProgram != program) {
2080
+ GL.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
2081
+ GL.currProgram = program;
2082
+ }
1987
2083
  glUseProgram(program);
1988
2084
  }
1989
2085
 
1990
2086
  var glDeleteProgram = _glDeleteProgram;
1991
- _glDeleteProgram = function(program) {
2087
+ _glDeleteProgram = function _glDeleteProgram(program) {
1992
2088
  glDeleteProgram(program);
1993
2089
  if (program == GL.currProgram) GL.currProgram = 0;
1994
2090
  };
@@ -1996,12 +2092,12 @@ var LibraryGL = {
1996
2092
  // If attribute 0 was not bound, bind it to 0 for WebGL performance reasons. Track if 0 is free for that.
1997
2093
  var zeroUsedPrograms = {};
1998
2094
  var glBindAttribLocation = _glBindAttribLocation;
1999
- _glBindAttribLocation = function(program, index, name) {
2095
+ _glBindAttribLocation = function _glBindAttribLocation(program, index, name) {
2000
2096
  if (index == 0) zeroUsedPrograms[program] = true;
2001
2097
  glBindAttribLocation(program, index, name);
2002
2098
  };
2003
2099
  var glLinkProgram = _glLinkProgram;
2004
- _glLinkProgram = function(program) {
2100
+ _glLinkProgram = function _glLinkProgram(program) {
2005
2101
  if (!(program in zeroUsedPrograms)) {
2006
2102
  Module.ctx.bindAttribLocation(GL.programs[program], 0, 'a_position');
2007
2103
  }
@@ -2009,11 +2105,13 @@ var LibraryGL = {
2009
2105
  };
2010
2106
 
2011
2107
  var glBindBuffer = _glBindBuffer;
2012
- _glBindBuffer = function(target, buffer) {
2108
+ _glBindBuffer = function _glBindBuffer(target, buffer) {
2013
2109
  glBindBuffer(target, buffer);
2014
2110
  if (target == Module.ctx.ARRAY_BUFFER) {
2015
2111
  if (GLEmulation.currentVao) {
2112
+ #if ASSERTIONS
2016
2113
  assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao');
2114
+ #endif
2017
2115
  GLEmulation.currentVao.arrayBuffer = buffer;
2018
2116
  }
2019
2117
  } else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
@@ -2022,7 +2120,7 @@ var LibraryGL = {
2022
2120
  };
2023
2121
 
2024
2122
  var glGetFloatv = _glGetFloatv;
2025
- _glGetFloatv = function(pname, params) {
2123
+ _glGetFloatv = function _glGetFloatv(pname, params) {
2026
2124
  if (pname == 0x0BA6) { // GL_MODELVIEW_MATRIX
2027
2125
  HEAPF32.set(GL.immediate.matrix['m'], params >> 2);
2028
2126
  } else if (pname == 0x0BA7) { // GL_PROJECTION_MATRIX
@@ -2045,7 +2143,7 @@ var LibraryGL = {
2045
2143
  };
2046
2144
 
2047
2145
  var glHint = _glHint;
2048
- _glHint = function(target, mode) {
2146
+ _glHint = function _glHint(target, mode) {
2049
2147
  if (target == 0x84EF) { // GL_TEXTURE_COMPRESSION_HINT
2050
2148
  return;
2051
2149
  }
@@ -2053,21 +2151,21 @@ var LibraryGL = {
2053
2151
  };
2054
2152
 
2055
2153
  var glEnableVertexAttribArray = _glEnableVertexAttribArray;
2056
- _glEnableVertexAttribArray = function(index) {
2154
+ _glEnableVertexAttribArray = function _glEnableVertexAttribArray(index) {
2057
2155
  glEnableVertexAttribArray(index);
2058
2156
  GLEmulation.enabledVertexAttribArrays[index] = 1;
2059
2157
  if (GLEmulation.currentVao) GLEmulation.currentVao.enabledVertexAttribArrays[index] = 1;
2060
2158
  };
2061
2159
 
2062
2160
  var glDisableVertexAttribArray = _glDisableVertexAttribArray;
2063
- _glDisableVertexAttribArray = function(index) {
2161
+ _glDisableVertexAttribArray = function _glDisableVertexAttribArray(index) {
2064
2162
  glDisableVertexAttribArray(index);
2065
2163
  delete GLEmulation.enabledVertexAttribArrays[index];
2066
2164
  if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledVertexAttribArrays[index];
2067
2165
  };
2068
2166
 
2069
2167
  var glVertexAttribPointer = _glVertexAttribPointer;
2070
- _glVertexAttribPointer = function(index, size, type, normalized, stride, pointer) {
2168
+ _glVertexAttribPointer = function _glVertexAttribPointer(index, size, type, normalized, stride, pointer) {
2071
2169
  glVertexAttribPointer(index, size, type, normalized, stride, pointer);
2072
2170
  if (GLEmulation.currentVao) { // TODO: avoid object creation here? likely not hot though
2073
2171
  GLEmulation.currentVao.vertexAttribPointers[index] = [index, size, type, normalized, stride, pointer];
@@ -2099,9 +2197,6 @@ var LibraryGL = {
2099
2197
  glGetShaderPrecisionFormat__sig: 'v',
2100
2198
  glGetShaderPrecisionFormat: function() { throw 'glGetShaderPrecisionFormat: TODO' },
2101
2199
 
2102
- glShaderBinary__sig: 'v',
2103
- glShaderBinary: function() { throw 'glShaderBinary: TODO' },
2104
-
2105
2200
  glDeleteObject__sig: 'vi',
2106
2201
  glDeleteObject: function(id) {
2107
2202
  if (GL.programs[id]) {
@@ -2113,11 +2208,6 @@ var LibraryGL = {
2113
2208
  }
2114
2209
  },
2115
2210
 
2116
- glReleaseShaderCompiler__sig: 'v',
2117
- glReleaseShaderCompiler: function() {
2118
- // NOP (as allowed by GLES 2.0 spec)
2119
- },
2120
-
2121
2211
  glGetObjectParameteriv__sig: 'viii',
2122
2212
  glGetObjectParameteriv: function(id, type, result) {
2123
2213
  if (GL.programs[id]) {
@@ -2153,7 +2243,9 @@ var LibraryGL = {
2153
2243
 
2154
2244
  glBindProgram__sig: 'vii',
2155
2245
  glBindProgram: function(type, id) {
2246
+ #if ASSERTIONS
2156
2247
  assert(id == 0);
2248
+ #endif
2157
2249
  },
2158
2250
 
2159
2251
  glGetPointerv: function(name, p) {
@@ -2164,8 +2256,13 @@ var LibraryGL = {
2164
2256
  case 0x8090: // GL_COLOR_ARRAY_POINTER
2165
2257
  attribute = GLImmediate.clientAttributes[GLImmediate.COLOR]; break;
2166
2258
  case 0x8092: // GL_TEXTURE_COORD_ARRAY_POINTER
2167
- attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0]; break;
2168
- default: throw 'TODO: glGetPointerv for ' + name;
2259
+ attribute = GLImmediate.clientAttributes[GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture]; break;
2260
+ default:
2261
+ GL.recordError(0x0500/*GL_INVALID_ENUM*/);
2262
+ #if GL_ASSERTIONS
2263
+ Module.printErr('GL_INVALID_ENUM in glGetPointerv: Unsupported name ' + name + '!');
2264
+ #endif
2265
+ return;
2169
2266
  }
2170
2267
  {{{ makeSetValue('p', '0', 'attribute ? attribute.pointer : 0', 'i32') }}};
2171
2268
  },
@@ -2186,14 +2283,14 @@ var LibraryGL = {
2186
2283
  function CNaiveListMap() {
2187
2284
  var list = [];
2188
2285
 
2189
- this.insert = function(key, val) {
2286
+ this.insert = function CNaiveListMap_insert(key, val) {
2190
2287
  if (this.contains(key|0)) return false;
2191
2288
  list.push([key, val]);
2192
2289
  return true;
2193
2290
  };
2194
2291
 
2195
2292
  var __contains_i;
2196
- this.contains = function(key) {
2293
+ this.contains = function CNaiveListMap_contains(key) {
2197
2294
  for (__contains_i = 0; __contains_i < list.length; ++__contains_i) {
2198
2295
  if (list[__contains_i][0] === key) return true;
2199
2296
  }
@@ -2201,7 +2298,7 @@ var LibraryGL = {
2201
2298
  };
2202
2299
 
2203
2300
  var __get_i;
2204
- this.get = function(key) {
2301
+ this.get = function CNaiveListMap_get(key) {
2205
2302
  for (__get_i = 0; __get_i < list.length; ++__get_i) {
2206
2303
  if (list[__get_i][0] === key) return list[__get_i][1];
2207
2304
  }
@@ -2235,7 +2332,7 @@ var LibraryGL = {
2235
2332
  function CNLNode() {
2236
2333
  var map = new CNaiveListMap();
2237
2334
 
2238
- this.child = function(keyFrag) {
2335
+ this.child = function CNLNode_child(keyFrag) {
2239
2336
  if (!map.contains(keyFrag|0)) {
2240
2337
  map.insert(keyFrag|0, new CNLNode());
2241
2338
  }
@@ -2243,11 +2340,11 @@ var LibraryGL = {
2243
2340
  };
2244
2341
 
2245
2342
  this.value = undefined;
2246
- this.get = function() {
2343
+ this.get = function CNLNode_get() {
2247
2344
  return this.value;
2248
2345
  };
2249
2346
 
2250
- this.set = function(val) {
2347
+ this.set = function CNLNode_set(val) {
2251
2348
  this.value = val;
2252
2349
  };
2253
2350
  }
@@ -2255,22 +2352,22 @@ var LibraryGL = {
2255
2352
  function CKeyView(root) {
2256
2353
  var cur;
2257
2354
 
2258
- this.reset = function() {
2355
+ this.reset = function CKeyView_reset() {
2259
2356
  cur = root;
2260
2357
  return this;
2261
2358
  };
2262
2359
  this.reset();
2263
2360
 
2264
- this.next = function(keyFrag) {
2361
+ this.next = function CKeyView_next(keyFrag) {
2265
2362
  cur = cur.child(keyFrag);
2266
2363
  return this;
2267
2364
  };
2268
2365
 
2269
- this.get = function() {
2366
+ this.get = function CKeyView_get() {
2270
2367
  return cur.get();
2271
2368
  };
2272
2369
 
2273
- this.set = function(val) {
2370
+ this.set = function CKeyView_set(val) {
2274
2371
  cur.set(val);
2275
2372
  };
2276
2373
  };
@@ -2278,17 +2375,17 @@ var LibraryGL = {
2278
2375
  var root;
2279
2376
  var staticKeyView;
2280
2377
 
2281
- this.createKeyView = function() {
2378
+ this.createKeyView = function CNLNode_createKeyView() {
2282
2379
  return new CKeyView(root);
2283
2380
  }
2284
2381
 
2285
- this.clear = function() {
2382
+ this.clear = function CNLNode_clear() {
2286
2383
  root = new CNLNode();
2287
2384
  staticKeyView = this.createKeyView();
2288
2385
  };
2289
2386
  this.clear();
2290
2387
 
2291
- this.getStaticKeyView = function() {
2388
+ this.getStaticKeyView = function CNLNode_getStaticKeyView() {
2292
2389
  staticKeyView.reset();
2293
2390
  return staticKeyView;
2294
2391
  };
@@ -2522,32 +2619,85 @@ var LibraryGL = {
2522
2619
  GL_SRC_ALPHA
2523
2620
  ];
2524
2621
 
2622
+ // Map GLenums to small values to efficiently pack the enums to bits for tighter access.
2623
+ this.traverseKey = {
2624
+ // mode
2625
+ 0x1E01 /* GL_REPLACE */: 0,
2626
+ 0x2100 /* GL_MODULATE */: 1,
2627
+ 0x0104 /* GL_ADD */: 2,
2628
+ 0x0BE2 /* GL_BLEND */: 3,
2629
+ 0x2101 /* GL_DECAL */: 4,
2630
+ 0x8570 /* GL_COMBINE */: 5,
2631
+
2632
+ // additional color and alpha combiners
2633
+ 0x84E7 /* GL_SUBTRACT */: 3,
2634
+ 0x8575 /* GL_INTERPOLATE */: 4,
2635
+
2636
+ // color and alpha src
2637
+ 0x1702 /* GL_TEXTURE */: 0,
2638
+ 0x8576 /* GL_CONSTANT */: 1,
2639
+ 0x8577 /* GL_PRIMARY_COLOR */: 2,
2640
+ 0x8578 /* GL_PREVIOUS */: 3,
2641
+
2642
+ // color and alpha op
2643
+ 0x0300 /* GL_SRC_COLOR */: 0,
2644
+ 0x0301 /* GL_ONE_MINUS_SRC_COLOR */: 1,
2645
+ 0x0302 /* GL_SRC_ALPHA */: 2,
2646
+ 0x0300 /* GL_ONE_MINUS_SRC_ALPHA */: 3
2647
+ };
2648
+
2649
+ // The tuple (key0,key1,key2) uniquely identifies the state of the variables in CTexEnv.
2650
+ // -1 on key0 denotes 'the whole cached key is dirty'
2651
+ this.key0 = -1;
2652
+ this.key1 = 0;
2653
+ this.key2 = 0;
2654
+
2655
+ this.computeKey0 = function() {
2656
+ var k = this.traverseKey;
2657
+ var key = k[this.mode] * 1638400; // 6 distinct values.
2658
+ key += k[this.colorCombiner] * 327680; // 5 distinct values.
2659
+ key += k[this.alphaCombiner] * 65536; // 5 distinct values.
2660
+ // The above three fields have 6*5*5=150 distinct values -> 8 bits.
2661
+ key += (this.colorScale-1) * 16384; // 10 bits used.
2662
+ key += (this.alphaScale-1) * 4096; // 12 bits used.
2663
+ key += k[this.colorSrc[0]] * 1024; // 14
2664
+ key += k[this.colorSrc[1]] * 256; // 16
2665
+ key += k[this.colorSrc[2]] * 64; // 18
2666
+ key += k[this.alphaSrc[0]] * 16; // 20
2667
+ key += k[this.alphaSrc[1]] * 4; // 22
2668
+ key += k[this.alphaSrc[2]]; // 24 bits used total.
2669
+ return key;
2670
+ }
2671
+ this.computeKey1 = function() {
2672
+ var k = this.traverseKey;
2673
+ key = k[this.colorOp[0]] * 4096;
2674
+ key += k[this.colorOp[1]] * 1024;
2675
+ key += k[this.colorOp[2]] * 256;
2676
+ key += k[this.alphaOp[0]] * 16;
2677
+ key += k[this.alphaOp[1]] * 4;
2678
+ key += k[this.alphaOp[2]];
2679
+ return key;
2680
+ }
2681
+ // TODO: remove this. The color should not be part of the key!
2682
+ this.computeKey2 = function() {
2683
+ return this.envColor[0] * 16777216 + this.envColor[1] * 65536 + this.envColor[2] * 256 + 1 + this.envColor[3];
2684
+ }
2685
+ this.recomputeKey = function() {
2686
+ this.key0 = this.computeKey0();
2687
+ this.key1 = this.computeKey1();
2688
+ this.key2 = this.computeKey2();
2689
+ }
2690
+ this.invalidateKey = function() {
2691
+ this.key0 = -1; // The key of this texture unit must be recomputed when rendering the next time.
2692
+ GL.immediate.currentRenderer = null; // The currently used renderer must be re-evaluated at next render.
2693
+ }
2525
2694
  this.traverseState = function(keyView) {
2526
- keyView.next(this.mode);
2527
- keyView.next(this.colorCombiner);
2528
- keyView.next(this.alphaCombiner);
2529
- keyView.next(this.colorCombiner);
2530
- keyView.next(this.alphaScale);
2531
- keyView.next(this.envColor[0]);
2532
- keyView.next(this.envColor[1]);
2533
- keyView.next(this.envColor[2]);
2534
- keyView.next(this.envColor[3]);
2535
-
2536
- keyView.next(this.colorSrc[0]);
2537
- keyView.next(this.colorSrc[1]);
2538
- keyView.next(this.colorSrc[2]);
2539
-
2540
- keyView.next(this.alphaSrc[0]);
2541
- keyView.next(this.alphaSrc[1]);
2542
- keyView.next(this.alphaSrc[2]);
2543
-
2544
- keyView.next(this.colorOp[0]);
2545
- keyView.next(this.colorOp[1]);
2546
- keyView.next(this.colorOp[2]);
2547
-
2548
- keyView.next(this.alphaOp[0]);
2549
- keyView.next(this.alphaOp[1]);
2550
- keyView.next(this.alphaOp[2]);
2695
+ if (this.key0 == -1) {
2696
+ this.recomputeKey();
2697
+ }
2698
+ keyView.next(this.key0);
2699
+ keyView.next(this.key1);
2700
+ keyView.next(this.key2);
2551
2701
  };
2552
2702
  }
2553
2703
 
@@ -2558,7 +2708,7 @@ var LibraryGL = {
2558
2708
  this.enabled_tex3D = false;
2559
2709
  this.enabled_texCube = false;
2560
2710
 
2561
- this.traverseState = function(keyView) {
2711
+ this.traverseState = function CTexUnit_traverseState(keyView) {
2562
2712
  var texUnitType = this.getTexType();
2563
2713
  keyView.next(texUnitType);
2564
2714
  if (!texUnitType) return;
@@ -2567,11 +2717,11 @@ var LibraryGL = {
2567
2717
  };
2568
2718
 
2569
2719
  // Class impls:
2570
- CTexUnit.prototype.enabled = function() {
2720
+ CTexUnit.prototype.enabled = function CTexUnit_enabled() {
2571
2721
  return this.getTexType() != 0;
2572
2722
  }
2573
2723
 
2574
- CTexUnit.prototype.genPassLines = function(passOutputVar, passInputVar, texUnitID) {
2724
+ CTexUnit.prototype.genPassLines = function CTexUnit_genPassLines(passOutputVar, passInputVar, texUnitID) {
2575
2725
  if (!this.enabled()) {
2576
2726
  return ["vec4 " + passOutputVar + " = " + passInputVar + ";"];
2577
2727
  }
@@ -2579,7 +2729,7 @@ var LibraryGL = {
2579
2729
  return this.env.genPassLines(passOutputVar, passInputVar, texUnitID);
2580
2730
  }
2581
2731
 
2582
- CTexUnit.prototype.getTexType = function() {
2732
+ CTexUnit.prototype.getTexType = function CTexUnit_getTexType() {
2583
2733
  if (this.enabled_texCube) {
2584
2734
  return GL_TEXTURE_CUBE_MAP;
2585
2735
  } else if (this.enabled_tex3D) {
@@ -2592,7 +2742,7 @@ var LibraryGL = {
2592
2742
  return 0;
2593
2743
  }
2594
2744
 
2595
- CTexEnv.prototype.genPassLines = function(passOutputVar, passInputVar, texUnitID) {
2745
+ CTexEnv.prototype.genPassLines = function CTexEnv_genPassLines(passOutputVar, passInputVar, texUnitID) {
2596
2746
  switch (this.mode) {
2597
2747
  case GL_REPLACE: {
2598
2748
  /* RGB:
@@ -2714,9 +2864,9 @@ var LibraryGL = {
2714
2864
  return Abort_NoSupport("Unsupported TexEnv mode: 0x" + this.mode.toString(16));
2715
2865
  }
2716
2866
 
2717
- CTexEnv.prototype.genCombinerLines = function(isColor, outputVar,
2718
- passInputVar, texUnitID,
2719
- combiner, srcArr, opArr)
2867
+ CTexEnv.prototype.genCombinerLines = function CTexEnv_getCombinerLines(isColor, outputVar,
2868
+ passInputVar, texUnitID,
2869
+ combiner, srcArr, opArr)
2720
2870
  {
2721
2871
  var argsNeeded = null;
2722
2872
  switch (combiner) {
@@ -2832,9 +2982,9 @@ var LibraryGL = {
2832
2982
  } else if (gl) {
2833
2983
  maxTexUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
2834
2984
  }
2835
-
2985
+ #if ASSERTIONS
2836
2986
  assert(maxTexUnits > 0);
2837
-
2987
+ #endif
2838
2988
  s_texUnits = [];
2839
2989
  for (var i = 0; i < maxTexUnits; i++) {
2840
2990
  s_texUnits.push(new CTexUnit());
@@ -2893,9 +3043,10 @@ var LibraryGL = {
2893
3043
  },
2894
3044
 
2895
3045
  getTexUnitType: function(texUnitID) {
3046
+ #if ASSERTIONS
2896
3047
  assert(texUnitID >= 0 &&
2897
3048
  texUnitID < s_texUnits.length);
2898
-
3049
+ #endif
2899
3050
  return s_texUnits[texUnitID].getTexType();
2900
3051
  },
2901
3052
 
@@ -2908,16 +3059,28 @@ var LibraryGL = {
2908
3059
  var cur = getCurTexUnit();
2909
3060
  switch (cap) {
2910
3061
  case GL_TEXTURE_1D:
2911
- cur.enabled_tex1D = true;
3062
+ if (!cur.enabled_tex1D) {
3063
+ GL.immediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
3064
+ cur.enabled_tex1D = true;
3065
+ }
2912
3066
  break;
2913
3067
  case GL_TEXTURE_2D:
2914
- cur.enabled_tex2D = true;
3068
+ if (!cur.enabled_tex2D) {
3069
+ GL.immediate.currentRenderer = null;
3070
+ cur.enabled_tex2D = true;
3071
+ }
2915
3072
  break;
2916
3073
  case GL_TEXTURE_3D:
2917
- cur.enabled_tex3D = true;
3074
+ if (!cur.enabled_tex3D) {
3075
+ GL.immediate.currentRenderer = null;
3076
+ cur.enabled_tex3D = true;
3077
+ }
2918
3078
  break;
2919
3079
  case GL_TEXTURE_CUBE_MAP:
2920
- cur.enabled_texCube = true;
3080
+ if (!cur.enabled_texCube) {
3081
+ GL.immediate.currentRenderer = null;
3082
+ cur.enabled_texCube = true;
3083
+ }
2921
3084
  break;
2922
3085
  }
2923
3086
  },
@@ -2926,16 +3089,28 @@ var LibraryGL = {
2926
3089
  var cur = getCurTexUnit();
2927
3090
  switch (cap) {
2928
3091
  case GL_TEXTURE_1D:
2929
- cur.enabled_tex1D = false;
3092
+ if (cur.enabled_tex1D) {
3093
+ GL.immediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
3094
+ cur.enabled_tex1D = false;
3095
+ }
2930
3096
  break;
2931
3097
  case GL_TEXTURE_2D:
2932
- cur.enabled_tex2D = false;
3098
+ if (cur.enabled_tex2D) {
3099
+ GL.immediate.currentRenderer = null;
3100
+ cur.enabled_tex2D = false;
3101
+ }
2933
3102
  break;
2934
3103
  case GL_TEXTURE_3D:
2935
- cur.enabled_tex3D = false;
3104
+ if (cur.enabled_tex3D) {
3105
+ GL.immediate.currentRenderer = null;
3106
+ cur.enabled_tex3D = false;
3107
+ }
2936
3108
  break;
2937
3109
  case GL_TEXTURE_CUBE_MAP:
2938
- cur.enabled_texCube = false;
3110
+ if (cur.enabled_texCube) {
3111
+ GL.immediate.currentRenderer = null;
3112
+ cur.enabled_texCube = false;
3113
+ }
2939
3114
  break;
2940
3115
  }
2941
3116
  },
@@ -2947,10 +3122,16 @@ var LibraryGL = {
2947
3122
  var env = getCurTexUnit().env;
2948
3123
  switch (pname) {
2949
3124
  case GL_RGB_SCALE:
2950
- env.colorScale = param;
3125
+ if (env.colorScale != param) {
3126
+ env.invalidateKey(); // We changed FFP emulation renderer state.
3127
+ env.colorScale = param;
3128
+ }
2951
3129
  break;
2952
3130
  case GL_ALPHA_SCALE:
2953
- env.alphaScale = param;
3131
+ if (env.alphaScale != param) {
3132
+ env.invalidateKey();
3133
+ env.alphaScale = param;
3134
+ }
2954
3135
  break;
2955
3136
 
2956
3137
  default:
@@ -2965,61 +3146,112 @@ var LibraryGL = {
2965
3146
  var env = getCurTexUnit().env;
2966
3147
  switch (pname) {
2967
3148
  case GL_TEXTURE_ENV_MODE:
2968
- env.mode = param;
3149
+ if (env.mode != param) {
3150
+ env.invalidateKey(); // We changed FFP emulation renderer state.
3151
+ env.mode = param;
3152
+ }
2969
3153
  break;
2970
3154
 
2971
3155
  case GL_COMBINE_RGB:
2972
- env.colorCombiner = param;
3156
+ if (env.colorCombiner != param) {
3157
+ env.invalidateKey();
3158
+ env.colorCombiner = param;
3159
+ }
2973
3160
  break;
2974
3161
  case GL_COMBINE_ALPHA:
2975
- env.alphaCombiner = param;
3162
+ if (env.alphaCombiner != param) {
3163
+ env.invalidateKey();
3164
+ env.alphaCombiner = param;
3165
+ }
2976
3166
  break;
2977
3167
 
2978
3168
  case GL_SRC0_RGB:
2979
- env.colorSrc[0] = param;
3169
+ if (env.colorSrc[0] != param) {
3170
+ env.invalidateKey();
3171
+ env.colorSrc[0] = param;
3172
+ }
2980
3173
  break;
2981
3174
  case GL_SRC1_RGB:
2982
- env.colorSrc[1] = param;
3175
+ if (env.colorSrc[1] != param) {
3176
+ env.invalidateKey();
3177
+ env.colorSrc[1] = param;
3178
+ }
2983
3179
  break;
2984
3180
  case GL_SRC2_RGB:
2985
- env.colorSrc[2] = param;
3181
+ if (env.colorSrc[2] != param) {
3182
+ env.invalidateKey();
3183
+ env.colorSrc[2] = param;
3184
+ }
2986
3185
  break;
2987
3186
 
2988
3187
  case GL_SRC0_ALPHA:
2989
- env.alphaSrc[0] = param;
3188
+ if (env.alphaSrc[0] != param) {
3189
+ env.invalidateKey();
3190
+ env.alphaSrc[0] = param;
3191
+ }
2990
3192
  break;
2991
3193
  case GL_SRC1_ALPHA:
2992
- env.alphaSrc[1] = param;
3194
+ if (env.alphaSrc[1] != param) {
3195
+ env.invalidateKey();
3196
+ env.alphaSrc[1] = param;
3197
+ }
2993
3198
  break;
2994
3199
  case GL_SRC2_ALPHA:
2995
- env.alphaSrc[2] = param;
3200
+ if (env.alphaSrc[2] != param) {
3201
+ env.invalidateKey();
3202
+ env.alphaSrc[2] = param;
3203
+ }
2996
3204
  break;
2997
3205
 
2998
3206
  case GL_OPERAND0_RGB:
2999
- env.colorOp[0] = param;
3207
+ if (env.colorOp[0] != param) {
3208
+ env.invalidateKey();
3209
+ env.colorOp[0] = param;
3210
+ }
3000
3211
  break;
3001
3212
  case GL_OPERAND1_RGB:
3002
- env.colorOp[1] = param;
3213
+ if (env.colorOp[1] != param) {
3214
+ env.invalidateKey();
3215
+ env.colorOp[1] = param;
3216
+ }
3003
3217
  break;
3004
3218
  case GL_OPERAND2_RGB:
3005
- env.colorOp[2] = param;
3219
+ if (env.colorOp[2] != param) {
3220
+ env.invalidateKey();
3221
+ env.colorOp[2] = param;
3222
+ }
3006
3223
  break;
3007
3224
 
3008
3225
  case GL_OPERAND0_ALPHA:
3009
- env.alphaOp[0] = param;
3226
+ if (env.alphaOp[0] != param) {
3227
+ env.invalidateKey();
3228
+ env.alphaOp[0] = param;
3229
+ }
3010
3230
  break;
3011
3231
  case GL_OPERAND1_ALPHA:
3012
- env.alphaOp[1] = param;
3232
+ if (env.alphaOp[1] != param) {
3233
+ env.invalidateKey();
3234
+ env.alphaOp[1] = param;
3235
+ }
3013
3236
  break;
3014
3237
  case GL_OPERAND2_ALPHA:
3015
- env.alphaOp[2] = param;
3238
+ if (env.alphaOp[2] != param) {
3239
+ env.invalidateKey();
3240
+ env.alphaOp[2] = param;
3241
+ }
3016
3242
  break;
3017
3243
 
3018
3244
  case GL_RGB_SCALE:
3019
- env.colorScale = param;
3245
+ if (env.colorScale != param) {
3246
+ env.invalidateKey();
3247
+ env.colorScale = param;
3248
+ }
3020
3249
  break;
3021
3250
  case GL_ALPHA_SCALE:
3022
- env.alphaScale = param;
3251
+ if (env.alphaScale != param) {
3252
+ env.invalidateKey();
3253
+ env.alphaScale = param;
3254
+ }
3023
3255
  break;
3024
3256
 
3025
3257
  default:
@@ -3035,7 +3267,10 @@ var LibraryGL = {
3035
3267
  case GL_TEXTURE_ENV_COLOR: {
3036
3268
  for (var i = 0; i < 4; i++) {
3037
3269
  var param = {{{ makeGetValue('params', 'i*4', 'float') }}};
3038
- env.envColor[i] = param;
3270
+ if (env.envColor[i] != param) {
3271
+ env.invalidateKey(); // We changed FFP emulation renderer state.
3272
+ env.envColor[i] = param;
3273
+ }
3039
3274
  }
3040
3275
  break
3041
3276
  }
@@ -3075,26 +3310,21 @@ var LibraryGL = {
3075
3310
  NORMAL: 1,
3076
3311
  COLOR: 2,
3077
3312
  TEXTURE0: 3,
3078
- TEXTURE1: 4,
3079
- TEXTURE2: 5,
3080
- TEXTURE3: 6,
3081
- TEXTURE4: 7,
3082
- TEXTURE5: 8,
3083
- TEXTURE6: 9,
3084
- NUM_ATTRIBUTES: 10, // Overwritten in init().
3085
- MAX_TEXTURES: 7, // Overwritten in init().
3313
+ NUM_ATTRIBUTES: -1, // Initialized in GL emulation init().
3314
+ MAX_TEXTURES: -1, // Initialized in GL emulation init().
3086
3315
 
3087
3316
  totalEnabledClientAttributes: 0,
3088
3317
  enabledClientAttributes: [0, 0],
3089
3318
  clientAttributes: [], // raw data, including possible unneeded ones
3090
3319
  liveClientAttributes: [], // the ones actually alive in the current computation, sorted
3320
+ currentRenderer: null, // Caches the currently active FFP emulation renderer, so that it does not have to be re-looked up unless relevant state changes.
3091
3321
  modifiedClientAttributes: false,
3092
3322
  clientActiveTexture: 0,
3093
3323
  clientColor: null,
3094
3324
  usedTexUnitList: [],
3095
3325
  fixedFunctionProgram: null,
3096
3326
 
3097
- setClientAttribute: function(name, size, type, stride, pointer) {
3327
+ setClientAttribute: function setClientAttribute(name, size, type, stride, pointer) {
3098
3328
  var attrib = this.clientAttributes[name];
3099
3329
  if (!attrib) {
3100
3330
  for (var i = 0; i <= name; i++) { // keep flat
@@ -3121,7 +3351,7 @@ var LibraryGL = {
3121
3351
  },
3122
3352
 
3123
3353
  // Renderers
3124
- addRendererComponent: function(name, size, type) {
3354
+ addRendererComponent: function addRendererComponent(name, size, type) {
3125
3355
  if (!this.rendererComponents[name]) {
3126
3356
  this.rendererComponents[name] = 1;
3127
3357
  #if ASSERTIONS
@@ -3137,13 +3367,18 @@ var LibraryGL = {
3137
3367
  }
3138
3368
  },
3139
3369
 
3140
- disableBeginEndClientAttributes: function() {
3370
+ disableBeginEndClientAttributes: function disableBeginEndClientAttributes() {
3141
3371
  for (var i = 0; i < this.NUM_ATTRIBUTES; i++) {
3142
3372
  if (this.rendererComponents[i]) this.enabledClientAttributes[i] = false;
3143
3373
  }
3144
3374
  },
3145
3375
 
3146
- getRenderer: function() {
3376
+ getRenderer: function getRenderer() {
3377
+ // If no FFP state has changed that would have forced to re-evaluate which FFP emulation shader to use,
3378
+ // we have the currently used renderer in cache, and can immediately return that.
3379
+ if (this.currentRenderer) {
3380
+ return this.currentRenderer;
3381
+ }
3147
3382
  // return a renderer object given the liveClientAttributes
3148
3383
  // we maintain a cache of renderers, optimized to not generate garbage
3149
3384
  var attributes = GL.immediate.liveClientAttributes;
@@ -3152,10 +3387,11 @@ var LibraryGL = {
3152
3387
  var keyView = cacheMap.getStaticKeyView().reset();
3153
3388
 
3154
3389
  // By attrib state:
3390
+ var enabledAttributesKey = 0;
3155
3391
  for (var i = 0; i < attributes.length; i++) {
3156
- var attribute = attributes[i];
3157
- keyView.next(attribute.name).next(attribute.size).next(attribute.type);
3392
+ enabledAttributesKey |= 1 << attributes[i].name;
3158
3393
  }
3394
+ keyView.next(enabledAttributesKey);
3159
3395
 
3160
3396
  // By fog state:
3161
3397
  var fogParam = 0;
@@ -3181,45 +3417,41 @@ var LibraryGL = {
3181
3417
  }
3182
3418
 
3183
3419
  // If we don't already have it, create it.
3184
- if (!keyView.get()) {
3420
+ var renderer = keyView.get();
3421
+ if (!renderer) {
3185
3422
  #if GL_DEBUG
3186
3423
  Module.printErr('generating renderer for ' + JSON.stringify(attributes));
3187
3424
  #endif
3188
- keyView.set(this.createRenderer());
3425
+ renderer = this.createRenderer();
3426
+ this.currentRenderer = renderer;
3427
+ keyView.set(renderer);
3428
+ return renderer;
3189
3429
  }
3190
- return keyView.get();
3430
+ this.currentRenderer = renderer; // Cache the currently used renderer, so later lookups without state changes can get this fast.
3431
+ return renderer;
3191
3432
  },
3192
3433
 
3193
- createRenderer: function(renderer) {
3434
+ createRenderer: function createRenderer(renderer) {
3194
3435
  var useCurrProgram = !!GL.currProgram;
3195
- var hasTextures = false, textureSizes = [], textureTypes = [];
3436
+ var hasTextures = false;
3196
3437
  for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
3197
3438
  var texAttribName = GL.immediate.TEXTURE0 + i;
3198
3439
  if (!GL.immediate.enabledClientAttributes[texAttribName])
3199
3440
  continue;
3200
3441
 
3442
+ #if ASSERTIONS
3201
3443
  if (!useCurrProgram) {
3202
- assert(GL.immediate.TexEnvJIT.getTexUnitType(i) != 0, "GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline.");
3444
+ if (GL.immediate.TexEnvJIT.getTexUnitType(i) == 0) {
3445
+ Runtime.warnOnce("GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline.");
3446
+ }
3203
3447
  }
3448
+ #endif
3204
3449
 
3205
- textureSizes[i] = GL.immediate.clientAttributes[texAttribName].size;
3206
- textureTypes[i] = GL.immediate.clientAttributes[texAttribName].type;
3207
3450
  hasTextures = true;
3208
3451
  }
3209
- var positionSize = GL.immediate.clientAttributes[GL.immediate.VERTEX].size;
3210
- var positionType = GL.immediate.clientAttributes[GL.immediate.VERTEX].type;
3211
- var colorSize = 0, colorType;
3212
- if (GL.immediate.enabledClientAttributes[GL.immediate.COLOR]) {
3213
- colorSize = GL.immediate.clientAttributes[GL.immediate.COLOR].size;
3214
- colorType = GL.immediate.clientAttributes[GL.immediate.COLOR].type;
3215
- }
3216
- var normalSize = 0, normalType;
3217
- if (GL.immediate.enabledClientAttributes[GL.immediate.NORMAL]) {
3218
- normalSize = GL.immediate.clientAttributes[GL.immediate.NORMAL].size;
3219
- normalType = GL.immediate.clientAttributes[GL.immediate.NORMAL].type;
3220
- }
3452
+
3221
3453
  var ret = {
3222
- init: function() {
3454
+ init: function init() {
3223
3455
  // For fixed-function shader generation.
3224
3456
  var uTexUnitPrefix = 'u_texUnit';
3225
3457
  var aTexCoordPrefix = 'a_texCoord';
@@ -3352,10 +3584,25 @@ var LibraryGL = {
3352
3584
  this.program = Module.ctx.createProgram();
3353
3585
  Module.ctx.attachShader(this.program, this.vertexShader);
3354
3586
  Module.ctx.attachShader(this.program, this.fragmentShader);
3355
- Module.ctx.bindAttribLocation(this.program, 0, 'a_position');
3587
+
3588
+ // As optimization, bind all attributes to prespecified locations, so that the FFP emulation
3589
+ // code can submit attributes to any generated FFP shader without having to examine each shader in turn.
3590
+ // These prespecified locations are only assumed if GL_FFP_ONLY is specified, since user could also create their
3591
+ // own shaders that didn't have attributes in the same locations.
3592
+ Module.ctx.bindAttribLocation(this.program, GL.immediate.VERTEX, 'a_position');
3593
+ Module.ctx.bindAttribLocation(this.program, GL.immediate.COLOR, 'a_color');
3594
+ Module.ctx.bindAttribLocation(this.program, GL.immediate.NORMAL, 'a_normal');
3595
+ for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
3596
+ Module.ctx.bindAttribLocation(this.program, GL.immediate.TEXTURE0 + i, 'a_texCoord'+i);
3597
+ Module.ctx.bindAttribLocation(this.program, GL.immediate.TEXTURE0 + i, aTexCoordPrefix+i);
3598
+ }
3356
3599
  Module.ctx.linkProgram(this.program);
3357
3600
  }
3358
3601
 
3602
+ // Stores a map that remembers which matrix uniforms are up-to-date in this FFP renderer, so they don't need to be resubmitted
3603
+ // each time we render with this program.
3604
+ this.textureMatrixVersion = {};
3605
+
3359
3606
  this.positionLocation = Module.ctx.getAttribLocation(this.program, 'a_position');
3360
3607
 
3361
3608
  this.texCoordLocations = [];
@@ -3398,7 +3645,9 @@ var LibraryGL = {
3398
3645
  this.projectionLocation = Module.ctx.getUniformLocation(this.program, 'u_projection');
3399
3646
 
3400
3647
  this.hasTextures = hasTextures;
3401
- this.hasNormal = normalSize > 0 && this.normalLocation >= 0;
3648
+ this.hasNormal = GL.immediate.enabledClientAttributes[GL.immediate.NORMAL] &&
3649
+ GL.immediate.clientAttributes[GL.immediate.NORMAL].size > 0 &&
3650
+ this.normalLocation >= 0;
3402
3651
  this.hasColor = (this.colorLocation === 0) || this.colorLocation > 0;
3403
3652
 
3404
3653
  this.floatType = Module.ctx.FLOAT; // minor optimization
@@ -3411,23 +3660,25 @@ var LibraryGL = {
3411
3660
  this.fogScaleLocation || this.fogDensityLocation);
3412
3661
  },
3413
3662
 
3414
- prepare: function() {
3663
+ prepare: function prepare() {
3415
3664
  // Calculate the array buffer
3416
3665
  var arrayBuffer;
3417
3666
  if (!GL.currArrayBuffer) {
3418
3667
  var start = GL.immediate.firstVertex*GL.immediate.stride;
3419
3668
  var end = GL.immediate.lastVertex*GL.immediate.stride;
3669
+ #if ASSERTIONS
3420
3670
  assert(end <= GL.MAX_TEMP_BUFFER_SIZE, 'too much vertex data');
3671
+ #endif
3421
3672
  arrayBuffer = GL.tempVertexBuffers[GL.tempBufferIndexLookup[end]];
3422
3673
  // TODO: consider using the last buffer we bound, if it was larger. downside is larger buffer, but we might avoid rebinding and preparing
3423
3674
  } else {
3424
3675
  arrayBuffer = GL.currArrayBuffer;
3425
3676
  }
3426
3677
 
3678
+ #if GL_UNSAFE_OPTS
3427
3679
  // If the array buffer is unchanged and the renderer as well, then we can avoid all the work here
3428
3680
  // XXX We use some heuristics here, and this may not work in all cases. Try disabling GL_UNSAFE_OPTS if you
3429
3681
  // have odd glitches
3430
- #if GL_UNSAFE_OPTS
3431
3682
  var lastRenderer = GL.immediate.lastRenderer;
3432
3683
  var canSkip = this == lastRenderer &&
3433
3684
  arrayBuffer == GL.immediate.lastArrayBuffer &&
@@ -3462,62 +3713,105 @@ var LibraryGL = {
3462
3713
  GL.immediate.fixedFunctionProgram = this.program;
3463
3714
  }
3464
3715
 
3465
- if (this.modelViewLocation) Module.ctx.uniformMatrix4fv(this.modelViewLocation, false, GL.immediate.matrix['m']);
3466
- if (this.projectionLocation) Module.ctx.uniformMatrix4fv(this.projectionLocation, false, GL.immediate.matrix['p']);
3716
+ if (this.modelViewLocation && this.modelViewMatrixVersion != GL.immediate.matrixVersion['m']) {
3717
+ this.modelViewMatrixVersion = GL.immediate.matrixVersion['m'];
3718
+ Module.ctx.uniformMatrix4fv(this.modelViewLocation, false, GL.immediate.matrix['m']);
3719
+ }
3720
+ if (this.projectionLocation && this.projectionMatrixVersion != GL.immediate.matrixVersion['p']) {
3721
+ this.projectionMatrixVersion = GL.immediate.matrixVersion['p'];
3722
+ Module.ctx.uniformMatrix4fv(this.projectionLocation, false, GL.immediate.matrix['p']);
3723
+ }
3467
3724
 
3468
3725
  var clientAttributes = GL.immediate.clientAttributes;
3726
+ var posAttr = clientAttributes[GL.immediate.VERTEX];
3469
3727
 
3470
3728
  #if GL_ASSERTIONS
3471
- GL.validateVertexAttribPointer(positionSize, positionType, GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
3729
+ GL.validateVertexAttribPointer(posAttr.size, posAttr.type, GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
3472
3730
  #endif
3473
- Module.ctx.vertexAttribPointer(this.positionLocation, positionSize, positionType, false,
3474
- GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
3731
+
3732
+ #if GL_FFP_ONLY
3733
+ if (!GL.currArrayBuffer) {
3734
+ Module.ctx.vertexAttribPointer(GL.immediate.VERTEX, posAttr.size, posAttr.type, false, GL.immediate.stride, posAttr.offset);
3735
+ GL.enableVertexAttribArray(GL.immediate.VERTEX);
3736
+ if (this.hasNormal) {
3737
+ var normalAttr = clientAttributes[GL.immediate.NORMAL];
3738
+ Module.ctx.vertexAttribPointer(GL.immediate.NORMAL, normalAttr.size, normalAttr.type, true, GL.immediate.stride, normalAttr.offset);
3739
+ GL.enableVertexAttribArray(GL.immediate.NORMAL);
3740
+ }
3741
+ }
3742
+ #else
3743
+ Module.ctx.vertexAttribPointer(this.positionLocation, posAttr.size, posAttr.type, false, GL.immediate.stride, posAttr.offset);
3475
3744
  Module.ctx.enableVertexAttribArray(this.positionLocation);
3745
+ if (this.hasNormal) {
3746
+ var normalAttr = clientAttributes[GL.immediate.NORMAL];
3747
+ #if GL_ASSERTIONS
3748
+ GL.validateVertexAttribPointer(normalAttr.size, normalAttr.type, GL.immediate.stride, normalAttr.offset);
3749
+ #endif
3750
+ Module.ctx.vertexAttribPointer(this.normalLocation, normalAttr.size, normalAttr.type, true, GL.immediate.stride, normalAttr.offset);
3751
+ Module.ctx.enableVertexAttribArray(this.normalLocation);
3752
+ }
3753
+ #endif
3476
3754
  if (this.hasTextures) {
3477
- //for (var i = 0; i < this.usedTexUnitList.length; i++) {
3478
- // var texUnitID = this.usedTexUnitList[i];
3479
3755
  for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
3480
- var texUnitID = i;
3481
- var attribLoc = this.texCoordLocations[texUnitID];
3756
+ #if GL_FFP_ONLY
3757
+ if (!GL.currArrayBuffer) {
3758
+ var attribLoc = GL.immediate.TEXTURE0+i;
3759
+ var texAttr = clientAttributes[attribLoc];
3760
+ if (texAttr.size) {
3761
+ Module.ctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GL.immediate.stride, texAttr.offset);
3762
+ GL.enableVertexAttribArray(attribLoc);
3763
+ } else {
3764
+ // These two might be dangerous, but let's try them.
3765
+ Module.ctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1);
3766
+ GL.disableVertexAttribArray(attribLoc);
3767
+ }
3768
+ }
3769
+ #else
3770
+ var attribLoc = this.texCoordLocations[i];
3482
3771
  if (attribLoc === undefined || attribLoc < 0) continue;
3772
+ var texAttr = clientAttributes[GL.immediate.TEXTURE0+i];
3483
3773
 
3484
- if (texUnitID < textureSizes.length && textureSizes[texUnitID]) {
3774
+ if (texAttr.size) {
3485
3775
  #if GL_ASSERTIONS
3486
- GL.validateVertexAttribPointer(textureSizes[texUnitID], textureTypes[texUnitID], GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset);
3776
+ GL.validateVertexAttribPointer(texAttr.size, texAttr.type, GL.immediate.stride, texAttr.offset);
3487
3777
  #endif
3488
- Module.ctx.vertexAttribPointer(attribLoc, textureSizes[texUnitID], textureTypes[texUnitID], false,
3489
- GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset);
3778
+ Module.ctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GL.immediate.stride, texAttr.offset);
3490
3779
  Module.ctx.enableVertexAttribArray(attribLoc);
3491
3780
  } else {
3492
3781
  // These two might be dangerous, but let's try them.
3493
3782
  Module.ctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1);
3494
3783
  Module.ctx.disableVertexAttribArray(attribLoc);
3495
3784
  }
3496
- }
3497
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
3498
- if (this.textureMatrixLocations[i]) { // XXX might we need this even without the condition we are currently in?
3499
- Module.ctx.uniformMatrix4fv(this.textureMatrixLocations[i], false, GL.immediate.matrix['t' + i]);
3785
+ #endif
3786
+ var t = 't'+i;
3787
+ if (this.textureMatrixLocations[i] && this.textureMatrixVersion[t] != GL.immediate.matrixVersion[t]) { // XXX might we need this even without the condition we are currently in?
3788
+ this.textureMatrixVersion[t] = GL.immediate.matrixVersion[t];
3789
+ Module.ctx.uniformMatrix4fv(this.textureMatrixLocations[i], false, GL.immediate.matrix[t]);
3500
3790
  }
3501
3791
  }
3502
3792
  }
3503
- if (colorSize) {
3793
+ if (GL.immediate.enabledClientAttributes[GL.immediate.COLOR]) {
3794
+ var colorAttr = clientAttributes[GL.immediate.COLOR];
3504
3795
  #if GL_ASSERTIONS
3505
- GL.validateVertexAttribPointer(colorSize, colorType, GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset);
3796
+ GL.validateVertexAttribPointer(colorAttr.size, colorAttr.type, GL.immediate.stride, colorAttr.offset);
3506
3797
  #endif
3507
- Module.ctx.vertexAttribPointer(this.colorLocation, colorSize, colorType, true,
3508
- GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset);
3798
+ #if GL_FFP_ONLY
3799
+ if (!GL.currArrayBuffer) {
3800
+ Module.ctx.vertexAttribPointer(GL.immediate.COLOR, colorAttr.size, colorAttr.type, true, GL.immediate.stride, colorAttr.offset);
3801
+ GL.enableVertexAttribArray(GL.immediate.COLOR);
3802
+ }
3803
+ #else
3804
+ Module.ctx.vertexAttribPointer(this.colorLocation, colorAttr.size, colorAttr.type, true, GL.immediate.stride, colorAttr.offset);
3509
3805
  Module.ctx.enableVertexAttribArray(this.colorLocation);
3806
+ #endif
3510
3807
  } else if (this.hasColor) {
3808
+ #if GL_FFP_ONLY
3809
+ GL.disableVertexAttribArray(GL.immediate.COLOR);
3810
+ Module.ctx.vertexAttrib4fv(GL.immediate.COLOR, GL.immediate.clientColor);
3811
+ #else
3511
3812
  Module.ctx.disableVertexAttribArray(this.colorLocation);
3512
3813
  Module.ctx.vertexAttrib4fv(this.colorLocation, GL.immediate.clientColor);
3513
- }
3514
- if (this.hasNormal) {
3515
- #if GL_ASSERTIONS
3516
- GL.validateVertexAttribPointer(normalSize, normalType, GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset);
3517
3814
  #endif
3518
- Module.ctx.vertexAttribPointer(this.normalLocation, normalSize, normalType, true,
3519
- GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset);
3520
- Module.ctx.enableVertexAttribArray(this.normalLocation);
3521
3815
  }
3522
3816
  if (this.hasFog) {
3523
3817
  if (this.fogColorLocation) Module.ctx.uniform4fv(this.fogColorLocation, GLEmulation.fogColor);
@@ -3527,11 +3821,12 @@ var LibraryGL = {
3527
3821
  }
3528
3822
  },
3529
3823
 
3530
- cleanup: function() {
3824
+ cleanup: function cleanup() {
3825
+ #if !GL_FFP_ONLY
3531
3826
  Module.ctx.disableVertexAttribArray(this.positionLocation);
3532
3827
  if (this.hasTextures) {
3533
- for (var i = 0; i < textureSizes.length; i++) {
3534
- if (textureSizes[i] && this.texCoordLocations[i] >= 0) {
3828
+ for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
3829
+ if (GL.immediate.enabledClientAttributes[GL.immediate.TEXTURE0+i] && this.texCoordLocations[i] >= 0) {
3535
3830
  Module.ctx.disableVertexAttribArray(this.texCoordLocations[i]);
3536
3831
  }
3537
3832
  }
@@ -3555,6 +3850,7 @@ var LibraryGL = {
3555
3850
  GL.immediate.lastProgram = null;
3556
3851
  #endif
3557
3852
  GL.immediate.matricesModified = true;
3853
+ #endif
3558
3854
  }
3559
3855
  };
3560
3856
  ret.init();
@@ -3565,7 +3861,7 @@ var LibraryGL = {
3565
3861
  // Replace some functions with immediate-mode aware versions. If there are no client
3566
3862
  // attributes enabled, and we use webgl-friendly modes (no GL_QUADS), then no need
3567
3863
  // for emulation
3568
- _glDrawArrays = function(mode, first, count) {
3864
+ _glDrawArrays = function _glDrawArrays(mode, first, count) {
3569
3865
  if (GL.immediate.totalEnabledClientAttributes == 0 && mode <= 6) {
3570
3866
  Module.ctx.drawArrays(mode, first, count);
3571
3867
  return;
@@ -3581,15 +3877,15 @@ var LibraryGL = {
3581
3877
  GL.immediate.mode = -1;
3582
3878
  };
3583
3879
 
3584
- _glDrawElements = function(mode, count, type, indices, start, end) { // start, end are given if we come from glDrawRangeElements
3880
+ _glDrawElements = function _glDrawElements(mode, count, type, indices, start, end) { // start, end are given if we come from glDrawRangeElements
3585
3881
  if (GL.immediate.totalEnabledClientAttributes == 0 && mode <= 6 && GL.currElementArrayBuffer) {
3586
3882
  Module.ctx.drawElements(mode, count, type, indices);
3587
3883
  return;
3588
3884
  }
3885
+ #if ASSERTIONS
3589
3886
  if (!GL.currElementArrayBuffer) {
3590
3887
  assert(type == Module.ctx.UNSIGNED_SHORT); // We can only emulate buffers of this kind, for now
3591
3888
  }
3592
- #if ASSERTIONS
3593
3889
  console.log("DrawElements doesn't actually prepareClientAttributes properly.");
3594
3890
  #endif
3595
3891
  GL.immediate.prepareClientAttributes(count, false);
@@ -3621,43 +3917,43 @@ var LibraryGL = {
3621
3917
  }
3622
3918
 
3623
3919
  var glActiveTexture = _glActiveTexture;
3624
- _glActiveTexture = function(texture) {
3920
+ _glActiveTexture = function _glActiveTexture(texture) {
3625
3921
  GL.immediate.TexEnvJIT.hook_activeTexture(texture);
3626
3922
  glActiveTexture(texture);
3627
3923
  };
3628
3924
 
3629
3925
  var glEnable = _glEnable;
3630
- _glEnable = function(cap) {
3926
+ _glEnable = function _glEnable(cap) {
3631
3927
  GL.immediate.TexEnvJIT.hook_enable(cap);
3632
3928
  glEnable(cap);
3633
3929
  };
3634
3930
  var glDisable = _glDisable;
3635
- _glDisable = function(cap) {
3931
+ _glDisable = function _glDisable(cap) {
3636
3932
  GL.immediate.TexEnvJIT.hook_disable(cap);
3637
3933
  glDisable(cap);
3638
3934
  };
3639
3935
 
3640
3936
  var glTexEnvf = (typeof(_glTexEnvf) != 'undefined') ? _glTexEnvf : function(){};
3641
- _glTexEnvf = function(target, pname, param) {
3937
+ _glTexEnvf = function _glTexEnvf(target, pname, param) {
3642
3938
  GL.immediate.TexEnvJIT.hook_texEnvf(target, pname, param);
3643
3939
  // Don't call old func, since we are the implementor.
3644
3940
  //glTexEnvf(target, pname, param);
3645
3941
  };
3646
3942
  var glTexEnvi = (typeof(_glTexEnvi) != 'undefined') ? _glTexEnvi : function(){};
3647
- _glTexEnvi = function(target, pname, param) {
3943
+ _glTexEnvi = function _glTexEnvi(target, pname, param) {
3648
3944
  GL.immediate.TexEnvJIT.hook_texEnvi(target, pname, param);
3649
3945
  // Don't call old func, since we are the implementor.
3650
3946
  //glTexEnvi(target, pname, param);
3651
3947
  };
3652
3948
  var glTexEnvfv = (typeof(_glTexEnvfv) != 'undefined') ? _glTexEnvfv : function(){};
3653
- _glTexEnvfv = function(target, pname, param) {
3949
+ _glTexEnvfv = function _glTexEnvfv(target, pname, param) {
3654
3950
  GL.immediate.TexEnvJIT.hook_texEnvfv(target, pname, param);
3655
3951
  // Don't call old func, since we are the implementor.
3656
3952
  //glTexEnvfv(target, pname, param);
3657
3953
  };
3658
3954
 
3659
3955
  var glGetIntegerv = _glGetIntegerv;
3660
- _glGetIntegerv = function(pname, params) {
3956
+ _glGetIntegerv = function _glGetIntegerv(pname, params) {
3661
3957
  switch (pname) {
3662
3958
  case 0x8B8D: { // GL_CURRENT_PROGRAM
3663
3959
  // Just query directly so we're working with WebGL objects.
@@ -3684,11 +3980,15 @@ var LibraryGL = {
3684
3980
 
3685
3981
  this.TexEnvJIT.init(Module.ctx);
3686
3982
 
3687
- GL.immediate.MAX_TEXTURES = Module.ctx.getParameter(Module.ctx.MAX_TEXTURE_IMAGE_UNITS);
3688
- GL.immediate.NUM_ATTRIBUTES = GL.immediate.TEXTURE0 + GL.immediate.MAX_TEXTURES;
3983
+ // User can override the maximum number of texture units that we emulate. Using fewer texture units increases runtime performance
3984
+ // slightly, so it is advantageous to choose as small value as needed.
3985
+ GL.immediate.MAX_TEXTURES = Module['GL_MAX_TEXTURE_IMAGE_UNITS'] || Module.ctx.getParameter(Module.ctx.MAX_TEXTURE_IMAGE_UNITS);
3986
+ GL.immediate.NUM_ATTRIBUTES = 3 /*pos+normal+color attributes*/ + GL.immediate.MAX_TEXTURES;
3689
3987
  GL.immediate.clientAttributes = [];
3988
+ GLEmulation.enabledClientAttribIndices = [];
3690
3989
  for (var i = 0; i < GL.immediate.NUM_ATTRIBUTES; i++) {
3691
3990
  GL.immediate.clientAttributes.push({});
3991
+ GLEmulation.enabledClientAttribIndices.push(false);
3692
3992
  }
3693
3993
 
3694
3994
  this.matrixStack['m'] = [];
@@ -3698,13 +3998,18 @@ var LibraryGL = {
3698
3998
  }
3699
3999
 
3700
4000
  // Initialize matrix library
3701
-
4001
+ // When user sets a matrix, increment a 'version number' on the new data, and when rendering, submit
4002
+ // the matrices to the shader program only if they have an old version of the data.
4003
+ GL.immediate.matrixVersion = {};
3702
4004
  GL.immediate.matrix['m'] = GL.immediate.matrix.lib.mat4.create();
4005
+ GL.immediate.matrixVersion['m'] = 0;
3703
4006
  GL.immediate.matrix.lib.mat4.identity(GL.immediate.matrix['m']);
3704
4007
  GL.immediate.matrix['p'] = GL.immediate.matrix.lib.mat4.create();
4008
+ GL.immediate.matrixVersion['p'] = 0;
3705
4009
  GL.immediate.matrix.lib.mat4.identity(GL.immediate.matrix['p']);
3706
4010
  for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
3707
4011
  GL.immediate.matrix['t' + i] = GL.immediate.matrix.lib.mat4.create();
4012
+ GL.immediate.matrixVersion['t' + i] = 0;
3708
4013
  }
3709
4014
 
3710
4015
  // Renderer cache
@@ -3725,7 +4030,7 @@ var LibraryGL = {
3725
4030
  // Modifies liveClientAttributes, stride, vertexPointer, vertexCounter
3726
4031
  // count: number of elements we will draw
3727
4032
  // beginEnd: whether we are drawing the results of a begin/end block
3728
- prepareClientAttributes: function(count, beginEnd) {
4033
+ prepareClientAttributes: function prepareClientAttributes(count, beginEnd) {
3729
4034
  // If no client attributes were modified since we were last called, do nothing. Note that this
3730
4035
  // does not work for glBegin/End, where we generate renderer components dynamically and then
3731
4036
  // disable them ourselves, but it does help with glDrawElements/Arrays.
@@ -3797,13 +4102,17 @@ var LibraryGL = {
3797
4102
  if (!attribute) break;
3798
4103
  attribute.offset = attribute.pointer - start;
3799
4104
  if (attribute.offset > bytes) { // ensure we start where we should
4105
+ #if ASSERTIONS
3800
4106
  assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment
4107
+ #endif
3801
4108
  bytes += attribute.offset - bytes;
3802
4109
  }
3803
4110
  bytes += attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot];
3804
4111
  if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment
3805
4112
  }
4113
+ #if ASSERTIONS
3806
4114
  assert(beginEnd || bytes <= stride); // if not begin-end, explicit stride should make sense with total byte size
4115
+ #endif
3807
4116
  if (bytes < stride) { // ensure the size is that of the stride
3808
4117
  bytes = stride;
3809
4118
  }
@@ -3819,7 +4128,7 @@ var LibraryGL = {
3819
4128
  }
3820
4129
  },
3821
4130
 
3822
- flush: function(numProvidedIndexes, startIndex, ptr) {
4131
+ flush: function flush(numProvidedIndexes, startIndex, ptr) {
3823
4132
  #if ASSERTIONS
3824
4133
  assert(numProvidedIndexes >= 0 || !numProvidedIndexes);
3825
4134
  #endif
@@ -3830,18 +4139,21 @@ var LibraryGL = {
3830
4139
 
3831
4140
  // Generate index data in a format suitable for GLES 2.0/WebGL
3832
4141
  var numVertexes = 4 * this.vertexCounter / GL.immediate.stride;
4142
+ #if ASSERTIONS
3833
4143
  assert(numVertexes % 1 == 0, "`numVertexes` must be an integer.");
3834
-
4144
+ #endif
3835
4145
  var emulatedElementArrayBuffer = false;
3836
4146
  var numIndexes = 0;
3837
4147
  if (numProvidedIndexes) {
3838
4148
  numIndexes = numProvidedIndexes;
3839
4149
  if (!GL.currArrayBuffer && GL.immediate.firstVertex > GL.immediate.lastVertex) {
3840
4150
  // Figure out the first and last vertex from the index data
4151
+ #if ASSERTIONS
3841
4152
  assert(!GL.currElementArrayBuffer); // If we are going to upload array buffer data, we need to find which range to
3842
4153
  // upload based on the indices. If they are in a buffer on the GPU, that is very
3843
4154
  // inconvenient! So if you do not have an array buffer, you should also not have
3844
4155
  // an element array buffer. But best is to use both buffers!
4156
+ #endif
3845
4157
  for (var i = 0; i < numProvidedIndexes; i++) {
3846
4158
  var currIndex = {{{ makeGetValue('ptr', 'i*2', 'i16', null, 1) }}};
3847
4159
  GL.immediate.firstVertex = Math.min(GL.immediate.firstVertex, currIndex);
@@ -3850,7 +4162,9 @@ var LibraryGL = {
3850
4162
  }
3851
4163
  if (!GL.currElementArrayBuffer) {
3852
4164
  // If no element array buffer is bound, then indices is a literal pointer to clientside data
4165
+ #if ASSERTIONS
3853
4166
  assert(numProvidedIndexes << 1 <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (a)');
4167
+ #endif
3854
4168
  var indexBuffer = GL.tempIndexBuffers[GL.tempBufferIndexLookup[numProvidedIndexes << 1]];
3855
4169
  Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, indexBuffer);
3856
4170
  Module.ctx.bufferSubData(Module.ctx.ELEMENT_ARRAY_BUFFER, 0, {{{ makeHEAPView('U16', 'ptr', 'ptr + (numProvidedIndexes << 1)') }}});
@@ -3862,11 +4176,15 @@ var LibraryGL = {
3862
4176
  // GL.immediate.firstVertex is the first vertex we want. Quad indexes are in the pattern
3863
4177
  // 0 1 2, 0 2 3, 4 5 6, 4 6 7, so we need to look at index firstVertex * 1.5 to see it.
3864
4178
  // Then since indexes are 2 bytes each, that means 3
4179
+ #if ASSERTIONS
3865
4180
  assert(GL.immediate.firstVertex % 4 == 0);
4181
+ #endif
3866
4182
  ptr = GL.immediate.firstVertex*3;
3867
4183
  var numQuads = numVertexes / 4;
3868
4184
  numIndexes = numQuads * 6; // 0 1 2, 0 2 3 pattern
4185
+ #if ASSERTIONS
3869
4186
  assert(ptr + (numIndexes << 1) <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (b)');
4187
+ #endif
3870
4188
  Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer);
3871
4189
  emulatedElementArrayBuffer = true;
3872
4190
  }
@@ -3883,7 +4201,7 @@ var LibraryGL = {
3883
4201
  Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null);
3884
4202
  }
3885
4203
 
3886
- #if GL_UNSAFE_OPTS == 0
4204
+ #if GL_UNSAFE_OPTS == 0 && !GL_FFP_ONLY
3887
4205
  renderer.cleanup();
3888
4206
  #endif
3889
4207
  }
@@ -4050,7 +4368,7 @@ var LibraryGL = {
4050
4368
  glColor4ubv__deps: ['glColor4ub'],
4051
4369
  glColor4ubv: function(p) {
4052
4370
  _glColor4ub({{{ makeGetValue('p', '0', 'i8') }}}, {{{ makeGetValue('p', '1', 'i8') }}}, {{{ makeGetValue('p', '2', 'i8') }}}, {{{ makeGetValue('p', '3', 'i8') }}});
4053
- },
4371
+ },
4054
4372
 
4055
4373
  glFogf: function(pname, param) { // partial support, TODO
4056
4374
  switch(pname) {
@@ -4131,10 +4449,12 @@ var LibraryGL = {
4131
4449
  if (disable && GL.immediate.enabledClientAttributes[attrib]) {
4132
4450
  GL.immediate.enabledClientAttributes[attrib] = false;
4133
4451
  GL.immediate.totalEnabledClientAttributes--;
4452
+ this.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
4134
4453
  if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap];
4135
4454
  } else if (!disable && !GL.immediate.enabledClientAttributes[attrib]) {
4136
4455
  GL.immediate.enabledClientAttributes[attrib] = true;
4137
4456
  GL.immediate.totalEnabledClientAttributes++;
4457
+ this.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
4138
4458
  if (GLEmulation.currentVao) GLEmulation.currentVao.enabledClientStates[cap] = 1;
4139
4459
  }
4140
4460
  GL.immediate.modifiedClientAttributes = true;
@@ -4146,15 +4466,40 @@ var LibraryGL = {
4146
4466
  glVertexPointer__deps: ['$GLEmulation'], // if any pointers are used, glVertexPointer must be, and if it is, then we need emulation
4147
4467
  glVertexPointer: function(size, type, stride, pointer) {
4148
4468
  GL.immediate.setClientAttribute(GL.immediate.VERTEX, size, type, stride, pointer);
4469
+ #if GL_FFP_ONLY
4470
+ if (GL.currArrayBuffer) {
4471
+ Module.ctx.vertexAttribPointer(GL.immediate.VERTEX, size, type, false, stride, pointer);
4472
+ GL.enableVertexAttribArray(GL.immediate.VERTEX);
4473
+ }
4474
+ #endif
4149
4475
  },
4150
4476
  glTexCoordPointer: function(size, type, stride, pointer) {
4151
4477
  GL.immediate.setClientAttribute(GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture, size, type, stride, pointer);
4478
+ #if GL_FFP_ONLY
4479
+ if (GL.currArrayBuffer) {
4480
+ var loc = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture;
4481
+ Module.ctx.vertexAttribPointer(loc, size, type, false, stride, pointer);
4482
+ GL.enableVertexAttribArray(loc);
4483
+ }
4484
+ #endif
4152
4485
  },
4153
4486
  glNormalPointer: function(type, stride, pointer) {
4154
4487
  GL.immediate.setClientAttribute(GL.immediate.NORMAL, 3, type, stride, pointer);
4488
+ #if GL_FFP_ONLY
4489
+ if (GL.currArrayBuffer) {
4490
+ Module.ctx.vertexAttribPointer(GL.immediate.NORMAL, size, type, true, stride, pointer);
4491
+ GL.enableVertexAttribArray(GL.immediate.NORMAL);
4492
+ }
4493
+ #endif
4155
4494
  },
4156
4495
  glColorPointer: function(size, type, stride, pointer) {
4157
4496
  GL.immediate.setClientAttribute(GL.immediate.COLOR, size, type, stride, pointer);
4497
+ #if GL_FFP_ONLY
4498
+ if (GL.currArrayBuffer) {
4499
+ Module.ctx.vertexAttribPointer(GL.immediate.COLOR, size, type, true, stride, pointer);
4500
+ GL.enableVertexAttribArray(GL.immediate.COLOR);
4501
+ }
4502
+ #endif
4158
4503
  },
4159
4504
 
4160
4505
  glClientActiveTexture__sig: 'vi',
@@ -4237,23 +4582,27 @@ var LibraryGL = {
4237
4582
 
4238
4583
  glPushMatrix: function() {
4239
4584
  GL.immediate.matricesModified = true;
4585
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4240
4586
  GL.immediate.matrixStack[GL.immediate.currentMatrix].push(
4241
4587
  Array.prototype.slice.call(GL.immediate.matrix[GL.immediate.currentMatrix]));
4242
4588
  },
4243
4589
 
4244
4590
  glPopMatrix: function() {
4245
4591
  GL.immediate.matricesModified = true;
4592
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4246
4593
  GL.immediate.matrix[GL.immediate.currentMatrix] = GL.immediate.matrixStack[GL.immediate.currentMatrix].pop();
4247
4594
  },
4248
4595
 
4249
4596
  glLoadIdentity__deps: ['$GL', '$GLImmediateSetup'],
4250
4597
  glLoadIdentity: function() {
4251
4598
  GL.immediate.matricesModified = true;
4599
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4252
4600
  GL.immediate.matrix.lib.mat4.identity(GL.immediate.matrix[GL.immediate.currentMatrix]);
4253
4601
  },
4254
4602
 
4255
4603
  glLoadMatrixd: function(matrix) {
4256
4604
  GL.immediate.matricesModified = true;
4605
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4257
4606
  GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
4258
4607
  },
4259
4608
 
@@ -4262,35 +4611,41 @@ var LibraryGL = {
4262
4611
  if (GL.debug) Module.printErr('glLoadMatrixf receiving: ' + Array.prototype.slice.call(HEAPF32.subarray(matrix >> 2, (matrix >> 2) + 16)));
4263
4612
  #endif
4264
4613
  GL.immediate.matricesModified = true;
4614
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4265
4615
  GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
4266
4616
  },
4267
4617
 
4268
4618
  glLoadTransposeMatrixd: function(matrix) {
4269
4619
  GL.immediate.matricesModified = true;
4620
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4270
4621
  GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
4271
4622
  GL.immediate.matrix.lib.mat4.transpose(GL.immediate.matrix[GL.immediate.currentMatrix]);
4272
4623
  },
4273
4624
 
4274
4625
  glLoadTransposeMatrixf: function(matrix) {
4275
4626
  GL.immediate.matricesModified = true;
4627
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4276
4628
  GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
4277
4629
  GL.immediate.matrix.lib.mat4.transpose(GL.immediate.matrix[GL.immediate.currentMatrix]);
4278
4630
  },
4279
4631
 
4280
4632
  glMultMatrixd: function(matrix) {
4281
4633
  GL.immediate.matricesModified = true;
4634
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4282
4635
  GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
4283
4636
  {{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}});
4284
4637
  },
4285
4638
 
4286
4639
  glMultMatrixf: function(matrix) {
4287
4640
  GL.immediate.matricesModified = true;
4641
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4288
4642
  GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
4289
4643
  {{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}});
4290
4644
  },
4291
4645
 
4292
4646
  glMultTransposeMatrixd: function(matrix) {
4293
4647
  GL.immediate.matricesModified = true;
4648
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4294
4649
  var colMajor = GL.immediate.matrix.lib.mat4.create();
4295
4650
  GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, colMajor);
4296
4651
  GL.immediate.matrix.lib.mat4.transpose(colMajor);
@@ -4299,6 +4654,7 @@ var LibraryGL = {
4299
4654
 
4300
4655
  glMultTransposeMatrixf: function(matrix) {
4301
4656
  GL.immediate.matricesModified = true;
4657
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4302
4658
  var colMajor = GL.immediate.matrix.lib.mat4.create();
4303
4659
  GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, colMajor);
4304
4660
  GL.immediate.matrix.lib.mat4.transpose(colMajor);
@@ -4307,6 +4663,7 @@ var LibraryGL = {
4307
4663
 
4308
4664
  glFrustum: function(left, right, bottom, top_, nearVal, farVal) {
4309
4665
  GL.immediate.matricesModified = true;
4666
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4310
4667
  GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
4311
4668
  GL.immediate.matrix.lib.mat4.frustum(left, right, bottom, top_, nearVal, farVal));
4312
4669
  },
@@ -4314,6 +4671,7 @@ var LibraryGL = {
4314
4671
 
4315
4672
  glOrtho: function(left, right, bottom, top_, nearVal, farVal) {
4316
4673
  GL.immediate.matricesModified = true;
4674
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4317
4675
  GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
4318
4676
  GL.immediate.matrix.lib.mat4.ortho(left, right, bottom, top_, nearVal, farVal));
4319
4677
  },
@@ -4321,18 +4679,21 @@ var LibraryGL = {
4321
4679
 
4322
4680
  glScaled: function(x, y, z) {
4323
4681
  GL.immediate.matricesModified = true;
4682
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4324
4683
  GL.immediate.matrix.lib.mat4.scale(GL.immediate.matrix[GL.immediate.currentMatrix], [x, y, z]);
4325
4684
  },
4326
4685
  glScalef: 'glScaled',
4327
4686
 
4328
4687
  glTranslated: function(x, y, z) {
4329
4688
  GL.immediate.matricesModified = true;
4689
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4330
4690
  GL.immediate.matrix.lib.mat4.translate(GL.immediate.matrix[GL.immediate.currentMatrix], [x, y, z]);
4331
4691
  },
4332
4692
  glTranslatef: 'glTranslated',
4333
4693
 
4334
4694
  glRotated: function(angle, x, y, z) {
4335
4695
  GL.immediate.matricesModified = true;
4696
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4336
4697
  GL.immediate.matrix.lib.mat4.rotate(GL.immediate.matrix[GL.immediate.currentMatrix], angle*Math.PI/180, [x, y, z]);
4337
4698
  },
4338
4699
  glRotatef: 'glRotated',
@@ -4415,6 +4776,7 @@ var LibraryGL = {
4415
4776
 
4416
4777
  gluPerspective: function(fov, aspect, near, far) {
4417
4778
  GL.immediate.matricesModified = true;
4779
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4418
4780
  GL.immediate.matrix[GL.immediate.currentMatrix] =
4419
4781
  GL.immediate.matrix.lib.mat4.perspective(fov, aspect, near, far,
4420
4782
  GL.immediate.matrix[GL.immediate.currentMatrix]);
@@ -4422,6 +4784,7 @@ var LibraryGL = {
4422
4784
 
4423
4785
  gluLookAt: function(ex, ey, ez, cx, cy, cz, ux, uy, uz) {
4424
4786
  GL.immediate.matricesModified = true;
4787
+ GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
4425
4788
  GL.immediate.matrix.lib.mat4.lookAt(GL.immediate.matrix[GL.immediate.currentMatrix], [ex, ey, ez],
4426
4789
  [cx, cy, cz], [ux, uy, uz]);
4427
4790
  },
@@ -4572,6 +4935,30 @@ var LibraryGL = {
4572
4935
  #endif
4573
4936
  },
4574
4937
 
4938
+ glShaderBinary__sig: 'v',
4939
+ glShaderBinary: function() {
4940
+ GL.recordError(0x0500/*GL_INVALID_ENUM*/);
4941
+ #if GL_ASSERTIONS
4942
+ Module.printErr("GL_INVALID_ENUM in glShaderBinary: WebGL does not support binary shader formats! Calls to glShaderBinary always fail.");
4943
+ #endif
4944
+ },
4945
+
4946
+ glReleaseShaderCompiler__sig: 'v',
4947
+ glReleaseShaderCompiler: function() {
4948
+ // NOP (as allowed by GLES 2.0 spec)
4949
+ },
4950
+
4951
+ glGetError__sig: 'i',
4952
+ glGetError: function() {
4953
+ // First return any GL error generated by the emscripten library_gl.js interop layer.
4954
+ if (GL.lastError) {
4955
+ var error = GL.lastError;
4956
+ GL.lastError = 0/*GL_NO_ERROR*/;
4957
+ return error;
4958
+ } else { // If there were none, return the GL error from the browser GL context.
4959
+ return Module.ctx.getError();
4960
+ }
4961
+ },
4575
4962
  // signatures of simple pass-through functions, see later
4576
4963
 
4577
4964
  glActiveTexture__sig: 'vi',
@@ -4605,16 +4992,15 @@ var LibraryGL = {
4605
4992
  glFlush__sig: 'v',
4606
4993
  glClearColor__sig: 'viiii',
4607
4994
  glIsEnabled__sig: 'ii',
4608
- glGetError__sig: 'i',
4609
4995
  glFrontFace__sig: 'vi',
4610
- glSampleCoverage__sig: 'vi',
4996
+ glSampleCoverage__sig: 'vii',
4611
4997
  };
4612
4998
 
4613
4999
 
4614
5000
  // Simple pass-through functions. Starred ones have return values. [X] ones have X in the C name but not in the JS name
4615
- [[0, 'getError* finish flush'],
4616
- [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear lineWidth clearStencil depthMask stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation sampleCoverage isEnabled*'],
4617
- [2, 'blendFunc blendEquationSeparate depthRange depthRange[f] stencilMaskSeparate hint polygonOffset vertexAttrib1f'],
5001
+ [[0, 'finish flush'],
5002
+ [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear lineWidth clearStencil depthMask stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation isEnabled*'],
5003
+ [2, 'blendFunc blendEquationSeparate depthRange depthRange[f] stencilMaskSeparate hint polygonOffset vertexAttrib1f sampleCoverage'],
4618
5004
  [3, 'texParameteri texParameterf vertexAttrib2f stencilFunc stencilOp'],
4619
5005
  [4, 'viewport clearColor scissor vertexAttrib3f colorMask renderbufferStorage blendFuncSeparate blendColor stencilFuncSeparate stencilOpSeparate'],
4620
5006
  [5, 'vertexAttrib4f'],
@@ -4687,7 +5073,7 @@ LibraryGL.emscripten_GetProcAddress__deps = [function() {
4687
5073
  tableImpl += '}\nreturn 0;';
4688
5074
  LibraryManager.library.emscripten_procAddressTable = new Function('name', tableImpl);
4689
5075
  }, 'emscripten_procAddressTable'];
4690
- LibraryGL.emscripten_GetProcAddress = function(name) {
5076
+ LibraryGL.emscripten_GetProcAddress = function _LibraryGL_emscripten_GetProcAddress(name) {
4691
5077
  name = name.replace('EXT', '').replace('ARB', '');
4692
5078
  switch(name) { // misc renamings
4693
5079
  case 'glCreateProgramObject': name = 'glCreateProgram'; break;