@woosh/meep-engine 3.9.0 → 3.11.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 (832) hide show
  1. package/README.md +168 -152
  2. package/build/bundle-worker-image-decoder.js +1 -1
  3. package/build/bundle-worker-terrain.js +1 -1
  4. package/package.json +3 -2
  5. package/src/REVIEW_2026_08_06.md +610 -610
  6. package/src/avif/encode_image_source.d.ts +70 -0
  7. package/src/avif/encode_image_source.d.ts.map +1 -0
  8. package/src/avif/encode_image_source.js +117 -0
  9. package/src/avif/encoder_worker.js +15 -126
  10. package/src/avif/index.d.ts +4 -2
  11. package/src/avif/index.js +21 -2
  12. package/src/avif/native/DECISIONS.md +537 -0
  13. package/src/avif/native/NOTICE.md +61 -0
  14. package/src/avif/native/api/AvifDecoder.d.ts +67 -0
  15. package/src/avif/native/api/AvifDecoder.d.ts.map +1 -0
  16. package/src/avif/native/api/AvifDecoder.js +121 -0
  17. package/src/avif/native/api/apply_transformations.d.ts +30 -0
  18. package/src/avif/native/api/apply_transformations.d.ts.map +1 -0
  19. package/src/avif/native/api/apply_transformations.js +120 -0
  20. package/src/avif/native/api/avif_to_sampler2d.d.ts +25 -0
  21. package/src/avif/native/api/avif_to_sampler2d.d.ts.map +1 -0
  22. package/src/avif/native/api/avif_to_sampler2d.js +42 -0
  23. package/src/avif/native/api/convert_to_rgba.d.ts +54 -0
  24. package/src/avif/native/api/convert_to_rgba.d.ts.map +1 -0
  25. package/src/avif/native/api/convert_to_rgba.js +204 -0
  26. package/src/avif/native/api/decode_avif.d.ts +24 -0
  27. package/src/avif/native/api/decode_avif.d.ts.map +1 -0
  28. package/src/avif/native/api/decode_avif.js +111 -0
  29. package/src/avif/native/api/decode_image_item.d.ts +18 -0
  30. package/src/avif/native/api/decode_image_item.d.ts.map +1 -0
  31. package/src/avif/native/api/decode_image_item.js +234 -0
  32. package/src/avif/native/api/encode_avif.d.ts +73 -0
  33. package/src/avif/native/api/encode_avif.d.ts.map +1 -0
  34. package/src/avif/native/api/encode_avif.js +488 -0
  35. package/src/avif/native/api/sampler2d_to_avif.d.ts +22 -0
  36. package/src/avif/native/api/sampler2d_to_avif.d.ts.map +1 -0
  37. package/src/avif/native/api/sampler2d_to_avif.js +108 -0
  38. package/src/avif/native/av1/decode/Av1FrameContext.d.ts +286 -0
  39. package/src/avif/native/av1/decode/Av1FrameContext.d.ts.map +1 -0
  40. package/src/avif/native/av1/decode/Av1FrameContext.js +622 -0
  41. package/src/avif/native/av1/decode/block_decoded.d.ts +27 -0
  42. package/src/avif/native/av1/decode/block_decoded.d.ts.map +1 -0
  43. package/src/avif/native/av1/decode/block_decoded.js +59 -0
  44. package/src/avif/native/av1/decode/decode_av1_still.d.ts +22 -0
  45. package/src/avif/native/av1/decode/decode_av1_still.d.ts.map +1 -0
  46. package/src/avif/native/av1/decode/decode_av1_still.js +309 -0
  47. package/src/avif/native/av1/decode/decode_coefficients.d.ts +20 -0
  48. package/src/avif/native/av1/decode/decode_coefficients.d.ts.map +1 -0
  49. package/src/avif/native/av1/decode/decode_coefficients.js +259 -0
  50. package/src/avif/native/av1/decode/decode_palette.d.ts +28 -0
  51. package/src/avif/native/av1/decode/decode_palette.d.ts.map +1 -0
  52. package/src/avif/native/av1/decode/decode_palette.js +442 -0
  53. package/src/avif/native/av1/decode/decode_tile.d.ts +14 -0
  54. package/src/avif/native/av1/decode/decode_tile.d.ts.map +1 -0
  55. package/src/avif/native/av1/decode/decode_tile.js +1213 -0
  56. package/src/avif/native/av1/decode/get_scan.d.ts +16 -0
  57. package/src/avif/native/av1/decode/get_scan.d.ts.map +1 -0
  58. package/src/avif/native/av1/decode/get_scan.js +138 -0
  59. package/src/avif/native/av1/decode/read_lr.d.ts +35 -0
  60. package/src/avif/native/av1/decode/read_lr.d.ts.map +1 -0
  61. package/src/avif/native/av1/decode/read_lr.js +277 -0
  62. package/src/avif/native/av1/decode/read_transform_type.d.ts +19 -0
  63. package/src/avif/native/av1/decode/read_transform_type.d.ts.map +1 -0
  64. package/src/avif/native/av1/decode/read_transform_type.js +92 -0
  65. package/src/avif/native/av1/decode/reconstruct.d.ts +36 -0
  66. package/src/avif/native/av1/decode/reconstruct.d.ts.map +1 -0
  67. package/src/avif/native/av1/decode/reconstruct.js +241 -0
  68. package/src/avif/native/av1/decode/transform_type.d.ts +49 -0
  69. package/src/avif/native/av1/decode/transform_type.d.ts.map +1 -0
  70. package/src/avif/native/av1/decode/transform_type.js +137 -0
  71. package/src/avif/native/av1/encode/Av1BlockSnapshot.d.ts +81 -0
  72. package/src/avif/native/av1/encode/Av1BlockSnapshot.d.ts.map +1 -0
  73. package/src/avif/native/av1/encode/Av1BlockSnapshot.js +299 -0
  74. package/src/avif/native/av1/encode/Av1EncodeContext.d.ts +384 -0
  75. package/src/avif/native/av1/encode/Av1EncodeContext.d.ts.map +1 -0
  76. package/src/avif/native/av1/encode/Av1EncodeContext.js +590 -0
  77. package/src/avif/native/av1/encode/build_headers.d.ts +50 -0
  78. package/src/avif/native/av1/encode/build_headers.d.ts.map +1 -0
  79. package/src/avif/native/av1/encode/build_headers.js +359 -0
  80. package/src/avif/native/av1/encode/choose_chroma_alpha.d.ts +26 -0
  81. package/src/avif/native/av1/encode/choose_chroma_alpha.d.ts.map +1 -0
  82. package/src/avif/native/av1/encode/choose_chroma_alpha.js +90 -0
  83. package/src/avif/native/av1/encode/choose_filters.d.ts +21 -0
  84. package/src/avif/native/av1/encode/choose_filters.d.ts.map +1 -0
  85. package/src/avif/native/av1/encode/choose_filters.js +318 -0
  86. package/src/avif/native/av1/encode/choose_restoration.d.ts +35 -0
  87. package/src/avif/native/av1/encode/choose_restoration.d.ts.map +1 -0
  88. package/src/avif/native/av1/encode/choose_restoration.js +616 -0
  89. package/src/avif/native/av1/encode/decode_effort.d.ts +57 -0
  90. package/src/avif/native/av1/encode/decode_effort.d.ts.map +1 -0
  91. package/src/avif/native/av1/encode/decode_effort.js +59 -0
  92. package/src/avif/native/av1/encode/encode_av1_still.d.ts +17 -0
  93. package/src/avif/native/av1/encode/encode_av1_still.d.ts.map +1 -0
  94. package/src/avif/native/av1/encode/encode_av1_still.js +194 -0
  95. package/src/avif/native/av1/encode/encode_effort.d.ts +56 -0
  96. package/src/avif/native/av1/encode/encode_effort.d.ts.map +1 -0
  97. package/src/avif/native/av1/encode/encode_effort.js +97 -0
  98. package/src/avif/native/av1/encode/encode_tile.d.ts +26 -0
  99. package/src/avif/native/av1/encode/encode_tile.d.ts.map +1 -0
  100. package/src/avif/native/av1/encode/encode_tile.js +2331 -0
  101. package/src/avif/native/av1/encode/quantise.d.ts +51 -0
  102. package/src/avif/native/av1/encode/quantise.d.ts.map +1 -0
  103. package/src/avif/native/av1/encode/quantise.js +212 -0
  104. package/src/avif/native/av1/encode/write_coefficients.d.ts +42 -0
  105. package/src/avif/native/av1/encode/write_coefficients.d.ts.map +1 -0
  106. package/src/avif/native/av1/encode/write_coefficients.js +367 -0
  107. package/src/avif/native/av1/encode/write_lr.d.ts +33 -0
  108. package/src/avif/native/av1/encode/write_lr.d.ts.map +1 -0
  109. package/src/avif/native/av1/encode/write_lr.js +174 -0
  110. package/src/avif/native/av1/encode/write_transform_type.d.ts +21 -0
  111. package/src/avif/native/av1/encode/write_transform_type.d.ts.map +1 -0
  112. package/src/avif/native/av1/encode/write_transform_type.js +70 -0
  113. package/src/avif/native/av1/entropy/CdfContext.d.ts +167 -0
  114. package/src/avif/native/av1/entropy/CdfContext.d.ts.map +1 -0
  115. package/src/avif/native/av1/entropy/CdfContext.js +433 -0
  116. package/src/avif/native/av1/entropy/SymbolReader.d.ts +103 -0
  117. package/src/avif/native/av1/entropy/SymbolReader.d.ts.map +1 -0
  118. package/src/avif/native/av1/entropy/SymbolReader.js +317 -0
  119. package/src/avif/native/av1/entropy/SymbolWriter.d.ts +107 -0
  120. package/src/avif/native/av1/entropy/SymbolWriter.d.ts.map +1 -0
  121. package/src/avif/native/av1/entropy/SymbolWriter.js +352 -0
  122. package/src/avif/native/av1/entropy/coefficient_context.d.ts +71 -0
  123. package/src/avif/native/av1/entropy/coefficient_context.d.ts.map +1 -0
  124. package/src/avif/native/av1/entropy/coefficient_context.js +325 -0
  125. package/src/avif/native/av1/entropy/partition_cdf.d.ts +54 -0
  126. package/src/avif/native/av1/entropy/partition_cdf.d.ts.map +1 -0
  127. package/src/avif/native/av1/entropy/partition_cdf.js +98 -0
  128. package/src/avif/native/av1/entropy/symbol_cost.d.ts +37 -0
  129. package/src/avif/native/av1/entropy/symbol_cost.d.ts.map +1 -0
  130. package/src/avif/native/av1/entropy/symbol_cost.js +76 -0
  131. package/src/avif/native/av1/filter/cdef.d.ts +15 -0
  132. package/src/avif/native/av1/filter/cdef.d.ts.map +1 -0
  133. package/src/avif/native/av1/filter/cdef.js +313 -0
  134. package/src/avif/native/av1/filter/loop_filter.d.ts +14 -0
  135. package/src/avif/native/av1/filter/loop_filter.d.ts.map +1 -0
  136. package/src/avif/native/av1/filter/loop_filter.js +377 -0
  137. package/src/avif/native/av1/filter/loop_restoration.d.ts +42 -0
  138. package/src/avif/native/av1/filter/loop_restoration.d.ts.map +1 -0
  139. package/src/avif/native/av1/filter/loop_restoration.js +451 -0
  140. package/src/avif/native/av1/filter/superres.d.ts +18 -0
  141. package/src/avif/native/av1/filter/superres.d.ts.map +1 -0
  142. package/src/avif/native/av1/filter/superres.js +86 -0
  143. package/src/avif/native/av1/grain/FilmGrainState.d.ts +62 -0
  144. package/src/avif/native/av1/grain/FilmGrainState.d.ts.map +1 -0
  145. package/src/avif/native/av1/grain/FilmGrainState.js +87 -0
  146. package/src/avif/native/av1/grain/film_grain.d.ts +16 -0
  147. package/src/avif/native/av1/grain/film_grain.d.ts.map +1 -0
  148. package/src/avif/native/av1/grain/film_grain.js +623 -0
  149. package/src/avif/native/av1/obu/FrameHeader.d.ts +248 -0
  150. package/src/avif/native/av1/obu/FrameHeader.d.ts.map +1 -0
  151. package/src/avif/native/av1/obu/FrameHeader.js +381 -0
  152. package/src/avif/native/av1/obu/ObuHeader.d.ts +53 -0
  153. package/src/avif/native/av1/obu/ObuHeader.d.ts.map +1 -0
  154. package/src/avif/native/av1/obu/ObuHeader.js +62 -0
  155. package/src/avif/native/av1/obu/SequenceHeader.d.ts +157 -0
  156. package/src/avif/native/av1/obu/SequenceHeader.d.ts.map +1 -0
  157. package/src/avif/native/av1/obu/SequenceHeader.js +225 -0
  158. package/src/avif/native/av1/obu/for_each_obu.d.ts +24 -0
  159. package/src/avif/native/av1/obu/for_each_obu.d.ts.map +1 -0
  160. package/src/avif/native/av1/obu/for_each_obu.js +50 -0
  161. package/src/avif/native/av1/obu/parse_frame_header.d.ts +18 -0
  162. package/src/avif/native/av1/obu/parse_frame_header.d.ts.map +1 -0
  163. package/src/avif/native/av1/obu/parse_frame_header.js +841 -0
  164. package/src/avif/native/av1/obu/parse_obu_header.d.ts +23 -0
  165. package/src/avif/native/av1/obu/parse_obu_header.d.ts.map +1 -0
  166. package/src/avif/native/av1/obu/parse_obu_header.js +69 -0
  167. package/src/avif/native/av1/obu/parse_sequence_header.d.ts +17 -0
  168. package/src/avif/native/av1/obu/parse_sequence_header.d.ts.map +1 -0
  169. package/src/avif/native/av1/obu/parse_sequence_header.js +263 -0
  170. package/src/avif/native/av1/obu/write_frame_header.d.ts +16 -0
  171. package/src/avif/native/av1/obu/write_frame_header.d.ts.map +1 -0
  172. package/src/avif/native/av1/obu/write_frame_header.js +579 -0
  173. package/src/avif/native/av1/obu/write_sequence_header.d.ts +17 -0
  174. package/src/avif/native/av1/obu/write_sequence_header.d.ts.map +1 -0
  175. package/src/avif/native/av1/obu/write_sequence_header.js +189 -0
  176. package/src/avif/native/av1/predict/IntraPredictionState.d.ts +49 -0
  177. package/src/avif/native/av1/predict/IntraPredictionState.d.ts.map +1 -0
  178. package/src/avif/native/av1/predict/IntraPredictionState.js +58 -0
  179. package/src/avif/native/av1/predict/intra_filter_type.d.ts +17 -0
  180. package/src/avif/native/av1/predict/intra_filter_type.d.ts.map +1 -0
  181. package/src/avif/native/av1/predict/intra_filter_type.js +79 -0
  182. package/src/avif/native/av1/predict/predict_chroma_from_luma.d.ts +50 -0
  183. package/src/avif/native/av1/predict/predict_chroma_from_luma.d.ts.map +1 -0
  184. package/src/avif/native/av1/predict/predict_chroma_from_luma.js +153 -0
  185. package/src/avif/native/av1/predict/predict_intra.d.ts +42 -0
  186. package/src/avif/native/av1/predict/predict_intra.d.ts.map +1 -0
  187. package/src/avif/native/av1/predict/predict_intra.js +803 -0
  188. package/src/avif/native/av1/predict/predict_palette.d.ts +23 -0
  189. package/src/avif/native/av1/predict/predict_palette.d.ts.map +1 -0
  190. package/src/avif/native/av1/predict/predict_palette.js +36 -0
  191. package/src/avif/native/av1/tables/av1_symbols.d.ts +411 -0
  192. package/src/avif/native/av1/tables/av1_symbols.d.ts.map +1 -0
  193. package/src/avif/native/av1/tables/av1_symbols.js +419 -0
  194. package/src/avif/native/av1/tables/block_tables.d.ts +181 -0
  195. package/src/avif/native/av1/tables/block_tables.d.ts.map +1 -0
  196. package/src/avif/native/av1/tables/block_tables.js +270 -0
  197. package/src/avif/native/av1/tables/cdf_tables.d.ts +961 -0
  198. package/src/avif/native/av1/tables/cdf_tables.d.ts.map +1 -0
  199. package/src/avif/native/av1/tables/cdf_tables.js +1893 -0
  200. package/src/avif/native/av1/tables/coefficient_tables.d.ts +41 -0
  201. package/src/avif/native/av1/tables/coefficient_tables.d.ts.map +1 -0
  202. package/src/avif/native/av1/tables/coefficient_tables.js +82 -0
  203. package/src/avif/native/av1/tables/derived_block_tables.d.ts +15 -0
  204. package/src/avif/native/av1/tables/derived_block_tables.d.ts.map +1 -0
  205. package/src/avif/native/av1/tables/derived_block_tables.js +23 -0
  206. package/src/avif/native/av1/tables/filter_tables.d.ts +171 -0
  207. package/src/avif/native/av1/tables/filter_tables.d.ts.map +1 -0
  208. package/src/avif/native/av1/tables/filter_tables.js +313 -0
  209. package/src/avif/native/av1/tables/grain_tables.d.ts +11 -0
  210. package/src/avif/native/av1/tables/grain_tables.d.ts.map +1 -0
  211. package/src/avif/native/av1/tables/grain_tables.js +190 -0
  212. package/src/avif/native/av1/tables/prediction_tables.d.ts +141 -0
  213. package/src/avif/native/av1/tables/prediction_tables.d.ts.map +1 -0
  214. package/src/avif/native/av1/tables/prediction_tables.js +223 -0
  215. package/src/avif/native/av1/tables/quantizer_matrix_tables.d.ts +21 -0
  216. package/src/avif/native/av1/tables/quantizer_matrix_tables.d.ts.map +1 -0
  217. package/src/avif/native/av1/tables/quantizer_matrix_tables.js +38 -0
  218. package/src/avif/native/av1/tables/quantizer_tables.d.ts +21 -0
  219. package/src/avif/native/av1/tables/quantizer_tables.d.ts.map +1 -0
  220. package/src/avif/native/av1/tables/quantizer_tables.js +160 -0
  221. package/src/avif/native/av1/tables/scan_tables.d.ts +321 -0
  222. package/src/avif/native/av1/tables/scan_tables.d.ts.map +1 -0
  223. package/src/avif/native/av1/tables/scan_tables.js +727 -0
  224. package/src/avif/native/av1/tables/segmentation_tables.d.ts +31 -0
  225. package/src/avif/native/av1/tables/segmentation_tables.d.ts.map +1 -0
  226. package/src/avif/native/av1/tables/segmentation_tables.js +48 -0
  227. package/src/avif/native/av1/tables/transform_tables.d.ts +91 -0
  228. package/src/avif/native/av1/tables/transform_tables.d.ts.map +1 -0
  229. package/src/avif/native/av1/tables/transform_tables.js +140 -0
  230. package/src/avif/native/av1/tables/unpack_table.d.ts +33 -0
  231. package/src/avif/native/av1/tables/unpack_table.d.ts.map +1 -0
  232. package/src/avif/native/av1/tables/unpack_table.js +73 -0
  233. package/src/avif/native/av1/transform/forward_transform_2d.d.ts +61 -0
  234. package/src/avif/native/av1/transform/forward_transform_2d.d.ts.map +1 -0
  235. package/src/avif/native/av1/transform/forward_transform_2d.js +574 -0
  236. package/src/avif/native/av1/transform/inverse_transform_1d.d.ts +76 -0
  237. package/src/avif/native/av1/transform/inverse_transform_1d.d.ts.map +1 -0
  238. package/src/avif/native/av1/transform/inverse_transform_1d.js +590 -0
  239. package/src/avif/native/av1/transform/inverse_transform_2d.d.ts +46 -0
  240. package/src/avif/native/av1/transform/inverse_transform_2d.d.ts.map +1 -0
  241. package/src/avif/native/av1/transform/inverse_transform_2d.js +180 -0
  242. package/src/avif/native/av1/util/ceil_log2.d.ts +13 -0
  243. package/src/avif/native/av1/util/ceil_log2.d.ts.map +1 -0
  244. package/src/avif/native/av1/util/ceil_log2.js +18 -0
  245. package/src/avif/native/av1/util/floor_log2.d.ts +20 -0
  246. package/src/avif/native/av1/util/floor_log2.d.ts.map +1 -0
  247. package/src/avif/native/av1/util/floor_log2.js +20 -0
  248. package/src/avif/native/av1/util/round2.d.ts +22 -0
  249. package/src/avif/native/av1/util/round2.d.ts.map +1 -0
  250. package/src/avif/native/av1/util/round2.js +27 -0
  251. package/src/avif/native/av1/util/round2_signed.d.ts +14 -0
  252. package/src/avif/native/av1/util/round2_signed.d.ts.map +1 -0
  253. package/src/avif/native/av1/util/round2_signed.js +17 -0
  254. package/src/avif/native/av1/util/tile_log2.d.ts +16 -0
  255. package/src/avif/native/av1/util/tile_log2.d.ts.map +1 -0
  256. package/src/avif/native/av1/util/tile_log2.js +23 -0
  257. package/src/avif/native/bitstream/BitReader.d.ts +174 -0
  258. package/src/avif/native/bitstream/BitReader.d.ts.map +1 -0
  259. package/src/avif/native/bitstream/BitReader.js +391 -0
  260. package/src/avif/native/bitstream/BitWriter.d.ts +122 -0
  261. package/src/avif/native/bitstream/BitWriter.d.ts.map +1 -0
  262. package/src/avif/native/bitstream/BitWriter.js +351 -0
  263. package/src/avif/native/color/ColourTransform.d.ts +62 -0
  264. package/src/avif/native/color/ColourTransform.d.ts.map +1 -0
  265. package/src/avif/native/color/ColourTransform.js +189 -0
  266. package/src/avif/native/color/YuvImage.d.ts +51 -0
  267. package/src/avif/native/color/YuvImage.d.ts.map +1 -0
  268. package/src/avif/native/color/YuvImage.js +66 -0
  269. package/src/avif/native/color/clamp_sample.d.ts +18 -0
  270. package/src/avif/native/color/clamp_sample.d.ts.map +1 -0
  271. package/src/avif/native/color/clamp_sample.js +25 -0
  272. package/src/avif/native/color/linear_to_transfer.d.ts +24 -0
  273. package/src/avif/native/color/linear_to_transfer.d.ts.map +1 -0
  274. package/src/avif/native/color/linear_to_transfer.js +126 -0
  275. package/src/avif/native/color/primaries.d.ts +20 -0
  276. package/src/avif/native/color/primaries.d.ts.map +1 -0
  277. package/src/avif/native/color/primaries.js +94 -0
  278. package/src/avif/native/color/rgb_row_to_ycbcr.d.ts +20 -0
  279. package/src/avif/native/color/rgb_row_to_ycbcr.d.ts.map +1 -0
  280. package/src/avif/native/color/rgb_row_to_ycbcr.js +78 -0
  281. package/src/avif/native/color/transfer_to_linear.d.ts +49 -0
  282. package/src/avif/native/color/transfer_to_linear.d.ts.map +1 -0
  283. package/src/avif/native/color/transfer_to_linear.js +171 -0
  284. package/src/avif/native/color/upsample_chroma_row.d.ts +35 -0
  285. package/src/avif/native/color/upsample_chroma_row.d.ts.map +1 -0
  286. package/src/avif/native/color/upsample_chroma_row.js +89 -0
  287. package/src/avif/native/color/ycbcr_row_to_rgb.d.ts +23 -0
  288. package/src/avif/native/color/ycbcr_row_to_rgb.d.ts.map +1 -0
  289. package/src/avif/native/color/ycbcr_row_to_rgb.js +78 -0
  290. package/src/avif/native/heif/AvifFile.d.ts +112 -0
  291. package/src/avif/native/heif/AvifFile.d.ts.map +1 -0
  292. package/src/avif/native/heif/AvifFile.js +142 -0
  293. package/src/avif/native/heif/ItemProperty.d.ts +244 -0
  294. package/src/avif/native/heif/ItemProperty.d.ts.map +1 -0
  295. package/src/avif/native/heif/ItemProperty.js +321 -0
  296. package/src/avif/native/heif/find_item_property.d.ts +17 -0
  297. package/src/avif/native/heif/find_item_property.d.ts.map +1 -0
  298. package/src/avif/native/heif/find_item_property.js +28 -0
  299. package/src/avif/native/heif/find_item_references.d.ts +16 -0
  300. package/src/avif/native/heif/find_item_references.d.ts.map +1 -0
  301. package/src/avif/native/heif/find_item_references.js +29 -0
  302. package/src/avif/native/heif/find_items_referencing.d.ts +17 -0
  303. package/src/avif/native/heif/find_items_referencing.d.ts.map +1 -0
  304. package/src/avif/native/heif/find_items_referencing.js +36 -0
  305. package/src/avif/native/heif/parse_avif_file.d.ts +15 -0
  306. package/src/avif/native/heif/parse_avif_file.d.ts.map +1 -0
  307. package/src/avif/native/heif/parse_avif_file.js +383 -0
  308. package/src/avif/native/heif/parse_image_grid.d.ts +18 -0
  309. package/src/avif/native/heif/parse_image_grid.d.ts.map +1 -0
  310. package/src/avif/native/heif/parse_image_grid.js +48 -0
  311. package/src/avif/native/heif/parse_item_property.d.ts +18 -0
  312. package/src/avif/native/heif/parse_item_property.d.ts.map +1 -0
  313. package/src/avif/native/heif/parse_item_property.js +243 -0
  314. package/src/avif/native/heif/read_item_data.d.ts +22 -0
  315. package/src/avif/native/heif/read_item_data.d.ts.map +1 -0
  316. package/src/avif/native/heif/read_item_data.js +97 -0
  317. package/src/avif/native/heif/write_avif_file.d.ts +50 -0
  318. package/src/avif/native/heif/write_avif_file.d.ts.map +1 -0
  319. package/src/avif/native/heif/write_avif_file.js +348 -0
  320. package/src/avif/native/heif/write_item_property.d.ts +16 -0
  321. package/src/avif/native/heif/write_item_property.d.ts.map +1 -0
  322. package/src/avif/native/heif/write_item_property.js +182 -0
  323. package/src/avif/native/index.d.ts +14 -0
  324. package/src/avif/native/index.d.ts.map +1 -0
  325. package/src/avif/native/index.js +56 -0
  326. package/src/avif/native/isobmff/BoxHeader.d.ts +50 -0
  327. package/src/avif/native/isobmff/BoxHeader.d.ts.map +1 -0
  328. package/src/avif/native/isobmff/BoxHeader.js +57 -0
  329. package/src/avif/native/isobmff/BoxWriter.d.ts +118 -0
  330. package/src/avif/native/isobmff/BoxWriter.d.ts.map +1 -0
  331. package/src/avif/native/isobmff/BoxWriter.js +264 -0
  332. package/src/avif/native/isobmff/ByteCursor.d.ts +125 -0
  333. package/src/avif/native/isobmff/ByteCursor.d.ts.map +1 -0
  334. package/src/avif/native/isobmff/ByteCursor.js +298 -0
  335. package/src/avif/native/isobmff/for_each_box.d.ts +23 -0
  336. package/src/avif/native/isobmff/for_each_box.d.ts.map +1 -0
  337. package/src/avif/native/isobmff/for_each_box.js +39 -0
  338. package/src/avif/native/isobmff/read_box_header.d.ts +22 -0
  339. package/src/avif/native/isobmff/read_box_header.d.ts.map +1 -0
  340. package/src/avif/native/isobmff/read_box_header.js +59 -0
  341. package/src/avif/native/isobmff/read_full_box_header.d.ts +26 -0
  342. package/src/avif/native/isobmff/read_full_box_header.d.ts.map +1 -0
  343. package/src/avif/native/isobmff/read_full_box_header.js +33 -0
  344. package/src/avif/threaded_image_encoder.d.ts +7 -2
  345. package/src/avif/threaded_image_encoder.d.ts.map +1 -1
  346. package/src/avif/threaded_image_encoder.js +107 -21
  347. package/src/core/binary/BinaryBuffer.d.ts +40 -0
  348. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  349. package/src/core/binary/BinaryBuffer.js +100 -0
  350. package/src/core/binary/hash/crc32.d.ts +16 -0
  351. package/src/core/binary/hash/crc32.d.ts.map +1 -0
  352. package/src/core/binary/hash/crc32.js +96 -0
  353. package/src/core/binary/utf8/utf8_decode.d.ts +21 -0
  354. package/src/core/binary/utf8/utf8_decode.d.ts.map +1 -0
  355. package/src/core/binary/utf8/utf8_decode.js +43 -0
  356. package/src/core/binary/utf8/utf8_encode_into.d.ts +20 -0
  357. package/src/core/binary/utf8/utf8_encode_into.d.ts.map +1 -0
  358. package/src/core/binary/utf8/utf8_encode_into.js +48 -0
  359. package/src/core/binary/utf8/utf8_encoded_length.d.ts +14 -0
  360. package/src/core/binary/utf8/utf8_encoded_length.d.ts.map +1 -0
  361. package/src/core/binary/utf8/utf8_encoded_length.js +36 -0
  362. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +417 -0
  363. package/src/core/color/COLOR_REVIEW_2026_08_28.md +779 -0
  364. package/src/core/color/Color.d.ts +128 -20
  365. package/src/core/color/Color.d.ts.map +1 -1
  366. package/src/core/color/Color.js +959 -866
  367. package/src/core/color/PQ/PQ_constants.d.ts +10 -0
  368. package/src/core/color/PQ/PQ_constants.d.ts.map +1 -1
  369. package/src/core/color/PQ/PQ_constants.js +10 -0
  370. package/src/core/color/PQ/linear_to_PQ.d.ts.map +1 -1
  371. package/src/core/color/PQ/linear_to_PQ.js +6 -0
  372. package/src/core/color/REC709_PRIMARIES.d.ts +50 -0
  373. package/src/core/color/REC709_PRIMARIES.d.ts.map +1 -0
  374. package/src/core/color/REC709_PRIMARIES.js +53 -0
  375. package/src/core/color/construct/color_from_hex.d.ts +21 -0
  376. package/src/core/color/construct/color_from_hex.d.ts.map +1 -0
  377. package/src/core/color/construct/color_from_hex.js +33 -0
  378. package/src/core/color/construct/color_from_temperature.d.ts +22 -0
  379. package/src/core/color/construct/color_from_temperature.d.ts.map +1 -0
  380. package/src/core/color/construct/color_from_temperature.js +33 -0
  381. package/src/core/color/construct/color_from_uint24.d.ts +19 -0
  382. package/src/core/color/construct/color_from_uint24.d.ts.map +1 -0
  383. package/src/core/color/construct/color_from_uint24.js +26 -0
  384. package/src/core/color/construct/color_from_uint32.d.ts +20 -0
  385. package/src/core/color/construct/color_from_uint32.d.ts.map +1 -0
  386. package/src/core/color/construct/color_from_uint32.js +39 -0
  387. package/src/core/color/construct/color_gray.d.ts +17 -0
  388. package/src/core/color/construct/color_gray.d.ts.map +1 -0
  389. package/src/core/color/construct/color_gray.js +22 -0
  390. package/src/core/color/hex/hex2rgb.d.ts +1 -11
  391. package/src/core/color/hex/hex2rgb.d.ts.map +1 -1
  392. package/src/core/color/hex/hex2rgb.js +7 -24
  393. package/src/core/color/hex/hex_to_rgb.d.ts +18 -0
  394. package/src/core/color/hex/hex_to_rgb.d.ts.map +1 -0
  395. package/src/core/color/hex/hex_to_rgb.js +62 -0
  396. package/src/core/color/hex/rgb2hex.d.ts +1 -8
  397. package/src/core/color/hex/rgb2hex.d.ts.map +1 -1
  398. package/src/core/color/hex/rgb2hex.js +7 -13
  399. package/src/core/color/hex/rgb_to_hex.d.ts +9 -0
  400. package/src/core/color/hex/rgb_to_hex.d.ts.map +1 -0
  401. package/src/core/color/hex/rgb_to_hex.js +13 -0
  402. package/src/core/color/hex/rgba_to_hex.d.ts +19 -0
  403. package/src/core/color/hex/rgba_to_hex.d.ts.map +1 -0
  404. package/src/core/color/hex/rgba_to_hex.js +23 -0
  405. package/src/core/color/hsv/hsv2rgb.d.ts +1 -12
  406. package/src/core/color/hsv/hsv2rgb.d.ts.map +1 -1
  407. package/src/core/color/hsv/hsv2rgb.js +8 -21
  408. package/src/core/color/hsv/hsv2rgb_float.d.ts +1 -12
  409. package/src/core/color/hsv/hsv2rgb_float.d.ts.map +1 -1
  410. package/src/core/color/hsv/hsv2rgb_float.js +8 -56
  411. package/src/core/color/hsv/hsv_to_rgb.d.ts +13 -0
  412. package/src/core/color/hsv/hsv_to_rgb.d.ts.map +1 -0
  413. package/src/core/color/hsv/hsv_to_rgb.js +39 -0
  414. package/src/core/color/hsv/hsv_to_rgb_uint8.d.ts +13 -0
  415. package/src/core/color/hsv/hsv_to_rgb_uint8.d.ts.map +1 -0
  416. package/src/core/color/hsv/hsv_to_rgb_uint8.js +21 -0
  417. package/src/core/color/hsv/hue_to_rgb_sextant.d.ts +24 -0
  418. package/src/core/color/hsv/hue_to_rgb_sextant.d.ts.map +1 -0
  419. package/src/core/color/hsv/hue_to_rgb_sextant.js +67 -0
  420. package/src/core/color/hsv/rgb2hsv.d.ts +1 -12
  421. package/src/core/color/hsv/rgb2hsv.d.ts.map +1 -1
  422. package/src/core/color/hsv/rgb2hsv.js +7 -42
  423. package/src/core/color/hsv/rgb_to_hsv.d.ts +13 -0
  424. package/src/core/color/hsv/rgb_to_hsv.d.ts.map +1 -0
  425. package/src/core/color/hsv/rgb_to_hsv.js +42 -0
  426. package/src/core/color/hunt/hpe_to_xyz.d.ts +2 -0
  427. package/src/core/color/hunt/hpe_to_xyz.d.ts.map +1 -0
  428. package/src/core/color/hunt/hpe_to_xyz.js +4 -0
  429. package/src/core/color/hunt/xyz_to_hpe.d.ts +1 -6
  430. package/src/core/color/hunt/xyz_to_hpe.d.ts.map +1 -1
  431. package/src/core/color/hunt/xyz_to_hpe.js +12 -15
  432. package/src/core/color/illuminant/D65_spd_tabulated.d.ts.map +1 -1
  433. package/src/core/color/illuminant/D65_spd_tabulated.js +107 -104
  434. package/src/core/color/int2rgb.d.ts +1 -10
  435. package/src/core/color/int2rgb.d.ts.map +1 -1
  436. package/src/core/color/int2rgb.js +7 -12
  437. package/src/core/color/int_to_rgb.d.ts +21 -0
  438. package/src/core/color/int_to_rgb.d.ts.map +1 -0
  439. package/src/core/color/int_to_rgb.js +33 -0
  440. package/src/core/color/kelvin/kelvin_to_rgb.d.ts.map +1 -1
  441. package/src/core/color/kelvin/kelvin_to_rgb.js +22 -2
  442. package/src/core/color/kelvin/rgb_to_kelvin.d.ts +22 -2
  443. package/src/core/color/kelvin/rgb_to_kelvin.d.ts.map +1 -1
  444. package/src/core/color/kelvin/rgb_to_kelvin.js +22 -2
  445. package/src/core/color/lab/lab_to_xyz.d.ts +20 -0
  446. package/src/core/color/lab/lab_to_xyz.d.ts.map +1 -0
  447. package/src/core/color/lab/lab_to_xyz.js +69 -0
  448. package/src/core/color/oklab/gamut_clip_adaptive_l0.d.ts +34 -0
  449. package/src/core/color/oklab/gamut_clip_adaptive_l0.d.ts.map +1 -0
  450. package/src/core/color/oklab/gamut_clip_adaptive_l0.js +46 -0
  451. package/src/core/color/oklab/gamut_clip_at_l0.d.ts +33 -0
  452. package/src/core/color/oklab/gamut_clip_at_l0.d.ts.map +1 -0
  453. package/src/core/color/oklab/gamut_clip_at_l0.js +84 -0
  454. package/src/core/color/oklab/gamut_clip_preserve_chroma.d.ts +24 -0
  455. package/src/core/color/oklab/gamut_clip_preserve_chroma.d.ts.map +1 -0
  456. package/src/core/color/oklab/gamut_clip_preserve_chroma.js +37 -0
  457. package/src/core/color/oklab/gamut_clip_project_to_lcusp.d.ts +23 -0
  458. package/src/core/color/oklab/gamut_clip_project_to_lcusp.d.ts.map +1 -0
  459. package/src/core/color/oklab/gamut_clip_project_to_lcusp.js +46 -0
  460. package/src/core/color/oklab/linear_srgb_to_okhsl.d.ts +19 -0
  461. package/src/core/color/oklab/linear_srgb_to_okhsl.d.ts.map +1 -0
  462. package/src/core/color/oklab/linear_srgb_to_okhsl.js +93 -0
  463. package/src/core/color/oklab/linear_srgb_to_okhsv.d.ts +12 -4
  464. package/src/core/color/oklab/linear_srgb_to_okhsv.d.ts.map +1 -1
  465. package/src/core/color/oklab/linear_srgb_to_okhsv.js +108 -84
  466. package/src/core/color/oklab/linear_srgb_to_oklab.d.ts +13 -4
  467. package/src/core/color/oklab/linear_srgb_to_oklab.d.ts.map +1 -1
  468. package/src/core/color/oklab/linear_srgb_to_oklab.js +28 -19
  469. package/src/core/color/oklab/okhsl_chroma_bounds.d.ts +51 -0
  470. package/src/core/color/oklab/okhsl_chroma_bounds.d.ts.map +1 -0
  471. package/src/core/color/oklab/okhsl_chroma_bounds.js +128 -0
  472. package/src/core/color/oklab/okhsl_to_linear_srgb.d.ts +19 -0
  473. package/src/core/color/oklab/okhsl_to_linear_srgb.d.ts.map +1 -0
  474. package/src/core/color/oklab/okhsl_to_linear_srgb.js +85 -0
  475. package/src/core/color/oklab/oklab_to_oklch.d.ts +24 -0
  476. package/src/core/color/oklab/oklab_to_oklch.d.ts.map +1 -0
  477. package/src/core/color/oklab/oklab_to_oklch.js +35 -0
  478. package/src/core/color/oklab/oklch_to_oklab.d.ts +18 -0
  479. package/src/core/color/oklab/oklch_to_oklab.d.ts.map +1 -0
  480. package/src/core/color/oklab/oklch_to_oklab.js +26 -0
  481. package/src/core/color/oklab/toe.d.ts +12 -0
  482. package/src/core/color/oklab/toe.d.ts.map +1 -1
  483. package/src/core/color/oklab/toe.js +34 -22
  484. package/src/core/color/operations/color_add.d.ts +21 -0
  485. package/src/core/color/operations/color_add.d.ts.map +1 -0
  486. package/src/core/color/operations/color_add.js +23 -0
  487. package/src/core/color/operations/color_add_scaled.d.ts +20 -0
  488. package/src/core/color/operations/color_add_scaled.d.ts.map +1 -0
  489. package/src/core/color/operations/color_add_scaled.js +30 -0
  490. package/src/core/color/operations/color_clamp.d.ts +22 -0
  491. package/src/core/color/operations/color_clamp.d.ts.map +1 -0
  492. package/src/core/color/operations/color_clamp.js +25 -0
  493. package/src/core/color/operations/color_darken.d.ts +2 -1
  494. package/src/core/color/operations/color_darken.d.ts.map +1 -1
  495. package/src/core/color/operations/color_darken.js +25 -24
  496. package/src/core/color/operations/color_desaturate.d.ts +2 -1
  497. package/src/core/color/operations/color_desaturate.d.ts.map +1 -1
  498. package/src/core/color/operations/color_desaturate.js +25 -24
  499. package/src/core/color/operations/color_get_hsl.d.ts +18 -0
  500. package/src/core/color/operations/color_get_hsl.d.ts.map +1 -0
  501. package/src/core/color/operations/color_get_hsl.js +60 -0
  502. package/src/core/color/operations/color_is_in_gamut.d.ts +20 -0
  503. package/src/core/color/operations/color_is_in_gamut.d.ts.map +1 -0
  504. package/src/core/color/operations/color_is_in_gamut.js +30 -0
  505. package/src/core/color/operations/color_lerp.d.ts +12 -3
  506. package/src/core/color/operations/color_lerp.d.ts.map +1 -1
  507. package/src/core/color/operations/color_lerp.js +55 -46
  508. package/src/core/color/operations/color_lighten.d.ts +9 -5
  509. package/src/core/color/operations/color_lighten.d.ts.map +1 -1
  510. package/src/core/color/operations/color_lighten.js +29 -24
  511. package/src/core/color/operations/color_mix_okhsv_channel.d.ts +24 -0
  512. package/src/core/color/operations/color_mix_okhsv_channel.d.ts.map +1 -0
  513. package/src/core/color/operations/color_mix_okhsv_channel.js +48 -0
  514. package/src/core/color/operations/color_multiply_rgb.d.ts +21 -0
  515. package/src/core/color/operations/color_multiply_rgb.d.ts.map +1 -0
  516. package/src/core/color/operations/color_multiply_rgb.js +26 -0
  517. package/src/core/color/operations/color_saturate.d.ts +9 -5
  518. package/src/core/color/operations/color_saturate.d.ts.map +1 -1
  519. package/src/core/color/operations/color_saturate.js +29 -24
  520. package/src/core/color/operations/color_scale_okhsv_channel.d.ts +1 -1
  521. package/src/core/color/operations/color_scale_okhsv_channel.d.ts.map +1 -1
  522. package/src/core/color/operations/color_scale_okhsv_channel.js +58 -45
  523. package/src/core/color/operations/color_srgb_apply.d.ts +28 -0
  524. package/src/core/color/operations/color_srgb_apply.d.ts.map +1 -0
  525. package/src/core/color/operations/color_srgb_apply.js +40 -0
  526. package/src/core/color/operations/color_sub.d.ts +16 -0
  527. package/src/core/color/operations/color_sub.d.ts.map +1 -0
  528. package/src/core/color/operations/color_sub.js +18 -0
  529. package/src/core/color/parse_color.d.ts +10 -1
  530. package/src/core/color/parse_color.d.ts.map +1 -1
  531. package/src/core/color/parse_color.js +100 -84
  532. package/src/core/color/parse_color_normalized.d.ts +24 -0
  533. package/src/core/color/parse_color_normalized.d.ts.map +1 -0
  534. package/src/core/color/parse_color_normalized.js +38 -0
  535. package/src/core/color/rgb2uint24.d.ts +1 -8
  536. package/src/core/color/rgb2uint24.d.ts.map +1 -1
  537. package/src/core/color/rgb2uint24.js +7 -20
  538. package/src/core/color/rgb2uint32.d.ts +1 -9
  539. package/src/core/color/rgb2uint32.d.ts.map +1 -1
  540. package/src/core/color/rgb2uint32.js +7 -18
  541. package/src/core/color/rgb_to_luminance.d.ts +14 -5
  542. package/src/core/color/rgb_to_luminance.d.ts.map +1 -1
  543. package/src/core/color/rgb_to_luminance.js +24 -13
  544. package/src/core/color/rgb_to_uint24.d.ts +9 -0
  545. package/src/core/color/rgb_to_uint24.d.ts.map +1 -0
  546. package/src/core/color/rgb_to_uint24.js +20 -0
  547. package/src/core/color/rgb_to_uint32.d.ts +10 -0
  548. package/src/core/color/rgb_to_uint32.d.ts.map +1 -0
  549. package/src/core/color/rgb_to_uint32.js +21 -0
  550. package/src/core/color/sRGB/linear_to_sRGB.d.ts +7 -0
  551. package/src/core/color/sRGB/linear_to_sRGB.d.ts.map +1 -1
  552. package/src/core/color/sRGB/linear_to_sRGB.js +39 -32
  553. package/src/core/color/xyz/hpe_to_xyz.d.ts +24 -0
  554. package/src/core/color/xyz/hpe_to_xyz.d.ts.map +1 -0
  555. package/src/core/color/xyz/hpe_to_xyz.js +39 -0
  556. package/src/core/color/xyz/rgb_to_xyz.d.ts +17 -2
  557. package/src/core/color/xyz/rgb_to_xyz.d.ts.map +1 -1
  558. package/src/core/color/xyz/rgb_to_xyz.js +44 -18
  559. package/src/core/color/xyz/xyz_cmf_tabulated.d.ts.map +1 -1
  560. package/src/core/color/xyz/xyz_cmf_tabulated.js +217 -211
  561. package/src/core/color/xyz/xyz_cmf_wyman.d.ts +4 -0
  562. package/src/core/color/xyz/xyz_cmf_wyman.d.ts.map +1 -1
  563. package/src/core/color/xyz/xyz_cmf_wyman.js +74 -65
  564. package/src/core/color/xyz/xyz_to_hpe.d.ts +18 -0
  565. package/src/core/color/xyz/xyz_to_hpe.d.ts.map +1 -0
  566. package/src/core/color/xyz/xyz_to_hpe.js +33 -0
  567. package/src/core/color/xyz/xyz_to_rgb.d.ts +17 -2
  568. package/src/core/color/xyz/xyz_to_rgb.d.ts.map +1 -1
  569. package/src/core/color/xyz/xyz_to_rgb.js +39 -16
  570. package/src/core/color/ycxcz/xyz_to_ycxcz.d.ts +7 -2
  571. package/src/core/color/ycxcz/xyz_to_ycxcz.d.ts.map +1 -1
  572. package/src/core/color/ycxcz/xyz_to_ycxcz.js +33 -28
  573. package/src/core/events/signal/Signal.js +820 -820
  574. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  575. package/src/core/geom/3d/shape/ConvexHullShape3D.js +28 -4
  576. package/src/core/math/clamp_index.d.ts +18 -0
  577. package/src/core/math/clamp_index.d.ts.map +1 -0
  578. package/src/core/math/clamp_index.js +23 -0
  579. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +803 -0
  580. package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts +5 -3
  581. package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts.map +1 -1
  582. package/src/engine/asset/loaders/image/jpeg/JpegFrame.js +5 -3
  583. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts +2 -1
  584. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts.map +1 -1
  585. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.js +2 -1
  586. package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts +17 -0
  587. package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts.map +1 -1
  588. package/src/engine/asset/loaders/image/jpeg/JpegImage.js +197 -157
  589. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts +0 -1
  590. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts.map +1 -1
  591. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.js +0 -1
  592. package/src/engine/asset/loaders/image/jpeg/jpeg_component_row.d.ts +28 -0
  593. package/src/engine/asset/loaders/image/jpeg/jpeg_component_row.d.ts.map +1 -0
  594. package/src/engine/asset/loaders/image/jpeg/jpeg_component_row.js +31 -0
  595. package/src/engine/asset/loaders/image/png/PNG.d.ts +3 -18
  596. package/src/engine/asset/loaders/image/png/PNG.d.ts.map +1 -1
  597. package/src/engine/asset/loaders/image/png/PNG.js +3 -139
  598. package/src/engine/asset/loaders/image/png/PNGReader.d.ts +16 -16
  599. package/src/engine/asset/loaders/image/png/PNGReader.d.ts.map +1 -1
  600. package/src/engine/asset/loaders/image/png/PNGReader.js +143 -160
  601. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_iTXt.js +3 -3
  602. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_zTXt.js +3 -3
  603. package/src/engine/asset/loaders/image/png/crc32.d.ts +1 -15
  604. package/src/engine/asset/loaders/image/png/crc32.d.ts.map +1 -1
  605. package/src/engine/asset/loaders/image/png/crc32.js +5 -89
  606. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.d.ts +12 -10
  607. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.d.ts.map +1 -1
  608. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.js +20 -45
  609. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.d.ts +2 -1
  610. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.d.ts.map +1 -1
  611. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.js +2 -0
  612. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.d.ts +2 -1
  613. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.d.ts.map +1 -1
  614. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.js +2 -0
  615. package/src/engine/asset/loaders/image/png/filter/png_unfilter.d.ts +22 -0
  616. package/src/engine/asset/loaders/image/png/filter/png_unfilter.d.ts.map +1 -0
  617. package/src/engine/asset/loaders/image/png/filter/png_unfilter.js +68 -0
  618. package/src/engine/asset/loaders/image/png/png_inflate.d.ts +20 -0
  619. package/src/engine/asset/loaders/image/png/png_inflate.d.ts.map +1 -0
  620. package/src/engine/asset/loaders/image/png/png_inflate.js +85 -0
  621. package/src/engine/asset/loaders/image/png/png_unpack_samples.d.ts +22 -0
  622. package/src/engine/asset/loaders/image/png/png_unpack_samples.d.ts.map +1 -0
  623. package/src/engine/asset/loaders/image/png/png_unpack_samples.js +38 -0
  624. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  625. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +135 -132
  626. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +16 -3
  627. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  628. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1157 -1149
  629. package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts +26 -0
  630. package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts.map +1 -1
  631. package/src/engine/graphics/render/frame_graph/FrameGraph.js +947 -900
  632. package/src/engine/physics/ecs/PhysicsSystem.d.ts +69 -81
  633. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  634. package/src/engine/physics/ecs/PhysicsSystem.js +83 -77
  635. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  636. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +451 -0
  637. package/src/shade/device/ShadeGPUCommandContext.d.ts +21 -0
  638. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  639. package/src/shade/device/ShadeGPUCommandContext.js +940 -749
  640. package/src/shade/device/timing/GPUTimerArray.d.ts +22 -4
  641. package/src/shade/device/timing/GPUTimerArray.d.ts.map +1 -1
  642. package/src/shade/device/timing/GPUTimerArray.js +88 -14
  643. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +876 -0
  644. package/src/shade/device/timing/profile/GPUFrameRecorder.d.ts +93 -0
  645. package/src/shade/device/timing/profile/GPUFrameRecorder.d.ts.map +1 -0
  646. package/src/shade/device/timing/profile/GPUFrameRecorder.js +297 -0
  647. package/src/shade/device/timing/profile/GPUProfileCapture.d.ts +62 -0
  648. package/src/shade/device/timing/profile/GPUProfileCapture.d.ts.map +1 -0
  649. package/src/shade/device/timing/profile/GPUProfileCapture.js +77 -0
  650. package/src/shade/device/timing/profile/GPUProfileFrame.d.ts +73 -0
  651. package/src/shade/device/timing/profile/GPUProfileFrame.d.ts.map +1 -0
  652. package/src/shade/device/timing/profile/GPUProfileFrame.js +88 -0
  653. package/src/shade/device/timing/profile/GPUProfileLevel.d.ts +20 -0
  654. package/src/shade/device/timing/profile/GPUProfileLevel.d.ts.map +1 -0
  655. package/src/shade/device/timing/profile/GPUProfileLevel.js +50 -0
  656. package/src/shade/device/timing/profile/GPUProfileMeta.d.ts +63 -0
  657. package/src/shade/device/timing/profile/GPUProfileMeta.d.ts.map +1 -0
  658. package/src/shade/device/timing/profile/GPUProfileMeta.js +73 -0
  659. package/src/shade/device/timing/profile/GPUProfileSession.d.ts +173 -0
  660. package/src/shade/device/timing/profile/GPUProfileSession.d.ts.map +1 -0
  661. package/src/shade/device/timing/profile/GPUProfileSession.js +470 -0
  662. package/src/shade/device/timing/profile/GPUProfileSpan.d.ts +60 -0
  663. package/src/shade/device/timing/profile/GPUProfileSpan.d.ts.map +1 -0
  664. package/src/shade/device/timing/profile/GPUProfileSpan.js +65 -0
  665. package/src/shade/device/timing/profile/GPUProfileSpanKind.d.ts +19 -0
  666. package/src/shade/device/timing/profile/GPUProfileSpanKind.d.ts.map +1 -0
  667. package/src/shade/device/timing/profile/GPUProfileSpanKind.js +25 -0
  668. package/src/shade/device/timing/profile/GPUProfileTopology.d.ts +159 -0
  669. package/src/shade/device/timing/profile/GPUProfileTopology.d.ts.map +1 -0
  670. package/src/shade/device/timing/profile/GPUProfileTopology.js +202 -0
  671. package/src/shade/device/timing/profile/GPUProfileWork.d.ts +90 -0
  672. package/src/shade/device/timing/profile/GPUProfileWork.d.ts.map +1 -0
  673. package/src/shade/device/timing/profile/GPUProfileWork.js +115 -0
  674. package/src/shade/device/timing/profile/SGPTDefect.d.ts +43 -0
  675. package/src/shade/device/timing/profile/SGPTDefect.d.ts.map +1 -0
  676. package/src/shade/device/timing/profile/SGPTDefect.js +65 -0
  677. package/src/shade/device/timing/profile/SGPTHeader.d.ts +38 -0
  678. package/src/shade/device/timing/profile/SGPTHeader.d.ts.map +1 -0
  679. package/src/shade/device/timing/profile/SGPTHeader.js +46 -0
  680. package/src/shade/device/timing/profile/SGPTRecordRef.d.ts +37 -0
  681. package/src/shade/device/timing/profile/SGPTRecordRef.d.ts.map +1 -0
  682. package/src/shade/device/timing/profile/SGPTRecordRef.js +45 -0
  683. package/src/shade/device/timing/profile/SGPTWriteStream.d.ts +103 -0
  684. package/src/shade/device/timing/profile/SGPTWriteStream.d.ts.map +1 -0
  685. package/src/shade/device/timing/profile/SGPTWriteStream.js +287 -0
  686. package/src/shade/device/timing/profile/SGPT_DEFECT.d.ts +19 -0
  687. package/src/shade/device/timing/profile/SGPT_DEFECT.d.ts.map +1 -0
  688. package/src/shade/device/timing/profile/SGPT_DEFECT.js +26 -0
  689. package/src/shade/device/timing/profile/SGPT_FLAG.d.ts +8 -0
  690. package/src/shade/device/timing/profile/SGPT_FLAG.d.ts.map +1 -0
  691. package/src/shade/device/timing/profile/SGPT_FLAG.js +15 -0
  692. package/src/shade/device/timing/profile/SGPT_FORMAT.md +345 -0
  693. package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.d.ts +10 -0
  694. package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.d.ts.map +1 -0
  695. package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.js +9 -0
  696. package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.d.ts +17 -0
  697. package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.d.ts.map +1 -0
  698. package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.js +16 -0
  699. package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.d.ts +16 -0
  700. package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.d.ts.map +1 -0
  701. package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.js +15 -0
  702. package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.d.ts +15 -0
  703. package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.d.ts.map +1 -0
  704. package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.js +29 -0
  705. package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.d.ts +7 -0
  706. package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.d.ts.map +1 -0
  707. package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.js +6 -0
  708. package/src/shade/device/timing/profile/SGPT_MAGIC.d.ts +7 -0
  709. package/src/shade/device/timing/profile/SGPT_MAGIC.d.ts.map +1 -0
  710. package/src/shade/device/timing/profile/SGPT_MAGIC.js +6 -0
  711. package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.d.ts +16 -0
  712. package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.d.ts.map +1 -0
  713. package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.js +15 -0
  714. package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.d.ts +7 -0
  715. package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.d.ts.map +1 -0
  716. package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.js +6 -0
  717. package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.d.ts +13 -0
  718. package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.d.ts.map +1 -0
  719. package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.js +23 -0
  720. package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.d.ts +12 -0
  721. package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.d.ts.map +1 -0
  722. package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.js +11 -0
  723. package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.d.ts +18 -0
  724. package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.d.ts.map +1 -0
  725. package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.js +46 -0
  726. package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts +20 -0
  727. package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts.map +1 -0
  728. package/src/shade/device/timing/profile/frame_graph_extract_topology.js +174 -0
  729. package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts +21 -0
  730. package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts.map +1 -0
  731. package/src/shade/device/timing/profile/make_profiling_pass_encoder.js +114 -0
  732. package/src/shade/device/timing/profile/parse_workgroup_size.d.ts +20 -0
  733. package/src/shade/device/timing/profile/parse_workgroup_size.d.ts.map +1 -0
  734. package/src/shade/device/timing/profile/parse_workgroup_size.js +43 -0
  735. package/src/shade/device/timing/profile/sgpt_fourcc.d.ts +18 -0
  736. package/src/shade/device/timing/profile/sgpt_fourcc.d.ts.map +1 -0
  737. package/src/shade/device/timing/profile/sgpt_fourcc.js +34 -0
  738. package/src/shade/device/timing/profile/sgpt_frame_codec.d.ts +42 -0
  739. package/src/shade/device/timing/profile/sgpt_frame_codec.d.ts.map +1 -0
  740. package/src/shade/device/timing/profile/sgpt_frame_codec.js +172 -0
  741. package/src/shade/device/timing/profile/sgpt_meta_codec.d.ts +20 -0
  742. package/src/shade/device/timing/profile/sgpt_meta_codec.d.ts.map +1 -0
  743. package/src/shade/device/timing/profile/sgpt_meta_codec.js +65 -0
  744. package/src/shade/device/timing/profile/sgpt_read_capture.d.ts +19 -0
  745. package/src/shade/device/timing/profile/sgpt_read_capture.d.ts.map +1 -0
  746. package/src/shade/device/timing/profile/sgpt_read_capture.js +134 -0
  747. package/src/shade/device/timing/profile/sgpt_read_header.d.ts +22 -0
  748. package/src/shade/device/timing/profile/sgpt_read_header.d.ts.map +1 -0
  749. package/src/shade/device/timing/profile/sgpt_read_header.js +94 -0
  750. package/src/shade/device/timing/profile/sgpt_read_records.d.ts +27 -0
  751. package/src/shade/device/timing/profile/sgpt_read_records.d.ts.map +1 -0
  752. package/src/shade/device/timing/profile/sgpt_read_records.js +153 -0
  753. package/src/shade/device/timing/profile/sgpt_topology_codec.d.ts +54 -0
  754. package/src/shade/device/timing/profile/sgpt_topology_codec.d.ts.map +1 -0
  755. package/src/shade/device/timing/profile/sgpt_topology_codec.js +329 -0
  756. package/src/shade/device/timing/profile/sgpt_write_header.d.ts +22 -0
  757. package/src/shade/device/timing/profile/sgpt_write_header.d.ts.map +1 -0
  758. package/src/shade/device/timing/profile/sgpt_write_header.js +47 -0
  759. package/src/shade/device/timing/profile/sgpt_write_record.d.ts +23 -0
  760. package/src/shade/device/timing/profile/sgpt_write_record.d.ts.map +1 -0
  761. package/src/shade/device/timing/profile/sgpt_write_record.js +62 -0
  762. package/src/shade/renderer/Renderer.d.ts +21 -0
  763. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  764. package/src/shade/renderer/Renderer.js +2513 -2455
  765. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  766. package/src/shade/renderer/scene/serialization/decode_image_source_hdr.d.ts +14 -3
  767. package/src/shade/renderer/scene/serialization/decode_image_source_hdr.d.ts.map +1 -1
  768. package/src/shade/renderer/scene/serialization/decode_image_source_hdr.js +50 -51
  769. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts.map +1 -1
  770. package/src/shade/renderer/scene/serialization/deserialize_scene.js +531 -521
  771. package/src/shade/renderer/scene/serialization/write_image_source.d.ts.map +1 -1
  772. package/src/shade/renderer/scene/serialization/write_image_source.js +6 -4
  773. package/src/shade/renderer/shader/chunk/color/chunk_rgb_to_luminance.d.ts.map +1 -1
  774. package/src/shade/renderer/shader/chunk/color/chunk_rgb_to_luminance.js +34 -32
  775. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.d.ts +31 -0
  776. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.d.ts.map +1 -1
  777. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.js +62 -31
  778. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_inverse_eotf_st2084.d.ts +10 -0
  779. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_inverse_eotf_st2084.d.ts.map +1 -1
  780. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_inverse_eotf_st2084.js +32 -22
  781. package/src/shade/renderer/shader/chunk/color/sRGB/chunk_sRGBTransferOETF.d.ts.map +1 -1
  782. package/src/shade/renderer/shader/chunk/color/sRGB/chunk_sRGBTransferOETF.js +22 -21
  783. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts +6 -0
  784. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts.map +1 -1
  785. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.js +110 -104
  786. package/src/shade/renderer/shader/chunk/color/xyz/chunk_rgb_to_xyz.d.ts.map +1 -1
  787. package/src/shade/renderer/shader/chunk/color/xyz/chunk_rgb_to_xyz.js +23 -21
  788. package/src/view/elements/ColorPickerView.js +296 -296
  789. package/src/avif/codec/dec/Readme.md +0 -14
  790. package/src/avif/codec/dec/avif_dec.cpp +0 -234
  791. package/src/avif/codec/dec/avif_dec.d.ts +0 -3
  792. package/src/avif/codec/dec/avif_dec.d.ts.map +0 -1
  793. package/src/avif/codec/dec/avif_dec.js +0 -16
  794. package/src/avif/codec/dec/avif_dec.wasm +0 -0
  795. package/src/avif/codec/enc/README.md +0 -37
  796. package/src/avif/codec/enc/avif_enc.cpp +0 -216
  797. package/src/avif/codec/enc/avif_enc.d.ts +0 -3
  798. package/src/avif/codec/enc/avif_enc.d.ts.map +0 -1
  799. package/src/avif/codec/enc/avif_enc.js +0 -6144
  800. package/src/avif/codec/enc/avif_enc.wasm +0 -0
  801. package/src/avif/codec/enc/avif_enc_mt.d.ts +0 -3
  802. package/src/avif/codec/enc/avif_enc_mt.d.ts.map +0 -1
  803. package/src/avif/codec/enc/avif_enc_mt.js +0 -6811
  804. package/src/avif/codec/enc/avif_enc_mt.wasm +0 -0
  805. package/src/avif/codec/enc/avif_enc_mt.worker.d.mts +0 -2
  806. package/src/avif/codec/enc/avif_enc_mt.worker.d.mts.map +0 -1
  807. package/src/avif/codec/enc/avif_enc_mt.worker.d.ts +0 -11
  808. package/src/avif/codec/enc/avif_enc_mt.worker.d.ts.map +0 -1
  809. package/src/avif/codec/enc/avif_enc_mt.worker.js +0 -171
  810. package/src/avif/codec/enc/avif_enc_mt.worker.mjs +0 -1
  811. package/src/avif/decode.d.ts +0 -3
  812. package/src/avif/decode.d.ts.map +0 -1
  813. package/src/avif/decode.js +0 -42
  814. package/src/avif/encode.d.ts +0 -3
  815. package/src/avif/encode.d.ts.map +0 -1
  816. package/src/avif/encode.js +0 -75
  817. package/src/avif/meta.d.ts +0 -24
  818. package/src/avif/meta.d.ts.map +0 -1
  819. package/src/avif/meta.js +0 -23
  820. package/src/avif/tsconfig.tsbuildinfo +0 -1
  821. package/src/avif/utils.d.ts +0 -17
  822. package/src/avif/utils.d.ts.map +0 -1
  823. package/src/avif/utils.js +0 -31
  824. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts +0 -23
  825. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts.map +0 -1
  826. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.js +0 -214
  827. package/src/engine/asset/loaders/image/png/inflate.d.ts +0 -7
  828. package/src/engine/asset/loaders/image/png/inflate.d.ts.map +0 -1
  829. package/src/engine/asset/loaders/image/png/inflate.js +0 -20
  830. package/src/engine/save/GameStateLoader.d.ts +0 -49
  831. package/src/engine/save/GameStateLoader.d.ts.map +0 -1
  832. package/src/engine/save/GameStateLoader.js +0 -168
@@ -1,1149 +1,1157 @@
1
- import { assert } from "../../../../../../core/assert.js";
2
- import { BvhClient } from "../../../../../../core/bvh2/bvh3/BvhClient.js";
3
- import { combine_hash } from "../../../../../../core/collection/array/combine_hash.js";
4
- import List from "../../../../../../core/collection/list/List.js";
5
- import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../../../../core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
6
- import { AABB3 } from "../../../../../../core/geom/3d/aabb/AABB3.js";
7
- import { aabb3_array_combine } from "../../../../../../core/geom/3d/aabb/aabb3_array_combine.js";
8
- import { aabb3_expand_array } from "../../../../../../core/geom/3d/aabb/aabb3_expand_array.js";
9
- import { m4_compose } from "../../../../../../core/geom/3d/mat4/m4_compose.js";
10
- import Quaternion from "../../../../../../core/geom/Quaternion.js";
11
- import { v3_dot_array } from "../../../../../../core/geom/vec3/v3_dot_array.js";
12
- import Vector3 from "../../../../../../core/geom/Vector3.js";
13
- import { lerp } from "../../../../../../core/math/lerp.js";
14
- import { max2 } from "../../../../../../core/math/max2.js";
15
- import { min2 } from "../../../../../../core/math/min2.js";
16
- import { BlendingType } from "../../../../texture/sampler/BlendingType.js";
17
- import { ParameterSet } from "../parameter/ParameterSet.js";
18
- import { ParticleParameter } from "../parameter/ParticleParameter.js";
19
- import { update_parameters } from "../simulator/update_parameters.js";
20
- import { computeEmissionFunction } from "./computeEmissionFunction.js";
21
- import {
22
- PARTICLE_ATTRIBUTE_AGE,
23
- PARTICLE_ATTRIBUTE_BLEND,
24
- PARTICLE_ATTRIBUTE_DEATH_AGE,
25
- PARTICLE_ATTRIBUTE_LAYER_POSITION,
26
- PARTICLE_ATTRIBUTE_POSITION,
27
- PARTICLE_ATTRIBUTE_ROTATION,
28
- PARTICLE_ATTRIBUTE_ROTATION_SPEED,
29
- PARTICLE_ATTRIBUTE_SIZE,
30
- PARTICLE_ATTRIBUTE_SIZE_INITIAL,
31
- PARTICLE_ATTRIBUTE_UV,
32
- PARTICLE_ATTRIBUTE_VELOCITY
33
- } from "./PARTICLE_ATTRIBUTES.js";
34
- import { ParticleEmitterFlag } from "./ParticleEmitterFlag.js";
35
- import { ParticleLayer } from "./ParticleLayer.js";
36
- import { ParticleParameters } from "./ParticleParameters.js";
37
- import { ParticlePool } from "./ParticlePool.js";
38
- import { PARTICULAR_PARTICLE_SPECIFICATION } from "./PARTICULAR_PARTICLE_SPECIFICATION.js";
39
- import { write_particle_patch_uv } from "./write_particle_patch_uv.js";
40
-
41
-
42
- const SERIALIZABLE_FLAGS = ParticleEmitterFlag.PreWarm
43
- | ParticleEmitterFlag.DepthSorting
44
- | ParticleEmitterFlag.DepthReadDisabled
45
- | ParticleEmitterFlag.DepthSoftDisabled
46
- | ParticleEmitterFlag.AlignOnVelocity
47
- ;
48
-
49
- /**
50
- * Used to store AABB3 corners during bounding box calculation
51
- * @readonly
52
- * @type {Float64Array}
53
- */
54
- const corners = new Float64Array(24);
55
-
56
- const scratch_sort_direction = new Float32Array(3);
57
-
58
- /**
59
- *
60
- * @type {Float32Array}
61
- */
62
- const scratch_aabb3 = new Float32Array(6);
63
-
64
- /**
65
- *
66
- * @type {number[]}
67
- */
68
- const scratch_v3_array = [];
69
-
70
- /**
71
- *
72
- * @param {ParameterSet} parameters
73
- */
74
- function generateStandardParameterSet(parameters) {
75
- const pScale = new ParticleParameter(ParticleParameters.Scale, 1);
76
- pScale.setDefault([1], [0]);
77
-
78
- const pColor = new ParticleParameter(ParticleParameters.Color, 4);
79
- pColor.setDefault([1, 1, 1, 1], [0]);
80
-
81
- parameters.add(pScale);
82
- parameters.add(pColor);
83
- }
84
-
85
-
86
- let id_counter = 0;
87
-
88
- export class ParticleEmitter {
89
- /**
90
- * @type {number}
91
- */
92
- id = id_counter++;
93
-
94
- /**
95
- * @private
96
- * @readonly
97
- * @type {List<ParticleLayer>}
98
- */
99
- layers = new List();
100
-
101
- /**
102
- *
103
- * @type {Vector3}
104
- */
105
- position = new Vector3(0, 0, 0);
106
- scale = new Vector3(1, 1, 1);
107
- rotation = new Quaternion(0, 0, 0, 1);
108
-
109
- /**
110
- *
111
- * @type {Vector3}
112
- * @readonly
113
- * @private
114
- */
115
- __lastSpawnPosition = new Vector3(0, 0, 0);
116
-
117
- /**
118
- * How long has this emitter been sleeping for?
119
- * This amount of time needs to be simulated when we wake the emitter up, but we can typically do it in a small number of large steps
120
- * @type {number}
121
- */
122
- sleepTime = 0;
123
-
124
- /**
125
- *
126
- * @type {BlendingType|number}
127
- */
128
- blendingMode = BlendingType.Normal;
129
-
130
- /**
131
- *
132
- * @type {ParticlePool|null}
133
- */
134
- particles = null;
135
-
136
- /**
137
- * @readonly
138
- * @type {BvhClient}
139
- */
140
- bvh_leaf = new BvhClient();
141
-
142
-
143
- /**
144
- * Upper-bound of bounds for an individual particle
145
- * @readonly
146
- * @type {AABB3}
147
- */
148
- particleBounds = new AABB3(Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity);
149
-
150
- /**
151
- * @readonly
152
- * @type {AABB3}
153
- */
154
- emissionBounds = new AABB3(0, 0, 0, 0, 0, 0);
155
-
156
-
157
- /**
158
- * Bit Field of {@link ParticleEmitterFlag}
159
- * @type {number}
160
- */
161
- flags = ParticleEmitterFlag.DepthSorting | ParticleEmitterFlag.HashNeedUpdate | ParticleEmitterFlag.Emitting;
162
-
163
- /**
164
- *
165
- * @type {number}
166
- * @private
167
- */
168
- __hash = 0;
169
-
170
-
171
- /**
172
- * @readonly
173
- * @type {ParameterSet}
174
- */
175
- parameters = new ParameterSet();
176
-
177
- constructor() {
178
- generateStandardParameterSet(this.parameters);
179
-
180
-
181
- this.position.onChanged.add(this.updateTransform, this);
182
- this.scale.onChanged.add(this.updateTransform, this);
183
- this.rotation.onChanged.add(this.updateTransform, this);
184
- }
185
-
186
- updateTransform() {
187
- this.setFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate);
188
-
189
- this.computeBoundingBox();
190
- }
191
-
192
- /**
193
- *
194
- * @param {number|ParticleEmitterFlag} flag
195
- * @returns {void}
196
- */
197
- setFlag(flag) {
198
- this.flags |= flag;
199
- }
200
-
201
- /**
202
- *
203
- * @param {number|ParticleEmitterFlag} flag
204
- * @returns {void}
205
- */
206
- clearFlag(flag) {
207
- this.flags &= ~flag;
208
- }
209
-
210
- /**
211
- *
212
- * @param {number|ParticleEmitterFlag} flag
213
- * @param {boolean} value
214
- */
215
- writeFlag(flag, value) {
216
- if (value) {
217
- this.setFlag(flag);
218
- } else {
219
- this.clearFlag(flag);
220
- }
221
- }
222
-
223
- /**
224
- *
225
- * @param {number|ParticleEmitterFlag} flag
226
- * @returns {boolean}
227
- */
228
- getFlag(flag) {
229
- return (this.flags & flag) === flag;
230
- }
231
-
232
- /**
233
- * @private
234
- */
235
- registerLayerParameters() {
236
- const layers = this.layers;
237
- const layer_count = layers.length;
238
-
239
- const parameters = this.parameters;
240
-
241
- parameters.setTrackCount(layer_count);
242
-
243
- for (let i = 0; i < layer_count; i++) {
244
- const layer = layers.get(i);
245
-
246
- parameters.setTracks(i, layer.parameterTracks);
247
- }
248
- }
249
-
250
- toJSON() {
251
- return {
252
- position: this.position.toJSON(),
253
- scale: this.scale.toJSON(),
254
- rotation: this.rotation.toJSON(),
255
- parameters: this.parameters.toJSON(),
256
- preWarm: this.getFlag(ParticleEmitterFlag.PreWarm),
257
- readDepth: !this.getFlag(ParticleEmitterFlag.DepthReadDisabled),
258
- softDepth: !this.getFlag(ParticleEmitterFlag.DepthSoftDisabled),
259
- velocityAlign: this.getFlag(ParticleEmitterFlag.AlignOnVelocity),
260
- depthSort: this.getFlag(ParticleEmitterFlag.DepthSorting),
261
- receiveLight: this.getFlag(ParticleEmitterFlag.Lit),
262
- blendingMode: this.blendingMode,
263
- layers: this.layers.toJSON()
264
- };
265
- }
266
-
267
- fromJSON(json) {
268
- if (typeof json.blendingMode === "number") {
269
- this.blendingMode = json.blendingMode;
270
- } else {
271
- this.blendingMode = BlendingType.Normal;
272
- }
273
-
274
- if (json.position !== undefined) {
275
- this.position.fromJSON(json.position);
276
- }
277
-
278
- if (json.scale !== undefined) {
279
- this.scale.fromJSON(json.scale);
280
- }
281
-
282
- if (json.rotation !== undefined) {
283
- this.rotation.fromJSON(json.rotation);
284
- }
285
-
286
- if (json.parameters !== undefined) {
287
- this.parameters.fromJSON(json.parameters);
288
- }
289
-
290
- if (typeof json.preWarm === "boolean") {
291
- this.writeFlag(ParticleEmitterFlag.PreWarm, json.preWarm);
292
- } else {
293
- this.writeFlag(ParticleEmitterFlag.PreWarm, false);
294
- }
295
-
296
- if (typeof json.readDepth === 'boolean') {
297
- this.writeFlag(ParticleEmitterFlag.DepthReadDisabled, !json.readDepth);
298
- } else {
299
- this.writeFlag(ParticleEmitterFlag.DepthReadDisabled, false);
300
- }
301
-
302
- if (typeof json.softDepth === 'boolean') {
303
- this.writeFlag(ParticleEmitterFlag.DepthSoftDisabled, !json.softDepth);
304
- } else {
305
- this.writeFlag(ParticleEmitterFlag.DepthSoftDisabled, false);
306
- }
307
-
308
- if (typeof json.velocityAlign === "boolean") {
309
- this.writeFlag(ParticleEmitterFlag.AlignOnVelocity, json.velocityAlign);
310
- } else {
311
- this.writeFlag(ParticleEmitterFlag.AlignOnVelocity, false);
312
- }
313
-
314
- if (typeof json.depthSort === "boolean") {
315
- this.writeFlag(ParticleEmitterFlag.DepthSorting, json.depthSort);
316
- } else {
317
- this.writeFlag(ParticleEmitterFlag.DepthSorting, true);
318
- }
319
-
320
- if (typeof json.receiveLight === "boolean") {
321
- this.writeFlag(ParticleEmitterFlag.Lit, json.receiveLight);
322
- } else {
323
- this.clearFlag(ParticleEmitterFlag.Lit);
324
- }
325
-
326
- this.layers.fromJSON(json.layers, ParticleLayer);
327
-
328
- this.writeFlag(ParticleEmitterFlag.Built, false);
329
- this.setFlag(ParticleEmitterFlag.Emitting);
330
-
331
- //register loaded layers
332
- this.registerLayerParameters();
333
- }
334
-
335
-
336
- /**
337
- *
338
- * @param {ParticleLayer} layer
339
- */
340
- addLayer(layer) {
341
- this.layers.add(layer);
342
-
343
- const numLayers = this.layers.length;
344
- this.parameters.setTrackCount(numLayers);
345
-
346
- this.parameters.setTracks(numLayers - 1, layer.parameterTracks);
347
- }
348
-
349
- /**
350
- *
351
- * @param {(layer: ParticleLayer, index: number) => void} visitor
352
- * @param {*} [thisArg]
353
- */
354
- traverseLayers(visitor, thisArg) {
355
- const layers = this.layers;
356
-
357
- const l = layers.length;
358
-
359
- for (let i = 0; i < l; i++) {
360
- const layer = layers.get(i);
361
-
362
- visitor.call(thisArg, layer, i);
363
- }
364
- }
365
-
366
- /**
367
- * Causes all active particles from a given layer to be destroyed immediately
368
- * @param {ParticleLayer} layer
369
- * @return {number} number of particles destroyed
370
- */
371
- destroyParticlesFromLayer(layer) {
372
- const layers = this.layers;
373
-
374
- const targetLayerIndex = layers.indexOf(layer);
375
-
376
- if (targetLayerIndex === -1) {
377
- //layer doesn't exist
378
- throw new Error('Layer not found');
379
- }
380
-
381
- const particles = this.particles;
382
- const occupancy = particles.occupancy;
383
-
384
- let removeCount = 0;
385
-
386
- for (
387
- let i = occupancy.nextSetBit(0);
388
- i !== -1;
389
- i = occupancy.nextSetBit(i + 1)
390
- ) {
391
-
392
- const layerPosition = particles.readAttributeScalar(i, PARTICLE_ATTRIBUTE_LAYER_POSITION);
393
-
394
- if (layerPosition !== targetLayerIndex) {
395
- // not the layer we want
396
- continue;
397
- }
398
-
399
- //destroy the particle
400
- occupancy.set(i, false);
401
-
402
- removeCount++;
403
-
404
- }
405
-
406
- if (removeCount > 0) {
407
- //remove dead particles from the pool
408
- particles.compact();
409
- }
410
-
411
- return removeCount;
412
- }
413
-
414
- computeEmissionBounds() {
415
-
416
- let bounds_x0 = Infinity;
417
- let bounds_y0 = Infinity;
418
- let bounds_z0 = Infinity;
419
-
420
- let bounds_x1 = -Infinity;
421
- let bounds_y1 = -Infinity;
422
- let bounds_z1 = -Infinity;
423
-
424
- const layers = this.layers;
425
- const numLayers = layers.length;
426
-
427
- const position = this.position;
428
- const rotation = this.rotation;
429
- const scale = this.scale;
430
-
431
- m4_compose(matrix4, position, rotation, scale);
432
-
433
- for (let i = 0; i < numLayers; i++) {
434
- const particleLayer = layers.get(i);
435
-
436
- particleLayer.computeBoundsAttributes();
437
-
438
- const s_2 = particleLayer.scaledSpriteHalfSize;
439
-
440
- const baseBoundingBox = particleLayer.baseBoundingBox;
441
- baseBoundingBox.getCorners(corners);
442
-
443
- for (let j = 0; j < 24; j += 3) {
444
-
445
- const x = corners[j];
446
- const y = corners[j + 1];
447
- const z = corners[j + 2];
448
-
449
- //apply matrix transform
450
- const _x = matrix4[0] * x + matrix4[4] * y + matrix4[8] * z + matrix4[12];
451
- const _y = matrix4[1] * x + matrix4[5] * y + matrix4[9] * z + matrix4[13];
452
- const _z = matrix4[2] * x + matrix4[6] * y + matrix4[10] * z + matrix4[14];
453
-
454
-
455
- //update bounds
456
- bounds_x0 = min2(bounds_x0, _x - s_2);
457
- bounds_y0 = min2(bounds_y0, _y - s_2);
458
- bounds_z0 = min2(bounds_z0, _z - s_2);
459
-
460
- bounds_x1 = max2(bounds_x1, _x + s_2);
461
- bounds_y1 = max2(bounds_y1, _y + s_2);
462
- bounds_z1 = max2(bounds_z1, _z + s_2);
463
- }
464
- }
465
-
466
- this.emissionBounds.setBounds(
467
- bounds_x0, bounds_y0, bounds_z0,
468
- bounds_x1, bounds_y1, bounds_z1
469
- );
470
-
471
- this.clearFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate);
472
- }
473
-
474
- computeParticleBounds() {
475
- //retire dead particles
476
- const particles = this.particles;
477
-
478
- particles.computeAttributeVector3AxisAlignedBoundingBox(PARTICLE_ATTRIBUTE_POSITION, scratch_aabb3);
479
-
480
- //expand bounds by maximum sprite size
481
- const extents = this.computeSpriteMaxHalfSize();
482
-
483
- aabb3_expand_array(scratch_aabb3, scratch_aabb3, extents);
484
-
485
- //write updated bonds
486
- const bb = this.particleBounds;
487
-
488
- bb.readFromArray(scratch_aabb3);
489
-
490
- this.clearFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
491
- }
492
-
493
- computeBoundingBox() {
494
-
495
- if (this.getFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate)) {
496
- //emission bounds need update
497
- this.computeEmissionBounds();
498
- }
499
-
500
- if (this.getFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate)) {
501
- //particle bounds need update
502
- this.computeParticleBounds();
503
- }
504
-
505
- const ebb = this.emissionBounds;
506
- const pbb = this.particleBounds;
507
-
508
- aabb3_array_combine(this.bvh_leaf.bounds, 0, ebb, 0, pbb, 0);
509
-
510
- this.bvh_leaf.write_bounds();
511
-
512
- }
513
-
514
- /**
515
- * @param {number} limit longest maximum life per layer, layers that exceed this value are ignored. Measured in seconds
516
- * @returns {number} in seconds
517
- */
518
- computeMaxEmittingParticleLife(limit = 60) {
519
- const layers = this.layers;
520
-
521
- const numLayers = layers.length;
522
-
523
- let i;
524
- let result = 0;
525
-
526
- for (i = 0; i < numLayers; i++) {
527
- const layer = layers.get(i);
528
-
529
- if (layer.emissionRate <= 0 && layer.emissionImmediate <= 0) {
530
- //skip layers with no emission
531
- continue;
532
- }
533
-
534
- const maxLifeTime = layer.particleLife.max;
535
-
536
- if (maxLifeTime > limit) {
537
- //ignore layer, it's above limit
538
- continue;
539
- }
540
-
541
- if (maxLifeTime > result) {
542
- result = maxLifeTime;
543
- }
544
- }
545
-
546
- return result;
547
- }
548
-
549
- build() {
550
-
551
- this.particles = new ParticlePool(PARTICULAR_PARTICLE_SPECIFICATION);
552
-
553
- //make overallocation a bit more aggressive to prevent frequent resizing
554
- this.particles.shrinkFactor = 0.5;
555
-
556
- this.particles.build();
557
-
558
- //build parameters
559
- this.parameters.build();
560
-
561
- //mark bounds for update
562
- this.writeFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate, true);
563
-
564
- //update bounding box
565
- this.computeBoundingBox();
566
-
567
- // mark as built
568
- this.setFlag(ParticleEmitterFlag.Built | ParticleEmitterFlag.HashNeedUpdate);
569
- }
570
-
571
- initialize() {
572
- //set buffered position to current position
573
- this.__lastSpawnPosition.copy(this.position);
574
-
575
- //emit immediate
576
- let i;
577
- const numLayers = this.layers.length;
578
-
579
- if (this.getFlag(ParticleEmitterFlag.PreWarm)) {
580
- //pre-warm the emitter
581
- for (i = 0; i < numLayers; i++) {
582
- const layer = this.layers.get(i);
583
- if (layer.emissionRate > 0 && layer.isEmitting) {
584
- const averageLifetime = (layer.particleLife.max + layer.particleLife.min) / 2;
585
- this.spawnLayerParticlesContinuous(i, averageLifetime);
586
- }
587
- }
588
- }
589
-
590
- for (i = 0; i < numLayers; i++) {
591
- //immediate emission
592
- const layer = this.layers.get(i);
593
- if (layer.emissionImmediate > 0 && layer.isEmitting) {
594
- this.spawnLayerParticlesImmediate(i, layer.emissionImmediate);
595
- }
596
- }
597
-
598
- // Mark as initialized
599
- this.setFlag(ParticleEmitterFlag.Initialized);
600
- }
601
-
602
- /**
603
- * @returns {number}
604
- */
605
- #computeHash() {
606
- const parameters_hash = this.parameters.hash();
607
- const layers_hash = this.layers.hash();
608
-
609
- /**
610
- * Extract relevant flags
611
- * @type {number}
612
- */
613
- const flags = this.flags & (SERIALIZABLE_FLAGS);
614
-
615
- return combine_hash(
616
- parameters_hash,
617
- layers_hash,
618
- this.blendingMode,
619
- flags
620
- );
621
- }
622
-
623
- hash() {
624
- if (this.getFlag(ParticleEmitterFlag.HashNeedUpdate)) {
625
- this.__hash = this.#computeHash();
626
- this.clearFlag(ParticleEmitterFlag.HashNeedUpdate);
627
- }
628
-
629
- return this.__hash;
630
- }
631
-
632
- /**
633
- *
634
- * @param {ParticleEmitter} other
635
- * @returns {boolean}
636
- */
637
- equals(other) {
638
- return this.blendingMode === other.blendingMode
639
- && this.parameters.equals(other.parameters)
640
- && this.layers.equals(other.layers)
641
- // compare the same flag set that #computeHash folds in, otherwise
642
- // equal objects can hash differently
643
- && (this.flags & SERIALIZABLE_FLAGS) === (other.flags & SERIALIZABLE_FLAGS);
644
- }
645
-
646
- /**
647
- * Order the live particles back to front along a view direction, so that whoever draws them
648
- * blends them in the right order.
649
- *
650
- * **The direction is the caller's**, because only whoever is drawing knows which way the frame
651
- * is being looked from. The predecessor took it off a three camera and read `planes[0]` of the
652
- * frustum calling it the near plane, where three's plane order puts the *right* one — so the
653
- * ordering it produced ran across the screen rather than into it.
654
- *
655
- * PRECONDITION: no dead particles may exist in the pool. Make sure to call
656
- * {@link ParticlePool#compact} before sorting.
657
- *
658
- * @param {number} direction_x unit view direction, pointing away from the viewer
659
- * @param {number} direction_y
660
- * @param {number} direction_z
661
- */
662
- sort(direction_x, direction_y, direction_z) {
663
- assert.isNumber(direction_x, 'direction_x');
664
- assert.isNumber(direction_y, 'direction_y');
665
- assert.isNumber(direction_z, 'direction_z');
666
-
667
- //sort particles by distance from camera to ensure proper rendering order
668
- // NOTE we don't use full distance calculation, but DOT product instead, as the final component is always the same and we only care about relative distance for comparison
669
-
670
- /**
671
- *
672
- * @type {ParticlePool}
673
- */
674
- const particles = this.particles;
675
-
676
- const particleCount = particles.size();
677
-
678
- //test pre-condition: NO DEAD PARTICLES IN THE POOL
679
- //assert.notOk(this.particles.hasHoles(), 'Broken pre-condition: particle pool must not have holes. Make sure to call "compact" before sorting');
680
-
681
- scratch_sort_direction[0] = direction_x;
682
- scratch_sort_direction[1] = direction_y;
683
- scratch_sort_direction[2] = direction_z;
684
-
685
- //Bind attribute array directly for faster access
686
- const positionAttribute = particles.attributes[PARTICLE_ATTRIBUTE_POSITION];
687
- const position_array = positionAttribute.array;
688
-
689
-
690
- if (particleCount <= 1) {
691
- //nothing to sort
692
- return;
693
- }
694
-
695
- //Stack-based implementation, avoiding recursion for performance improvement
696
- const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
697
-
698
- const stack_top = stack.pointer;
699
- let stackPointer = stack_top;
700
-
701
- stack[stackPointer++] = 0;
702
- stack[stackPointer++] = particleCount - 1;
703
-
704
- let i, j;
705
-
706
- while (stackPointer > stack_top) {
707
- stackPointer -= 2;
708
-
709
- const right = stack[stackPointer + 1];
710
- const left = stack[stackPointer];
711
-
712
- i = left;
713
- j = right;
714
-
715
- const pivot_index = (left + right) >> 1;
716
-
717
- const pivot = v3_dot_array(position_array, pivot_index * 3, scratch_sort_direction, 0);
718
-
719
- /* partition */
720
- while (i <= j) {
721
-
722
- while (v3_dot_array(position_array, i * 3, scratch_sort_direction, 0) > pivot) {
723
- i++;
724
- }
725
-
726
- while (v3_dot_array(position_array, j * 3, scratch_sort_direction, 0) < pivot) {
727
- j--;
728
- }
729
-
730
- if (i <= j) {
731
-
732
- if (i !== j) {
733
- //do swap
734
- particles.swap(i, j);
735
- }
736
-
737
- i++;
738
- j--;
739
- }
740
- }
741
-
742
- /* recursion */
743
- if (left < j) {
744
- stack[stackPointer++] = left;
745
- stack[stackPointer++] = j;
746
- }
747
- if (i < right) {
748
- stack[stackPointer++] = i;
749
- stack[stackPointer++] = right;
750
- }
751
- }
752
- }
753
-
754
- update() {
755
- this.particles.update();
756
-
757
- //check if sprites need updating
758
- if (this.getFlag(ParticleEmitterFlag.SpritesNeedUpdate)) {
759
- this.#updateSprites();
760
- }
761
- }
762
-
763
- /**
764
- *
765
- * @return {number}
766
- */
767
- computeSpriteMaxHalfSize() {
768
- const layers = this.layers;
769
- const n = layers.length;
770
-
771
- let result = 0;
772
-
773
- for (let i = 0; i < n; i++) {
774
- const particleLayer = layers.get(i);
775
-
776
- result = max2(result, particleLayer.computeScaledSpriteHalfSize());
777
- }
778
-
779
- return result;
780
- }
781
-
782
- /**
783
- *
784
- * @param {number} timeDelta
785
- */
786
- advance(timeDelta) {
787
- this.emit(timeDelta);
788
-
789
- this.setFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
790
- }
791
-
792
- /**
793
- * Write sprite UVs
794
- */
795
- #updateSprites() {
796
- const particles = this.particles;
797
-
798
- const occupancy = particles.occupancy;
799
-
800
- const layers = this.layers;
801
-
802
- let missingFlag = false;
803
-
804
- //cycle through each particle
805
- for (let i = occupancy.nextSetBit(0); i !== -1; i = occupancy.nextSetBit(i + 1)) {
806
- const layerIndex = particles.readAttributeScalar(i, PARTICLE_ATTRIBUTE_LAYER_POSITION);
807
-
808
- const layer = layers.get(layerIndex);
809
-
810
- const atlasPatch = layer.__atlasPatch;
811
-
812
- if (atlasPatch !== null) {
813
-
814
- write_particle_patch_uv(atlasPatch, particles, i);
815
- } else {
816
- missingFlag = true;
817
- }
818
- }
819
-
820
- this.writeFlag(ParticleEmitterFlag.SpritesNeedUpdate, missingFlag);
821
- }
822
-
823
- /**
824
- * @private
825
- * @param {int} layerIndex
826
- * @param {number} timeDelta period over which particles are being spawned, this will ensure that spawned particles have different initial age
827
- */
828
- spawnLayerParticlesContinuous(layerIndex, timeDelta) {
829
- const layer = this.layers.get(layerIndex);
830
-
831
- const random = Math.random;
832
-
833
- /**
834
- *
835
- * @type {ParticlePool}
836
- */
837
- const particles = this.particles;
838
-
839
-
840
- const emissionFunction = computeEmissionFunction(layer.emissionFrom, layer.emissionShape);
841
-
842
- const emissionPeriod = 1 / layer.emissionRate;
843
-
844
- //compute transform matrix of the emitter
845
- const emitter_position = this.position;
846
- const last_spawn_position = this.__lastSpawnPosition;
847
-
848
- m4_compose(matrix4, emitter_position, this.rotation, this.scale);
849
-
850
- let time = -layer.timeSinceLastEmission;
851
-
852
- while (time + emissionPeriod < timeDelta) {
853
- time += emissionPeriod;
854
-
855
- const ref = particles.create();
856
-
857
- // randomize position across the supplied time interval
858
- const f = time / timeDelta;
859
-
860
- //compute position for particle
861
- emissionFunction(random, scratch_v3_array, 0);
862
-
863
- v3position.fromArray(scratch_v3_array, 0);
864
-
865
- //apply layer transform
866
- v3position.multiply(layer.scale);
867
- v3position.add(layer.position);
868
-
869
- if (this.getFlag(ParticleEmitterFlag.PositionChanged)) {
870
- //compute position in between
871
- matrix4[12] = lerp(emitter_position.x, last_spawn_position.x, f);
872
- matrix4[13] = lerp(emitter_position.y, last_spawn_position.y, f);
873
- matrix4[14] = lerp(emitter_position.z, last_spawn_position.z, f);
874
- }
875
-
876
- //apply emitter transform
877
- v3position.applyMatrix4(matrix4);
878
-
879
-
880
- //randomize initial age across time delta
881
- const initialAge = f * timeDelta;
882
-
883
- //write age
884
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_AGE, initialAge);
885
-
886
- //write rotation
887
- const rotation = layer.particleRotation.sampleRandom(random);
888
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION, rotation);
889
-
890
- //write rotation speed
891
- const rotationSpeed = layer.particleRotationSpeed.sampleRandom(random);
892
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION_SPEED, rotationSpeed);
893
-
894
- //initialize velocity
895
- layer.particleVelocityDirection.sampleRandomDirection(random, v3velocity);
896
- const speed = layer.particleSpeed.sampleRandom(random);
897
-
898
- v3velocity.multiplyScalar(speed);
899
-
900
- particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_VELOCITY, v3velocity.x, v3velocity.y, v3velocity.z);
901
-
902
- //write position
903
- const p_x = v3position.x + v3velocity.x * initialAge;
904
- const p_y = v3position.y + v3velocity.y * initialAge;
905
- const p_z = v3position.z + v3velocity.z * initialAge;
906
-
907
- particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_POSITION, p_x, p_y, p_z);
908
-
909
- //write death age
910
- const deathAge = layer.particleLife.sampleRandom(random);
911
-
912
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_DEATH_AGE, deathAge);
913
-
914
- //write particle size
915
- const size = layer.particleSize.sampleRandom(random);
916
-
917
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
918
-
919
- //write UV
920
- const atlasPatch = layer.__atlasPatch;
921
- if (atlasPatch !== null) {
922
- //patch exists, write it
923
- write_particle_patch_uv(atlasPatch, particles, ref);
924
- } else {
925
- this.setFlag(ParticleEmitterFlag.SpritesNeedUpdate);
926
- }
927
-
928
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerIndex);
929
-
930
- update_parameters(ref, particles, layer, initialAge / deathAge);
931
-
932
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_BLEND, this.blendingMode);
933
- }
934
-
935
- //update time buffer
936
- layer.timeSinceLastEmission = timeDelta - time;
937
-
938
- this.setFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
939
- }
940
-
941
- /**
942
- * @private
943
- * @param {int} layerIndex
944
- * @param {number} count how many particles to spawn
945
- */
946
- spawnLayerParticlesImmediate(layerIndex, count) {
947
- if (count <= 0) {
948
- return;
949
- }
950
-
951
- const layers = this.layers;
952
-
953
- const layer = layers.get(layerIndex);
954
-
955
- const random = Math.random;
956
-
957
- /**
958
- *
959
- * @type {ParticlePool}
960
- */
961
- const particles = this.particles;
962
-
963
- const emissionFunction = computeEmissionFunction(layer.emissionFrom, layer.emissionShape);
964
-
965
- //compute transform matrix of the emitter
966
- m4_compose(matrix4, this.position, this.rotation, this.scale);
967
-
968
- //pre-grow particle pool
969
- particles.growCapacity(particles.capacity + count);
970
-
971
- let spritesNeedUpdate = false;
972
-
973
- for (let j = 0; j < count; j++) {
974
- const ref = particles.create();
975
-
976
- //compute position for particle
977
- emissionFunction(random, scratch_v3_array, 0);
978
-
979
- v3position.fromArray(scratch_v3_array, 0);
980
-
981
- //apply layer transform
982
- v3position.multiply(layer.scale);
983
- v3position.add(layer.position);
984
-
985
- //apply emitter transform
986
- v3position.applyMatrix4(matrix4);
987
-
988
-
989
- //randomize initial age across time delta
990
- const initialAge = 0;
991
-
992
- //write age
993
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_AGE, initialAge);
994
-
995
- //write rotation
996
- const rotation = layer.particleRotation.sampleRandom(random);
997
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION, rotation);
998
-
999
- //write rotation speed
1000
- const rotationSpeed = layer.particleRotationSpeed.sampleRandom(random);
1001
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION_SPEED, rotationSpeed);
1002
-
1003
- //initialize velocity
1004
- layer.particleVelocityDirection.sampleRandomDirection(random, v3velocity);
1005
- const speed = layer.particleSpeed.sampleRandom(random);
1006
-
1007
- v3velocity.multiplyScalar(speed);
1008
-
1009
- particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_VELOCITY, v3velocity.x, v3velocity.y, v3velocity.z);
1010
-
1011
- //write position
1012
- const p_x = v3position.x + v3velocity.x * initialAge;
1013
- const p_y = v3position.y + v3velocity.y * initialAge;
1014
- const p_z = v3position.z + v3velocity.z * initialAge;
1015
-
1016
- particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_POSITION,
1017
- p_x,
1018
- p_y,
1019
- p_z
1020
- );
1021
-
1022
- //write death age
1023
- const deathAge = layer.particleLife.sampleRandom(random);
1024
-
1025
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_DEATH_AGE, deathAge);
1026
-
1027
- //write size
1028
- const size = layer.particleSize.sampleRandom(random);
1029
-
1030
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
1031
-
1032
- //write UV
1033
- const atlasPatch = layer.__atlasPatch;
1034
-
1035
- if (atlasPatch !== null) {
1036
- //patch exists, write it
1037
- write_particle_patch_uv(atlasPatch, particles, ref);
1038
- } else {
1039
- //patch is not loaded yet, request update
1040
- spritesNeedUpdate = true;
1041
- }
1042
-
1043
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerIndex);
1044
-
1045
- update_parameters(ref, particles, layer, initialAge / deathAge);
1046
-
1047
- particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_BLEND, this.blendingMode);
1048
- }
1049
-
1050
- if (spritesNeedUpdate) {
1051
- this.setFlag(ParticleEmitterFlag.SpritesNeedUpdate);
1052
- }
1053
-
1054
- this.setFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
1055
- }
1056
-
1057
- /**
1058
- * @private
1059
- * @param {number} timeDelta
1060
- */
1061
- emit(timeDelta) {
1062
- if (!this.getFlag(ParticleEmitterFlag.Emitting)) {
1063
- return;
1064
- }
1065
-
1066
- const layers = this.layers;
1067
- const numLayers = layers.length;
1068
-
1069
- if (!this.position.equals(this.__lastSpawnPosition)) {
1070
- this.setFlag(ParticleEmitterFlag.PositionChanged);
1071
- }
1072
-
1073
- //emit new particles
1074
- for (let i = 0; i < numLayers; i++) {
1075
- /**
1076
- * @type {ParticleLayer}
1077
- */
1078
- const layer = layers.get(i);
1079
-
1080
- if (!layer.isEmitting) {
1081
- //this layer is not spawning any particles, ignore it
1082
- continue;
1083
- }
1084
-
1085
- const particleLife = layer.particleLife;
1086
-
1087
- const averageLifetime = (particleLife.max + particleLife.min) / 2;
1088
-
1089
- //emitting more than averageLifetime lifetime is unproductive, so we'll crop the emission
1090
- let emissionDelta;
1091
- if (timeDelta > averageLifetime) {
1092
- emissionDelta = averageLifetime;
1093
- layer.timeSinceLastEmission = 0;
1094
- } else {
1095
- emissionDelta = timeDelta;
1096
- }
1097
-
1098
- this.spawnLayerParticlesContinuous(i, emissionDelta);
1099
- }
1100
-
1101
- if (this.getFlag(ParticleEmitterFlag.PositionChanged)) {
1102
- this.__lastSpawnPosition.copy(this.position);
1103
- this.clearFlag(ParticleEmitterFlag.PositionChanged);
1104
- }
1105
- }
1106
-
1107
-
1108
- /**
1109
- * Cleanup used resources
1110
- */
1111
- dispose() {
1112
- if (this.particles !== null) {
1113
- this.particles.dispose();
1114
- }
1115
- }
1116
-
1117
- /**
1118
- *
1119
- * @param json
1120
- * @returns {ParticleEmitter}
1121
- */
1122
- static fromJSON(json) {
1123
- const result = new ParticleEmitter();
1124
- result.fromJSON(json);
1125
- return result
1126
- }
1127
- }
1128
-
1129
- ParticleEmitter.typeName = "ParticleEmitter";
1130
-
1131
- ParticleEmitter.Attributes = {
1132
- PARTICLE_ATTRIBUTE_AGE,
1133
- PARTICLE_ATTRIBUTE_DEATH_AGE,
1134
- PARTICLE_ATTRIBUTE_LAYER_POSITION,
1135
- PARTICLE_ATTRIBUTE_POSITION,
1136
- PARTICLE_ATTRIBUTE_ROTATION,
1137
- PARTICLE_ATTRIBUTE_ROTATION_SPEED,
1138
- PARTICLE_ATTRIBUTE_SIZE,
1139
- PARTICLE_ATTRIBUTE_UV,
1140
- PARTICLE_ATTRIBUTE_VELOCITY
1141
- };
1142
-
1143
- ParticleEmitter.SERIALIZABLE_FLAGS = SERIALIZABLE_FLAGS;
1144
-
1145
-
1146
- const matrix4 = new Float32Array(16);
1147
-
1148
- const v3position = new Vector3();
1149
- const v3velocity = new Vector3();
1
+ import { assert } from "../../../../../../core/assert.js";
2
+ import { BvhClient } from "../../../../../../core/bvh2/bvh3/BvhClient.js";
3
+ import { combine_hash } from "../../../../../../core/collection/array/combine_hash.js";
4
+ import List from "../../../../../../core/collection/list/List.js";
5
+ import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../../../../core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
6
+ import { AABB3 } from "../../../../../../core/geom/3d/aabb/AABB3.js";
7
+ import { aabb3_array_combine } from "../../../../../../core/geom/3d/aabb/aabb3_array_combine.js";
8
+ import { aabb3_expand_array } from "../../../../../../core/geom/3d/aabb/aabb3_expand_array.js";
9
+ import { m4_compose } from "../../../../../../core/geom/3d/mat4/m4_compose.js";
10
+ import Quaternion from "../../../../../../core/geom/Quaternion.js";
11
+ import { v3_dot_array } from "../../../../../../core/geom/vec3/v3_dot_array.js";
12
+ import Vector3 from "../../../../../../core/geom/Vector3.js";
13
+ import { lerp } from "../../../../../../core/math/lerp.js";
14
+ import { max2 } from "../../../../../../core/math/max2.js";
15
+ import { min2 } from "../../../../../../core/math/min2.js";
16
+ import { BlendingType } from "../../../../texture/sampler/BlendingType.js";
17
+ import { ParameterSet } from "../parameter/ParameterSet.js";
18
+ import { ParticleParameter } from "../parameter/ParticleParameter.js";
19
+ import { update_parameters } from "../simulator/update_parameters.js";
20
+ import { computeEmissionFunction } from "./computeEmissionFunction.js";
21
+ import {
22
+ PARTICLE_ATTRIBUTE_AGE,
23
+ PARTICLE_ATTRIBUTE_BLEND,
24
+ PARTICLE_ATTRIBUTE_DEATH_AGE,
25
+ PARTICLE_ATTRIBUTE_LAYER_POSITION,
26
+ PARTICLE_ATTRIBUTE_POSITION,
27
+ PARTICLE_ATTRIBUTE_ROTATION,
28
+ PARTICLE_ATTRIBUTE_ROTATION_SPEED,
29
+ PARTICLE_ATTRIBUTE_SIZE,
30
+ PARTICLE_ATTRIBUTE_SIZE_INITIAL,
31
+ PARTICLE_ATTRIBUTE_UV,
32
+ PARTICLE_ATTRIBUTE_VELOCITY
33
+ } from "./PARTICLE_ATTRIBUTES.js";
34
+ import { ParticleEmitterFlag } from "./ParticleEmitterFlag.js";
35
+ import { ParticleLayer } from "./ParticleLayer.js";
36
+ import { ParticleParameters } from "./ParticleParameters.js";
37
+ import { ParticlePool } from "./ParticlePool.js";
38
+ import { PARTICULAR_PARTICLE_SPECIFICATION } from "./PARTICULAR_PARTICLE_SPECIFICATION.js";
39
+ import { write_particle_patch_uv } from "./write_particle_patch_uv.js";
40
+
41
+
42
+ const SERIALIZABLE_FLAGS = ParticleEmitterFlag.PreWarm
43
+ | ParticleEmitterFlag.DepthSorting
44
+ | ParticleEmitterFlag.DepthReadDisabled
45
+ | ParticleEmitterFlag.DepthSoftDisabled
46
+ | ParticleEmitterFlag.AlignOnVelocity
47
+ ;
48
+
49
+ /**
50
+ * Used to store AABB3 corners during bounding box calculation
51
+ * @readonly
52
+ * @type {Float64Array}
53
+ */
54
+ const corners = new Float64Array(24);
55
+
56
+ const scratch_sort_direction = new Float32Array(3);
57
+
58
+ /**
59
+ *
60
+ * @type {Float32Array}
61
+ */
62
+ const scratch_aabb3 = new Float32Array(6);
63
+
64
+ /**
65
+ *
66
+ * @type {number[]}
67
+ */
68
+ const scratch_v3_array = [];
69
+
70
+ /**
71
+ *
72
+ * @param {ParameterSet} parameters
73
+ */
74
+ function generateStandardParameterSet(parameters) {
75
+ const pScale = new ParticleParameter(ParticleParameters.Scale, 1);
76
+ pScale.setDefault([1], [0]);
77
+
78
+ const pColor = new ParticleParameter(ParticleParameters.Color, 4);
79
+ pColor.setDefault([1, 1, 1, 1], [0]);
80
+
81
+ parameters.add(pScale);
82
+ parameters.add(pColor);
83
+ }
84
+
85
+
86
+ let id_counter = 0;
87
+
88
+ export class ParticleEmitter {
89
+ /**
90
+ * @type {number}
91
+ */
92
+ id = id_counter++;
93
+
94
+ /**
95
+ * @private
96
+ * @readonly
97
+ * @type {List<ParticleLayer>}
98
+ */
99
+ layers = new List();
100
+
101
+ /**
102
+ *
103
+ * @type {Vector3}
104
+ */
105
+ position = new Vector3(0, 0, 0);
106
+ scale = new Vector3(1, 1, 1);
107
+ rotation = new Quaternion(0, 0, 0, 1);
108
+
109
+ /**
110
+ *
111
+ * @type {Vector3}
112
+ * @readonly
113
+ * @private
114
+ */
115
+ __lastSpawnPosition = new Vector3(0, 0, 0);
116
+
117
+ /**
118
+ * How long has this emitter been sleeping for?
119
+ * This amount of time needs to be simulated when we wake the emitter up, but we can typically do it in a small number of large steps
120
+ * @type {number}
121
+ */
122
+ sleepTime = 0;
123
+
124
+ /**
125
+ *
126
+ * @type {BlendingType|number}
127
+ */
128
+ blendingMode = BlendingType.Normal;
129
+
130
+ /**
131
+ *
132
+ * @type {ParticlePool|null}
133
+ */
134
+ particles = null;
135
+
136
+ /**
137
+ * @readonly
138
+ * @type {BvhClient}
139
+ */
140
+ bvh_leaf = new BvhClient();
141
+
142
+
143
+ /**
144
+ * Upper-bound of bounds for an individual particle
145
+ * @readonly
146
+ * @type {AABB3}
147
+ */
148
+ particleBounds = new AABB3(Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity);
149
+
150
+ /**
151
+ * @readonly
152
+ * @type {AABB3}
153
+ */
154
+ emissionBounds = new AABB3(0, 0, 0, 0, 0, 0);
155
+
156
+
157
+ /**
158
+ * Bit Field of {@link ParticleEmitterFlag}
159
+ * @type {number}
160
+ */
161
+ flags = ParticleEmitterFlag.DepthSorting | ParticleEmitterFlag.HashNeedUpdate | ParticleEmitterFlag.Emitting;
162
+
163
+ /**
164
+ *
165
+ * @type {number}
166
+ * @private
167
+ */
168
+ __hash = 0;
169
+
170
+
171
+ /**
172
+ * @readonly
173
+ * @type {ParameterSet}
174
+ */
175
+ parameters = new ParameterSet();
176
+
177
+ constructor() {
178
+ generateStandardParameterSet(this.parameters);
179
+
180
+
181
+ this.position.onChanged.add(this.updateTransform, this);
182
+ this.scale.onChanged.add(this.updateTransform, this);
183
+ this.rotation.onChanged.add(this.updateTransform, this);
184
+ }
185
+
186
+ updateTransform() {
187
+ this.setFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate);
188
+
189
+ this.computeBoundingBox();
190
+ }
191
+
192
+ /**
193
+ *
194
+ * @param {number|ParticleEmitterFlag} flag
195
+ * @returns {void}
196
+ */
197
+ setFlag(flag) {
198
+ this.flags |= flag;
199
+ }
200
+
201
+ /**
202
+ *
203
+ * @param {number|ParticleEmitterFlag} flag
204
+ * @returns {void}
205
+ */
206
+ clearFlag(flag) {
207
+ this.flags &= ~flag;
208
+ }
209
+
210
+ /**
211
+ *
212
+ * @param {number|ParticleEmitterFlag} flag
213
+ * @param {boolean} value
214
+ */
215
+ writeFlag(flag, value) {
216
+ if (value) {
217
+ this.setFlag(flag);
218
+ } else {
219
+ this.clearFlag(flag);
220
+ }
221
+ }
222
+
223
+ /**
224
+ *
225
+ * @param {number|ParticleEmitterFlag} flag
226
+ * @returns {boolean}
227
+ */
228
+ getFlag(flag) {
229
+ return (this.flags & flag) === flag;
230
+ }
231
+
232
+ /**
233
+ * @private
234
+ */
235
+ registerLayerParameters() {
236
+ const layers = this.layers;
237
+ const layer_count = layers.length;
238
+
239
+ const parameters = this.parameters;
240
+
241
+ parameters.setTrackCount(layer_count);
242
+
243
+ for (let i = 0; i < layer_count; i++) {
244
+ const layer = layers.get(i);
245
+
246
+ parameters.setTracks(i, layer.parameterTracks);
247
+ }
248
+ }
249
+
250
+ toJSON() {
251
+ return {
252
+ position: this.position.toJSON(),
253
+ scale: this.scale.toJSON(),
254
+ rotation: this.rotation.toJSON(),
255
+ parameters: this.parameters.toJSON(),
256
+ preWarm: this.getFlag(ParticleEmitterFlag.PreWarm),
257
+ readDepth: !this.getFlag(ParticleEmitterFlag.DepthReadDisabled),
258
+ softDepth: !this.getFlag(ParticleEmitterFlag.DepthSoftDisabled),
259
+ velocityAlign: this.getFlag(ParticleEmitterFlag.AlignOnVelocity),
260
+ depthSort: this.getFlag(ParticleEmitterFlag.DepthSorting),
261
+ receiveLight: this.getFlag(ParticleEmitterFlag.Lit),
262
+ blendingMode: this.blendingMode,
263
+ layers: this.layers.toJSON()
264
+ };
265
+ }
266
+
267
+ fromJSON(json) {
268
+ if (typeof json.blendingMode === "number") {
269
+ this.blendingMode = json.blendingMode;
270
+ } else {
271
+ this.blendingMode = BlendingType.Normal;
272
+ }
273
+
274
+ if (json.position !== undefined) {
275
+ this.position.fromJSON(json.position);
276
+ }
277
+
278
+ if (json.scale !== undefined) {
279
+ this.scale.fromJSON(json.scale);
280
+ }
281
+
282
+ if (json.rotation !== undefined) {
283
+ this.rotation.fromJSON(json.rotation);
284
+ }
285
+
286
+ if (json.parameters !== undefined) {
287
+ this.parameters.fromJSON(json.parameters);
288
+ }
289
+
290
+ if (typeof json.preWarm === "boolean") {
291
+ this.writeFlag(ParticleEmitterFlag.PreWarm, json.preWarm);
292
+ } else {
293
+ this.writeFlag(ParticleEmitterFlag.PreWarm, false);
294
+ }
295
+
296
+ if (typeof json.readDepth === 'boolean') {
297
+ this.writeFlag(ParticleEmitterFlag.DepthReadDisabled, !json.readDepth);
298
+ } else {
299
+ this.writeFlag(ParticleEmitterFlag.DepthReadDisabled, false);
300
+ }
301
+
302
+ if (typeof json.softDepth === 'boolean') {
303
+ this.writeFlag(ParticleEmitterFlag.DepthSoftDisabled, !json.softDepth);
304
+ } else {
305
+ this.writeFlag(ParticleEmitterFlag.DepthSoftDisabled, false);
306
+ }
307
+
308
+ if (typeof json.velocityAlign === "boolean") {
309
+ this.writeFlag(ParticleEmitterFlag.AlignOnVelocity, json.velocityAlign);
310
+ } else {
311
+ this.writeFlag(ParticleEmitterFlag.AlignOnVelocity, false);
312
+ }
313
+
314
+ if (typeof json.depthSort === "boolean") {
315
+ this.writeFlag(ParticleEmitterFlag.DepthSorting, json.depthSort);
316
+ } else {
317
+ this.writeFlag(ParticleEmitterFlag.DepthSorting, true);
318
+ }
319
+
320
+ if (typeof json.receiveLight === "boolean") {
321
+ this.writeFlag(ParticleEmitterFlag.Lit, json.receiveLight);
322
+ } else {
323
+ this.clearFlag(ParticleEmitterFlag.Lit);
324
+ }
325
+
326
+ this.layers.fromJSON(json.layers, ParticleLayer);
327
+
328
+ this.writeFlag(ParticleEmitterFlag.Built, false);
329
+ this.setFlag(ParticleEmitterFlag.Emitting);
330
+
331
+ //register loaded layers
332
+ this.registerLayerParameters();
333
+ }
334
+
335
+
336
+ /**
337
+ *
338
+ * @param {ParticleLayer} layer
339
+ */
340
+ addLayer(layer) {
341
+ this.layers.add(layer);
342
+
343
+ const numLayers = this.layers.length;
344
+ this.parameters.setTrackCount(numLayers);
345
+
346
+ this.parameters.setTracks(numLayers - 1, layer.parameterTracks);
347
+ }
348
+
349
+ /**
350
+ *
351
+ * @param {(layer: ParticleLayer, index: number) => void} visitor
352
+ * @param {*} [thisArg]
353
+ */
354
+ traverseLayers(visitor, thisArg) {
355
+ const layers = this.layers;
356
+
357
+ const l = layers.length;
358
+
359
+ for (let i = 0; i < l; i++) {
360
+ const layer = layers.get(i);
361
+
362
+ visitor.call(thisArg, layer, i);
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Causes all active particles from a given layer to be destroyed immediately
368
+ * @param {ParticleLayer} layer
369
+ * @return {number} number of particles destroyed
370
+ */
371
+ destroyParticlesFromLayer(layer) {
372
+ const layers = this.layers;
373
+
374
+ const targetLayerIndex = layers.indexOf(layer);
375
+
376
+ if (targetLayerIndex === -1) {
377
+ //layer doesn't exist
378
+ throw new Error('Layer not found');
379
+ }
380
+
381
+ const particles = this.particles;
382
+ const occupancy = particles.occupancy;
383
+
384
+ let removeCount = 0;
385
+
386
+ for (
387
+ let i = occupancy.nextSetBit(0);
388
+ i !== -1;
389
+ i = occupancy.nextSetBit(i + 1)
390
+ ) {
391
+
392
+ const layerPosition = particles.readAttributeScalar(i, PARTICLE_ATTRIBUTE_LAYER_POSITION);
393
+
394
+ if (layerPosition !== targetLayerIndex) {
395
+ // not the layer we want
396
+ continue;
397
+ }
398
+
399
+ //destroy the particle
400
+ occupancy.set(i, false);
401
+
402
+ removeCount++;
403
+
404
+ }
405
+
406
+ if (removeCount > 0) {
407
+ //remove dead particles from the pool
408
+ particles.compact();
409
+ }
410
+
411
+ return removeCount;
412
+ }
413
+
414
+ computeEmissionBounds() {
415
+
416
+ let bounds_x0 = Infinity;
417
+ let bounds_y0 = Infinity;
418
+ let bounds_z0 = Infinity;
419
+
420
+ let bounds_x1 = -Infinity;
421
+ let bounds_y1 = -Infinity;
422
+ let bounds_z1 = -Infinity;
423
+
424
+ const layers = this.layers;
425
+ const numLayers = layers.length;
426
+
427
+ const position = this.position;
428
+ const rotation = this.rotation;
429
+ const scale = this.scale;
430
+
431
+ m4_compose(matrix4, position, rotation, scale);
432
+
433
+ for (let i = 0; i < numLayers; i++) {
434
+ const particleLayer = layers.get(i);
435
+
436
+ particleLayer.computeBoundsAttributes();
437
+
438
+ const s_2 = particleLayer.scaledSpriteHalfSize;
439
+
440
+ const baseBoundingBox = particleLayer.baseBoundingBox;
441
+ baseBoundingBox.getCorners(corners);
442
+
443
+ for (let j = 0; j < 24; j += 3) {
444
+
445
+ const x = corners[j];
446
+ const y = corners[j + 1];
447
+ const z = corners[j + 2];
448
+
449
+ //apply matrix transform
450
+ const _x = matrix4[0] * x + matrix4[4] * y + matrix4[8] * z + matrix4[12];
451
+ const _y = matrix4[1] * x + matrix4[5] * y + matrix4[9] * z + matrix4[13];
452
+ const _z = matrix4[2] * x + matrix4[6] * y + matrix4[10] * z + matrix4[14];
453
+
454
+
455
+ //update bounds
456
+ bounds_x0 = min2(bounds_x0, _x - s_2);
457
+ bounds_y0 = min2(bounds_y0, _y - s_2);
458
+ bounds_z0 = min2(bounds_z0, _z - s_2);
459
+
460
+ bounds_x1 = max2(bounds_x1, _x + s_2);
461
+ bounds_y1 = max2(bounds_y1, _y + s_2);
462
+ bounds_z1 = max2(bounds_z1, _z + s_2);
463
+ }
464
+ }
465
+
466
+ this.emissionBounds.setBounds(
467
+ bounds_x0, bounds_y0, bounds_z0,
468
+ bounds_x1, bounds_y1, bounds_z1
469
+ );
470
+
471
+ this.clearFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate);
472
+ }
473
+
474
+ computeParticleBounds() {
475
+ //retire dead particles
476
+ const particles = this.particles;
477
+
478
+ particles.computeAttributeVector3AxisAlignedBoundingBox(PARTICLE_ATTRIBUTE_POSITION, scratch_aabb3);
479
+
480
+ //expand bounds by maximum sprite size
481
+ const extents = this.computeSpriteMaxHalfSize();
482
+
483
+ aabb3_expand_array(scratch_aabb3, scratch_aabb3, extents);
484
+
485
+ //write updated bonds
486
+ const bb = this.particleBounds;
487
+
488
+ bb.readFromArray(scratch_aabb3);
489
+
490
+ this.clearFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
491
+ }
492
+
493
+ computeBoundingBox() {
494
+
495
+ if (this.getFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate)) {
496
+ //emission bounds need update
497
+ this.computeEmissionBounds();
498
+ }
499
+
500
+ if (this.getFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate)) {
501
+ //particle bounds need update
502
+ this.computeParticleBounds();
503
+ }
504
+
505
+ const ebb = this.emissionBounds;
506
+ const pbb = this.particleBounds;
507
+
508
+ aabb3_array_combine(this.bvh_leaf.bounds, 0, ebb, 0, pbb, 0);
509
+
510
+ this.bvh_leaf.write_bounds();
511
+
512
+ }
513
+
514
+ /**
515
+ * @param {number} limit longest maximum life per layer, layers that exceed this value are ignored. Measured in seconds
516
+ * @returns {number} in seconds
517
+ */
518
+ computeMaxEmittingParticleLife(limit = 60) {
519
+ const layers = this.layers;
520
+
521
+ const numLayers = layers.length;
522
+
523
+ let i;
524
+ let result = 0;
525
+
526
+ for (i = 0; i < numLayers; i++) {
527
+ const layer = layers.get(i);
528
+
529
+ if (layer.emissionRate <= 0 && layer.emissionImmediate <= 0) {
530
+ //skip layers with no emission
531
+ continue;
532
+ }
533
+
534
+ const maxLifeTime = layer.particleLife.max;
535
+
536
+ if (maxLifeTime > limit) {
537
+ //ignore layer, it's above limit
538
+ continue;
539
+ }
540
+
541
+ if (maxLifeTime > result) {
542
+ result = maxLifeTime;
543
+ }
544
+ }
545
+
546
+ return result;
547
+ }
548
+
549
+ build() {
550
+
551
+ this.particles = new ParticlePool(PARTICULAR_PARTICLE_SPECIFICATION);
552
+
553
+ //make overallocation a bit more aggressive to prevent frequent resizing
554
+ this.particles.shrinkFactor = 0.5;
555
+
556
+ this.particles.build();
557
+
558
+ //build parameters
559
+ this.parameters.build();
560
+
561
+ //mark bounds for update
562
+ this.writeFlag(ParticleEmitterFlag.BaseBoundsNeedUpdate, true);
563
+
564
+ //update bounding box
565
+ this.computeBoundingBox();
566
+
567
+ // mark as built
568
+ this.setFlag(ParticleEmitterFlag.Built | ParticleEmitterFlag.HashNeedUpdate);
569
+ }
570
+
571
+ initialize() {
572
+ //set buffered position to current position
573
+ this.__lastSpawnPosition.copy(this.position);
574
+
575
+ //emit immediate
576
+ let i;
577
+ const numLayers = this.layers.length;
578
+
579
+ if (this.getFlag(ParticleEmitterFlag.PreWarm)) {
580
+ //pre-warm the emitter
581
+ for (i = 0; i < numLayers; i++) {
582
+ const layer = this.layers.get(i);
583
+ if (layer.emissionRate > 0 && layer.isEmitting) {
584
+ const averageLifetime = (layer.particleLife.max + layer.particleLife.min) / 2;
585
+ this.spawnLayerParticlesContinuous(i, averageLifetime);
586
+ }
587
+ }
588
+ }
589
+
590
+ for (i = 0; i < numLayers; i++) {
591
+ //immediate emission
592
+ const layer = this.layers.get(i);
593
+ if (layer.emissionImmediate > 0 && layer.isEmitting) {
594
+ this.spawnLayerParticlesImmediate(i, layer.emissionImmediate);
595
+ }
596
+ }
597
+
598
+ // Mark as initialized
599
+ this.setFlag(ParticleEmitterFlag.Initialized);
600
+ }
601
+
602
+ /**
603
+ * @returns {number}
604
+ */
605
+ #computeHash() {
606
+ const parameters_hash = this.parameters.hash();
607
+ const layers_hash = this.layers.hash();
608
+
609
+ /**
610
+ * Extract relevant flags
611
+ * @type {number}
612
+ */
613
+ const flags = this.flags & (SERIALIZABLE_FLAGS);
614
+
615
+ return combine_hash(
616
+ parameters_hash,
617
+ layers_hash,
618
+ this.blendingMode,
619
+ flags
620
+ );
621
+ }
622
+
623
+ hash() {
624
+ if (this.getFlag(ParticleEmitterFlag.HashNeedUpdate)) {
625
+ this.__hash = this.#computeHash();
626
+ this.clearFlag(ParticleEmitterFlag.HashNeedUpdate);
627
+ }
628
+
629
+ return this.__hash;
630
+ }
631
+
632
+ /**
633
+ *
634
+ * @param {ParticleEmitter} other
635
+ * @returns {boolean}
636
+ */
637
+ equals(other) {
638
+ return this.blendingMode === other.blendingMode
639
+ && this.parameters.equals(other.parameters)
640
+ && this.layers.equals(other.layers)
641
+ // compare the same flag set that #computeHash folds in, otherwise
642
+ // equal objects can hash differently
643
+ && (this.flags & SERIALIZABLE_FLAGS) === (other.flags & SERIALIZABLE_FLAGS);
644
+ }
645
+
646
+ /**
647
+ * Order the live particles back to front along a view direction, so that whoever draws them
648
+ * blends them in the right order.
649
+ *
650
+ * **The direction is the caller's**, because only whoever is drawing knows which way the frame
651
+ * is being looked from. The predecessor took it off a three camera and read `planes[0]` of the
652
+ * frustum calling it the near plane, where three's plane order puts the *right* one — so the
653
+ * ordering it produced ran across the screen rather than into it.
654
+ *
655
+ * PRECONDITION: no dead particles may exist in the pool. Make sure to call
656
+ * {@link ParticlePool#compact} before sorting.
657
+ *
658
+ * @param {number} direction_x unit view direction, pointing away from the viewer
659
+ * @param {number} direction_y
660
+ * @param {number} direction_z
661
+ */
662
+ sort(direction_x, direction_y, direction_z) {
663
+ assert.isNumber(direction_x, 'direction_x');
664
+ assert.isNumber(direction_y, 'direction_y');
665
+ assert.isNumber(direction_z, 'direction_z');
666
+
667
+ //sort particles by distance from camera to ensure proper rendering order
668
+ // NOTE we don't use full distance calculation, but DOT product instead, as the final component is always the same and we only care about relative distance for comparison
669
+
670
+ /**
671
+ *
672
+ * @type {ParticlePool}
673
+ */
674
+ const particles = this.particles;
675
+
676
+ const particleCount = particles.size();
677
+
678
+ //test pre-condition: NO DEAD PARTICLES IN THE POOL
679
+ //assert.notOk(this.particles.hasHoles(), 'Broken pre-condition: particle pool must not have holes. Make sure to call "compact" before sorting');
680
+
681
+ scratch_sort_direction[0] = direction_x;
682
+ scratch_sort_direction[1] = direction_y;
683
+ scratch_sort_direction[2] = direction_z;
684
+
685
+ //Bind attribute array directly for faster access
686
+ const positionAttribute = particles.attributes[PARTICLE_ATTRIBUTE_POSITION];
687
+ const position_array = positionAttribute.array;
688
+
689
+
690
+ if (particleCount <= 1) {
691
+ //nothing to sort
692
+ return;
693
+ }
694
+
695
+ //Stack-based implementation, avoiding recursion for performance improvement
696
+ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
697
+
698
+ const stack_top = stack.pointer;
699
+ let stackPointer = stack_top;
700
+
701
+ stack[stackPointer++] = 0;
702
+ stack[stackPointer++] = particleCount - 1;
703
+
704
+ let i, j;
705
+
706
+ while (stackPointer > stack_top) {
707
+ stackPointer -= 2;
708
+
709
+ const right = stack[stackPointer + 1];
710
+ const left = stack[stackPointer];
711
+
712
+ i = left;
713
+ j = right;
714
+
715
+ const pivot_index = (left + right) >> 1;
716
+
717
+ const pivot = v3_dot_array(position_array, pivot_index * 3, scratch_sort_direction, 0);
718
+
719
+ /* partition */
720
+ while (i <= j) {
721
+
722
+ while (v3_dot_array(position_array, i * 3, scratch_sort_direction, 0) > pivot) {
723
+ i++;
724
+ }
725
+
726
+ while (v3_dot_array(position_array, j * 3, scratch_sort_direction, 0) < pivot) {
727
+ j--;
728
+ }
729
+
730
+ if (i <= j) {
731
+
732
+ if (i !== j) {
733
+ //do swap
734
+ particles.swap(i, j);
735
+ }
736
+
737
+ i++;
738
+ j--;
739
+ }
740
+ }
741
+
742
+ /* recursion */
743
+ if (left < j) {
744
+ stack[stackPointer++] = left;
745
+ stack[stackPointer++] = j;
746
+ }
747
+ if (i < right) {
748
+ stack[stackPointer++] = i;
749
+ stack[stackPointer++] = right;
750
+ }
751
+ }
752
+ }
753
+
754
+ update() {
755
+ this.particles.update();
756
+
757
+ //check if sprites need updating
758
+ if (this.getFlag(ParticleEmitterFlag.SpritesNeedUpdate)) {
759
+ this.#updateSprites();
760
+ }
761
+ }
762
+
763
+ /**
764
+ *
765
+ * @return {number}
766
+ */
767
+ computeSpriteMaxHalfSize() {
768
+ const layers = this.layers;
769
+ const n = layers.length;
770
+
771
+ let result = 0;
772
+
773
+ for (let i = 0; i < n; i++) {
774
+ const particleLayer = layers.get(i);
775
+
776
+ result = max2(result, particleLayer.computeScaledSpriteHalfSize());
777
+ }
778
+
779
+ return result;
780
+ }
781
+
782
+ /**
783
+ *
784
+ * @param {number} timeDelta
785
+ */
786
+ advance(timeDelta) {
787
+ this.emit(timeDelta);
788
+
789
+ this.setFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
790
+ }
791
+
792
+ /**
793
+ * Write sprite UVs
794
+ */
795
+ #updateSprites() {
796
+ const particles = this.particles;
797
+
798
+ const occupancy = particles.occupancy;
799
+
800
+ const layers = this.layers;
801
+
802
+ let missingFlag = false;
803
+
804
+ //cycle through each particle
805
+ for (let i = occupancy.nextSetBit(0); i !== -1; i = occupancy.nextSetBit(i + 1)) {
806
+ const layerIndex = particles.readAttributeScalar(i, PARTICLE_ATTRIBUTE_LAYER_POSITION);
807
+
808
+ const layer = layers.get(layerIndex);
809
+
810
+ const atlasPatch = layer.__atlasPatch;
811
+
812
+ if (atlasPatch !== null) {
813
+
814
+ write_particle_patch_uv(atlasPatch, particles, i);
815
+ } else {
816
+ missingFlag = true;
817
+ }
818
+ }
819
+
820
+ this.writeFlag(ParticleEmitterFlag.SpritesNeedUpdate, missingFlag);
821
+ }
822
+
823
+ /**
824
+ * @private
825
+ * @param {int} layerIndex
826
+ * @param {number} timeDelta period over which particles are being spawned, this will ensure that spawned particles have different initial age
827
+ */
828
+ spawnLayerParticlesContinuous(layerIndex, timeDelta) {
829
+ const layer = this.layers.get(layerIndex);
830
+
831
+ const random = Math.random;
832
+
833
+ /**
834
+ *
835
+ * @type {ParticlePool}
836
+ */
837
+ const particles = this.particles;
838
+
839
+
840
+ const emissionFunction = computeEmissionFunction(layer.emissionFrom, layer.emissionShape);
841
+
842
+ const emissionPeriod = 1 / layer.emissionRate;
843
+
844
+ //compute transform matrix of the emitter
845
+ const emitter_position = this.position;
846
+ const last_spawn_position = this.__lastSpawnPosition;
847
+
848
+ m4_compose(matrix4, emitter_position, this.rotation, this.scale);
849
+
850
+ let time = -layer.timeSinceLastEmission;
851
+
852
+ while (time + emissionPeriod < timeDelta) {
853
+ time += emissionPeriod;
854
+
855
+ const ref = particles.create();
856
+
857
+ // randomize position across the supplied time interval
858
+ const f = time / timeDelta;
859
+
860
+ //compute position for particle
861
+ emissionFunction(random, scratch_v3_array, 0);
862
+
863
+ v3position.fromArray(scratch_v3_array, 0);
864
+
865
+ //apply layer transform
866
+ v3position.multiply(layer.scale);
867
+ v3position.add(layer.position);
868
+
869
+ if (this.getFlag(ParticleEmitterFlag.PositionChanged)) {
870
+ //compute position in between
871
+ matrix4[12] = lerp(emitter_position.x, last_spawn_position.x, f);
872
+ matrix4[13] = lerp(emitter_position.y, last_spawn_position.y, f);
873
+ matrix4[14] = lerp(emitter_position.z, last_spawn_position.z, f);
874
+ }
875
+
876
+ //apply emitter transform
877
+ v3position.applyMatrix4(matrix4);
878
+
879
+
880
+ //randomize initial age across time delta
881
+ const initialAge = f * timeDelta;
882
+
883
+ //write age
884
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_AGE, initialAge);
885
+
886
+ //write rotation
887
+ const rotation = layer.particleRotation.sampleRandom(random);
888
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION, rotation);
889
+
890
+ //write rotation speed
891
+ const rotationSpeed = layer.particleRotationSpeed.sampleRandom(random);
892
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION_SPEED, rotationSpeed);
893
+
894
+ //initialize velocity
895
+ layer.particleVelocityDirection.sampleRandomDirection(random, v3velocity);
896
+ const speed = layer.particleSpeed.sampleRandom(random);
897
+
898
+ v3velocity.multiplyScalar(speed);
899
+
900
+ particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_VELOCITY, v3velocity.x, v3velocity.y, v3velocity.z);
901
+
902
+ //write position
903
+ const p_x = v3position.x + v3velocity.x * initialAge;
904
+ const p_y = v3position.y + v3velocity.y * initialAge;
905
+ const p_z = v3position.z + v3velocity.z * initialAge;
906
+
907
+ particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_POSITION, p_x, p_y, p_z);
908
+
909
+ //write death age
910
+ const deathAge = layer.particleLife.sampleRandom(random);
911
+
912
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_DEATH_AGE, deathAge);
913
+
914
+ //write particle size
915
+ const size = layer.particleSize.sampleRandom(random);
916
+
917
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
918
+
919
+ //write UV
920
+ const atlasPatch = layer.__atlasPatch;
921
+ if (atlasPatch !== null) {
922
+ //patch exists, write it
923
+ write_particle_patch_uv(atlasPatch, particles, ref);
924
+ } else {
925
+ this.setFlag(ParticleEmitterFlag.SpritesNeedUpdate);
926
+ }
927
+
928
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerIndex);
929
+
930
+ update_parameters(ref, particles, layer, initialAge / deathAge);
931
+
932
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_BLEND, this.blendingMode);
933
+ }
934
+
935
+ //update time buffer
936
+ layer.timeSinceLastEmission = timeDelta - time;
937
+
938
+ this.setFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
939
+ }
940
+
941
+ /**
942
+ * @private
943
+ * @param {int} layerIndex
944
+ * @param {number} count how many particles to spawn
945
+ */
946
+ spawnLayerParticlesImmediate(layerIndex, count) {
947
+ if (count <= 0) {
948
+ return;
949
+ }
950
+
951
+ const layers = this.layers;
952
+
953
+ const layer = layers.get(layerIndex);
954
+
955
+ const random = Math.random;
956
+
957
+ /**
958
+ *
959
+ * @type {ParticlePool}
960
+ */
961
+ const particles = this.particles;
962
+
963
+ const emissionFunction = computeEmissionFunction(layer.emissionFrom, layer.emissionShape);
964
+
965
+ //compute transform matrix of the emitter
966
+ m4_compose(matrix4, this.position, this.rotation, this.scale);
967
+
968
+ //pre-grow particle pool
969
+ particles.growCapacity(particles.capacity + count);
970
+
971
+ let spritesNeedUpdate = false;
972
+
973
+ for (let j = 0; j < count; j++) {
974
+ const ref = particles.create();
975
+
976
+ //compute position for particle
977
+ emissionFunction(random, scratch_v3_array, 0);
978
+
979
+ v3position.fromArray(scratch_v3_array, 0);
980
+
981
+ //apply layer transform
982
+ v3position.multiply(layer.scale);
983
+ v3position.add(layer.position);
984
+
985
+ //apply emitter transform
986
+ v3position.applyMatrix4(matrix4);
987
+
988
+
989
+ //randomize initial age across time delta
990
+ const initialAge = 0;
991
+
992
+ //write age
993
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_AGE, initialAge);
994
+
995
+ //write rotation
996
+ const rotation = layer.particleRotation.sampleRandom(random);
997
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION, rotation);
998
+
999
+ //write rotation speed
1000
+ const rotationSpeed = layer.particleRotationSpeed.sampleRandom(random);
1001
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_ROTATION_SPEED, rotationSpeed);
1002
+
1003
+ //initialize velocity
1004
+ layer.particleVelocityDirection.sampleRandomDirection(random, v3velocity);
1005
+ const speed = layer.particleSpeed.sampleRandom(random);
1006
+
1007
+ v3velocity.multiplyScalar(speed);
1008
+
1009
+ particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_VELOCITY, v3velocity.x, v3velocity.y, v3velocity.z);
1010
+
1011
+ //write position
1012
+ const p_x = v3position.x + v3velocity.x * initialAge;
1013
+ const p_y = v3position.y + v3velocity.y * initialAge;
1014
+ const p_z = v3position.z + v3velocity.z * initialAge;
1015
+
1016
+ particles.writeAttributeVector3(ref, PARTICLE_ATTRIBUTE_POSITION,
1017
+ p_x,
1018
+ p_y,
1019
+ p_z
1020
+ );
1021
+
1022
+ //write death age
1023
+ const deathAge = layer.particleLife.sampleRandom(random);
1024
+
1025
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_DEATH_AGE, deathAge);
1026
+
1027
+ //write size
1028
+ const size = layer.particleSize.sampleRandom(random);
1029
+
1030
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
1031
+
1032
+ //write UV
1033
+ const atlasPatch = layer.__atlasPatch;
1034
+
1035
+ if (atlasPatch !== null) {
1036
+ //patch exists, write it
1037
+ write_particle_patch_uv(atlasPatch, particles, ref);
1038
+ } else {
1039
+ //patch is not loaded yet, request update
1040
+ spritesNeedUpdate = true;
1041
+ }
1042
+
1043
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerIndex);
1044
+
1045
+ update_parameters(ref, particles, layer, initialAge / deathAge);
1046
+
1047
+ particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_BLEND, this.blendingMode);
1048
+ }
1049
+
1050
+ if (spritesNeedUpdate) {
1051
+ this.setFlag(ParticleEmitterFlag.SpritesNeedUpdate);
1052
+ }
1053
+
1054
+ this.setFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);
1055
+ }
1056
+
1057
+ /**
1058
+ * @private
1059
+ * @param {number} timeDelta
1060
+ */
1061
+ emit(timeDelta) {
1062
+ if (!this.getFlag(ParticleEmitterFlag.Emitting)) {
1063
+ return;
1064
+ }
1065
+
1066
+ const layers = this.layers;
1067
+ const numLayers = layers.length;
1068
+
1069
+ if (!this.position.equals(this.__lastSpawnPosition)) {
1070
+ this.setFlag(ParticleEmitterFlag.PositionChanged);
1071
+ }
1072
+
1073
+ //emit new particles
1074
+ for (let i = 0; i < numLayers; i++) {
1075
+ /**
1076
+ * @type {ParticleLayer}
1077
+ */
1078
+ const layer = layers.get(i);
1079
+
1080
+ if (!layer.isEmitting) {
1081
+ //this layer is not spawning any particles, ignore it
1082
+ continue;
1083
+ }
1084
+
1085
+ const particleLife = layer.particleLife;
1086
+
1087
+ const averageLifetime = (particleLife.max + particleLife.min) / 2;
1088
+
1089
+ //emitting more than averageLifetime lifetime is unproductive, so we'll crop the emission
1090
+ let emissionDelta;
1091
+ if (timeDelta > averageLifetime) {
1092
+ emissionDelta = averageLifetime;
1093
+ layer.timeSinceLastEmission = 0;
1094
+ } else {
1095
+ emissionDelta = timeDelta;
1096
+ }
1097
+
1098
+ this.spawnLayerParticlesContinuous(i, emissionDelta);
1099
+ }
1100
+
1101
+ if (this.getFlag(ParticleEmitterFlag.PositionChanged)) {
1102
+ this.__lastSpawnPosition.copy(this.position);
1103
+ this.clearFlag(ParticleEmitterFlag.PositionChanged);
1104
+ }
1105
+ }
1106
+
1107
+
1108
+ /**
1109
+ * Cleanup used resources, returning the emitter to its pre-{@link build} state.
1110
+ *
1111
+ * The pool and the parameter tracks are what `build` produces, so dropping them has to drop
1112
+ * the flags that say they exist as well - a disposed emitter that still reads as `Built` gets
1113
+ * written into by whoever picks it up next, and the pool it writes into has no attributes left.
1114
+ * {@link ParticleEmitterSystem3#rebuild} clears the same pair before building again.
1115
+ */
1116
+ dispose() {
1117
+ if (this.particles !== null) {
1118
+ this.particles.dispose();
1119
+ this.particles = null;
1120
+ }
1121
+
1122
+ this.clearFlag(ParticleEmitterFlag.Built | ParticleEmitterFlag.Initialized);
1123
+ }
1124
+
1125
+ /**
1126
+ *
1127
+ * @param json
1128
+ * @returns {ParticleEmitter}
1129
+ */
1130
+ static fromJSON(json) {
1131
+ const result = new ParticleEmitter();
1132
+ result.fromJSON(json);
1133
+ return result
1134
+ }
1135
+ }
1136
+
1137
+ ParticleEmitter.typeName = "ParticleEmitter";
1138
+
1139
+ ParticleEmitter.Attributes = {
1140
+ PARTICLE_ATTRIBUTE_AGE,
1141
+ PARTICLE_ATTRIBUTE_DEATH_AGE,
1142
+ PARTICLE_ATTRIBUTE_LAYER_POSITION,
1143
+ PARTICLE_ATTRIBUTE_POSITION,
1144
+ PARTICLE_ATTRIBUTE_ROTATION,
1145
+ PARTICLE_ATTRIBUTE_ROTATION_SPEED,
1146
+ PARTICLE_ATTRIBUTE_SIZE,
1147
+ PARTICLE_ATTRIBUTE_UV,
1148
+ PARTICLE_ATTRIBUTE_VELOCITY
1149
+ };
1150
+
1151
+ ParticleEmitter.SERIALIZABLE_FLAGS = SERIALIZABLE_FLAGS;
1152
+
1153
+
1154
+ const matrix4 = new Float32Array(16);
1155
+
1156
+ const v3position = new Vector3();
1157
+ const v3velocity = new Vector3();