@vpmedia/phaser 1.112.0 → 1.113.0

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 (295) hide show
  1. package/dist/index.js +1261 -1314
  2. package/dist/index.js.map +1 -1
  3. package/dist/phaser/core/animation.d.ts +14 -10
  4. package/dist/phaser/core/animation.d.ts.map +1 -1
  5. package/dist/phaser/core/animation_manager.d.ts +10 -8
  6. package/dist/phaser/core/animation_manager.d.ts.map +1 -1
  7. package/dist/phaser/core/animation_parser.d.ts +5 -4
  8. package/dist/phaser/core/animation_parser.d.ts.map +1 -1
  9. package/dist/phaser/core/array_set.d.ts.map +1 -1
  10. package/dist/phaser/core/cache.d.ts +4 -3
  11. package/dist/phaser/core/cache.d.ts.map +1 -1
  12. package/dist/phaser/core/const.d.ts.map +1 -1
  13. package/dist/phaser/core/device.d.ts.map +1 -1
  14. package/dist/phaser/core/device_util.d.ts.map +1 -1
  15. package/dist/phaser/core/dom.d.ts +3 -2
  16. package/dist/phaser/core/dom.d.ts.map +1 -1
  17. package/dist/phaser/core/event_manager.d.ts.map +1 -1
  18. package/dist/phaser/core/factory.d.ts +1 -1
  19. package/dist/phaser/core/factory.d.ts.map +1 -1
  20. package/dist/phaser/core/frame.d.ts.map +1 -1
  21. package/dist/phaser/core/frame_data.d.ts.map +1 -1
  22. package/dist/phaser/core/game.d.ts.map +1 -1
  23. package/dist/phaser/core/input.d.ts +8 -6
  24. package/dist/phaser/core/input.d.ts.map +1 -1
  25. package/dist/phaser/core/input_handler.d.ts +40 -30
  26. package/dist/phaser/core/input_handler.d.ts.map +1 -1
  27. package/dist/phaser/core/input_mouse.d.ts +3 -2
  28. package/dist/phaser/core/input_mouse.d.ts.map +1 -1
  29. package/dist/phaser/core/input_mspointer.d.ts +3 -2
  30. package/dist/phaser/core/input_mspointer.d.ts.map +1 -1
  31. package/dist/phaser/core/input_pointer.d.ts +6 -4
  32. package/dist/phaser/core/input_pointer.d.ts.map +1 -1
  33. package/dist/phaser/core/input_touch.d.ts +3 -2
  34. package/dist/phaser/core/input_touch.d.ts.map +1 -1
  35. package/dist/phaser/core/loader.d.ts +4 -3
  36. package/dist/phaser/core/loader.d.ts.map +1 -1
  37. package/dist/phaser/core/loader_parser.d.ts +9 -8
  38. package/dist/phaser/core/loader_parser.d.ts.map +1 -1
  39. package/dist/phaser/core/raf.d.ts +3 -2
  40. package/dist/phaser/core/raf.d.ts.map +1 -1
  41. package/dist/phaser/core/registry.d.ts +7 -0
  42. package/dist/phaser/core/registry.d.ts.map +1 -0
  43. package/dist/phaser/core/scale_manager.d.ts +1 -1
  44. package/dist/phaser/core/scale_manager.d.ts.map +1 -1
  45. package/dist/phaser/core/scene.d.ts +0 -1
  46. package/dist/phaser/core/scene.d.ts.map +1 -1
  47. package/dist/phaser/core/scene_manager.d.ts +1 -1
  48. package/dist/phaser/core/scene_manager.d.ts.map +1 -1
  49. package/dist/phaser/core/signal.d.ts +0 -1
  50. package/dist/phaser/core/signal.d.ts.map +1 -1
  51. package/dist/phaser/core/signal_binding.d.ts +4 -3
  52. package/dist/phaser/core/signal_binding.d.ts.map +1 -1
  53. package/dist/phaser/core/sound.d.ts +6 -4
  54. package/dist/phaser/core/sound.d.ts.map +1 -1
  55. package/dist/phaser/core/sound_manager.d.ts +3 -2
  56. package/dist/phaser/core/sound_manager.d.ts.map +1 -1
  57. package/dist/phaser/core/sound_sprite.d.ts +5 -4
  58. package/dist/phaser/core/sound_sprite.d.ts.map +1 -1
  59. package/dist/phaser/core/stage.d.ts +3 -2
  60. package/dist/phaser/core/stage.d.ts.map +1 -1
  61. package/dist/phaser/core/time.d.ts +1 -1
  62. package/dist/phaser/core/time.d.ts.map +1 -1
  63. package/dist/phaser/core/timer.d.ts +1 -1
  64. package/dist/phaser/core/timer.d.ts.map +1 -1
  65. package/dist/phaser/core/timer_event.d.ts.map +1 -1
  66. package/dist/phaser/core/tween.d.ts +10 -7
  67. package/dist/phaser/core/tween.d.ts.map +1 -1
  68. package/dist/phaser/core/tween_data.d.ts +3 -2
  69. package/dist/phaser/core/tween_data.d.ts.map +1 -1
  70. package/dist/phaser/core/tween_easing.d.ts.map +1 -1
  71. package/dist/phaser/core/tween_manager.d.ts +3 -2
  72. package/dist/phaser/core/tween_manager.d.ts.map +1 -1
  73. package/dist/phaser/core/world.d.ts +3 -2
  74. package/dist/phaser/core/world.d.ts.map +1 -1
  75. package/dist/phaser/display/bitmap_text.d.ts +3 -2
  76. package/dist/phaser/display/bitmap_text.d.ts.map +1 -1
  77. package/dist/phaser/display/button.d.ts +3 -2
  78. package/dist/phaser/display/button.d.ts.map +1 -1
  79. package/dist/phaser/display/canvas/buffer.d.ts.map +1 -1
  80. package/dist/phaser/display/canvas/graphics.d.ts +7 -6
  81. package/dist/phaser/display/canvas/graphics.d.ts.map +1 -1
  82. package/dist/phaser/display/canvas/pool.d.ts +2 -2
  83. package/dist/phaser/display/canvas/pool.d.ts.map +1 -1
  84. package/dist/phaser/display/canvas/renderer.d.ts +10 -8
  85. package/dist/phaser/display/canvas/renderer.d.ts.map +1 -1
  86. package/dist/phaser/display/canvas/tinter.d.ts +3 -2
  87. package/dist/phaser/display/canvas/tinter.d.ts.map +1 -1
  88. package/dist/phaser/display/canvas/util.d.ts +2 -2
  89. package/dist/phaser/display/canvas/util.d.ts.map +1 -1
  90. package/dist/phaser/display/display_object.d.ts +14 -12
  91. package/dist/phaser/display/display_object.d.ts.map +1 -1
  92. package/dist/phaser/display/graphics.d.ts +8 -5
  93. package/dist/phaser/display/graphics.d.ts.map +1 -1
  94. package/dist/phaser/display/graphics_data.d.ts.map +1 -1
  95. package/dist/phaser/display/graphics_data_util.d.ts.map +1 -1
  96. package/dist/phaser/display/group.d.ts +4 -3
  97. package/dist/phaser/display/group.d.ts.map +1 -1
  98. package/dist/phaser/display/image.d.ts +13 -10
  99. package/dist/phaser/display/image.d.ts.map +1 -1
  100. package/dist/phaser/display/sprite_batch.d.ts +3 -2
  101. package/dist/phaser/display/sprite_batch.d.ts.map +1 -1
  102. package/dist/phaser/display/sprite_util.d.ts +18 -15
  103. package/dist/phaser/display/sprite_util.d.ts.map +1 -1
  104. package/dist/phaser/display/text.d.ts +11 -9
  105. package/dist/phaser/display/text.d.ts.map +1 -1
  106. package/dist/phaser/display/webgl/abstract_filter.d.ts.map +1 -1
  107. package/dist/phaser/display/webgl/base_texture.d.ts.map +1 -1
  108. package/dist/phaser/display/webgl/blend_manager.d.ts +0 -1
  109. package/dist/phaser/display/webgl/blend_manager.d.ts.map +1 -1
  110. package/dist/phaser/display/webgl/earcut.d.ts +1 -1
  111. package/dist/phaser/display/webgl/earcut.d.ts.map +1 -1
  112. package/dist/phaser/display/webgl/earcut_node.d.ts.map +1 -1
  113. package/dist/phaser/display/webgl/fast_sprite_batch.d.ts +4 -3
  114. package/dist/phaser/display/webgl/fast_sprite_batch.d.ts.map +1 -1
  115. package/dist/phaser/display/webgl/filter_manager.d.ts +2 -1
  116. package/dist/phaser/display/webgl/filter_manager.d.ts.map +1 -1
  117. package/dist/phaser/display/webgl/filter_texture.d.ts +2 -1
  118. package/dist/phaser/display/webgl/filter_texture.d.ts.map +1 -1
  119. package/dist/phaser/display/webgl/graphics.d.ts +7 -6
  120. package/dist/phaser/display/webgl/graphics.d.ts.map +1 -1
  121. package/dist/phaser/display/webgl/graphics_data.d.ts +2 -1
  122. package/dist/phaser/display/webgl/graphics_data.d.ts.map +1 -1
  123. package/dist/phaser/display/webgl/render_texture.d.ts +4 -2
  124. package/dist/phaser/display/webgl/render_texture.d.ts.map +1 -1
  125. package/dist/phaser/display/webgl/renderer.d.ts +16 -11
  126. package/dist/phaser/display/webgl/renderer.d.ts.map +1 -1
  127. package/dist/phaser/display/webgl/shader/complex.d.ts +16 -6
  128. package/dist/phaser/display/webgl/shader/complex.d.ts.map +1 -1
  129. package/dist/phaser/display/webgl/shader/fast.d.ts +19 -7
  130. package/dist/phaser/display/webgl/shader/fast.d.ts.map +1 -1
  131. package/dist/phaser/display/webgl/shader/normal.d.ts +33 -12
  132. package/dist/phaser/display/webgl/shader/normal.d.ts.map +1 -1
  133. package/dist/phaser/display/webgl/shader/primitive.d.ts +15 -6
  134. package/dist/phaser/display/webgl/shader/primitive.d.ts.map +1 -1
  135. package/dist/phaser/display/webgl/shader/strip.d.ts +15 -6
  136. package/dist/phaser/display/webgl/shader/strip.d.ts.map +1 -1
  137. package/dist/phaser/display/webgl/shader_manager.d.ts +16 -11
  138. package/dist/phaser/display/webgl/shader_manager.d.ts.map +1 -1
  139. package/dist/phaser/display/webgl/sprite_batch.d.ts +29 -20
  140. package/dist/phaser/display/webgl/sprite_batch.d.ts.map +1 -1
  141. package/dist/phaser/display/webgl/stencil_manager.d.ts +12 -10
  142. package/dist/phaser/display/webgl/stencil_manager.d.ts.map +1 -1
  143. package/dist/phaser/display/webgl/texture.d.ts +3 -2
  144. package/dist/phaser/display/webgl/texture.d.ts.map +1 -1
  145. package/dist/phaser/display/webgl/texture_util.d.ts.map +1 -1
  146. package/dist/phaser/display/webgl/util.d.ts.map +1 -1
  147. package/dist/phaser/geom/circle.d.ts +4 -1
  148. package/dist/phaser/geom/circle.d.ts.map +1 -1
  149. package/dist/phaser/geom/ellipse.d.ts.map +1 -1
  150. package/dist/phaser/geom/line.d.ts +1 -1
  151. package/dist/phaser/geom/line.d.ts.map +1 -1
  152. package/dist/phaser/geom/matrix.d.ts.map +1 -1
  153. package/dist/phaser/geom/point.d.ts.map +1 -1
  154. package/dist/phaser/geom/polygon.d.ts.map +1 -1
  155. package/dist/phaser/geom/rectangle.d.ts.map +1 -1
  156. package/dist/phaser/geom/rounded_rectangle.d.ts.map +1 -1
  157. package/dist/phaser/geom/util/circle.d.ts.map +1 -1
  158. package/dist/phaser/geom/util/ellipse.d.ts +3 -2
  159. package/dist/phaser/geom/util/ellipse.d.ts.map +1 -1
  160. package/dist/phaser/geom/util/line.d.ts.map +1 -1
  161. package/dist/phaser/geom/util/matrix.d.ts +2 -2
  162. package/dist/phaser/geom/util/matrix.d.ts.map +1 -1
  163. package/dist/phaser/geom/util/point.d.ts.map +1 -1
  164. package/dist/phaser/geom/util/rectangle.d.ts +1 -1
  165. package/dist/phaser/geom/util/rectangle.d.ts.map +1 -1
  166. package/dist/phaser/util/math.d.ts.map +1 -1
  167. package/package.json +5 -5
  168. package/src/phaser/core/animation.ts +64 -60
  169. package/src/phaser/core/animation_manager.ts +50 -53
  170. package/src/phaser/core/animation_parser.ts +9 -9
  171. package/src/phaser/core/array_set.ts +16 -17
  172. package/src/phaser/core/cache.ts +92 -93
  173. package/src/phaser/core/const.ts +1 -1
  174. package/src/phaser/core/device.ts +24 -29
  175. package/src/phaser/core/device_util.ts +22 -26
  176. package/src/phaser/core/dom.ts +54 -65
  177. package/src/phaser/core/event_manager.ts +64 -94
  178. package/src/phaser/core/factory.ts +14 -14
  179. package/src/phaser/core/frame.ts +28 -28
  180. package/src/phaser/core/frame_data.test.ts +100 -0
  181. package/src/phaser/core/frame_data.ts +24 -24
  182. package/src/phaser/core/frame_util.ts +2 -2
  183. package/src/phaser/core/game.ts +47 -48
  184. package/src/phaser/core/input.ts +104 -110
  185. package/src/phaser/core/input_handler.test.ts +113 -0
  186. package/src/phaser/core/input_handler.ts +199 -218
  187. package/src/phaser/core/input_mouse.ts +71 -54
  188. package/src/phaser/core/input_mspointer.ts +52 -39
  189. package/src/phaser/core/input_pointer.ts +81 -80
  190. package/src/phaser/core/input_touch.ts +49 -36
  191. package/src/phaser/core/loader.ts +173 -152
  192. package/src/phaser/core/loader_parser.ts +39 -57
  193. package/src/phaser/core/raf.ts +8 -7
  194. package/src/phaser/core/registry.test.ts +31 -0
  195. package/src/phaser/core/registry.ts +9 -0
  196. package/src/phaser/core/scale_manager.ts +156 -152
  197. package/src/phaser/core/scene.ts +9 -13
  198. package/src/phaser/core/scene_manager.ts +47 -47
  199. package/src/phaser/core/signal.test.ts +4 -4
  200. package/src/phaser/core/signal.ts +41 -52
  201. package/src/phaser/core/signal_binding.ts +26 -25
  202. package/src/phaser/core/signal_dispatch.test.ts +180 -0
  203. package/src/phaser/core/sound.ts +75 -83
  204. package/src/phaser/core/sound_manager.ts +52 -51
  205. package/src/phaser/core/sound_sprite.ts +17 -16
  206. package/src/phaser/core/stage.ts +25 -24
  207. package/src/phaser/core/time.ts +52 -52
  208. package/src/phaser/core/timer.test.ts +187 -0
  209. package/src/phaser/core/timer.ts +82 -69
  210. package/src/phaser/core/timer_event.ts +10 -10
  211. package/src/phaser/core/tween.ts +90 -93
  212. package/src/phaser/core/tween_data.ts +45 -51
  213. package/src/phaser/core/tween_easing.test.ts +106 -0
  214. package/src/phaser/core/tween_easing.ts +151 -123
  215. package/src/phaser/core/tween_manager.ts +19 -18
  216. package/src/phaser/core/world.ts +4 -3
  217. package/src/phaser/display/bitmap_text.ts +56 -64
  218. package/src/phaser/display/button.ts +33 -32
  219. package/src/phaser/display/canvas/buffer.ts +8 -8
  220. package/src/phaser/display/canvas/graphics.ts +36 -37
  221. package/src/phaser/display/canvas/masker.ts +2 -2
  222. package/src/phaser/display/canvas/pool.test.ts +106 -0
  223. package/src/phaser/display/canvas/pool.ts +25 -27
  224. package/src/phaser/display/canvas/renderer.ts +32 -31
  225. package/src/phaser/display/canvas/tinter.ts +25 -25
  226. package/src/phaser/display/canvas/util.ts +7 -10
  227. package/src/phaser/display/display_object.ts +114 -118
  228. package/src/phaser/display/graphics.ts +121 -119
  229. package/src/phaser/display/graphics_data.ts +12 -12
  230. package/src/phaser/display/graphics_data_util.ts +2 -3
  231. package/src/phaser/display/group.ts +50 -57
  232. package/src/phaser/display/image.ts +55 -52
  233. package/src/phaser/display/sprite_batch.ts +3 -2
  234. package/src/phaser/display/sprite_util.ts +48 -54
  235. package/src/phaser/display/text.ts +199 -204
  236. package/src/phaser/display/webgl/abstract_filter.ts +9 -9
  237. package/src/phaser/display/webgl/base_texture.ts +21 -24
  238. package/src/phaser/display/webgl/blend_manager.ts +6 -10
  239. package/src/phaser/display/webgl/earcut.ts +73 -37
  240. package/src/phaser/display/webgl/earcut_node.ts +10 -10
  241. package/src/phaser/display/webgl/fast_sprite_batch.ts +34 -34
  242. package/src/phaser/display/webgl/filter_manager.ts +13 -12
  243. package/src/phaser/display/webgl/filter_texture.ts +14 -13
  244. package/src/phaser/display/webgl/graphics.ts +51 -57
  245. package/src/phaser/display/webgl/graphics_data.ts +15 -14
  246. package/src/phaser/display/webgl/mask_manager.ts +2 -2
  247. package/src/phaser/display/webgl/render_texture.ts +26 -25
  248. package/src/phaser/display/webgl/renderer.ts +57 -62
  249. package/src/phaser/display/webgl/shader/complex.ts +28 -12
  250. package/src/phaser/display/webgl/shader/fast.ts +30 -12
  251. package/src/phaser/display/webgl/shader/normal.ts +70 -57
  252. package/src/phaser/display/webgl/shader/primitive.ts +26 -11
  253. package/src/phaser/display/webgl/shader/shader.test.ts +148 -0
  254. package/src/phaser/display/webgl/shader/strip.ts +27 -12
  255. package/src/phaser/display/webgl/shader_manager.test.ts +124 -0
  256. package/src/phaser/display/webgl/shader_manager.ts +26 -34
  257. package/src/phaser/display/webgl/sprite_batch.ts +67 -61
  258. package/src/phaser/display/webgl/stencil_manager.ts +23 -34
  259. package/src/phaser/display/webgl/texture.ts +43 -50
  260. package/src/phaser/display/webgl/texture_util.ts +2 -3
  261. package/src/phaser/display/webgl/util.ts +26 -25
  262. package/src/phaser/geom/circle.test.ts +2 -3
  263. package/src/phaser/geom/circle.ts +36 -36
  264. package/src/phaser/geom/ellipse.test.ts +73 -71
  265. package/src/phaser/geom/ellipse.ts +14 -14
  266. package/src/phaser/geom/line.test.ts +5 -5
  267. package/src/phaser/geom/line.ts +35 -35
  268. package/src/phaser/geom/matrix.test.ts +1 -1
  269. package/src/phaser/geom/matrix.ts +27 -27
  270. package/src/phaser/geom/point.test.ts +1 -2
  271. package/src/phaser/geom/point.ts +35 -35
  272. package/src/phaser/geom/polygon.test.ts +82 -0
  273. package/src/phaser/geom/polygon.ts +16 -16
  274. package/src/phaser/geom/rectangle.test.ts +14 -14
  275. package/src/phaser/geom/rectangle.ts +83 -75
  276. package/src/phaser/geom/rounded_rectangle.test.ts +1 -7
  277. package/src/phaser/geom/rounded_rectangle.ts +9 -9
  278. package/src/phaser/geom/util/circle.test.ts +25 -23
  279. package/src/phaser/geom/util/circle.ts +9 -18
  280. package/src/phaser/geom/util/ellipse.test.ts +7 -5
  281. package/src/phaser/geom/util/ellipse.ts +3 -2
  282. package/src/phaser/geom/util/line.test.ts +10 -8
  283. package/src/phaser/geom/util/line.ts +6 -16
  284. package/src/phaser/geom/util/matrix.test.ts +20 -18
  285. package/src/phaser/geom/util/matrix.ts +8 -15
  286. package/src/phaser/geom/util/point.test.ts +8 -6
  287. package/src/phaser/geom/util/point.ts +24 -28
  288. package/src/phaser/geom/util/polygon.test.ts +12 -10
  289. package/src/phaser/geom/util/polygon.ts +2 -2
  290. package/src/phaser/geom/util/rectangle.test.ts +10 -8
  291. package/src/phaser/geom/util/rectangle.ts +18 -37
  292. package/src/phaser/geom/util/rounded_rectangle.test.ts +11 -9
  293. package/src/phaser/geom/util/rounded_rectangle.ts +1 -1
  294. package/src/phaser/util/math.test.ts +11 -11
  295. package/src/phaser/util/math.ts +29 -46
@@ -0,0 +1,148 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { ComplexPrimitiveShader } from './complex.js';
3
+ import { FastShader } from './fast.js';
4
+ import { PrimitiveShader } from './primitive.js';
5
+ import { StripShader } from './strip.js';
6
+
7
+ type StubOptions = {
8
+ linkStatus?: boolean;
9
+ program?: object | null;
10
+ attribLocations?: Record<string, number>;
11
+ };
12
+
13
+ const createStubGl = (options: StubOptions = {}) => {
14
+ const { linkStatus = true, program = {}, attribLocations = {} } = options;
15
+ const uniformLocations = new Map<string, object>();
16
+ const deleteProgram = vi.fn();
17
+ const useProgram = vi.fn();
18
+ const gl = {
19
+ VERTEX_SHADER: 1,
20
+ FRAGMENT_SHADER: 2,
21
+ COMPILE_STATUS: 3,
22
+ LINK_STATUS: 4,
23
+ createShader: vi.fn(() => ({})),
24
+ shaderSource: vi.fn(),
25
+ compileShader: vi.fn(),
26
+ getShaderParameter: vi.fn(() => true),
27
+ getShaderInfoLog: vi.fn(() => ''),
28
+ createProgram: vi.fn(() => program),
29
+ attachShader: vi.fn(),
30
+ linkProgram: vi.fn(),
31
+ getProgramParameter: vi.fn(() => linkStatus),
32
+ getProgramInfoLog: vi.fn(() => 'link failed'),
33
+ useProgram,
34
+ deleteProgram,
35
+ getUniformLocation: vi.fn((_program: unknown, name: string) => {
36
+ if (!uniformLocations.has(name)) {
37
+ uniformLocations.set(name, { name });
38
+ }
39
+ return uniformLocations.get(name);
40
+ }),
41
+ getAttribLocation: vi.fn((_program: unknown, name: string) => attribLocations[name] ?? 0),
42
+ } as unknown as WebGLRenderingContext;
43
+ return { gl, deleteProgram, useProgram };
44
+ };
45
+
46
+ describe('WebGL shaders', () => {
47
+ describe('PrimitiveShader', () => {
48
+ it('resolves its uniforms and attributes on construction', () => {
49
+ const { gl } = createStubGl({ attribLocations: { aVertexPosition: 0, aColor: 1 } });
50
+ const shader = new PrimitiveShader(gl);
51
+ expect(shader.program).not.toBeNull();
52
+ expect(shader.projectionVector).toBeDefined();
53
+ expect(shader.attributes).toStrictEqual([0, 1]);
54
+ });
55
+
56
+ it('releases the program on destroy', () => {
57
+ const { gl, deleteProgram } = createStubGl();
58
+ const shader = new PrimitiveShader(gl);
59
+ shader.destroy();
60
+ expect(deleteProgram).toHaveBeenCalledWith(shader.program);
61
+ expect(shader.attributes).toBeNull();
62
+ expect(shader.gl).toBeNull();
63
+ });
64
+
65
+ it('leaves the program null when compilation fails', () => {
66
+ const { gl, useProgram } = createStubGl({ program: null });
67
+ const shader = new PrimitiveShader(gl);
68
+ expect(shader.program).toBeNull();
69
+ expect(useProgram).not.toHaveBeenCalled();
70
+ });
71
+
72
+ it('destroys cleanly after a failed compile', () => {
73
+ const { gl } = createStubGl({ program: null });
74
+ const shader = new PrimitiveShader(gl);
75
+ expect(() => {
76
+ shader.destroy();
77
+ }).not.toThrow();
78
+ });
79
+ });
80
+
81
+ describe('StripShader', () => {
82
+ it('resolves its uniforms and attributes on construction', () => {
83
+ const { gl } = createStubGl({
84
+ attribLocations: { aVertexPosition: 0, aTextureCoord: 1, aColor: 2 },
85
+ });
86
+ const shader = new StripShader(gl);
87
+ expect(shader.attributes).toStrictEqual([0, 1]);
88
+ expect(shader.uSampler).toBeDefined();
89
+ expect(shader.translationMatrix).toBeDefined();
90
+ });
91
+
92
+ it('clears its attributes on destroy', () => {
93
+ const { gl } = createStubGl();
94
+ const shader = new StripShader(gl);
95
+ shader.destroy();
96
+ expect(shader.attributes).toBeNull();
97
+ });
98
+ });
99
+
100
+ describe('ComplexPrimitiveShader', () => {
101
+ it('resolves the uniforms it declares', () => {
102
+ const { gl } = createStubGl();
103
+ const shader = new ComplexPrimitiveShader(gl);
104
+ expect(shader.tintColor).toBeDefined();
105
+ expect(shader.color).toBeDefined();
106
+ expect(shader.flipY).toBeDefined();
107
+ });
108
+
109
+ it('leaves colorAttribute unresolved, as the shader never reads aColor', () => {
110
+ const { gl } = createStubGl();
111
+ const shader = new ComplexPrimitiveShader(gl);
112
+ expect(shader.colorAttribute).toBeUndefined();
113
+ expect(shader.attributes).toStrictEqual([0, undefined]);
114
+ });
115
+ });
116
+
117
+ describe('FastShader', () => {
118
+ it('resolves the full attribute set in batch order', () => {
119
+ const { gl } = createStubGl({
120
+ attribLocations: {
121
+ aVertexPosition: 0,
122
+ aPositionCoord: 1,
123
+ aScale: 2,
124
+ aRotation: 3,
125
+ aTextureCoord: 4,
126
+ aColor: 5,
127
+ },
128
+ });
129
+ const shader = new FastShader(gl);
130
+ expect(shader.attributes).toStrictEqual([0, 1, 2, 3, 4, 5]);
131
+ });
132
+
133
+ it('falls back to slot 2 when the driver reports aColor as -1', () => {
134
+ const { gl } = createStubGl({ attribLocations: { aColor: -1 } });
135
+ const shader = new FastShader(gl);
136
+ expect(shader.colorAttribute).toBe(2);
137
+ });
138
+
139
+ it('releases the program and buffers on destroy', () => {
140
+ const { gl, deleteProgram } = createStubGl();
141
+ const shader = new FastShader(gl);
142
+ shader.destroy();
143
+ expect(deleteProgram).toHaveBeenCalled();
144
+ expect(shader.gl).toBeNull();
145
+ expect(shader.attributes).toBeNull();
146
+ });
147
+ });
148
+ });
@@ -4,17 +4,26 @@ import { compileProgram } from '../util.js';
4
4
  // the next one is used for rendering triangle strips
5
5
 
6
6
  export class StripShader {
7
- [key: string]: any;
8
- gl!: any;
9
- _UID!: any;
10
- program!: any;
11
- fragmentSrc!: any;
12
- vertexSrc!: any;
7
+ public gl: WebGLRenderingContext | null;
8
+ public _UID: string;
9
+ public program: WebGLProgram | null;
10
+ public fragmentSrc: string[];
11
+ public vertexSrc: string[];
12
+ public uSampler!: WebGLUniformLocation | null;
13
+ public projectionVector!: WebGLUniformLocation | null;
14
+ public offsetVector!: WebGLUniformLocation | null;
15
+ public translationMatrix!: WebGLUniformLocation | null;
16
+ public alpha!: WebGLUniformLocation | null;
17
+ public colorAttribute!: number;
18
+ public aVertexPosition!: number;
19
+ public aTextureCoord!: number;
20
+ public uniforms: unknown = null;
21
+ public attributes: number[] | null = null;
13
22
  /**
14
23
  * Creates a new StripShader instance.
15
24
  * @param {WebGLRenderingContext} gl - The WebGL rendering context.
16
25
  */
17
- constructor(gl: WebGLRenderingContext) {
26
+ public constructor(gl: WebGLRenderingContext) {
18
27
  this.gl = gl;
19
28
  this._UID = uuidv4();
20
29
  /** @type {WebGLProgram} */
@@ -55,9 +64,15 @@ export class StripShader {
55
64
  /**
56
65
  * Destroys this shader and cleans up resources.
57
66
  */
58
- init() {
59
- const gl = this.gl;
67
+ public init(): void {
68
+ const { gl } = this;
69
+ if (!gl) {
70
+ return;
71
+ }
60
72
  const program = compileProgram(gl, this.vertexSrc, this.fragmentSrc);
73
+ if (!program) {
74
+ return;
75
+ }
61
76
  gl.useProgram(program);
62
77
  // get and store the uniforms for the shader
63
78
  this.uSampler = gl.getUniformLocation(program, 'uSampler');
@@ -77,10 +92,10 @@ export class StripShader {
77
92
  /**
78
93
  * Binds this shader to the WebGL context.
79
94
  */
80
- destroy() {
81
- this.gl.deleteProgram(this.program);
95
+ public destroy(): void {
96
+ this.gl?.deleteProgram(this.program);
82
97
  this.uniforms = null;
83
98
  this.gl = null;
84
- this.attribute = null;
99
+ this.attributes = null;
85
100
  }
86
101
  }
@@ -0,0 +1,124 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import type { NormalShader } from './shader/normal.js';
3
+ import type { IdentifiedWebGLRenderingContext } from './util.js';
4
+ import { WebGLShaderManager } from './shader_manager.js';
5
+
6
+ const createGlMocks = () => ({
7
+ enableVertexAttribArray: vi.fn(),
8
+ disableVertexAttribArray: vi.fn(),
9
+ useProgram: vi.fn(),
10
+ });
11
+
12
+ type GlMocks = ReturnType<typeof createGlMocks>;
13
+
14
+ const createManager = (): { manager: WebGLShaderManager; gl: GlMocks } => {
15
+ const gl = createGlMocks();
16
+ const manager = new WebGLShaderManager();
17
+ manager.gl = { id: 0, ...gl } as unknown as IdentifiedWebGLRenderingContext;
18
+ return { manager, gl };
19
+ };
20
+
21
+ const shaderStub = (uid: string, attributes: number[]): NormalShader =>
22
+ ({ _UID: uid, program: {}, attributes }) as unknown as NormalShader;
23
+
24
+ describe('WebGLShaderManager', () => {
25
+ describe('constructor', () => {
26
+ it('starts with ten disabled attribute slots', () => {
27
+ const manager = new WebGLShaderManager();
28
+ expect(manager.attribState).toHaveLength(10);
29
+ expect(manager.attribState.every((enabled) => enabled === false)).toBe(true);
30
+ });
31
+ });
32
+
33
+ describe('setAttribs', () => {
34
+ it('enables exactly the requested attribute slots', () => {
35
+ const { manager, gl } = createManager();
36
+ manager.setAttribs([0, 2]);
37
+ expect(gl.enableVertexAttribArray).toHaveBeenCalledTimes(2);
38
+ expect(gl.enableVertexAttribArray).toHaveBeenCalledWith(0);
39
+ expect(gl.enableVertexAttribArray).toHaveBeenCalledWith(2);
40
+ });
41
+
42
+ it('only touches slots whose state actually changed', () => {
43
+ const { manager, gl } = createManager();
44
+ manager.setAttribs([0, 1]);
45
+ vi.clearAllMocks();
46
+ manager.setAttribs([0, 1]);
47
+ expect(gl.enableVertexAttribArray).not.toHaveBeenCalled();
48
+ expect(gl.disableVertexAttribArray).not.toHaveBeenCalled();
49
+ });
50
+
51
+ it('disables slots dropped between calls', () => {
52
+ const { manager, gl } = createManager();
53
+ manager.setAttribs([0, 1, 2]);
54
+ vi.clearAllMocks();
55
+ manager.setAttribs([0]);
56
+ expect(gl.disableVertexAttribArray).toHaveBeenCalledWith(1);
57
+ expect(gl.disableVertexAttribArray).toHaveBeenCalledWith(2);
58
+ expect(gl.enableVertexAttribArray).not.toHaveBeenCalled();
59
+ });
60
+
61
+ it('mirrors the sparse temp state, leaving untouched slots unset', () => {
62
+ const { manager } = createManager();
63
+ manager.setAttribs([1, 3]);
64
+ expect(manager.attribState.slice(0, 4)).toStrictEqual([undefined, true, undefined, true]);
65
+ });
66
+
67
+ it('disables the previously enabled slots when given no attributes', () => {
68
+ const { manager, gl } = createManager();
69
+ manager.setAttribs([0, 1]);
70
+ vi.clearAllMocks();
71
+ manager.setAttribs([]);
72
+ expect(gl.disableVertexAttribArray).toHaveBeenCalledWith(0);
73
+ expect(gl.disableVertexAttribArray).toHaveBeenCalledWith(1);
74
+ expect(manager.attribState[0]).toBe(false);
75
+ expect(manager.attribState[1]).toBe(false);
76
+ });
77
+ });
78
+
79
+ describe('setShader', () => {
80
+ it('binds a new shader and reports that it switched', () => {
81
+ const { manager, gl } = createManager();
82
+ const shader = shaderStub('a', [0, 1]);
83
+ expect(manager.setShader(shader)).toBe(true);
84
+ expect(manager.currentShader).toBe(shader);
85
+ expect(gl.useProgram).toHaveBeenCalledWith(shader.program);
86
+ });
87
+
88
+ it('skips rebinding the shader already in use', () => {
89
+ const { manager, gl } = createManager();
90
+ const shader = shaderStub('a', [0, 1]);
91
+ manager.setShader(shader);
92
+ vi.clearAllMocks();
93
+ expect(manager.setShader(shader)).toBe(false);
94
+ expect(gl.useProgram).not.toHaveBeenCalled();
95
+ });
96
+
97
+ it('rebinds when a different shader is supplied', () => {
98
+ const { manager } = createManager();
99
+ manager.setShader(shaderStub('a', [0]));
100
+ const next = shaderStub('b', [0, 1]);
101
+ expect(manager.setShader(next)).toBe(true);
102
+ expect(manager.currentShader).toBe(next);
103
+ });
104
+ });
105
+
106
+ describe('destroy', () => {
107
+ it('clears attribute state and forgets the current shader', () => {
108
+ const { manager } = createManager();
109
+ manager.setShader(shaderStub('a', [0]));
110
+ manager.destroy();
111
+ expect(manager.attribState).toStrictEqual([]);
112
+ expect(manager.tempAttribState).toStrictEqual([]);
113
+ expect(manager.currentShader).toBeNull();
114
+ expect(manager._currentId).toBeNull();
115
+ });
116
+
117
+ it('tolerates shaders that were never created', () => {
118
+ const { manager } = createManager();
119
+ expect(() => {
120
+ manager.destroy();
121
+ }).not.toThrow();
122
+ });
123
+ });
124
+ });
@@ -6,28 +6,22 @@ import { StripShader } from './shader/strip.js';
6
6
  import type { IdentifiedWebGLRenderingContext } from './util.js';
7
7
 
8
8
  export class WebGLShaderManager {
9
- [key: string]: any;
10
- gl!: any;
11
- primitiveShader!: any;
12
- complexPrimitiveShader!: any;
13
- defaultShader!: any;
14
- fastShader!: any;
15
- stripShader!: any;
16
- maxAttibs!: any;
17
- attribState!: any;
18
- tempAttribState!: any;
19
- stack!: any;
9
+ public gl!: IdentifiedWebGLRenderingContext;
10
+ public primitiveShader: PrimitiveShader | null = null;
11
+ public complexPrimitiveShader: ComplexPrimitiveShader | null = null;
12
+ public defaultShader: NormalShader | null = null;
13
+ public fastShader: FastShader | null = null;
14
+ public stripShader: StripShader | null = null;
15
+ public maxAttibs = 10;
16
+ public attribState: (boolean | undefined)[];
17
+ public tempAttribState: (boolean | undefined)[];
18
+ public stack: NormalShader[];
19
+ public currentShader: NormalShader | null = null;
20
+ public _currentId: string | null = null;
20
21
  /**
21
22
  * Initializes the shader manager with a WebGL context.
22
23
  */
23
- constructor() {
24
- this.gl = null;
25
- this.primitiveShader = null;
26
- this.complexPrimitiveShader = null;
27
- this.defaultShader = null;
28
- this.fastShader = null;
29
- this.stripShader = null;
30
- this.maxAttibs = 10;
24
+ public constructor() {
31
25
  this.attribState = [];
32
26
  this.tempAttribState = [];
33
27
  for (let i = 0; i < this.maxAttibs; i += 1) {
@@ -40,7 +34,7 @@ export class WebGLShaderManager {
40
34
  * Initializes the shader manager with a WebGL context.
41
35
  * @param {WebGLRenderingContext & { id: number }} gl - The WebGL rendering context.
42
36
  */
43
- setContext(gl: IdentifiedWebGLRenderingContext) {
37
+ public setContext(gl: IdentifiedWebGLRenderingContext) {
44
38
  this.gl = gl;
45
39
  this.primitiveShader = new PrimitiveShader(gl);
46
40
  this.complexPrimitiveShader = new ComplexPrimitiveShader(gl);
@@ -54,18 +48,17 @@ export class WebGLShaderManager {
54
48
  * Sets up the shader manager for WebGL rendering.
55
49
  * @param {number[]} attribs - The attribute locations to set up.
56
50
  */
57
- setAttribs(attribs: number[]) {
51
+ public setAttribs(attribs: number[]) {
58
52
  // reset temp state
59
53
  let i;
60
54
  for (i = 0; i < this.tempAttribState.length; i += 1) {
61
55
  this.tempAttribState[i] = false;
62
56
  }
63
57
  // set the new attribs
64
- for (i = 0; i < attribs.length; i += 1) {
65
- const attribId = attribs[i];
58
+ for (const attribId of attribs) {
66
59
  this.tempAttribState[attribId] = true;
67
60
  }
68
- const gl = this.gl;
61
+ const { gl } = this;
69
62
  for (i = 0; i < this.attribState.length; i += 1) {
70
63
  if (this.attribState[i] !== this.tempAttribState[i]) {
71
64
  this.attribState[i] = this.tempAttribState[i];
@@ -83,7 +76,7 @@ export class WebGLShaderManager {
83
76
  * @param {NormalShader} shader - The shader to set up.
84
77
  * @returns {boolean} Whether the shader setup was successful.
85
78
  */
86
- setShader(shader: NormalShader) {
79
+ public setShader(shader: NormalShader): boolean {
87
80
  if (this._currentId === shader._UID) {
88
81
  return false;
89
82
  }
@@ -97,16 +90,15 @@ export class WebGLShaderManager {
97
90
  /**
98
91
  * Destroys the manager.
99
92
  */
100
- destroy() {
101
- this.attribState = null;
102
- this.tempAttribState = null;
93
+ public destroy(): void {
94
+ this.attribState = [];
95
+ this.tempAttribState = [];
103
96
  this.currentShader = null;
104
97
  this._currentId = null;
105
- this.primitiveShader.destroy();
106
- this.complexPrimitiveShader.destroy();
107
- this.defaultShader.destroy();
108
- this.fastShader.destroy();
109
- this.stripShader.destroy();
110
- this.gl = null;
98
+ this.primitiveShader?.destroy();
99
+ this.complexPrimitiveShader?.destroy();
100
+ this.defaultShader?.destroy();
101
+ this.fastShader?.destroy();
102
+ this.stripShader?.destroy();
111
103
  }
112
104
  }