webruby 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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;