x_ite 5.0.3 → 6.1.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 (385) hide show
  1. package/.vscode/settings.json +12 -5
  2. package/.vscode/tasks.json +25 -1
  3. package/Makefile +36 -28
  4. package/README.md +6 -11
  5. package/build/bin/dist.pl +0 -6
  6. package/build/bin/examples-and-tests.pl +75 -0
  7. package/build/bin/tests-menu.pl +57 -0
  8. package/build/bin/version.pl +7 -4
  9. package/build/parts/default.start.frag.js +3 -2
  10. package/dist/assets/components/annotation.js +3 -2
  11. package/dist/assets/components/annotation.min.js +1 -1
  12. package/dist/assets/components/cad-geometry.js +3 -2
  13. package/dist/assets/components/cad-geometry.min.js +1 -1
  14. package/dist/assets/components/cube-map-texturing.js +8 -20
  15. package/dist/assets/components/cube-map-texturing.min.js +1 -1
  16. package/dist/assets/components/dis.js +3 -2
  17. package/dist/assets/components/dis.min.js +1 -1
  18. package/dist/assets/components/event-utilities.js +4 -3
  19. package/dist/assets/components/event-utilities.min.js +1 -1
  20. package/dist/assets/components/geometry2d.js +38 -52
  21. package/dist/assets/components/geometry2d.min.js +1 -1
  22. package/dist/assets/components/geospatial.js +34 -1686
  23. package/dist/assets/components/geospatial.min.js +1 -1
  24. package/dist/assets/components/h-anim.js +71 -77
  25. package/dist/assets/components/h-anim.min.js +1 -1
  26. package/dist/assets/components/key-device-sensor.js +4 -3
  27. package/dist/assets/components/key-device-sensor.min.js +1 -1
  28. package/dist/assets/components/layout.js +101 -173
  29. package/dist/assets/components/layout.min.js +1 -1
  30. package/dist/assets/components/nurbs.js +3 -2
  31. package/dist/assets/components/nurbs.min.js +1 -1
  32. package/dist/assets/components/particle-systems.js +1926 -1669
  33. package/dist/assets/components/particle-systems.min.js +1 -1
  34. package/dist/assets/components/picking.js +34 -41
  35. package/dist/assets/components/picking.min.js +1 -1
  36. package/dist/assets/components/projective-texture-mapping.js +73 -86
  37. package/dist/assets/components/projective-texture-mapping.min.js +1 -1
  38. package/dist/assets/components/rigid-body-physics.js +37 -57
  39. package/dist/assets/components/rigid-body-physics.min.js +1 -1
  40. package/dist/assets/components/scripting.js +3 -2
  41. package/dist/assets/components/scripting.min.js +1 -1
  42. package/dist/assets/components/texturing-3d.js +27 -33
  43. package/dist/assets/components/texturing-3d.min.js +3 -3
  44. package/dist/assets/components/volume-rendering.js +12 -11
  45. package/dist/assets/components/volume-rendering.min.js +1 -1
  46. package/dist/assets/components/x_ite.js +3 -2
  47. package/dist/assets/components/x_ite.min.js +1 -1
  48. package/dist/assets/images/Shading.png +0 -0
  49. package/dist/assets/linetype/1.png +0 -0
  50. package/dist/assets/linetype/10.png +0 -0
  51. package/dist/assets/linetype/11.png +0 -0
  52. package/dist/assets/linetype/12.png +0 -0
  53. package/dist/assets/linetype/13.png +0 -0
  54. package/dist/assets/linetype/14.png +0 -0
  55. package/dist/assets/linetype/15.png +0 -0
  56. package/dist/assets/linetype/16.png +0 -0
  57. package/dist/assets/linetype/2.png +0 -0
  58. package/dist/assets/linetype/3.png +0 -0
  59. package/dist/assets/linetype/4.png +0 -0
  60. package/dist/assets/linetype/5.png +0 -0
  61. package/dist/assets/linetype/6.png +0 -0
  62. package/dist/assets/linetype/7.png +0 -0
  63. package/dist/assets/linetype/8.png +0 -0
  64. package/dist/assets/linetype/9.png +0 -0
  65. package/dist/assets/shaders/webgl1/Gouraud.vs +1 -1
  66. package/dist/assets/shaders/webgl1/Line.fs +0 -21
  67. package/dist/assets/shaders/webgl1/Line.vs +0 -10
  68. package/dist/assets/shaders/webgl1/PBR.fs +1 -1
  69. package/dist/assets/shaders/webgl1/PBR.vs +1 -1
  70. package/dist/assets/shaders/webgl1/Phong.fs +1 -1
  71. package/dist/assets/shaders/webgl1/Point.vs +1 -1
  72. package/dist/assets/shaders/webgl2/Depth.vs +29 -1
  73. package/dist/assets/shaders/webgl2/Gouraud.vs +32 -4
  74. package/dist/assets/shaders/webgl2/Line.fs +24 -12
  75. package/dist/assets/shaders/webgl2/Line.vs +36 -11
  76. package/dist/assets/shaders/webgl2/LineTransform.fs +4 -0
  77. package/dist/assets/shaders/webgl2/LineTransform.vs +57 -0
  78. package/dist/assets/shaders/webgl2/PBR.fs +1 -1
  79. package/dist/assets/shaders/webgl2/PBR.vs +35 -7
  80. package/dist/assets/shaders/webgl2/Phong.fs +1 -1
  81. package/dist/assets/shaders/webgl2/Phong.vs +31 -3
  82. package/dist/assets/shaders/webgl2/Point.vs +30 -2
  83. package/dist/assets/shaders/webgl2/Unlit.vs +31 -3
  84. package/dist/example.html +6 -6
  85. package/dist/x_ite.css +199 -224
  86. package/dist/x_ite.js +16335 -15917
  87. package/dist/x_ite.min.js +17 -17
  88. package/dist/x_ite.zip +0 -0
  89. package/docs/404.md +6 -0
  90. package/docs/Accessing-the-External-Browser.md +21 -15
  91. package/docs/Browser-Support.md +6 -0
  92. package/docs/Custom-Shaders.md +18 -25
  93. package/docs/Features.md +11 -5
  94. package/docs/Gemfile +44 -0
  95. package/docs/Gemfile.lock +122 -0
  96. package/docs/Glossary.md +6 -0
  97. package/docs/How-To-Configure-Your-Web-Server.md +6 -0
  98. package/docs/Supported-Nodes.md +9 -1
  99. package/docs/What's-New.md +93 -39
  100. package/docs/XHTML-DOM-Integration.md +6 -0
  101. package/docs/_config.yml +2 -2
  102. package/docs/assets/css/main.scss +26 -0
  103. package/docs/index.md +42 -50
  104. package/docs/reference/Browser-Services.md +9 -3
  105. package/docs/reference/Constants-Services.md +6 -0
  106. package/docs/reference/ECMAScript-Object-and-Function-Definitions.md +12 -6
  107. package/docs/reference/Field-Services-and-Objects.md +105 -1
  108. package/docs/reference/Prototype-Services.md +11 -0
  109. package/docs/reference/Route-Services.md +9 -0
  110. package/docs/reference/Scene-Services.md +17 -2
  111. package/docs/reference/Script-Node-Authoring-Interface.md +7 -1
  112. package/docs/tutorials/Adding-backgrounds.md +6 -0
  113. package/docs/tutorials/Adding-fog.md +6 -0
  114. package/docs/tutorials/Adding-sound.md +6 -0
  115. package/docs/tutorials/Animating-transforms.md +6 -0
  116. package/docs/tutorials/Basic-Nodes.md +6 -0
  117. package/docs/tutorials/Building-a-X3D-world.md +6 -0
  118. package/docs/tutorials/Building-elevation-grids.md +6 -0
  119. package/docs/tutorials/Building-extruded-shapes.md +6 -0
  120. package/docs/tutorials/Building-primitive-shapes.md +6 -0
  121. package/docs/tutorials/Building-shapes-out-of-points,-lines,-and-faces.md +6 -0
  122. package/docs/tutorials/Controlling-appearance-with-materials.md +6 -0
  123. package/docs/tutorials/Controlling-color-on-coordinate-based-geometry.md +6 -0
  124. package/docs/tutorials/Controlling-detail.md +6 -0
  125. package/docs/tutorials/Controlling-how-textures-are-mapped.md +6 -0
  126. package/docs/tutorials/Controlling-navigation.md +6 -0
  127. package/docs/tutorials/Controlling-shading-on-coordinate-based-geometry.md +6 -0
  128. package/docs/tutorials/Controlling-the-viewpoint.md +6 -0
  129. package/docs/tutorials/Creating-new-node-types.md +6 -0
  130. package/docs/tutorials/Grouping-nodes.md +6 -0
  131. package/docs/tutorials/Hello,-World!.md +6 -0
  132. package/docs/tutorials/Improving-Performance.md +6 -0
  133. package/docs/tutorials/Increasing-Rendering-Speed.md +6 -0
  134. package/docs/tutorials/Introducing-X3D.md +6 -0
  135. package/docs/tutorials/Introducing-animation.md +6 -0
  136. package/docs/tutorials/Introducing-script-use.md +6 -0
  137. package/docs/tutorials/Lighting-your-world.md +6 -0
  138. package/docs/tutorials/Mapping-textures.md +6 -0
  139. package/docs/tutorials/Naming-nodes.md +6 -0
  140. package/docs/tutorials/Providing-information-about-your-world.md +6 -0
  141. package/docs/tutorials/Sensing-the-viewer.md +6 -0
  142. package/docs/tutorials/Sensing-viewer-actions.md +6 -0
  143. package/docs/tutorials/Transforming-Shapes.md +6 -0
  144. package/docs/tutorials/Writing-program-scripts-with-ECMAScript.md +6 -0
  145. package/docs/tutorials/index.md +42 -36
  146. package/package.json +6 -7
  147. package/src/assets/components/geometry2d.js +1 -1
  148. package/src/assets/components/key-device-sensor.js +1 -1
  149. package/src/assets/components/layout.js +1 -1
  150. package/src/assets/components/particle-systems.js +1 -1
  151. package/src/assets/components/volume-rendering.js +1 -1
  152. package/src/assets/images/Shading.png +0 -0
  153. package/src/assets/linetype/1.png +0 -0
  154. package/src/assets/linetype/10.png +0 -0
  155. package/src/assets/linetype/11.png +0 -0
  156. package/src/assets/linetype/12.png +0 -0
  157. package/src/assets/linetype/13.png +0 -0
  158. package/src/assets/linetype/14.png +0 -0
  159. package/src/assets/linetype/15.png +0 -0
  160. package/src/assets/linetype/16.png +0 -0
  161. package/src/assets/linetype/2.png +0 -0
  162. package/src/assets/linetype/3.png +0 -0
  163. package/src/assets/linetype/4.png +0 -0
  164. package/src/assets/linetype/5.png +0 -0
  165. package/src/assets/linetype/6.png +0 -0
  166. package/src/assets/linetype/7.png +0 -0
  167. package/src/assets/linetype/8.png +0 -0
  168. package/src/assets/linetype/9.png +0 -0
  169. package/src/assets/shaders/Types.glsl +1 -9
  170. package/src/assets/shaders/webgl1/Gouraud.fs +1 -1
  171. package/src/assets/shaders/webgl1/Gouraud.vs +2 -3
  172. package/src/assets/shaders/webgl1/Line.fs +3 -28
  173. package/src/assets/shaders/webgl1/Line.vs +6 -20
  174. package/src/assets/shaders/webgl1/PBR.fs +6 -6
  175. package/src/assets/shaders/webgl1/PBR.vs +1 -1
  176. package/src/assets/shaders/webgl1/Phong.fs +10 -10
  177. package/src/assets/shaders/webgl1/Point.vs +2 -2
  178. package/src/assets/shaders/webgl1/Unlit.fs +4 -4
  179. package/src/assets/shaders/webgl1/include/Normal.glsl +1 -1
  180. package/src/assets/shaders/webgl1/include/Texture.glsl +3 -8
  181. package/src/assets/shaders/webgl2/Depth.vs +4 -1
  182. package/src/assets/shaders/webgl2/Gouraud.fs +1 -1
  183. package/src/assets/shaders/webgl2/Gouraud.vs +8 -6
  184. package/src/assets/shaders/webgl2/Line.fs +11 -17
  185. package/src/assets/shaders/webgl2/Line.vs +17 -21
  186. package/src/assets/shaders/webgl2/LineTransform.fs +6 -0
  187. package/src/assets/shaders/webgl2/LineTransform.vs +77 -0
  188. package/src/assets/shaders/webgl2/PBR.fs +6 -6
  189. package/src/assets/shaders/webgl2/PBR.vs +10 -7
  190. package/src/assets/shaders/webgl2/Phong.fs +11 -11
  191. package/src/assets/shaders/webgl2/Phong.vs +6 -3
  192. package/src/assets/shaders/webgl2/Point.vs +5 -4
  193. package/src/assets/shaders/webgl2/Unlit.fs +5 -5
  194. package/src/assets/shaders/webgl2/Unlit.vs +6 -3
  195. package/src/assets/shaders/webgl2/include/Line2.glsl +20 -0
  196. package/src/assets/shaders/webgl2/include/Normal.glsl +1 -1
  197. package/src/assets/shaders/webgl2/include/Particle.glsl +36 -0
  198. package/src/assets/shaders/webgl2/include/Texture.glsl +3 -3
  199. package/src/example.html +6 -6
  200. package/src/examples.js +5 -4
  201. package/src/standard/Math/Algorithm.js +12 -28
  202. package/src/standard/Math/Geometry/Line2.js +163 -0
  203. package/src/standard/Math/Geometry/Line3.js +3 -5
  204. package/src/standard/Math/Geometry/Plane3.js +0 -2
  205. package/src/standard/Math/Geometry/Triangle3.js +1 -1
  206. package/src/standard/Math/Geometry/ViewVolume.js +121 -103
  207. package/src/standard/Math/Numbers/Color3.js +6 -0
  208. package/src/standard/Math/Numbers/Color4.js +7 -0
  209. package/src/standard/Math/Numbers/Complex.js +48 -34
  210. package/src/standard/Math/Numbers/Matrix2.js +62 -2
  211. package/src/standard/Math/Numbers/Matrix3.js +129 -110
  212. package/src/standard/Math/Numbers/Matrix4.js +138 -119
  213. package/src/standard/Math/Numbers/Quaternion.js +12 -5
  214. package/src/standard/Math/Numbers/Rotation4.js +8 -1
  215. package/src/standard/Math/Numbers/Vector2.js +42 -9
  216. package/src/standard/Math/Numbers/Vector3.js +50 -14
  217. package/src/standard/Math/Numbers/Vector4.js +48 -11
  218. package/src/standard/Math/Utility/BVH.js +45 -17
  219. package/src/tests.js +68 -66
  220. package/src/x_ite/Base/X3DBaseNode.js +22 -11
  221. package/src/x_ite/Base/X3DField.js +1 -1
  222. package/src/x_ite/Browser/Core/BrowserOptions.js +24 -143
  223. package/src/x_ite/Browser/Core/BrowserTimings.js +6 -4
  224. package/src/x_ite/Browser/Core/Context.js +185 -0
  225. package/src/x_ite/Browser/Core/ContextMenu.js +398 -211
  226. package/src/x_ite/Browser/Core/Notification.js +1 -0
  227. package/src/x_ite/Browser/Core/X3DCoreContext.js +35 -146
  228. package/src/x_ite/Browser/Followers/X3DArrayFollowerTemplate.js +1 -1
  229. package/src/x_ite/Browser/Geometry2D/Disk2DOptions.js +1 -0
  230. package/src/x_ite/Browser/Geometry2D/X3DGeometry2DContext.js +2 -2
  231. package/src/x_ite/Browser/Geometry3D/X3DGeometry3DContext.js +41 -2
  232. package/src/x_ite/Browser/Geospatial/Geocentric.js +2 -2
  233. package/src/x_ite/Browser/Interpolation/CatmullRomSplineInterpolatorTemplate.js +1 -1
  234. package/src/x_ite/Browser/Layout/ScreenText.js +18 -65
  235. package/src/x_ite/Browser/Layout/X3DLayoutContext.js +59 -16
  236. package/src/x_ite/Browser/Navigation/ExamineViewer.js +13 -20
  237. package/src/x_ite/Browser/Navigation/LookAtViewer.js +1 -4
  238. package/src/x_ite/Browser/Navigation/PlaneViewer.js +0 -3
  239. package/src/x_ite/Browser/Navigation/X3DFlyViewer.js +15 -8
  240. package/src/x_ite/Browser/Navigation/X3DViewer.js +12 -20
  241. package/src/x_ite/Browser/Networking/X3DNetworkingContext.js +11 -7
  242. package/src/x_ite/Browser/ParticleSystems/BVH.glsl +183 -0
  243. package/src/x_ite/Browser/ParticleSystems/Box3.glsl +47 -0
  244. package/src/x_ite/Browser/ParticleSystems/GeometryTypes.js +66 -0
  245. package/src/x_ite/Browser/ParticleSystems/Line3.glsl +55 -0
  246. package/src/x_ite/Browser/ParticleSystems/Plane3.glsl +160 -0
  247. package/src/x_ite/Browser/PointingDeviceSensor/PointingDevice.js +27 -3
  248. package/src/x_ite/Browser/PointingDeviceSensor/X3DPointingDeviceSensorContext.js +41 -37
  249. package/src/x_ite/Browser/Rendering/X3DRenderingContext.js +21 -13
  250. package/src/x_ite/Browser/Shaders/Shader.js +33 -12
  251. package/src/x_ite/Browser/Shaders/ShaderSource.js +6 -0
  252. package/src/x_ite/Browser/Shaders/ShaderTest.js +16 -10
  253. package/src/x_ite/Browser/Shape/X3DShapeContext.js +50 -9
  254. package/src/x_ite/Browser/Text/X3DTextContext.js +4 -13
  255. package/src/x_ite/Browser/Text/X3DTextGeometry.js +2 -1
  256. package/src/x_ite/Browser/Texturing/X3DTexturingContext.js +71 -34
  257. package/src/x_ite/Browser/Texturing3D/DICOMParser.js +2 -2
  258. package/src/x_ite/Browser/Time/X3DTimeContext.js +4 -2
  259. package/src/x_ite/Browser/VERSION.js +1 -1
  260. package/src/x_ite/Browser/X3DBrowser.js +7 -6
  261. package/src/x_ite/Browser/X3DBrowserContext.js +43 -10
  262. package/src/x_ite/Components/Core/X3DNode.js +4 -0
  263. package/src/x_ite/Components/Core/X3DPrototypeInstance.js +0 -2
  264. package/src/x_ite/Components/CubeMapTexturing/ComposedCubeMapTexture.js +3 -4
  265. package/src/x_ite/Components/CubeMapTexturing/GeneratedCubeMapTexture.js +1 -12
  266. package/src/x_ite/Components/CubeMapTexturing/ImageCubeMapTexture.js +1 -2
  267. package/src/x_ite/Components/EnvironmentalEffects/TextureBackground.js +1 -1
  268. package/src/x_ite/Components/EnvironmentalEffects/X3DBackgroundNode.js +76 -77
  269. package/src/x_ite/Components/EnvironmentalEffects/X3DFogObject.js +2 -9
  270. package/src/x_ite/Components/EnvironmentalSensor/ProximitySensor.js +51 -65
  271. package/src/x_ite/Components/EventUtilities/X3DSequencerNode.js +1 -1
  272. package/src/x_ite/Components/Followers/ColorDamper.js +1 -1
  273. package/src/x_ite/Components/Followers/X3DChaserNode.js +18 -32
  274. package/src/x_ite/Components/Followers/X3DDamperNode.js +1 -6
  275. package/src/x_ite/Components/Followers/X3DFollowerNode.js +1 -1
  276. package/src/x_ite/Components/Geometry2D/Disk2D.js +30 -46
  277. package/src/x_ite/Components/Geometry2D/TriangleSet2D.js +1 -1
  278. package/src/x_ite/Components/Geometry3D/ElevationGrid.js +12 -4
  279. package/src/x_ite/Components/Geometry3D/IndexedFaceSet.js +4 -4
  280. package/src/x_ite/Components/Geospatial/GeoCoordinate.js +10 -27
  281. package/src/x_ite/Components/Geospatial/GeoLOD.js +1 -1
  282. package/src/x_ite/Components/Geospatial/GeoPositionInterpolator.js +5 -10
  283. package/src/x_ite/Components/Geospatial/GeoTouchSensor.js +9 -16
  284. package/src/x_ite/Components/Geospatial/GeoTransform.js +6 -18
  285. package/src/x_ite/Components/Geospatial/GeoViewpoint.js +26 -30
  286. package/src/x_ite/Components/Geospatial/X3DGeospatialObject.js +20 -27
  287. package/src/x_ite/Components/Grouping/X3DGroupingNode.js +8 -8
  288. package/src/x_ite/Components/Grouping/X3DTransformNode.js +0 -4
  289. package/src/x_ite/Components/HAnim/HAnimHumanoid.js +68 -75
  290. package/src/x_ite/Components/Interpolation/OrientationInterpolator.js +4 -11
  291. package/src/x_ite/Components/Interpolation/X3DInterpolatorNode.js +1 -1
  292. package/src/x_ite/Components/Layout/LayoutGroup.js +4 -9
  293. package/src/x_ite/Components/Layout/ScreenFontStyle.js +1 -1
  294. package/src/x_ite/Components/Layout/ScreenGroup.js +16 -80
  295. package/src/x_ite/Components/Lighting/DirectionalLight.js +28 -36
  296. package/src/x_ite/Components/Lighting/PointLight.js +32 -47
  297. package/src/x_ite/Components/Lighting/SpotLight.js +33 -48
  298. package/src/x_ite/Components/Navigation/Billboard.js +49 -56
  299. package/src/x_ite/Components/Navigation/LOD.js +2 -2
  300. package/src/x_ite/Components/Navigation/OrthoViewpoint.js +29 -30
  301. package/src/x_ite/Components/Navigation/Viewpoint.js +16 -20
  302. package/src/x_ite/Components/Navigation/X3DViewpointNode.js +82 -111
  303. package/src/x_ite/Components/Networking/Anchor.js +18 -7
  304. package/src/x_ite/Components/ParticleSystems/BoundedPhysicsModel.js +6 -6
  305. package/src/x_ite/Components/ParticleSystems/ConeEmitter.js +44 -36
  306. package/src/x_ite/Components/ParticleSystems/ExplosionEmitter.js +26 -17
  307. package/src/x_ite/Components/ParticleSystems/ForcePhysicsModel.js +20 -7
  308. package/src/x_ite/Components/ParticleSystems/ParticleSystem.js +463 -882
  309. package/src/x_ite/Components/ParticleSystems/PointEmitter.js +39 -35
  310. package/src/x_ite/Components/ParticleSystems/PolylineEmitter.js +112 -128
  311. package/src/x_ite/Components/ParticleSystems/SurfaceEmitter.js +105 -112
  312. package/src/x_ite/Components/ParticleSystems/VolumeEmitter.js +138 -176
  313. package/src/x_ite/Components/ParticleSystems/WindPhysicsModel.js +16 -11
  314. package/src/x_ite/Components/ParticleSystems/X3DParticleEmitterNode.js +807 -217
  315. package/src/x_ite/Components/Picking/LinePickSensor.js +31 -39
  316. package/src/x_ite/Components/PointingDeviceSensor/CylinderSensor.js +91 -108
  317. package/src/x_ite/Components/PointingDeviceSensor/PlaneSensor.js +56 -59
  318. package/src/x_ite/Components/PointingDeviceSensor/SphereSensor.js +54 -71
  319. package/src/x_ite/Components/PointingDeviceSensor/TouchSensor.js +8 -15
  320. package/src/x_ite/Components/ProjectiveTextureMapping/TextureProjectorParallel.js +43 -50
  321. package/src/x_ite/Components/ProjectiveTextureMapping/TextureProjectorPerspective.js +32 -39
  322. package/src/x_ite/Components/Rendering/ClipPlane.js +3 -11
  323. package/src/x_ite/Components/Rendering/Color.js +12 -24
  324. package/src/x_ite/Components/Rendering/ColorRGBA.js +13 -25
  325. package/src/x_ite/Components/Rendering/IndexedLineSet.js +26 -4
  326. package/src/x_ite/Components/Rendering/LineSet.js +35 -13
  327. package/src/x_ite/Components/Rendering/PointSet.js +35 -13
  328. package/src/x_ite/Components/Rendering/X3DComposedGeometryNode.js +13 -5
  329. package/src/x_ite/Components/Rendering/X3DGeometryNode.js +331 -387
  330. package/src/x_ite/Components/Rendering/X3DLineGeometryNode.js +350 -140
  331. package/src/x_ite/Components/Rendering/X3DPointGeometryNode.js +116 -126
  332. package/src/x_ite/Components/RigidBodyPhysics/DoubleAxisHingeJoint.js +24 -38
  333. package/src/x_ite/Components/RigidBodyPhysics/SingleAxisHingeJoint.js +10 -17
  334. package/src/x_ite/Components/Shaders/ComposedShader.js +35 -75
  335. package/src/x_ite/Components/Shaders/FloatVertexAttribute.js +8 -11
  336. package/src/x_ite/Components/Shaders/Matrix3VertexAttribute.js +10 -14
  337. package/src/x_ite/Components/Shaders/Matrix4VertexAttribute.js +10 -14
  338. package/src/x_ite/Components/Shaders/ShaderPart.js +1 -10
  339. package/src/x_ite/Components/Shaders/X3DProgrammableShaderObject.js +220 -210
  340. package/src/x_ite/Components/Shaders/X3DShaderNode.js +28 -10
  341. package/src/x_ite/Components/Shaders/X3DVertexAttributeNode.js +15 -1
  342. package/src/x_ite/Components/Shape/Appearance.js +37 -4
  343. package/src/x_ite/Components/Shape/FillProperties.js +12 -1
  344. package/src/x_ite/Components/Shape/LineProperties.js +33 -1
  345. package/src/x_ite/Components/Shape/PointProperties.js +24 -3
  346. package/src/x_ite/Components/Shape/Shape.js +30 -39
  347. package/src/x_ite/Components/Shape/TwoSidedMaterial.js +3 -1
  348. package/src/x_ite/Components/Sound/Sound.js +31 -41
  349. package/src/x_ite/Components/Text/Text.js +6 -20
  350. package/src/x_ite/Components/Texturing/ImageTexture.js +1 -1
  351. package/src/x_ite/Components/Texturing/MovieTexture.js +1 -1
  352. package/src/x_ite/Components/Texturing/PixelTexture.js +2 -2
  353. package/src/x_ite/Components/Texturing/TextureCoordinate.js +5 -5
  354. package/src/x_ite/Components/Texturing/TextureProperties.js +4 -4
  355. package/src/x_ite/Components/Texturing/X3DSingleTextureNode.js +5 -4
  356. package/src/x_ite/Components/Texturing/X3DTexture2DNode.js +24 -33
  357. package/src/x_ite/Components/Texturing3D/TextureCoordinate3D.js +5 -5
  358. package/src/x_ite/Components/Texturing3D/TextureCoordinate4D.js +5 -5
  359. package/src/x_ite/Components/Texturing3D/X3DTexture3DNode.js +12 -19
  360. package/src/x_ite/Components/VolumeRendering/X3DVolumeDataNode.js +8 -8
  361. package/src/x_ite/Components.js +2 -2
  362. package/src/x_ite/Fallback.js +9 -3
  363. package/src/x_ite/Fields/SFColor.js +4 -0
  364. package/src/x_ite/Fields/SFColorRGBA.js +4 -0
  365. package/src/x_ite/Fields/SFImage.js +2 -11
  366. package/src/x_ite/Fields/SFMatrixPrototypeTemplate.js +4 -0
  367. package/src/x_ite/Fields/SFRotation.js +4 -0
  368. package/src/x_ite/Fields/SFString.js +4 -0
  369. package/src/x_ite/Fields/SFVecPrototypeTemplate.js +22 -2
  370. package/src/x_ite/Parser/XMLParser.js +1 -1
  371. package/src/x_ite/Rendering/TextureBuffer.js +43 -36
  372. package/src/x_ite/Rendering/VertexArray.js +103 -0
  373. package/src/x_ite/Rendering/X3DRenderObject.js +127 -148
  374. package/src/x_ite/X3D.js +32 -26
  375. package/src/x_ite.config.js +0 -5
  376. package/src/x_ite.css +216 -175
  377. package/src/x_ite.html +15 -10
  378. package/src/x_ite.js +49 -1
  379. package/x_ite.min.html +15 -10
  380. package/dist/assets/hatching/0.png +0 -0
  381. package/dist/assets/linetype/0.png +0 -0
  382. package/src/assets/hatching/0.png +0 -0
  383. package/src/assets/linetype/0.png +0 -0
  384. package/src/spinner.css +0 -67
  385. package/src/x_ite/Browser/Shape/LineStipples.xcf +0 -0
@@ -4,8 +4,88 @@
4
4
  var module = { }, exports, process;
5
5
 
6
6
  const
7
- define = window [Symbol .for ("X_ITE.X3D-5.0.3")] .define,
8
- require = window [Symbol .for ("X_ITE.X3D-5.0.3")] .require;
7
+ X3D = window [Symbol .for ("X_ITE.X3D-6.1.0")],
8
+ define = X3D .define,
9
+ require = X3D .require;
10
+ /* -*- Mode: JavaScript; coding: utf-8; tab-width: 3; indent-tabs-mode: tab; c-basic-offset: 3 -*-
11
+ *******************************************************************************
12
+ *
13
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
14
+ *
15
+ * Copyright create3000, Scheffelstraße 31a, Leipzig, Germany 2011.
16
+ *
17
+ * All rights reserved. Holger Seelig <holger.seelig@yahoo.de>.
18
+ *
19
+ * The copyright notice above does not evidence any actual of intended
20
+ * publication of such source code, and is an unpublished work by create3000.
21
+ * This material contains CONFIDENTIAL INFORMATION that is the property of
22
+ * create3000.
23
+ *
24
+ * No permission is granted to copy, distribute, or create derivative works from
25
+ * the contents of this software, in whole or in part, without the prior written
26
+ * permission of create3000.
27
+ *
28
+ * NON-MILITARY USE ONLY
29
+ *
30
+ * All create3000 software are effectively free software with a non-military use
31
+ * restriction. It is free. Well commented source is provided. You may reuse the
32
+ * source in any way you please with the exception anything that uses it must be
33
+ * marked to indicate is contains 'non-military use only' components.
34
+ *
35
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
36
+ *
37
+ * Copyright 2015, 2016 Holger Seelig <holger.seelig@yahoo.de>.
38
+ *
39
+ * This file is part of the X_ITE Project.
40
+ *
41
+ * X_ITE is free software: you can redistribute it and/or modify it under the
42
+ * terms of the GNU General Public License version 3 only, as published by the
43
+ * Free Software Foundation.
44
+ *
45
+ * X_ITE is distributed in the hope that it will be useful, but WITHOUT ANY
46
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
47
+ * A PARTICULAR PURPOSE. See the GNU General Public License version 3 for more
48
+ * details (a copy is included in the LICENSE file that accompanied this code).
49
+ *
50
+ * You should have received a copy of the GNU General Public License version 3
51
+ * along with X_ITE. If not, see <http://www.gnu.org/licenses/gpl.html> for a
52
+ * copy of the GPLv3 License.
53
+ *
54
+ * For Silvio, Joy and Adi.
55
+ *
56
+ ******************************************************************************/
57
+
58
+
59
+ define ('x_ite/Browser/ParticleSystems/GeometryTypes',[],function ()
60
+ {
61
+ "use strict";
62
+
63
+ let i = 0;
64
+
65
+ const GeometryTypes = {
66
+ POINT: i ++,
67
+ LINE: i ++,
68
+ TRIANGLE: i ++,
69
+ QUAD: i ++,
70
+ SPRITE: i ++,
71
+ GEOMETRY: i ++,
72
+ };
73
+
74
+ return GeometryTypes;
75
+ });
76
+
77
+
78
+ define('text!x_ite/Browser/ParticleSystems/Line3.glsl',[],function () { return 'struct Line3 {\n vec3 point;\n vec3 direction;\n};\n\n// Line3\n// line3 (const in vec3 point1, const in vec3 point2)\n// {\n// return Line3 (point1, normalize (point2 - point1));\n// }\n\n/* Line intersect triangle */\n\nbool\nintersects (const in Line3 line, const in vec3 a, const in vec3 b, const in vec3 c, out vec3 r)\n{\n // find vectors for two edges sharing vert0\n vec3 edge1 = b - a;\n vec3 edge2 = c - a;\n\n // begin calculating determinant - also used to calculate U parameter\n vec3 pvec = cross (line .direction, edge2);\n\n // if determinant is near zero, ray lies in plane of triangle\n float det = dot (edge1, pvec);\n\n // Non culling intersection\n\n if (det == 0.0)\n return false;\n\n float inv_det = 1.0 / det;\n\n // calculate distance from vert0 to ray point\n vec3 tvec = line .point - a;\n\n // calculate U parameter and test bounds\n float u = dot (tvec, pvec) * inv_det;\n\n if (u < 0.0 || u > 1.0)\n return false;\n\n // prepare to test V parameter\n vec3 qvec = cross (tvec, edge1);\n\n // calculate V parameter and test bounds\n float v = dot (line .direction, qvec) * inv_det;\n\n if (v < 0.0 || u + v > 1.0)\n return false;\n\n r = vec3 (u, v, 1.0 - u - v);\n\n return true;\n}\n';});
79
+
80
+
81
+ define('text!x_ite/Browser/ParticleSystems/Plane3.glsl',[],function () { return 'struct Plane3\n{\n vec3 normal;\n float distanceFromOrigin;\n};\n\nPlane3\nplane3 (const in vec3 point, const in vec3 normal)\n{\n return Plane3 (normal, dot (normal, point));\n}\n\nfloat\nplane_distance (const in Plane3 plane, const in vec3 point)\n{\n return dot (point, plane .normal) - plane .distanceFromOrigin;\n}\n\n/* Plane intersect line */\nbool\nintersects (const in Plane3 plane, const in Line3 line, out vec3 point)\n{\n // Check if the line is parallel to the plane.\n float theta = dot (line .direction, plane .normal);\n\n // Plane and line are parallel.\n if (theta == 0.0)\n return false;\n\n // Plane and line are not parallel. The intersection point can be calculated now.\n float t = (plane .distanceFromOrigin - dot (plane .normal, line .point)) / theta;\n\n point = line .point + line .direction * t;\n\n return true;\n}\n\n/* Find find the first point that is farther to the plane than value. */\n// int\n// upper_bound (const in vec4 points [ARRAY_SIZE], in int count, const in float value, const in Plane3 plane)\n// {\n// int first = 0;\n// int step = 0;\n\n// while (count > 0)\n// {\n// int index = first;\n\n// step = count >> 1;\n\n// index += step;\n\n// if (value < plane_distance (plane, points [index] .xyz))\n// {\n// count = step;\n// }\n// else\n// {\n// first = ++ index;\n// count -= step + 1;\n// }\n// }\n\n// return first;\n// }\n\n/* CombSort: sort points in distance to a plane. */\nvoid\nsort (inout vec4 points [ARRAY_SIZE], const in int count, const in Plane3 plane)\n{\n const float shrink = 1.0 / 1.3;\n\n int gap = count;\n bool exchanged = true;\n\n while (exchanged)\n {\n gap = int (float (gap) * shrink);\n\n if (gap <= 1)\n {\n exchanged = false;\n gap = 1;\n }\n\n for (int i = 0, l = count - gap; i < l; ++ i)\n {\n int j = gap + i;\n\n if (plane_distance (plane, points [i] .xyz) > plane_distance (plane, points [j] .xyz))\n {\n vec4 tmp1 = points [i];\n points [i] = points [j];\n points [j] = tmp1;\n\n exchanged = true;\n }\n }\n }\n}\n\n\n// /* CombSort: sort points and normals in distance to a plane. */\n// void\n// sort (inout vec4 points [ARRAY_SIZE], inout vec3 normals [ARRAY_SIZE], const in int count, const in Plane3 plane)\n// {\n// const float shrink = 1.0 / 1.3;\n\n// int gap = count;\n// bool exchanged = true;\n\n// while (exchanged)\n// {\n// gap = int (float (gap) * shrink);\n\n// if (gap <= 1)\n// {\n// exchanged = false;\n// gap = 1;\n// }\n\n// for (int i = 0, l = count - gap; i < l; ++ i)\n// {\n// int j = gap + i;\n\n// if (plane_distance (plane, points [i] .xyz) > plane_distance (plane, points [j] .xyz))\n// {\n// vec4 tmp1 = points [i];\n// points [i] = points [j];\n// points [j] = tmp1;\n\n// vec3 tmp2 = normals [i];\n// normals [i] = normals [j];\n// normals [j] = tmp2;\n\n// exchanged = true;\n// }\n// }\n// }\n// }\n\nint\nmin_index (const in vec4 points [ARRAY_SIZE], const in int count, const in float value, const in Plane3 plane)\n{\n int index = -1;\n float dist = 1000000.0;\n\n for (int i = 0; i < count; ++ i)\n {\n float d = plane_distance (plane, points [i] .xyz);\n\n if (d >= value && d < dist)\n {\n dist = d;\n index = i;\n }\n }\n\n return index;\n}\n';});
82
+
83
+
84
+ define('text!x_ite/Browser/ParticleSystems/Box3.glsl',[],function () { return 'bool\nintersects (const in vec3 min, const in vec3 max, const in Line3 line)\n{\n vec3 intersection;\n\n // front\n\n if (intersects (plane3 (max, vec3 (0.0, 0.0, 1.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xy, max .xy), vec4 (min .xy, intersection .xy))))\n return true;\n }\n\n // back\n\n if (intersects (plane3 (min, vec3 (0.0, 0.0, -1.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xy, max .xy), vec4 (min .xy, intersection .xy))))\n return true;\n }\n\n // top\n\n if (intersects (plane3 (max, vec3 (0.0, 1.0, 0.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xz, max .xz), vec4 (min .xz, intersection .xz))))\n return true;\n }\n\n // bottom\n\n if (intersects (plane3 (min, vec3 (0.0, -1.0, 0.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .xz, max .xz), vec4 (min .xz, intersection .xz))))\n return true;\n }\n\n // right\n\n if (intersects (plane3 (max, vec3 (1.0, 0.0, 0.0)), line, intersection))\n {\n if (all (greaterThanEqual (vec4 (intersection .yz, max .yz), vec4 (min .yz, intersection .yz))))\n return true;\n }\n\n return false;\n}\n';});
85
+
86
+
87
+ define('text!x_ite/Browser/ParticleSystems/BVH.glsl',[],function () { return '#define BVH_NODE 0\n#define BVH_TRIANGLE 1\n#define BVH_STACK_SIZE 32\n\nint bvhNodeIndex = 0;\n\nvoid\nsetBVHIndex (const in int index)\n{\n bvhNodeIndex = index;\n}\n\nint\ngetBVHRoot (const in sampler2D volume, const in int hierarchyIndex, const in int rootIndex)\n{\n return int (texelFetch (volume, rootIndex, 0) .x) + hierarchyIndex;\n}\n\nint\ngetBVHType (const in sampler2D volume)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .x);\n}\n\nvec3\ngetBVHMin (const in sampler2D volume)\n{\n return texelFetch (volume, bvhNodeIndex + 1, 0) .xyz;\n}\n\nvec3\ngetBVHMax (const in sampler2D volume)\n{\n return texelFetch (volume, bvhNodeIndex + 2, 0) .xyz;\n}\n\nint\ngetBVHLeft (const in sampler2D volume, const in int hierarchyIndex)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .y) + hierarchyIndex;\n}\n\nint\ngetBVHRight (const in sampler2D volume, const in int hierarchyIndex)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .z) + hierarchyIndex;\n}\n\nint\ngetBVHTriangle (const in sampler2D volume)\n{\n return int (texelFetch (volume, bvhNodeIndex, 0) .y);\n}\n\n/* Ray triangle intersection test */\n\nint\ngetIntersections (const in sampler2D volume, const in int verticesIndex, const in int hierarchyIndex, const in int rootIndex, const in Line3 line, out vec4 points [ARRAY_SIZE])\n{\n int current = getBVHRoot (volume, hierarchyIndex, rootIndex);\n int count = 0;\n int stackIndex = -1;\n int stack [BVH_STACK_SIZE];\n\n while (stackIndex >= 0 || current >= 0)\n {\n if (current >= 0)\n {\n setBVHIndex (current);\n\n if (getBVHType (volume) == BVH_NODE)\n {\n // Node\n\n if (intersects (getBVHMin (volume), getBVHMax (volume), line))\n {\n stack [++ stackIndex] = current;\n\n current = getBVHLeft (volume, hierarchyIndex);\n }\n else\n {\n current = -1;\n }\n }\n else\n {\n // Triangle\n\n int t = getBVHTriangle (volume);\n int v = verticesIndex + t;\n vec3 r = vec3 (0.0);\n\n vec3 a = texelFetch (volume, v, 0) .xyz;\n vec3 b = texelFetch (volume, v + 1, 0) .xyz;\n vec3 c = texelFetch (volume, v + 2, 0) .xyz;\n\n if (intersects (line, a, b, c, r))\n points [count ++] = vec4 (r .z * a + r .x * b + r .y * c, 1.0);\n\n current = -1;\n }\n }\n else\n {\n setBVHIndex (stack [stackIndex --]);\n\n current = getBVHRight (volume, hierarchyIndex);\n }\n }\n\n return count;\n}\n\nint\ngetIntersections (const in sampler2D volume, const in int verticesIndex, const in int normalsIndex, const in int hierarchyIndex, const in int rootIndex, const in Line3 line, out vec4 points [ARRAY_SIZE], out vec3 normals [ARRAY_SIZE])\n{\n int current = getBVHRoot (volume, hierarchyIndex, rootIndex);\n int count = 0;\n int stackIndex = -1;\n int stack [BVH_STACK_SIZE];\n\n while (stackIndex >= 0 || current >= 0)\n {\n if (current >= 0)\n {\n setBVHIndex (current);\n\n if (getBVHType (volume) == BVH_NODE)\n {\n // Node\n\n if (intersects (getBVHMin (volume), getBVHMax (volume), line))\n {\n stack [++ stackIndex] = current;\n\n current = getBVHLeft (volume, hierarchyIndex);\n }\n else\n {\n current = -1;\n }\n }\n else\n {\n // Triangle\n\n int t = getBVHTriangle (volume);\n int v = verticesIndex + t;\n vec3 r = vec3 (0.0);\n\n vec3 a = texelFetch (volume, v, 0) .xyz;\n vec3 b = texelFetch (volume, v + 1, 0) .xyz;\n vec3 c = texelFetch (volume, v + 2, 0) .xyz;\n\n if (intersects (line, a, b, c, r))\n {\n points [count] = vec4 (r .z * a + r .x * b + r .y * c, 1.0);\n\n int n = normalsIndex + t;\n\n vec3 n0 = texelFetch (volume, n, 0) .xyz;\n vec3 n1 = texelFetch (volume, n + 1, 0) .xyz;\n vec3 n2 = texelFetch (volume, n + 2, 0) .xyz;\n\n normals [count] = save_normalize (r .z * n0 + r .x * n1 + r .y * n2);\n\n ++ count;\n }\n\n current = -1;\n }\n }\n else\n {\n setBVHIndex (stack [stackIndex --]);\n\n current = getBVHRight (volume, hierarchyIndex);\n }\n }\n\n return count;\n}\n';});
88
+
9
89
  /* -*- Mode: JavaScript; coding: utf-8; tab-width: 3; indent-tabs-mode: tab; c-basic-offset: 3 -*-
10
90
  *******************************************************************************
11
91
  *
@@ -57,41 +137,23 @@ const
57
137
 
58
138
  define ('x_ite/Components/ParticleSystems/X3DParticleEmitterNode',[
59
139
  "x_ite/Components/Core/X3DNode",
140
+ "x_ite/Browser/ParticleSystems/GeometryTypes",
60
141
  "x_ite/Base/X3DConstants",
61
- "standard/Math/Numbers/Vector3",
62
- "standard/Math/Numbers/Rotation4",
63
- "standard/Math/Geometry/Line3",
64
- "standard/Math/Geometry/Plane3",
65
- "standard/Math/Algorithm",
66
- "standard/Math/Algorithms/QuickSort",
142
+ "text!x_ite/Browser/ParticleSystems/Line3.glsl",
143
+ "text!x_ite/Browser/ParticleSystems/Plane3.glsl",
144
+ "text!x_ite/Browser/ParticleSystems/Box3.glsl",
145
+ "text!x_ite/Browser/ParticleSystems/BVH.glsl",
67
146
  ],
68
147
  function (X3DNode,
148
+ GeometryTypes,
69
149
  X3DConstants,
70
- Vector3,
71
- Rotation4,
72
- Line3,
73
- Plane3,
74
- Algorithm,
75
- QuickSort)
150
+ Line3Source,
151
+ Plane3Source,
152
+ Box3Source,
153
+ BVHSource)
76
154
  {
77
155
  "use strict";
78
156
 
79
- var
80
- normal = new Vector3 (0, 0, 0),
81
- fromPosition = new Vector3 (0, 0, 0),
82
- line = new Line3 (Vector3 .Zero, Vector3 .zAxis),
83
- plane = new Plane3 (Vector3 .Zero, Vector3 .zAxis);
84
-
85
- function PlaneCompare (a, b)
86
- {
87
- return plane .getDistanceToPoint (a) < plane .getDistanceToPoint (b);
88
- }
89
-
90
- function PlaneCompareValue (a, b)
91
- {
92
- return a < plane .getDistanceToPoint (b);
93
- }
94
-
95
157
  function X3DParticleEmitterNode (executionContext)
96
158
  {
97
159
  X3DNode .call (this, executionContext);
@@ -102,10 +164,23 @@ function (X3DNode,
102
164
  this ._mass .setUnit ("mass");
103
165
  this ._surfaceArea .setUnit ("area");
104
166
 
105
- this .rotations = [ ];
106
- this .intersections = [ ];
107
- this .intersectionNormals = [ ];
108
- this .sorter = new QuickSort (this .intersections, PlaneCompare);
167
+ this .samplers = [ ];
168
+ this .uniforms = { };
169
+ this .functions = [ ];
170
+ this .program = null;
171
+
172
+ this .addSampler ("forces");
173
+ this .addSampler ("boundedVolume");
174
+ this .addSampler ("colorRamp");
175
+ this .addSampler ("texCoordRamp");
176
+
177
+ this .addUniform ("speed", "uniform float speed;");
178
+ this .addUniform ("variation", "uniform float variation;");
179
+
180
+ this .addFunction (Line3Source);
181
+ this .addFunction (Plane3Source);
182
+ this .addFunction (Box3Source);
183
+ this .addFunction (BVHSource);
109
184
  }
110
185
 
111
186
  X3DParticleEmitterNode .prototype = Object .assign (Object .create (X3DNode .prototype),
@@ -115,26 +190,28 @@ function (X3DNode,
115
190
  {
116
191
  X3DNode .prototype .initialize .call (this);
117
192
 
118
- this ._speed .addInterest ("set_speed__", this);
193
+ const gl = this .getBrowser () .getContext ();
194
+
195
+ if (gl .getVersion () < 2)
196
+ return;
197
+
198
+ // Create program.
199
+
200
+ this .program = this .createProgram ();
201
+ this .transformFeedback = gl .createTransformFeedback ();
202
+
203
+ // Initialize fields.
204
+
205
+ this ._on .addInterest ("set_on__", this);
206
+ this ._speed .addInterest ("set_speed__", this);
119
207
  this ._variation .addInterest ("set_variation__", this);
120
- this ._mass .addInterest ("set_mass__", this);
208
+ this ._mass .addInterest ("set_mass__", this);
121
209
 
210
+ this .set_on__ ();
122
211
  this .set_speed__ ();
123
212
  this .set_variation__ ();
124
213
  this .set_mass__ ();
125
214
  },
126
- set_speed__: function ()
127
- {
128
- this .speed = this ._speed .getValue ();
129
- },
130
- set_variation__: function ()
131
- {
132
- this .variation = this ._variation .getValue ();
133
- },
134
- set_mass__: function ()
135
- {
136
- this .mass = this ._mass .getValue ();
137
- },
138
215
  isExplosive: function ()
139
216
  {
140
217
  return false;
@@ -143,28 +220,21 @@ function (X3DNode,
143
220
  {
144
221
  return this .mass;
145
222
  },
146
- getRandomLifetime: function (particleLifetime, lifetimeVariation)
223
+ set_on__: function ()
147
224
  {
148
- var
149
- v = particleLifetime * lifetimeVariation,
150
- min = Math .max (0, particleLifetime - v),
151
- max = particleLifetime + v;
152
-
153
- return Math .random () * (max - min) + min;
225
+ this .on = this ._on .getValue ();
154
226
  },
155
- getRandomSpeed: function ()
227
+ set_speed__: function ()
156
228
  {
157
- var
158
- speed = this .speed,
159
- v = speed * this .variation,
160
- min = Math .max (0, speed - v),
161
- max = speed + v;
162
-
163
- return Math .random () * (max - min) + min;
229
+ this .setUniform ("uniform1f", "speed", this ._speed .getValue ());
230
+ },
231
+ set_variation__: function ()
232
+ {
233
+ this .setUniform ("uniform1f", "variation", this ._variation .getValue ());
164
234
  },
165
- getSphericalRandomVelocity: function (velocity)
235
+ set_mass__: function ()
166
236
  {
167
- return this .getRandomNormal (velocity) .multiply (this .getRandomSpeed ());
237
+ this .mass = this ._mass .getValue ();
168
238
  },
169
239
  getRandomValue: function (min, max)
170
240
  {
@@ -172,244 +242,844 @@ function (X3DNode,
172
242
  },
173
243
  getRandomNormal: function (normal)
174
244
  {
175
- var
245
+ const
176
246
  theta = this .getRandomValue (-1, 1) * Math .PI,
177
247
  cphi = this .getRandomValue (-1, 1),
178
248
  phi = Math .acos (cphi),
179
249
  r = Math .sin (phi);
180
250
 
181
- return normal .set (Math .sin (theta) * r,
182
- Math .cos (theta) * r,
183
- cphi);
184
- },
185
- getRandomNormalWithAngle: function (angle, normal)
186
- {
187
- var
188
- theta = (Math .random () * 2 - 1) * Math .PI,
189
- cphi = this .getRandomValue (Math .cos (angle), 1),
190
- phi = Math .acos (cphi),
191
- r = Math .sin (phi);
251
+ return normal .set (Math .sin (theta) * r,
252
+ Math .cos (theta) * r,
253
+ cphi);
254
+ },
255
+ animate: function (particleSystem, deltaTime)
256
+ {
257
+ const
258
+ browser = this .getBrowser (),
259
+ gl = browser .getContext (),
260
+ inputParticles = particleSystem .inputParticles,
261
+ particleStride = particleSystem .particleStride,
262
+ particleOffsets = particleSystem .particleOffsets,
263
+ program = this .program;
264
+
265
+ // Start
266
+
267
+ gl .useProgram (program);
268
+
269
+ // Uniforms
270
+
271
+ gl .uniform1i (program .randomSeed, Math .random () * 0xffffffff);
272
+ gl .uniform1i (program .geometryType, particleSystem .geometryType);
273
+ gl .uniform1i (program .createParticles, particleSystem .createParticles && this .on);
274
+ gl .uniform1f (program .particleLifetime, particleSystem .particleLifetime);
275
+ gl .uniform1f (program .lifetimeVariation, particleSystem .lifetimeVariation);
276
+ gl .uniform1f (program .deltaTime, deltaTime);
277
+ gl .uniform2f (program .particleSize, particleSystem ._particleSize .x, particleSystem ._particleSize .y);
278
+
279
+ // Forces
280
+
281
+ gl .uniform1i (program .numForces, particleSystem .numForces);
282
+
283
+ if (particleSystem .numForces)
284
+ {
285
+ gl .activeTexture (gl .TEXTURE0 + program .forcesTextureUnit);
286
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .forcesTexture);
287
+ }
288
+
289
+ // Bounded Physics
290
+
291
+ if (particleSystem .boundedHierarchyRoot < 0)
292
+ {
293
+ gl .uniform1i (program .boundedHierarchyRoot, -1);
294
+ }
295
+ else
296
+ {
297
+ gl .uniform1i (program .boundedVerticesIndex, particleSystem .boundedVerticesIndex);
298
+ gl .uniform1i (program .boundedNormalsIndex, particleSystem .boundedNormalsIndex);
299
+ gl .uniform1i (program .boundedHierarchyIndex, particleSystem .boundedHierarchyIndex);
300
+ gl .uniform1i (program .boundedHierarchyRoot, particleSystem .boundedHierarchyRoot);
301
+
302
+ gl .activeTexture (gl .TEXTURE0 + program .boundedVolumeTextureUnit);
303
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .boundedTexture);
304
+ }
305
+
306
+ // Colors
307
+
308
+ gl .uniform1i (program .numColors, particleSystem .numColors);
309
+
310
+ if (particleSystem .numColors)
311
+ {
312
+ gl .activeTexture (gl .TEXTURE0 + program .colorRampTextureUnit);
313
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .colorRampTexture);
314
+ }
315
+
316
+ // TexCoords
317
+
318
+ gl .uniform1i (program .numTexCoords, particleSystem .numTexCoords);
319
+
320
+ if (particleSystem .numTexCoords)
321
+ {
322
+ gl .uniform1i (program .texCoordCount, particleSystem .texCoordCount);
323
+
324
+ gl .activeTexture (gl .TEXTURE0 + program .texCoordRampTextureUnit);
325
+ gl .bindTexture (gl .TEXTURE_2D, particleSystem .texCoordRampTexture);
326
+ }
327
+
328
+ // Other textures
329
+
330
+ this .activateTextures (gl, program);
331
+
332
+ // Input attributes
333
+
334
+ if (inputParticles .emitterArrayObject .enable (gl, program))
335
+ {
336
+ for (const [i, attribute] of program .inputs)
337
+ {
338
+ gl .bindBuffer (gl .ARRAY_BUFFER, inputParticles);
339
+ gl .enableVertexAttribArray (attribute);
340
+ gl .vertexAttribPointer (attribute, 4, gl .FLOAT, false, particleStride, particleOffsets [i]);
341
+ }
342
+
343
+ gl .bindBuffer (gl .ARRAY_BUFFER, null);
344
+ }
345
+
346
+ // Transform particles.
347
+
348
+ gl .bindTransformFeedback (gl .TRANSFORM_FEEDBACK, this .transformFeedback);
349
+ gl .bindBufferBase (gl .TRANSFORM_FEEDBACK_BUFFER, 0, particleSystem .outputParticles);
350
+ gl .enable (gl .RASTERIZER_DISCARD);
351
+ gl .beginTransformFeedback (gl .POINTS);
352
+ gl .drawArrays (gl .POINTS, 0, particleSystem .numParticles);
353
+ gl .endTransformFeedback ();
354
+ gl .disable (gl .RASTERIZER_DISCARD);
355
+ gl .bindTransformFeedback (gl .TRANSFORM_FEEDBACK, null);
356
+
357
+ // DEBUG
358
+
359
+ // const data = new Float32Array (particleSystem .numParticles * (particleStride / 4));
360
+ // gl .bindBuffer (gl .ARRAY_BUFFER, particleSystem .outputParticles);
361
+ // gl .getBufferSubData (gl .ARRAY_BUFFER, 0, data);
362
+ // console .log (data .slice (0, particleStride / 4));
363
+ },
364
+ addSampler: function (name)
365
+ {
366
+ this .samplers .push (name);
367
+ },
368
+ addUniform: function (name, uniform)
369
+ {
370
+ this .uniforms [name] = uniform;
371
+ },
372
+ setUniform: function (func, name, value1, value2, value3)
373
+ {
374
+ const
375
+ gl = this .getBrowser () .getContext (),
376
+ program = this .program;
377
+
378
+ gl .useProgram (program);
379
+ gl [func] (program [name], value1, value2, value3);
380
+ },
381
+ addFunction: function (func)
382
+ {
383
+ this .functions .push (func);
384
+ },
385
+ createProgram: function ()
386
+ {
387
+ const
388
+ browser = this .getBrowser (),
389
+ gl = browser .getContext ();
390
+
391
+ const vertexShaderSource = /* glsl */ `#version 300 es
392
+
393
+ precision highp float;
394
+ precision highp int;
395
+ precision highp sampler2D;
396
+
397
+ uniform int randomSeed;
398
+ uniform int geometryType;
399
+ uniform bool createParticles;
400
+ uniform float particleLifetime;
401
+ uniform float lifetimeVariation;
402
+ uniform float deltaTime;
403
+ uniform vec2 particleSize;
404
+
405
+ uniform int numForces;
406
+ uniform sampler2D forces;
407
+
408
+ uniform int boundedVerticesIndex;
409
+ uniform int boundedNormalsIndex;
410
+ uniform int boundedHierarchyIndex;
411
+ uniform int boundedHierarchyRoot;
412
+ uniform sampler2D boundedVolume;
413
+
414
+ uniform int numColors;
415
+ uniform sampler2D colorRamp;
416
+
417
+ uniform int texCoordCount;
418
+ uniform int numTexCoords;
419
+ uniform sampler2D texCoordRamp;
420
+
421
+ ${Object .values (this .uniforms) .join ("\n")}
422
+
423
+ in vec4 input0;
424
+ in vec4 input2;
425
+ in vec4 input6;
426
+
427
+ out vec4 output0;
428
+ out vec4 output1;
429
+ out vec4 output2;
430
+
431
+ out vec4 output3;
432
+ out vec4 output4;
433
+ out vec4 output5;
434
+ out vec4 output6;
435
+
436
+ // Constants
437
+
438
+ ${Object .entries (GeometryTypes) .map (([k, v]) => `#define ${k} ${v}`) .join ("\n")}
439
+
440
+ const int ARRAY_SIZE = 32;
441
+ const float M_PI = 3.14159265359;
442
+
443
+ uniform float NaN;
444
+
445
+ // Texture
446
+
447
+ vec4
448
+ texelFetch (const in sampler2D sampler, const in int index, const in int lod)
449
+ {
450
+ int x = textureSize (sampler, lod) .x;
451
+ ivec2 p = ivec2 (index % x, index / x);
452
+ vec4 t = texelFetch (sampler, p, lod);
453
+
454
+ return t;
455
+ }
456
+
457
+ // Math
458
+
459
+ // Save normalize, that will not divide by zero.
460
+ vec3
461
+ save_normalize (const in vec3 vector)
462
+ {
463
+ float l = length (vector);
464
+
465
+ if (l == 0.0)
466
+ return vec3 (0.0);
467
+
468
+ return vector / l;
469
+ }
470
+
471
+ // Quaternion
472
+
473
+ vec4
474
+ Quaternion (const in vec3 fromVector, const in vec3 toVector)
475
+ {
476
+ vec3 from = save_normalize (fromVector);
477
+ vec3 to = save_normalize (toVector);
478
+
479
+ float cos_angle = dot (from, to);
480
+ vec3 cross_vec = cross (from, to);
481
+ float cross_len = length (cross_vec);
482
+
483
+ if (cross_len == 0.0)
484
+ {
485
+ if (cos_angle > 0.0)
486
+ {
487
+ return vec4 (0.0, 0.0, 0.0, 1.0);
488
+ }
489
+ else
490
+ {
491
+ vec3 t = cross (from, vec3 (1.0, 0.0, 0.0));
492
+
493
+ if (dot (t, t) == 0.0)
494
+ t = cross (from, vec3 (0.0, 1.0, 0.0));
495
+
496
+ t = save_normalize (t);
497
+
498
+ return vec4 (t, 0.0);
499
+ }
500
+ }
501
+ else
502
+ {
503
+ float s = sqrt (abs (1.0 - cos_angle) * 0.5);
504
+
505
+ cross_vec = save_normalize (cross_vec);
506
+
507
+ return vec4 (cross_vec * s, sqrt (abs (1.0 + cos_angle) * 0.5));
508
+ }
509
+ }
510
+
511
+ vec3
512
+ multVecQuat (const in vec3 v, const in vec4 q)
513
+ {
514
+ float a = q .w * q .w - q .x * q .x - q .y * q .y - q .z * q .z;
515
+ float b = 2.0 * (v .x * q .x + v .y * q .y + v .z * q .z);
516
+ float c = 2.0 * q .w;
517
+ vec3 r = a * v .xyz + b * q .xyz + c * (q .yzx * v .zxy - q .zxy * v .yzx);
518
+
519
+ return r;
520
+ }
521
+
522
+ mat3
523
+ Matrix3 (const in vec4 quaternion)
524
+ {
525
+ float x = quaternion .x;
526
+ float y = quaternion .y;
527
+ float z = quaternion .z;
528
+ float w = quaternion .w;
529
+ float A = y * y;
530
+ float B = z * z;
531
+ float C = x * y;
532
+ float D = z * w;
533
+ float E = z * x;
534
+ float F = y * w;
535
+ float G = x * x;
536
+ float H = y * z;
537
+ float I = x * w;
538
+
539
+ return mat3 (1.0 - 2.0 * (A + B),
540
+ 2.0 * (C + D),
541
+ 2.0 * (E - F),
542
+ 2.0 * (C - D),
543
+ 1.0 - 2.0 * (B + G),
544
+ 2.0 * (H + I),
545
+ 2.0 * (E + F),
546
+ 2.0 * (H - I),
547
+ 1.0 - 2.0 * (A + G));
548
+ }
549
+
550
+ /* Random number generation */
551
+
552
+ uint seed = 1u;
553
+
554
+ void
555
+ srand (const in int value)
556
+ {
557
+ seed = uint (value);
558
+ }
559
+
560
+ // Return a uniform distributed random floating point number in the interval [0, 1].
561
+ float
562
+ random ()
563
+ {
564
+ seed = seed * 1103515245u + 12345u;
565
+
566
+ return float (seed) / 4294967295.0;
567
+ }
568
+
569
+ float
570
+ getRandomValue (const in float min, const in float max)
571
+ {
572
+ return min + random () * (max - min);
573
+ }
574
+
575
+ float
576
+ getRandomLifetime ()
577
+ {
578
+ float v = particleLifetime * lifetimeVariation;
579
+ float min_ = max (0.0, particleLifetime - v);
580
+ float max_ = particleLifetime + v;
581
+
582
+ return getRandomValue (min_, max_);
583
+ }
584
+
585
+ float
586
+ getRandomSpeed ()
587
+ {
588
+ float v = speed * variation;
589
+ float min_ = max (0.0, speed - v);
590
+ float max_ = speed + v;
591
+
592
+ return getRandomValue (min_, max_);
593
+ }
594
+
595
+ vec3
596
+ getRandomNormal ()
597
+ {
598
+ float theta = getRandomValue (-M_PI, M_PI);
599
+ float cphi = getRandomValue (-1.0, 1.0);
600
+ float r = sqrt (1.0 - cphi * cphi); // sin (acos (cphi));
601
+
602
+ return vec3 (sin (theta) * r, cos (theta) * r, cphi);
603
+ }
604
+
605
+ vec3
606
+ getRandomNormalWithAngle (const in float angle)
607
+ {
608
+ float theta = getRandomValue (-M_PI, M_PI);
609
+ float cphi = getRandomValue (cos (angle), 1.0);
610
+ float r = sqrt (1.0 - cphi * cphi); // sin (acos (cphi));
611
+
612
+ return vec3 (sin (theta) * r, cos (theta) * r, cphi);
613
+ }
614
+
615
+ vec3
616
+ getRandomNormalWithDirectionAndAngle (const in vec3 direction, const in float angle)
617
+ {
618
+ vec4 rotation = Quaternion (vec3 (0.0, 0.0, 1.0), direction);
619
+ vec3 normal = getRandomNormalWithAngle (angle);
620
+
621
+ return multVecQuat (normal, rotation);
622
+ }
623
+
624
+ vec3
625
+ getRandomSurfaceNormal (const in vec3 direction)
626
+ {
627
+ float theta = getRandomValue (-M_PI, M_PI);
628
+ float cphi = pow (random (), 1.0 / 3.0);
629
+ float r = sqrt (1.0 - cphi * cphi); // sin (acos (cphi));
630
+ vec3 normal = vec3 (sin (theta) * r, cos (theta) * r, cphi);
631
+ vec4 rotation = Quaternion (vec3 (0.0, 0.0, 1.0), direction);
632
+
633
+ return multVecQuat (normal, rotation);
634
+ }
635
+
636
+ vec3
637
+ getRandomSphericalVelocity ()
638
+ {
639
+ vec3 normal = getRandomNormal ();
640
+ float speed = getRandomSpeed ();
641
+
642
+ return normal * speed;
643
+ }
644
+
645
+ // Algorithms
646
+
647
+ int
648
+ upperBound (const in sampler2D sampler, in int count, const in float value)
649
+ {
650
+ int first = 0;
651
+ int step = 0;
652
+
653
+ while (count > 0)
654
+ {
655
+ int index = first;
656
+
657
+ step = count >> 1;
658
+
659
+ index += step;
660
+
661
+ if (value < texelFetch (sampler, index, 0) .x)
662
+ {
663
+ count = step;
664
+ }
665
+ else
666
+ {
667
+ first = ++ index;
668
+ count -= step + 1;
669
+ }
670
+ }
671
+
672
+ return first;
673
+ }
674
+
675
+ void
676
+ interpolate (const in sampler2D sampler, const in int count, const in float fraction, out int index0, out int index1, out float weight)
677
+ {
678
+ // Determine index0, index1 and weight.
679
+
680
+ if (count == 1 || fraction <= texelFetch (sampler, 0, 0) .x)
681
+ {
682
+ index0 = 0;
683
+ index1 = 0;
684
+ weight = 0.0;
685
+ }
686
+ else if (fraction >= texelFetch (sampler, count - 1, 0) .x)
687
+ {
688
+ index0 = count - 2;
689
+ index1 = count - 1;
690
+ weight = 1.0;
691
+ }
692
+ else
693
+ {
694
+ int index = upperBound (sampler, count, fraction);
695
+
696
+ if (index < count)
697
+ {
698
+ index1 = index;
699
+ index0 = index - 1;
700
+
701
+ float key0 = texelFetch (sampler, index0, 0) .x;
702
+ float key1 = texelFetch (sampler, index1, 0) .x;
703
+
704
+ weight = clamp ((fraction - key0) / (key1 - key0), 0.0, 1.0);
705
+ }
706
+ else
707
+ {
708
+ index0 = 0;
709
+ index1 = 0;
710
+ weight = 0.0;
711
+ }
712
+ }
713
+ }
714
+
715
+ void
716
+ interpolate (const in sampler2D sampler, const in int count, const in float fraction, out int index0)
717
+ {
718
+ // Determine index0.
719
+
720
+ if (count == 1 || fraction <= texelFetch (sampler, 0, 0) .x)
721
+ {
722
+ index0 = 0;
723
+ }
724
+ else if (fraction >= texelFetch (sampler, count - 1, 0) .x)
725
+ {
726
+ index0 = count - 2;
727
+ }
728
+ else
729
+ {
730
+ int index = upperBound (sampler, count, fraction);
731
+
732
+ if (index < count)
733
+ index0 = index - 1;
734
+ else
735
+ index0 = 0;
736
+ }
737
+ }
738
+
739
+ vec3
740
+ getRandomBarycentricCoord ()
741
+ {
742
+ // Random barycentric coordinates.
743
+
744
+ float u = random ();
745
+ float v = random ();
746
+
747
+ if (u + v > 1.0)
748
+ {
749
+ u = 1.0 - u;
750
+ v = 1.0 - v;
751
+ }
752
+
753
+ float t = 1.0 - u - v;
754
+
755
+ return vec3 (t, u, v);
756
+ }
757
+
758
+ void
759
+ getRandomPointOnSurface (const in sampler2D surface, const in int verticesIndex, const in int normalsIndex, out vec4 position, out vec3 normal)
760
+ {
761
+ // Determine index0, index1 and weight.
762
+
763
+ float lastAreaSoFar = texelFetch (surface, verticesIndex - 1, 0) .x;
764
+ float fraction = random () * lastAreaSoFar;
765
+
766
+ int index0;
767
+ int index1;
768
+ int index2;
769
+ float weight;
770
+
771
+ interpolate (surface, verticesIndex, fraction, index0, index1, weight);
772
+
773
+ // Interpolate and return position.
774
+
775
+ index0 *= 3;
776
+ index1 = index0 + 1;
777
+ index2 = index0 + 2;
778
+
779
+ vec4 vertex0 = texelFetch (surface, verticesIndex + index0, 0);
780
+ vec4 vertex1 = texelFetch (surface, verticesIndex + index1, 0);
781
+ vec4 vertex2 = texelFetch (surface, verticesIndex + index2, 0);
782
+
783
+ vec3 normal0 = texelFetch (surface, normalsIndex + index0, 0) .xyz;
784
+ vec3 normal1 = texelFetch (surface, normalsIndex + index1, 0) .xyz;
785
+ vec3 normal2 = texelFetch (surface, normalsIndex + index2, 0) .xyz;
786
+
787
+ // Random barycentric coordinates.
788
+
789
+ vec3 r = getRandomBarycentricCoord ();
790
+
791
+ // Calculate position and direction.
792
+
793
+ position = r .z * vertex0 + r .x * vertex1 + r .y * vertex2;
794
+ normal = save_normalize (r .z * normal0 + r .x * normal1 + r .y * normal2);
795
+ }
796
+
797
+ // Functions
798
+
799
+ ${this .functions .join ("\n")}
800
+
801
+ // Current values
802
+
803
+ vec4
804
+ getColor (const in float lifetime, const in float elapsedTime)
805
+ {
806
+ if (numColors > 0)
807
+ {
808
+ // Determine index0, index1 and weight.
809
+
810
+ float fraction = elapsedTime / lifetime;
811
+
812
+ int index0;
813
+ int index1;
814
+ float weight;
815
+
816
+ interpolate (colorRamp, numColors, fraction, index0, index1, weight);
817
+
818
+ // Interpolate and return color.
819
+
820
+ vec4 color0 = texelFetch (colorRamp, numColors + index0, 0);
821
+ vec4 color1 = texelFetch (colorRamp, numColors + index1, 0);
822
+
823
+ return mix (color0, color1, weight);
824
+ }
825
+ else
826
+ {
827
+ return vec4 (1.0);
828
+ }
829
+ }
830
+
831
+ void
832
+ bounce (const in vec4 fromPosition, inout vec4 toPosition, inout vec3 velocity)
833
+ {
834
+ if (boundedHierarchyRoot < 0)
835
+ return;
836
+
837
+ Line3 line = Line3 (fromPosition .xyz, save_normalize (velocity));
838
+
839
+ vec4 points [ARRAY_SIZE];
840
+ vec3 normals [ARRAY_SIZE];
841
+
842
+ int numIntersections = getIntersections (boundedVolume, boundedVerticesIndex, boundedNormalsIndex, boundedHierarchyIndex, boundedHierarchyRoot, line, points, normals);
843
+
844
+ if (numIntersections == 0)
845
+ return;
846
+
847
+ Plane3 plane1 = plane3 (line .point, line .direction);
848
+
849
+ int index = min_index (points, numIntersections, 0.0, plane1);
850
+
851
+ if (index == -1)
852
+ return;
853
+
854
+ Plane3 plane2 = plane3 (points [index] .xyz, normals [index]);
855
+
856
+ if (sign (plane_distance (plane2, fromPosition .xyz)) == sign (plane_distance (plane2, toPosition .xyz)))
857
+ return;
858
+
859
+ velocity = reflect (velocity, normals [index]);
860
+ toPosition = vec4 (points [index] .xyz + reflect (points [index] .xyz - fromPosition .xyz, normals [index]), 1.0);
861
+ }
192
862
 
193
- return normal .set (Math .sin (theta) * r,
194
- Math .cos (theta) * r,
195
- cphi);
196
- },
197
- getRandomNormalWithDirectionAndAngle: function (direction, angle, normal)
198
- {
199
- rotation .setFromToVec (Vector3 .zAxis, direction);
863
+ int
864
+ getTexCoordIndex0 (const in float lifetime, const in float elapsedTime)
865
+ {
866
+ if (numTexCoords == 0)
867
+ {
868
+ return -1;
869
+ }
870
+ else
871
+ {
872
+ float fraction = elapsedTime / lifetime;
873
+ int index0 = 0;
200
874
 
201
- return rotation .multVecRot (this .getRandomNormalWithAngle (angle, normal));
202
- },
203
- getRandomSurfaceNormal: function (normal)
204
- {
205
- var
206
- theta = this .getRandomValue (-1, 1) * Math .PI,
207
- cphi = Math .pow (Math .random (), 1/3),
208
- phi = Math .acos (cphi),
209
- r = Math .sin (phi);
875
+ interpolate (texCoordRamp, numTexCoords, fraction, index0);
210
876
 
211
- return normal .set (Math .sin (theta) * r,
212
- Math .cos (theta) * r,
213
- cphi);
214
- },
215
- animate: function (particleSystem, deltaTime)
216
- {
217
- var
218
- particles = particleSystem .particles,
219
- numParticles = particleSystem .numParticles,
220
- createParticles = particleSystem .createParticles,
221
- particleLifetime = particleSystem .particleLifetime,
222
- lifetimeVariation = particleSystem .lifetimeVariation,
223
- speeds = particleSystem .speeds, // speed of velocities
224
- velocities = particleSystem .velocities, // resulting velocities from forces
225
- turbulences = particleSystem .turbulences, // turbulences
226
- rotations = this .rotations, // rotation to direction of force
227
- numForces = particleSystem .numForces, // number of forces
228
- boundedPhysics = particleSystem .boundedVertices .length,
229
- boundedVolume = particleSystem .boundedVolume;
230
-
231
- for (var i = rotations .length; i < numForces; ++ i)
232
- rotations [i] = new Rotation4 (0, 0, 1, 0);
233
-
234
- for (var i = 0; i < numForces; ++ i)
235
- rotations [i] .setFromToVec (Vector3 .zAxis, velocities [i]);
236
-
237
- for (var i = 0; i < numParticles; ++ i)
877
+ return numTexCoords + index0 * texCoordCount;
878
+ }
879
+ }
880
+
881
+ void
882
+ main ()
238
883
  {
239
- var
240
- particle = particles [i],
241
- elapsedTime = particle .elapsedTime + deltaTime;
884
+ int life = int (input0 [0]);
885
+ float lifetime = input0 [1];
886
+ float elapsedTime = input0 [2] + deltaTime;
242
887
 
243
- if (elapsedTime > particle .lifetime)
888
+ srand ((gl_VertexID + randomSeed) * randomSeed);
889
+
890
+ if (elapsedTime > lifetime)
244
891
  {
245
892
  // Create new particle or hide particle.
246
893
 
247
- particle .lifetime = this .getRandomLifetime (particleLifetime, lifetimeVariation);
248
- particle .elapsedTime = 0;
894
+ lifetime = getRandomLifetime ();
895
+ elapsedTime = 0.0;
896
+
897
+ output0 = vec4 (max (life + 1, 1), lifetime, elapsedTime, getTexCoordIndex0 (lifetime, elapsedTime));
249
898
 
250
899
  if (createParticles)
251
900
  {
252
- ++ particle .life;
253
- this .getRandomPosition (particle .position);
254
- this .getRandomVelocity (particle .velocity);
901
+ output1 = getColor (lifetime, elapsedTime);
902
+ output2 = vec4 (getRandomVelocity (), 0.0);
903
+ output6 = getRandomPosition ();
255
904
  }
256
905
  else
257
- particle .position .set (Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY);
906
+ {
907
+ output1 = vec4 (0.0);
908
+ output2 = vec4 (0.0);
909
+ output6 = vec4 (NaN);
910
+ }
258
911
  }
259
912
  else
260
913
  {
261
914
  // Animate particle.
262
915
 
263
- var
264
- position = particle .position,
265
- velocity = particle .velocity;
916
+ vec3 velocity = input2 .xyz;
917
+ vec4 position = input6;
266
918
 
267
- for (var f = 0; f < numForces; ++ f)
919
+ for (int i = 0; i < numForces; ++ i)
268
920
  {
269
- velocity .add (rotations [f] .multVecRot (this .getRandomNormalWithAngle (turbulences [f], normal)) .multiply (speeds [f]));
921
+ vec4 force = texelFetch (forces, i, 0);
922
+ float turbulence = force .w;
923
+ vec3 normal = getRandomNormalWithDirectionAndAngle (force .xyz, turbulence);
924
+ float speed = length (force .xyz);
925
+
926
+ velocity += normal * speed;
270
927
  }
271
928
 
272
- if (boundedPhysics)
273
- {
274
- fromPosition .x = position .x;
275
- fromPosition .y = position .y;
276
- fromPosition .z = position .z;
929
+ position .xyz += velocity * deltaTime;
277
930
 
278
- position .x += velocity .x * deltaTime;
279
- position .y += velocity .y * deltaTime;
280
- position .z += velocity .z * deltaTime;
931
+ bounce (input6, position, velocity);
281
932
 
282
- this .bounce (boundedVolume, fromPosition, position, velocity);
283
- }
284
- else
933
+ output0 = vec4 (life, lifetime, elapsedTime, getTexCoordIndex0 (lifetime, elapsedTime));
934
+ output1 = getColor (lifetime, elapsedTime);
935
+ output2 = vec4 (velocity, 0.0);
936
+ output6 = position;
937
+ }
938
+
939
+ switch (geometryType)
940
+ {
941
+ case POINT:
942
+ case SPRITE:
943
+ case GEOMETRY:
285
944
  {
286
- position .x += velocity .x * deltaTime;
287
- position .y += velocity .y * deltaTime;
288
- position .z += velocity .z * deltaTime;
945
+ output3 = vec4 (1.0, 0.0, 0.0, 0.0);
946
+ output4 = vec4 (0.0, 1.0, 0.0, 0.0);
947
+ output5 = vec4 (0.0, 0.0, 1.0, 0.0);
948
+ break;
289
949
  }
950
+ case LINE:
951
+ {
952
+ mat3 r = Matrix3 (Quaternion (vec3 (0.0, 0.0, 1.0), output2 .xyz));
953
+ mat3 s = mat3 (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, particleSize .y);
954
+ mat3 m = r * s;
290
955
 
291
- particle .elapsedTime = elapsedTime;
956
+ output3 = vec4 (m [0], 0.0);
957
+ output4 = vec4 (m [1], 0.0);
958
+ output5 = vec4 (m [2], 0.0);
959
+ break;
960
+ }
961
+ default: // QUAD, TRIANGLE
962
+ {
963
+ output3 = vec4 (particleSize .x, 0.0, 0.0, 0.0);
964
+ output4 = vec4 (0.0, particleSize .y, 0.0, 0.0);
965
+ output5 = vec4 (0.0, 0.0, 1.0, 0.0);
966
+ break;
967
+ }
292
968
  }
293
969
  }
970
+ `;
294
971
 
295
- // Animate color if needed.
972
+ const fragmentShaderSource = /* glsl */ `#version 300 es
296
973
 
297
- if (particleSystem .geometryContext .colorMaterial)
298
- this .getColors (particles, particleSystem .colorKeys, particleSystem .colorRamp, numParticles);
299
- },
300
- bounce: function (boundedVolume, fromPosition, toPosition, velocity)
301
- {
302
- normal .assign (velocity) .normalize ();
974
+ precision highp float;
303
975
 
304
- line .set (fromPosition, normal);
976
+ void
977
+ main () { }
978
+ `;
305
979
 
306
- var
307
- intersections = this .intersections,
308
- intersectionNormals = this .intersectionNormals,
309
- numIntersections = boundedVolume .intersectsLine (line, intersections, intersectionNormals);
980
+ // Vertex shader
310
981
 
311
- if (numIntersections)
312
- {
313
- for (var i = 0; i < numIntersections; ++ i)
314
- intersections [i] .index = i;
982
+ const vertexShader = gl .createShader (gl .VERTEX_SHADER);
315
983
 
316
- plane .set (fromPosition, normal);
984
+ gl .shaderSource (vertexShader, vertexShaderSource);
985
+ gl .compileShader (vertexShader);
317
986
 
318
- this .sorter .sort (0, numIntersections);
987
+ // Fragment shader
319
988
 
320
- var index = Algorithm .upperBound (intersections, 0, numIntersections, 0, PlaneCompareValue);
989
+ const fragmentShader = gl .createShader (gl .FRAGMENT_SHADER);
321
990
 
322
- if (index < numIntersections)
323
- {
324
- var
325
- intersection = intersections [index],
326
- intersectionNormal = intersectionNormals [intersection .index];
991
+ gl .shaderSource (fragmentShader, fragmentShaderSource);
992
+ gl .compileShader (fragmentShader);
327
993
 
328
- plane .set (intersection, intersectionNormal);
994
+ // Program
329
995
 
330
- if (plane .getDistanceToPoint (fromPosition) * plane .getDistanceToPoint (toPosition) < 0)
331
- {
332
- var dot2 = 2 * intersectionNormal .dot (velocity);
996
+ const program = gl .createProgram ();
333
997
 
334
- velocity .x -= intersectionNormal .x * dot2;
335
- velocity .y -= intersectionNormal .y * dot2;
336
- velocity .z -= intersectionNormal .z * dot2;
998
+ gl .attachShader (program, vertexShader);
999
+ gl .attachShader (program, fragmentShader);
1000
+ gl .transformFeedbackVaryings (program, Array .from ({length: 7}, (_, i) => "output" + i), gl .INTERLEAVED_ATTRIBS);
1001
+ gl .linkProgram (program);
337
1002
 
338
- normal .assign (velocity) .normalize ();
1003
+ if (!gl .getProgramParameter (program, gl .LINK_STATUS))
1004
+ console .error ("Couldn't initialize particle shader: " + gl .getProgramInfoLog (program));
339
1005
 
340
- var distance = intersection .distance (fromPosition);
1006
+ program .inputs = [
1007
+ [0, gl .getAttribLocation (program, "input0")],
1008
+ [2, gl .getAttribLocation (program, "input2")],
1009
+ [6, gl .getAttribLocation (program, "input6")],
1010
+ ];
341
1011
 
342
- toPosition .x = intersection .x + normal .x * distance;
343
- toPosition .y = intersection .y + normal .y * distance;
344
- toPosition .z = intersection .z + normal .z * distance;
345
- }
346
- }
347
- }
348
- },
349
- getColors: function (particles, colorKeys, colorRamp, numParticles)
350
- {
351
- var
352
- length = colorKeys .length,
353
- index0 = 0,
354
- index1 = 0,
355
- weight = 0;
1012
+ program .randomSeed = gl .getUniformLocation (program, "randomSeed");
1013
+ program .geometryType = gl .getUniformLocation (program, "geometryType");
1014
+ program .createParticles = gl .getUniformLocation (program, "createParticles");
1015
+ program .particleLifetime = gl .getUniformLocation (program, "particleLifetime");
1016
+ program .lifetimeVariation = gl .getUniformLocation (program, "lifetimeVariation");
1017
+ program .deltaTime = gl .getUniformLocation (program, "deltaTime");
1018
+ program .particleSize = gl .getUniformLocation (program, "particleSize");
356
1019
 
357
- for (var i = 0; i < numParticles; ++ i)
358
- {
359
- // Determine index0, index1 and weight.
1020
+ program .numForces = gl .getUniformLocation (program, "numForces");
1021
+ program .forces = gl .getUniformLocation (program, "forces");
360
1022
 
361
- var
362
- particle = particles [i],
363
- fraction = particle .elapsedTime / particle .lifetime,
364
- color = particle .color;
1023
+ program .boundedVerticesIndex = gl .getUniformLocation (program, "boundedVerticesIndex");
1024
+ program .boundedNormalsIndex = gl .getUniformLocation (program, "boundedNormalsIndex");
1025
+ program .boundedHierarchyIndex = gl .getUniformLocation (program, "boundedHierarchyIndex");
1026
+ program .boundedHierarchyRoot = gl .getUniformLocation (program, "boundedHierarchyRoot");
1027
+ program .boundedVolume = gl .getUniformLocation (program, "boundedVolume");
365
1028
 
366
- if (length == 1 || fraction <= colorKeys [0])
367
- {
368
- index0 = 0;
369
- index1 = 0;
370
- weight = 0;
371
- }
372
- else if (fraction >= colorKeys [length - 1])
373
- {
374
- index0 = length - 2;
375
- index1 = length - 1;
376
- weight = 1;
377
- }
378
- else
379
- {
380
- var index = Algorithm .upperBound (colorKeys, 0, length, fraction, Algorithm .less);
1029
+ program .numColors = gl .getUniformLocation (program, "numColors");
1030
+ program .colorRamp = gl .getUniformLocation (program, "colorRamp");
381
1031
 
382
- if (index < length)
383
- {
384
- index1 = index;
385
- index0 = index - 1;
1032
+ program .texCoordCount = gl .getUniformLocation (program, "texCoordCount");
1033
+ program .numTexCoords = gl .getUniformLocation (program, "numTexCoords");
1034
+ program .texCoordRamp = gl .getUniformLocation (program, "texCoordRamp");
386
1035
 
387
- var
388
- key0 = colorKeys [index0],
389
- key1 = colorKeys [index1];
1036
+ for (const name of Object .keys (this .uniforms))
1037
+ program [name] = gl .getUniformLocation (program, name);
390
1038
 
391
- weight = Algorithm .clamp ((fraction - key0) / (key1 - key0), 0, 1);
392
- }
393
- else
394
- {
395
- index0 = 0;
396
- index1 = 0;
397
- weight = 0;
398
- }
399
- }
1039
+ program .NaN = gl .getUniformLocation (program, "NaN");
400
1040
 
401
- // Interpolate and set color.
1041
+ gl .useProgram (program);
402
1042
 
403
- var
404
- color0 = colorRamp [index0],
405
- color1 = colorRamp [index1];
1043
+ for (const name of this .samplers)
1044
+ {
1045
+ const location = gl .getUniformLocation (program, name);
406
1046
 
407
- // Algorithm .lerp (color0, color1, weight);
408
- color .x = color0 .x + weight * (color1 .x - color0 .x);
409
- color .y = color0 .y + weight * (color1 .y - color0 .y);
410
- color .z = color0 .z + weight * (color1 .z - color0 .z);
411
- color .w = color0 .w + weight * (color1 .w - color0 .w);
1047
+ gl .uniform1i (location, program [name + "TextureUnit"] = browser .getTexture2DUnit ());
412
1048
  }
1049
+
1050
+ gl .uniform1f (program .NaN, NaN);
1051
+
1052
+ browser .resetTextureUnits ();
1053
+
1054
+ return program;
1055
+ },
1056
+ activateTextures: function ()
1057
+ { },
1058
+ createTexture: function ()
1059
+ {
1060
+ const
1061
+ gl = this .getBrowser () .getContext (),
1062
+ texture = gl .createTexture ();
1063
+
1064
+ gl .bindTexture (gl .TEXTURE_2D, texture);
1065
+
1066
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_S, gl .CLAMP_TO_EDGE);
1067
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_T, gl .CLAMP_TO_EDGE);
1068
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MAG_FILTER, gl .NEAREST);
1069
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MIN_FILTER, gl .NEAREST);
1070
+
1071
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, 1, 1, 0, gl .RGBA, gl .FLOAT, new Float32Array (4));
1072
+
1073
+ return texture;
1074
+ },
1075
+ getTexture2DUnit: function (browser, object, property)
1076
+ {
1077
+ const textureUnit = object [property];
1078
+
1079
+ if (textureUnit === undefined)
1080
+ return object [property] = browser .getTexture2DUnit ();
1081
+
1082
+ return textureUnit;
413
1083
  },
414
1084
  });
415
1085
 
@@ -488,25 +1158,38 @@ function (Fields,
488
1158
 
489
1159
  this .addType (X3DConstants .PointEmitter);
490
1160
 
491
- this ._position .setUnit ("length");
492
- this ._speed .setUnit ("speed");
493
- this ._mass .setUnit ("mass");
494
- this ._surfaceArea .setUnit ("area");
1161
+ this ._position .setUnit ("length");
1162
+
1163
+ this .addUniform ("position", "uniform vec3 position;");
1164
+ this .addUniform ("direction", "uniform vec3 direction;");
1165
+
1166
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
1167
+ {
1168
+ if (direction == vec3 (0.0))
1169
+ return getRandomSphericalVelocity ();
1170
+
1171
+ else
1172
+ return direction * getRandomSpeed ();
1173
+ }`);
495
1174
 
496
- this .direction = new Vector3 (0, 0, 0);
1175
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
1176
+ {
1177
+ return vec4 (position, 1.0);
1178
+ }`);
497
1179
  }
498
1180
 
499
1181
  PointEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
500
1182
  {
501
1183
  constructor: PointEmitter,
502
1184
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
503
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
504
- new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
505
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
506
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
507
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
508
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
509
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
1185
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1186
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
1187
+ new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1188
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
1189
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1190
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1191
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
1192
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
510
1193
  ]),
511
1194
  getTypeName: function ()
512
1195
  {
@@ -524,7 +1207,10 @@ function (Fields,
524
1207
  {
525
1208
  X3DParticleEmitterNode .prototype .initialize .call (this);
526
1209
 
527
- this ._position .addInterest ("set_position__", this);
1210
+ if (this .getBrowser () .getContext () .getVersion () < 2)
1211
+ return;
1212
+
1213
+ this ._position .addInterest ("set_position__", this);
528
1214
  this ._direction .addInterest ("set_direction__", this);
529
1215
 
530
1216
  this .set_position__ ();
@@ -532,33 +1218,21 @@ function (Fields,
532
1218
  },
533
1219
  set_position__: function ()
534
1220
  {
535
- this .position = this ._position .getValue ()
536
- },
537
- set_direction__: function ()
538
- {
539
- this .direction .assign (this ._direction .getValue ()) .normalize ();
1221
+ const position = this ._position .getValue ();
540
1222
 
541
- if (this .direction .equals (Vector3 .Zero))
542
- this .getRandomVelocity = this .getSphericalRandomVelocity;
543
- else
544
- delete this .getRandomVelocity;
545
- },
546
- getRandomPosition: function (position)
547
- {
548
- return position .assign (this .position);
1223
+ this .setUniform ("uniform3f", "position", position .x, position .y, position .z);
549
1224
  },
550
- getRandomVelocity: function (velocity)
1225
+ set_direction__: (function ()
551
1226
  {
552
- var
553
- direction = this .direction,
554
- speed = this .getRandomSpeed ();
1227
+ const direction = new Vector3 (0, 0, 0);
555
1228
 
556
- velocity .x = direction .x * speed;
557
- velocity .y = direction .y * speed;
558
- velocity .z = direction .z * speed;
1229
+ return function ()
1230
+ {
1231
+ direction .assign (this ._direction .getValue ()) .normalize ();
559
1232
 
560
- return velocity;
561
- },
1233
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
1234
+ };
1235
+ })(),
562
1236
  });
563
1237
 
564
1238
  return PointEmitter;
@@ -830,17 +1504,17 @@ function (Fields,
830
1504
  },
831
1505
  addGeometry: function (boundedNormals, boundedVertices)
832
1506
  {
833
- if (this .geometryNode)
1507
+ if (this .geometryNode && this ._enabled .getValue ())
834
1508
  {
835
- var
1509
+ const
836
1510
  normals = this .geometryNode .getNormals () .getValue (),
837
1511
  vertices = this .geometryNode .getVertices () .getValue ();
838
1512
 
839
- for (var i = 0, length = normals .length; i < length; ++ i)
840
- boundedNormals .push (normals [i]);
1513
+ for (const value of normals)
1514
+ boundedNormals .push (value);
841
1515
 
842
- for (var i = 0, length = vertices .length; i < length; ++ i)
843
- boundedVertices .push (vertices [i]);
1516
+ for (const value of vertices)
1517
+ boundedVertices .push (value);
844
1518
  }
845
1519
  },
846
1520
  });
@@ -903,16 +1577,12 @@ define ('x_ite/Components/ParticleSystems/ConeEmitter',[
903
1577
  "x_ite/Base/FieldDefinitionArray",
904
1578
  "x_ite/Components/ParticleSystems/X3DParticleEmitterNode",
905
1579
  "x_ite/Base/X3DConstants",
906
- "standard/Math/Numbers/Vector3",
907
- "standard/Math/Numbers/Rotation4",
908
1580
  ],
909
1581
  function (Fields,
910
1582
  X3DFieldDefinition,
911
1583
  FieldDefinitionArray,
912
1584
  X3DParticleEmitterNode,
913
- X3DConstants,
914
- Vector3,
915
- Rotation4)
1585
+ X3DConstants)
916
1586
  {
917
1587
  "use strict";
918
1588
 
@@ -922,27 +1592,47 @@ function (Fields,
922
1592
 
923
1593
  this .addType (X3DConstants .ConeEmitter);
924
1594
 
925
- this ._position .setUnit ("length");
926
- this ._angle .setUnit ("angle");
927
- this ._speed .setUnit ("speed");
928
- this ._mass .setUnit ("mass");
929
- this ._surfaceArea .setUnit ("area");
1595
+ this ._position .setUnit ("length");
1596
+ this ._angle .setUnit ("angle");
1597
+
1598
+ this .addUniform ("position", "uniform vec3 position;");
1599
+ this .addUniform ("direction", "uniform vec3 direction;");
1600
+ this .addUniform ("angle", "uniform float angle;");
1601
+
1602
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
1603
+ {
1604
+ if (direction == vec3 (0.0))
1605
+ {
1606
+ return getRandomSphericalVelocity ();
1607
+ }
1608
+ else
1609
+ {
1610
+ vec3 normal = getRandomNormalWithDirectionAndAngle (direction, angle);
1611
+ float speed = getRandomSpeed ();
930
1612
 
931
- this .rotation = new Rotation4 (0, 0, 1, 0);
1613
+ return normal * speed;
1614
+ }
1615
+ }`);
1616
+
1617
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
1618
+ {
1619
+ return vec4 (position, 1.0);
1620
+ }`);
932
1621
  }
933
1622
 
934
1623
  ConeEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
935
1624
  {
936
1625
  constructor: ConeEmitter,
937
1626
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
938
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
939
- new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
940
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
941
- new X3DFieldDefinition (X3DConstants .inputOutput, "angle", new Fields .SFFloat (0.7854)),
942
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
943
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
944
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
945
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
1627
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1628
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
1629
+ new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1630
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
1631
+ new X3DFieldDefinition (X3DConstants .inputOutput, "angle", new Fields .SFFloat (0.7854)),
1632
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1633
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1634
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
1635
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
946
1636
  ]),
947
1637
  getTypeName: function ()
948
1638
  {
@@ -960,6 +1650,9 @@ function (Fields,
960
1650
  {
961
1651
  X3DParticleEmitterNode .prototype .initialize .call (this);
962
1652
 
1653
+ if (this .getBrowser () .getContext () .getVersion () < 2)
1654
+ return;
1655
+
963
1656
  this ._position .addInterest ("set_position__", this);
964
1657
  this ._direction .addInterest ("set_direction__", this);
965
1658
  this ._angle .addInterest ("set_angle__", this);
@@ -970,31 +1663,20 @@ function (Fields,
970
1663
  },
971
1664
  set_position__: function ()
972
1665
  {
973
- this .position = this ._position .getValue ()
1666
+ const position = this ._position .getValue ();
1667
+
1668
+ this .setUniform ("uniform3f", "position", position .x, position .y, position .z);
974
1669
  },
975
1670
  set_direction__: function ()
976
1671
  {
977
- var direction = this ._direction .getValue ();
1672
+ const direction = this ._direction .getValue ();
978
1673
 
979
- this .rotation .setFromToVec (Vector3 .zAxis, direction);
980
-
981
- if (direction .equals (Vector3 .Zero))
982
- this .getRandomVelocity = this .getSphericalRandomVelocity;
983
- else
984
- delete this .getRandomVelocity;
1674
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
985
1675
  },
986
1676
  set_angle__: function ()
987
1677
  {
988
- this .angle = this ._angle .getValue ()
1678
+ this .setUniform ("uniform1f", "angle", this ._angle .getValue ());
989
1679
  },
990
- getRandomPosition: function (position)
991
- {
992
- return position .assign (this .position);
993
- },
994
- getRandomVelocity: function (velocity)
995
- {
996
- return this .rotation .multVecRot (this .getRandomNormalWithAngle (this .angle, velocity) .multiply (this .getRandomSpeed ()));
997
- },
998
1680
  });
999
1681
 
1000
1682
  return ConeEmitter;
@@ -1070,24 +1752,32 @@ function (Fields,
1070
1752
 
1071
1753
  this .addType (X3DConstants .ExplosionEmitter);
1072
1754
 
1073
- this ._position .setUnit ("length");
1074
- this ._speed .setUnit ("speed");
1075
- this ._mass .setUnit ("mass");
1076
- this ._surfaceArea .setUnit ("area");
1755
+ this ._position .setUnit ("length");
1756
+
1757
+ this .addUniform ("position", "uniform vec3 position;");
1077
1758
 
1078
- this .getRandomVelocity = this .getSphericalRandomVelocity;
1759
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
1760
+ {
1761
+ return getRandomSphericalVelocity ();
1762
+ }`);
1763
+
1764
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
1765
+ {
1766
+ return vec4 (position, 1.0);
1767
+ }`);
1079
1768
  }
1080
1769
 
1081
1770
  ExplosionEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
1082
1771
  {
1083
1772
  constructor: ExplosionEmitter,
1084
1773
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
1085
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1086
- new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1087
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1088
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1089
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
1090
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
1774
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
1775
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
1776
+ new X3DFieldDefinition (X3DConstants .inputOutput, "position", new Fields .SFVec3f ()),
1777
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
1778
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
1779
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
1780
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
1091
1781
  ]),
1092
1782
  getTypeName: function ()
1093
1783
  {
@@ -1105,21 +1795,22 @@ function (Fields,
1105
1795
  {
1106
1796
  X3DParticleEmitterNode .prototype .initialize .call (this);
1107
1797
 
1798
+ if (this .getBrowser () .getContext () .getVersion () < 2)
1799
+ return;
1800
+
1108
1801
  this ._position .addInterest ("set_position__", this);
1109
1802
 
1110
1803
  this .set_position__ ();
1111
1804
  },
1112
- set_position__: function ()
1113
- {
1114
- this .position = this ._position .getValue ()
1115
- },
1116
1805
  isExplosive: function ()
1117
1806
  {
1118
1807
  return true;
1119
1808
  },
1120
- getRandomPosition: function (position)
1809
+ set_position__: function ()
1121
1810
  {
1122
- return position .assign (this .position);
1811
+ const position = this ._position .getValue ();
1812
+
1813
+ this .setUniform ("uniform3f", "position", position .x, position .y, position .z);
1123
1814
  },
1124
1815
  });
1125
1816
 
@@ -1181,12 +1872,14 @@ define ('x_ite/Components/ParticleSystems/ForcePhysicsModel',[
1181
1872
  "x_ite/Base/FieldDefinitionArray",
1182
1873
  "x_ite/Components/ParticleSystems/X3DParticlePhysicsModelNode",
1183
1874
  "x_ite/Base/X3DConstants",
1875
+ "standard/Math/Numbers/Vector3",
1184
1876
  ],
1185
1877
  function (Fields,
1186
1878
  X3DFieldDefinition,
1187
1879
  FieldDefinitionArray,
1188
1880
  X3DParticlePhysicsModelNode,
1189
- X3DConstants)
1881
+ X3DConstants,
1882
+ Vector3)
1190
1883
  {
1191
1884
  "use strict";
1192
1885
 
@@ -1219,14 +1912,25 @@ function (Fields,
1219
1912
  {
1220
1913
  return "physics";
1221
1914
  },
1222
- addForce: function (i, emitterNode, forces, turbulences)
1915
+ addForce: (function ()
1223
1916
  {
1224
- if (this ._enabled .getValue ())
1917
+ const force = new Vector3 (0, 0, 0);
1918
+
1919
+ return function (i, emitterNode, timeByMass, forces)
1225
1920
  {
1226
- forces [i] .assign (this ._force .getValue ());
1227
- turbulences [i] = 0;
1228
- }
1229
- },
1921
+ if (this ._enabled .getValue ())
1922
+ {
1923
+ forces .set (force .assign (this ._force .getValue ()) .multiply (timeByMass), i * 4);
1924
+ forces [i * 4 + 3] = 0;
1925
+
1926
+ return true;
1927
+ }
1928
+ else
1929
+ {
1930
+ return false;
1931
+ }
1932
+ };
1933
+ })(),
1230
1934
  });
1231
1935
 
1232
1936
  return ForcePhysicsModel;
@@ -1308,28 +2012,24 @@ function (Vector3,
1308
2012
  // left: We do not have to test for left.
1309
2013
  ];
1310
2014
 
2015
+ const
2016
+ NODE = 0,
2017
+ TRIANGLE = 1;
2018
+
1311
2019
  function SortComparator (vertices, axis)
1312
2020
  {
1313
- function compare (a, b)
2021
+ return function compare (a, b)
1314
2022
  {
1315
- const
1316
- vertices = compare .vertices;
1317
- axis = compare .axis;
1318
-
1319
- return Math .min (vertices [a + axis], vertices [a + 4 + axis], vertices [a + 8 + axis]) <
1320
- Math .min (vertices [b + axis], vertices [b + 4 + axis], vertices [b + 8 + axis]);
2023
+ return Math .min (vertices [a + axis], vertices [a + 4 + axis], vertices [a + 8 + axis]) <
2024
+ Math .min (vertices [b + axis], vertices [b + 4 + axis], vertices [b + 8 + axis]);
1321
2025
  }
1322
-
1323
- compare .vertices = vertices;
1324
- compare .axis = axis;
1325
-
1326
- return compare;
1327
2026
  }
1328
2027
 
1329
2028
  function Triangle (tree, triangle)
1330
2029
  {
1331
2030
  this .vertices = tree .vertices;
1332
2031
  this .normals = tree .normals;
2032
+ this .triangle = triangle;
1333
2033
  this .i4 = triangle * 12;
1334
2034
  this .i3 = triangle * 9;
1335
2035
  }
@@ -1379,6 +2079,14 @@ function (Vector3,
1379
2079
  }
1380
2080
  }
1381
2081
  },
2082
+ toArray: function (array)
2083
+ {
2084
+ const index = array .length / 4;
2085
+
2086
+ array .push (TRIANGLE, this .triangle * 3, 0, 0);
2087
+
2088
+ return index;
2089
+ },
1382
2090
  };
1383
2091
 
1384
2092
  function Node (tree, triangles, first, size)
@@ -1537,15 +2245,30 @@ function (Vector3,
1537
2245
  return 0;
1538
2246
  }
1539
2247
  },
2248
+ toArray: function (array)
2249
+ {
2250
+ const
2251
+ left = this .left .toArray (array),
2252
+ right = this .right .toArray (array),
2253
+ min = this .min,
2254
+ max = this .max,
2255
+ index = array .length / 4;
2256
+
2257
+ array .push (NODE, left, right, 0,
2258
+ min .x, min .y, min .z, 0,
2259
+ max .x, max .y, max .z, 0);
2260
+
2261
+ return index;
2262
+ },
1540
2263
  };
1541
2264
 
1542
2265
  function BVH (vertices, normals)
1543
2266
  {
2267
+ const numTriangles = vertices .length / 12;
2268
+
1544
2269
  this .vertices = vertices;
1545
2270
  this .normals = normals;
1546
2271
 
1547
- const numTriangles = vertices .length / 12;
1548
-
1549
2272
  switch (numTriangles)
1550
2273
  {
1551
2274
  case 0:
@@ -1566,8 +2289,7 @@ function (Vector3,
1566
2289
  triangles .push (i);
1567
2290
 
1568
2291
  this .sorter = new QuickSort (triangles, SortComparator (vertices, 0));
1569
-
1570
- this .root = new Node (this, triangles, 0, numTriangles);
2292
+ this .root = new Node (this, triangles, 0, numTriangles);
1571
2293
  break;
1572
2294
  }
1573
2295
  }
@@ -1576,7 +2298,6 @@ function (Vector3,
1576
2298
  BVH .prototype =
1577
2299
  {
1578
2300
  constructor: BVH,
1579
-
1580
2301
  intersectsLine: function (line, intersections, intersectionNormals)
1581
2302
  {
1582
2303
  intersections .size = 0;
@@ -1589,6 +2310,17 @@ function (Vector3,
1589
2310
 
1590
2311
  return 0;
1591
2312
  },
2313
+ toArray: function (array)
2314
+ {
2315
+ if (this .root)
2316
+ {
2317
+ const root = this .root .toArray (array);
2318
+
2319
+ array .push (root, 0, 0, 0);
2320
+ }
2321
+
2322
+ return array;
2323
+ },
1592
2324
  };
1593
2325
 
1594
2326
  return BVH;
@@ -1648,69 +2380,70 @@ define ('x_ite/Components/ParticleSystems/ParticleSystem',[
1648
2380
  "x_ite/Base/X3DFieldDefinition",
1649
2381
  "x_ite/Base/FieldDefinitionArray",
1650
2382
  "x_ite/Components/Shape/X3DShapeNode",
2383
+ "x_ite/Browser/ParticleSystems/GeometryTypes",
2384
+ "x_ite/Rendering/VertexArray",
1651
2385
  "x_ite/Rendering/TraverseType",
1652
2386
  "x_ite/Base/X3DConstants",
1653
2387
  "x_ite/Base/X3DCast",
1654
2388
  "x_ite/Browser/Shape/AlphaMode",
1655
2389
  "standard/Math/Numbers/Vector3",
1656
- "standard/Math/Numbers/Vector4",
1657
2390
  "standard/Math/Numbers/Matrix4",
1658
2391
  "standard/Math/Numbers/Matrix3",
1659
- "standard/Math/Algorithms/QuickSort",
1660
- "standard/Math/Algorithm",
1661
2392
  "standard/Math/Utility/BVH",
1662
2393
  ],
1663
2394
  function (Fields,
1664
2395
  X3DFieldDefinition,
1665
2396
  FieldDefinitionArray,
1666
2397
  X3DShapeNode,
2398
+ GeometryTypes,
2399
+ VertexArray,
1667
2400
  TraverseType,
1668
2401
  X3DConstants,
1669
2402
  X3DCast,
1670
2403
  AlphaMode,
1671
2404
  Vector3,
1672
- Vector4,
1673
2405
  Matrix4,
1674
2406
  Matrix3,
1675
- QuickSort,
1676
- Algorithm,
1677
2407
  BVH)
1678
2408
  {
1679
2409
  "use strict";
1680
2410
 
1681
- var i = 0;
1682
-
1683
- const
1684
- POINT = i ++,
1685
- LINE = i ++,
1686
- TRIANGLE = i ++,
1687
- QUAD = i ++,
1688
- GEOMETRY = i ++,
1689
- SPRITE = i ++;
1690
-
1691
- const GeometryTypes = {
1692
- POINT: POINT,
1693
- LINE: LINE,
1694
- TRIANGLE: TRIANGLE,
1695
- QUAD: QUAD,
1696
- GEOMETRY: GEOMETRY,
1697
- SPRITE: SPRITE,
1698
- };
1699
-
1700
- const
1701
- invModelViewMatrix = new Matrix4 (),
1702
- billboardToScreen = new Vector3 (0, 0, 0),
1703
- viewerYAxis = new Vector3 (0, 0, 0),
1704
- vector = new Vector3 (0, 0, 0),
1705
- normal = new Vector3 (0, 0, 0),
1706
- s1 = new Vector3 (0, 0, 0),
1707
- s2 = new Vector3 (0, 0, 0),
1708
- s3 = new Vector3 (0, 0, 0),
1709
- s4 = new Vector3 (0, 0, 0),
1710
- x = new Vector3 (0, 0, 0),
1711
- y = new Vector3 (0, 0, 0);
1712
-
1713
- function compareDistance (lhs, rhs) { return lhs .distance < rhs .distance; }
2411
+ const PointGeometry = new Float32Array ([0, 0, 0, 1]);
2412
+
2413
+ const LineGeometry = new Float32Array ([
2414
+ // TexCoords
2415
+ 0, 0, 0, 1,
2416
+ 1, 0, 0, 1,
2417
+ // Vertices
2418
+ 0, 0, -0.5, 1,
2419
+ 0, 0, 0.5, 1,
2420
+ ]);
2421
+
2422
+ // p4 ------ p3
2423
+ // | / |
2424
+ // | / |
2425
+ // | / |
2426
+ // | / |
2427
+ // p1 ------ p2
2428
+
2429
+ const QuadGeometry = new Float32Array ([
2430
+ // TexCoords
2431
+ 0, 0, 0, 1,
2432
+ 1, 0, 0, 1,
2433
+ 1, 1, 0, 1,
2434
+ 0, 0, 0, 1,
2435
+ 1, 1, 0, 1,
2436
+ 0, 1, 0, 1,
2437
+ // Normal
2438
+ 0, 0, 1,
2439
+ // Vertices
2440
+ -0.5, -0.5, 0, 1,
2441
+ 0.5, -0.5, 0, 1,
2442
+ 0.5, 0.5, 0, 1,
2443
+ -0.5, -0.5, 0, 1,
2444
+ 0.5, 0.5, 0, 1,
2445
+ -0.5, 0.5, 0, 1,
2446
+ ]);
1714
2447
 
1715
2448
  function ParticleSystem (executionContext)
1716
2449
  {
@@ -1720,39 +2453,25 @@ function (Fields,
1720
2453
 
1721
2454
  this ._particleSize .setUnit ("length");
1722
2455
 
1723
- this .createParticles = true;
1724
- this .particles = [ ];
1725
- this .velocities = [ ];
1726
- this .speeds = [ ];
1727
- this .turbulences = [ ];
1728
- this .geometryType = POINT;
1729
2456
  this .maxParticles = 0;
1730
2457
  this .numParticles = 0;
1731
- this .particleLifetime = 0;
1732
- this .lifetimeVariation = 0;
1733
- this .emitterNode = null;
1734
2458
  this .forcePhysicsModelNodes = [ ];
2459
+ this .forces = new Float32Array (4);
1735
2460
  this .boundedPhysicsModelNodes = [ ];
1736
2461
  this .boundedNormals = [ ];
1737
2462
  this .boundedVertices = [ ];
1738
- this .boundedVolume = null;
2463
+ this .colorRamp = new Float32Array ();
2464
+ this .texCoordRamp = new Float32Array ();
2465
+ this .geometryContext = { };
1739
2466
  this .creationTime = 0;
1740
2467
  this .pauseTime = 0;
1741
2468
  this .deltaTime = 0;
1742
- this .numForces = 0;
1743
- this .colorKeys = [ ];
1744
- this .colorRamppNode = null;
1745
- this .colorRamp = [ ];
1746
- this .texCoordKeys = [ ];
1747
- this .texCoordRampNode = null;
1748
- this .texCoordRamp = [ ];
1749
- this .texCoordAnim = false;
1750
- this .vertexCount = 0;
1751
- this .shaderNode = null;
1752
- this .rotation = new Matrix3 ();
1753
- this .particleSorter = new QuickSort (this .particles, compareDistance);
1754
- this .sortParticles = false;
1755
- this .geometryContext = { };
2469
+ this .particleStride = Float32Array .BYTES_PER_ELEMENT * 7 * 4; // 7 x vec4
2470
+ this .particleOffsets = Array .from ({length: 7}, (_, i) => Float32Array .BYTES_PER_ELEMENT * 4 * i); // i x vec4
2471
+ this .particleOffset = this .particleOffsets [0];
2472
+ this .colorOffset = this .particleOffsets [1];
2473
+ this .matrixOffset = this .particleOffsets [3];
2474
+ this .texCoordOffset = 0;
1756
2475
  }
1757
2476
 
1758
2477
  ParticleSystem .prototype = Object .assign (Object .create (X3DShapeNode .prototype),
@@ -1802,6 +2521,9 @@ function (Fields,
1802
2521
  browser = this .getBrowser (),
1803
2522
  gl = browser .getContext ();
1804
2523
 
2524
+ if (browser .getContext () .getVersion () < 2)
2525
+ return;
2526
+
1805
2527
  this .isLive () .addInterest ("set_live__", this);
1806
2528
 
1807
2529
  browser .getBrowserOptions () ._Shading .addInterest ("set_shader__", this);
@@ -1809,6 +2531,7 @@ function (Fields,
1809
2531
  this ._enabled .addInterest ("set_enabled__", this);
1810
2532
  this ._createParticles .addInterest ("set_createParticles__", this);
1811
2533
  this ._geometryType .addInterest ("set_geometryType__", this);
2534
+ this ._geometryType .addInterest ("set_texCoord__", this);
1812
2535
  this ._maxParticles .addInterest ("set_enabled__", this);
1813
2536
  this ._particleLifetime .addInterest ("set_particleLifetime__", this);
1814
2537
  this ._lifetimeVariation .addInterest ("set_lifetimeVariation__", this);
@@ -1819,38 +2542,42 @@ function (Fields,
1819
2542
  this ._texCoordKey .addInterest ("set_texCoord__", this);
1820
2543
  this ._texCoordRamp .addInterest ("set_texCoordRamp__", this);
1821
2544
 
1822
- this .idBuffer = gl .createBuffer ();
1823
- this .positionBuffer = gl .createBuffer ();
1824
- this .elapsedTimeBuffer = gl .createBuffer ();
1825
- this .lifeBuffer = gl .createBuffer ();
1826
- this .colorBuffer = gl .createBuffer ();
1827
- this .texCoordBuffers = [ gl .createBuffer () ];
1828
- this .normalBuffer = gl .createBuffer ();
1829
- this .vertexBuffer = gl .createBuffer ();
1830
-
1831
- for (var i = 1, channels = this .getBrowser () .getMaxTextures (); i < channels; ++ i)
1832
- this .texCoordBuffers .push (this .texCoordBuffers [0]);
1833
-
1834
- this .idArray = new Float32Array ();
1835
- this .positionArray = new Float32Array ();
1836
- this .elapsedTimeArray = new Float32Array ();
1837
- this .lifeArray = new Float32Array ();
1838
- this .colorArray = new Float32Array ();
1839
- this .texCoordArray = new Float32Array ();
1840
- this .normalArray = new Float32Array ();
1841
- this .vertexArray = new Float32Array ();
1842
-
1843
- this .primitiveMode = gl .TRIANGLES;
2545
+ // Create particles stuff.
2546
+
2547
+ this .inputParticles = this .createBuffer ();
2548
+ this .outputParticles = this .createBuffer ();
2549
+
2550
+ this .inputParticles . emitterArrayObject = new VertexArray ();
2551
+ this .inputParticles . vertexArrayObject = new VertexArray ();
2552
+ this .inputParticles .shadowArrayObject = new VertexArray ();
2553
+ this .outputParticles .emitterArrayObject = new VertexArray ();
2554
+ this .outputParticles .vertexArrayObject = new VertexArray ();
2555
+ this .outputParticles .shadowArrayObject = new VertexArray ();
2556
+
2557
+ // Create forces stuff.
2558
+
2559
+ this .forcesTexture = this .createTexture ();
2560
+ this .boundedTexture = this .createTexture ();
2561
+ this .colorRampTexture = this .createTexture ();
2562
+ this .texCoordRampTexture = this .createTexture ();
2563
+
2564
+ // Create GL stuff.
2565
+
2566
+ this .geometryBuffer = this .createBuffer ();
2567
+ this .texCoordBuffers = new Array (browser .getMaxTextures ()) .fill (this .geometryBuffer);
1844
2568
 
1845
2569
  // Geometry context
1846
2570
 
1847
- this .geometryContext .fogCoords = false;
2571
+ this .geometryContext .fogCoords = false;
1848
2572
  this .geometryContext .textureCoordinateNode = browser .getDefaultTextureCoordinate ();
1849
2573
  this .geometryContext .textureCoordinateMapping = new Map ();
1850
2574
 
1851
- // Call order is higly important at startup.
2575
+ // Init fields.
2576
+ // Call order is very important at startup.
2577
+
1852
2578
  this .set_emitter__ ();
1853
2579
  this .set_enabled__ ();
2580
+ this .set_geometryType__ ();
1854
2581
  this .set_createParticles__ ();
1855
2582
  this .set_particleLifetime__ ();
1856
2583
  this .set_lifetimeVariation__ ();
@@ -1874,7 +2601,7 @@ function (Fields,
1874
2601
  {
1875
2602
  switch (this .geometryType)
1876
2603
  {
1877
- case POINT:
2604
+ case GeometryTypes .POINT:
1878
2605
  {
1879
2606
  this .setTransparent (true);
1880
2607
  break;
@@ -1883,7 +2610,7 @@ function (Fields,
1883
2610
  {
1884
2611
  this .setTransparent (this .getAppearance () .getTransparent () ||
1885
2612
  (this .colorRampNode && this .colorRampNode .getTransparent ()) ||
1886
- (this .geometryType === GEOMETRY && this .geometryNode && this .geometryNode .getTransparent ()));
2613
+ (this .geometryType === GeometryTypes .GEOMETRY && this .geometryNode && this .geometryNode .getTransparent ()));
1887
2614
  break;
1888
2615
  }
1889
2616
  }
@@ -1923,7 +2650,7 @@ function (Fields,
1923
2650
  {
1924
2651
  if (this ._enabled .getValue () && this ._maxParticles .getValue ())
1925
2652
  {
1926
- if (! this ._isActive .getValue ())
2653
+ if (!this ._isActive .getValue ())
1927
2654
  {
1928
2655
  if (this .isLive () .getValue ())
1929
2656
  {
@@ -1935,6 +2662,8 @@ function (Fields,
1935
2662
  this .pauseTime = performance .now () / 1000;
1936
2663
 
1937
2664
  this ._isActive = true;
2665
+
2666
+ delete this .traverse;
1938
2667
  }
1939
2668
  }
1940
2669
  else
@@ -1949,6 +2678,7 @@ function (Fields,
1949
2678
  this ._isActive = false;
1950
2679
 
1951
2680
  this .numParticles = 0;
2681
+ this .traverse = Function .prototype;
1952
2682
  }
1953
2683
  }
1954
2684
 
@@ -1960,161 +2690,83 @@ function (Fields,
1960
2690
  },
1961
2691
  set_geometryType__: function ()
1962
2692
  {
1963
- var
1964
- gl = this .getBrowser () .getContext (),
1965
- maxParticles = this .maxParticles;
1966
-
1967
- // geometryType
2693
+ const
2694
+ browser = this .getBrowser (),
2695
+ gl = browser .getContext ();
1968
2696
 
1969
- this .geometryType = GeometryTypes [this ._geometryType .getValue ()];
2697
+ // Set geometryType.
1970
2698
 
1971
- if (! this .geometryType)
1972
- this .geometryType = POINT;
2699
+ this .geometryType = GeometryTypes .hasOwnProperty (this ._geometryType .getValue ())
2700
+ ? GeometryTypes [this ._geometryType .getValue ()]
2701
+ : GeometryTypes .QUAD;
1973
2702
 
1974
- // Create buffers
2703
+ // Create buffers.
1975
2704
 
1976
2705
  switch (this .geometryType)
1977
2706
  {
1978
- case POINT:
2707
+ case GeometryTypes .POINT:
1979
2708
  {
1980
- this .idArray = new Float32Array (maxParticles);
1981
- this .positionArray = new Float32Array (3 * maxParticles);
1982
- this .elapsedTimeArray = new Float32Array (maxParticles);
1983
- this .lifeArray = new Float32Array (maxParticles);
1984
- this .colorArray = new Float32Array (4 * maxParticles);
1985
- this .texCoordArray = new Float32Array ();
1986
- this .normalArray = new Float32Array ();
1987
- this .vertexArray = new Float32Array (4 * maxParticles);
1988
-
1989
- for (var i = 0, a = this .idArray, l = a .length; i < l; ++ i)
1990
- a [i] = i;
1991
-
1992
- this .colorArray .fill (1);
1993
- this .vertexArray .fill (1);
1994
-
1995
- this .testWireframe = false;
1996
- this .primitiveMode = gl .POINTS;
2709
+ this .geometryContext .geometryType = 0;
2710
+
1997
2711
  this .texCoordCount = 0;
1998
2712
  this .vertexCount = 1;
2713
+ this .hasNormals = false;
2714
+ this .primitiveMode = gl .POINTS;
2715
+
2716
+ this .verticesOffset = 0;
2717
+
2718
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
2719
+ gl .bufferData (gl .ARRAY_BUFFER, PointGeometry, gl .DYNAMIC_DRAW);
1999
2720
 
2000
- this .geometryContext .geometryType = 0;
2001
2721
  break;
2002
2722
  }
2003
- case LINE:
2723
+ case GeometryTypes .LINE:
2004
2724
  {
2005
- this .idArray = new Float32Array (2 * maxParticles);
2006
- this .positionArray = new Float32Array (2 * 3 * maxParticles);
2007
- this .elapsedTimeArray = new Float32Array (2 * maxParticles);
2008
- this .lifeArray = new Float32Array (2 * maxParticles);
2009
- this .colorArray = new Float32Array (2 * 4 * maxParticles);
2010
- this .texCoordArray = new Float32Array ();
2011
- this .normalArray = new Float32Array ();
2012
- this .vertexArray = new Float32Array (2 * 4 * maxParticles);
2013
-
2014
- for (var i = 0, a = this .idArray, l = a .length; i < l; ++ i)
2015
- a [i] = Math .floor (i / 2);
2016
-
2017
- this .colorArray .fill (1);
2018
- this .vertexArray .fill (1);
2019
-
2020
- this .testWireframe = false;
2021
- this .primitiveMode = gl .LINES;
2725
+ this .geometryContext .geometryType = 1;
2726
+
2022
2727
  this .texCoordCount = 2;
2023
2728
  this .vertexCount = 2;
2729
+ this .hasNormals = false;
2730
+ this .primitiveMode = gl .LINES;
2024
2731
 
2025
- this .geometryContext .geometryType = 1;
2026
- break;
2027
- }
2028
- case TRIANGLE:
2029
- case QUAD:
2030
- case SPRITE:
2031
- {
2032
- this .idArray = new Float32Array (6 * maxParticles);
2033
- this .positionArray = new Float32Array (6 * 3 * maxParticles);
2034
- this .elapsedTimeArray = new Float32Array (6 * maxParticles);
2035
- this .lifeArray = new Float32Array (6 * maxParticles);
2036
- this .colorArray = new Float32Array (6 * 4 * maxParticles);
2037
- this .texCoordArray = new Float32Array (6 * 4 * maxParticles);
2038
- this .normalArray = new Float32Array (6 * 3 * maxParticles);
2039
- this .vertexArray = new Float32Array (6 * 4 * maxParticles);
2040
-
2041
- for (var i = 0, a = this .idArray, l = a .length; i < l; ++ i)
2042
- a [i] = Math .floor (i / 6);
2043
-
2044
- this .colorArray .fill (1);
2045
- this .vertexArray .fill (1);
2046
-
2047
- var
2048
- texCoordArray = this .texCoordArray,
2049
- normalArray = this .normalArray;
2050
-
2051
- for (var i = 0, length = 6 * 3 * maxParticles; i < length; i += 3)
2052
- {
2053
- normalArray [i] = 0;
2054
- normalArray [i + 1] = 0;
2055
- normalArray [i + 2] = 1;
2056
- }
2057
-
2058
- gl .bindBuffer (gl .ARRAY_BUFFER, this .normalBuffer);
2059
- gl .bufferData (gl .ARRAY_BUFFER, this .normalArray, gl .STATIC_DRAW);
2732
+ this .texCoordsOffset = 0;
2733
+ this .verticesOffset = Float32Array .BYTES_PER_ELEMENT * 8;
2060
2734
 
2061
- for (var i = 0; i < maxParticles; ++ i)
2062
- {
2063
- var i24 = i * 24;
2064
-
2065
- // p4 ------ p3
2066
- // | / |
2067
- // | / |
2068
- // | / |
2069
- // | / |
2070
- // p1 ------ p2
2071
-
2072
- // p1
2073
- texCoordArray [i24] = texCoordArray [i24 + 12] = 0;
2074
- texCoordArray [i24 + 1] = texCoordArray [i24 + 13] = 0;
2075
- texCoordArray [i24 + 2] = texCoordArray [i24 + 14] = 0;
2076
- texCoordArray [i24 + 3] = texCoordArray [i24 + 15] = 1;
2077
-
2078
- // p2
2079
- texCoordArray [i24 + 4] = 1;
2080
- texCoordArray [i24 + 5] = 0;
2081
- texCoordArray [i24 + 6] = 0;
2082
- texCoordArray [i24 + 7] = 1;
2083
-
2084
- // p3
2085
- texCoordArray [i24 + 8] = texCoordArray [i24 + 16] = 1;
2086
- texCoordArray [i24 + 9] = texCoordArray [i24 + 17] = 1;
2087
- texCoordArray [i24 + 10] = texCoordArray [i24 + 18] = 0;
2088
- texCoordArray [i24 + 11] = texCoordArray [i24 + 19] = 1;
2089
-
2090
- // p4
2091
- texCoordArray [i24 + 20] = 0;
2092
- texCoordArray [i24 + 21] = 1;
2093
- texCoordArray [i24 + 22] = 0;
2094
- texCoordArray [i24 + 23] = 1;
2095
- }
2735
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
2736
+ gl .bufferData (gl .ARRAY_BUFFER, LineGeometry, gl .DYNAMIC_DRAW);
2096
2737
 
2097
- gl .bindBuffer (gl .ARRAY_BUFFER, this .texCoordBuffers [0]);
2098
- gl .bufferData (gl .ARRAY_BUFFER, this .texCoordArray, gl .STATIC_DRAW);
2738
+ break;
2739
+ }
2740
+ case GeometryTypes .TRIANGLE:
2741
+ case GeometryTypes .QUAD:
2742
+ case GeometryTypes .SPRITE:
2743
+ {
2744
+ this .geometryContext .geometryType = 2;
2099
2745
 
2100
- this .testWireframe = true;
2101
- this .primitiveMode = gl .TRIANGLES;
2102
2746
  this .texCoordCount = 4;
2103
2747
  this .vertexCount = 6;
2748
+ this .hasNormals = true;
2749
+ this .primitiveMode = gl .TRIANGLES;
2750
+
2751
+ this .texCoordsOffset = 0;
2752
+ this .normalOffset = Float32Array .BYTES_PER_ELEMENT * 24;
2753
+ this .verticesOffset = Float32Array .BYTES_PER_ELEMENT * 27;
2754
+
2755
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
2756
+ gl .bufferData (gl .ARRAY_BUFFER, QuadGeometry, gl .DYNAMIC_DRAW);
2104
2757
 
2105
- this .geometryContext .geometryType = 2;
2106
2758
  break;
2107
2759
  }
2108
- case GEOMETRY:
2760
+ case GeometryTypes .GEOMETRY:
2109
2761
  {
2110
2762
  this .texCoordCount = 0;
2111
2763
  this .vertexCount = 0;
2764
+
2112
2765
  break;
2113
2766
  }
2114
2767
  }
2115
2768
 
2116
- gl .bindBuffer (gl .ARRAY_BUFFER, this .idBuffer);
2117
- gl .bufferData (gl .ARRAY_BUFFER, this .idArray, gl .STATIC_DRAW);
2769
+ this .updateVertexArrays ();
2118
2770
 
2119
2771
  this .set_shader__ ();
2120
2772
  this .set_transparent__ ();
@@ -2123,20 +2775,17 @@ function (Fields,
2123
2775
  {
2124
2776
  switch (this .geometryType)
2125
2777
  {
2126
- case POINT:
2778
+ case GeometryTypes .POINT:
2127
2779
  {
2128
2780
  this .shaderNode = this .getBrowser () .getPointShader ();
2129
2781
  break;
2130
2782
  }
2131
- case LINE:
2783
+ case GeometryTypes .LINE:
2132
2784
  {
2133
2785
  this .shaderNode = this .getBrowser () .getLineShader ();
2134
2786
  break;
2135
2787
  }
2136
- case TRIANGLE:
2137
- case QUAD:
2138
- case SPRITE:
2139
- case GEOMETRY:
2788
+ default:
2140
2789
  {
2141
2790
  this .shaderNode = null;
2142
2791
  break;
@@ -2145,37 +2794,18 @@ function (Fields,
2145
2794
  },
2146
2795
  set_maxParticles__: function ()
2147
2796
  {
2148
- var
2149
- particles = this .particles,
2150
- maxParticles = Math .max (0, this ._maxParticles .getValue ());
2151
-
2152
- for (var i = this .numParticles, length = Math .min (particles .length, maxParticles); i < length; ++ i)
2153
- {
2154
- particles [i] .life = 1;
2155
- particles [i] .lifetime = -1;
2156
- }
2157
-
2158
- for (var i = particles .length, length = maxParticles; i < length; ++ i)
2159
- {
2160
- particles [i] = {
2161
- id: i,
2162
- life: 1,
2163
- lifetime: -1,
2164
- elapsedTime: 0,
2165
- position: new Vector3 (0, 0, 0),
2166
- velocity: new Vector3 (0, 0, 0),
2167
- color: new Vector4 (1, 1, 1, 1),
2168
- distance: 0,
2169
- };
2170
- }
2797
+ const
2798
+ lastNumParticles = this .numParticles,
2799
+ maxParticles = Math .max (0, this ._maxParticles .getValue ());
2171
2800
 
2172
2801
  this .maxParticles = maxParticles;
2173
- this .numParticles = Math .min (this .numParticles, maxParticles);
2802
+ this .numParticles = Math .min (lastNumParticles, maxParticles);
2174
2803
 
2175
- if (! this .emitterNode .isExplosive ())
2804
+ if (!this .emitterNode .isExplosive ())
2176
2805
  this .creationTime = performance .now () / 1000;
2177
2806
 
2178
- this .set_geometryType__ ();
2807
+ this .resizeBuffers (lastNumParticles);
2808
+ this .updateVertexArrays ();
2179
2809
  },
2180
2810
  set_particleLifetime__: function ()
2181
2811
  {
@@ -2189,33 +2819,33 @@ function (Fields,
2189
2819
  {
2190
2820
  this .emitterNode = X3DCast (X3DConstants .X3DParticleEmitterNode, this ._emitter);
2191
2821
 
2192
- if (! this .emitterNode)
2822
+ if (!this .emitterNode)
2193
2823
  this .emitterNode = this .getBrowser () .getDefaultEmitter ();
2194
2824
 
2195
2825
  this .createParticles = this ._createParticles .getValue ();
2196
2826
  },
2197
2827
  set_physics__: function ()
2198
2828
  {
2199
- var
2829
+ const
2200
2830
  physics = this ._physics .getValue (),
2201
2831
  forcePhysicsModelNodes = this .forcePhysicsModelNodes,
2202
2832
  boundedPhysicsModelNodes = this .boundedPhysicsModelNodes;
2203
2833
 
2204
- for (var i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2834
+ for (let i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2205
2835
  boundedPhysicsModelNodes [i] .removeInterest ("set_boundedPhysics__", this);
2206
2836
 
2207
2837
  forcePhysicsModelNodes .length = 0;
2208
2838
  boundedPhysicsModelNodes .length = 0;
2209
2839
 
2210
- for (var i = 0, length = physics .length; i < length; ++ i)
2840
+ for (let i = 0, length = physics .length; i < length; ++ i)
2211
2841
  {
2212
2842
  try
2213
2843
  {
2214
- var
2844
+ const
2215
2845
  innerNode = physics [i] .getValue () .getInnerNode (),
2216
2846
  type = innerNode .getType ();
2217
2847
 
2218
- for (var t = type .length - 1; t >= 0; -- t)
2848
+ for (let t = type .length - 1; t >= 0; -- t)
2219
2849
  {
2220
2850
  switch (type [t])
2221
2851
  {
@@ -2246,7 +2876,8 @@ function (Fields,
2246
2876
  },
2247
2877
  set_boundedPhysics__: function ()
2248
2878
  {
2249
- var
2879
+ const
2880
+ gl = this .getBrowser () .getContext (),
2250
2881
  boundedPhysicsModelNodes = this .boundedPhysicsModelNodes,
2251
2882
  boundedNormals = this .boundedNormals,
2252
2883
  boundedVertices = this .boundedVertices;
@@ -2254,13 +2885,43 @@ function (Fields,
2254
2885
  boundedNormals .length = 0;
2255
2886
  boundedVertices .length = 0;
2256
2887
 
2257
- for (var i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2888
+ for (let i = 0, length = boundedPhysicsModelNodes .length; i < length; ++ i)
2258
2889
  {
2259
2890
  boundedPhysicsModelNodes [i] .addGeometry (boundedNormals, boundedVertices);
2260
2891
  }
2261
2892
 
2262
- this .boundedVolume = new BVH (boundedVertices, boundedNormals);
2263
- },
2893
+ // Texture
2894
+
2895
+ const
2896
+ boundedHierarchy = new BVH (boundedVertices, boundedNormals) .toArray ([ ]),
2897
+ numBoundedVertices = boundedVertices .length / 4,
2898
+ numBoundedNormals = boundedNormals .length / 3,
2899
+ boundedHierarchyLength = boundedHierarchy .length / 4,
2900
+ boundedArraySize = Math .ceil (Math .sqrt (numBoundedVertices + numBoundedNormals + boundedHierarchyLength)),
2901
+ boundedArray = new Float32Array (boundedArraySize * boundedArraySize * 4);
2902
+
2903
+ this .boundedVerticesIndex = 0;
2904
+ this .boundedNormalsIndex = numBoundedVertices;
2905
+ this .boundedHierarchyIndex = this .boundedNormalsIndex + numBoundedNormals;
2906
+ this .boundedHierarchyRoot = this .boundedHierarchyIndex + boundedHierarchyLength - 1;
2907
+
2908
+ boundedArray .set (boundedVertices);
2909
+
2910
+ for (let s = this .boundedNormalsIndex * 4, n = 0, l = boundedNormals .length; n < l; s += 4, n += 3)
2911
+ {
2912
+ boundedArray [s + 0] = boundedNormals [n + 0];
2913
+ boundedArray [s + 1] = boundedNormals [n + 1];
2914
+ boundedArray [s + 2] = boundedNormals [n + 2];
2915
+ }
2916
+
2917
+ boundedArray .set (boundedHierarchy, this .boundedHierarchyIndex * 4);
2918
+
2919
+ if (boundedArraySize)
2920
+ {
2921
+ gl .bindTexture (gl .TEXTURE_2D, this .boundedTexture);
2922
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, boundedArraySize, boundedArraySize, 0, gl .RGBA, gl .FLOAT, boundedArray);
2923
+ }
2924
+ },
2264
2925
  set_colorRamp__: function ()
2265
2926
  {
2266
2927
  if (this .colorRampNode)
@@ -2276,25 +2937,35 @@ function (Fields,
2276
2937
  },
2277
2938
  set_color__: function ()
2278
2939
  {
2279
- var
2280
- colorKey = this ._colorKey,
2281
- colorKeys = this .colorKeys,
2282
- colorRamp = this .colorRamp;
2940
+ const
2941
+ gl = this .getBrowser () .getContext (),
2942
+ colorKey = this ._colorKey,
2943
+ numColors = colorKey .length,
2944
+ textureSize = Math .ceil (Math .sqrt (numColors * 2));
2945
+
2946
+ let colorRamp = this .colorRamp;
2283
2947
 
2284
- for (var i = 0, length = colorKey .length; i < length; ++ i)
2285
- colorKeys [i] = colorKey [i];
2948
+ if (textureSize * textureSize * 4 > colorRamp .length)
2949
+ colorRamp = this .colorRamp = new Float32Array (textureSize * textureSize * 4);
2286
2950
 
2287
- colorKeys .length = length;
2951
+ for (let i = 0; i < numColors; ++ i)
2952
+ colorRamp [i * 4] = colorKey [i];
2288
2953
 
2289
2954
  if (this .colorRampNode)
2290
- this .colorRampNode .getVectors (this .colorRamp);
2955
+ colorRamp .set (this .colorRampNode .addColors ([ ], numColors) .slice (0, numColors * 4), numColors * 4);
2956
+ else
2957
+ colorRamp .fill (1, numColors * 4);
2291
2958
 
2292
- for (var i = colorRamp .length, length = colorKey .length; i < length; ++ i)
2293
- colorRamp [i] = new Vector4 (1, 1, 1, 1);
2959
+ if (textureSize)
2960
+ {
2961
+ gl .bindTexture (gl .TEXTURE_2D, this .colorRampTexture);
2962
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, textureSize, textureSize, 0, gl .RGBA, gl .FLOAT, colorRamp);
2963
+ }
2294
2964
 
2295
- colorRamp .length = length;
2965
+ this .numColors = numColors;
2966
+ this .geometryContext .colorMaterial = !! (numColors && this .colorRampNode);
2296
2967
 
2297
- this .geometryContext .colorMaterial = !! (colorKeys .length && this .colorRampNode);
2968
+ this .updateVertexArrays ();
2298
2969
  },
2299
2970
  set_texCoordRamp__: function ()
2300
2971
  {
@@ -2310,48 +2981,117 @@ function (Fields,
2310
2981
  },
2311
2982
  set_texCoord__: function ()
2312
2983
  {
2313
- var
2984
+ const
2985
+ gl = this .getBrowser () .getContext (),
2314
2986
  texCoordKey = this ._texCoordKey,
2315
- texCoordKeys = this .texCoordKeys,
2316
- texCoordRamp = this .texCoordRamp;
2987
+ numTexCoords = texCoordKey .length,
2988
+ textureSize = Math .ceil (Math .sqrt (numTexCoords + numTexCoords * this .texCoordCount));
2317
2989
 
2318
- for (var i = 0, length = texCoordKey .length; i < length; ++ i)
2319
- texCoordKeys [i] = texCoordKey [i];
2990
+ let texCoordRamp = this .texCoordRamp;
2320
2991
 
2321
- texCoordKeys .length = length;
2992
+ if (textureSize * textureSize * 4 > texCoordRamp .length)
2993
+ texCoordRamp = this .texCoordRamp = new Float32Array (textureSize * textureSize * 4);
2994
+ else
2995
+ texCoordRamp .fill (0);
2996
+
2997
+ for (let i = 0; i < numTexCoords; ++ i)
2998
+ texCoordRamp [i * 4] = texCoordKey [i];
2322
2999
 
2323
3000
  if (this .texCoordRampNode)
2324
- this .texCoordRampNode .getTexCoord (texCoordRamp);
3001
+ texCoordRamp .set (this .texCoordRampNode .getTexCoord ([ ]) .slice (0, numTexCoords * this .texCoordCount * 4), numTexCoords * 4);
2325
3002
 
2326
- for (var i = texCoordRamp .length, length = texCoordKey .length * this .texCoordCount; i < length; ++ i)
2327
- texCoordRamp [i] = new Vector4 (0, 0, 0, 0);
3003
+ if (textureSize)
3004
+ {
3005
+ gl .bindTexture (gl .TEXTURE_2D, this .texCoordRampTexture);
3006
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, textureSize, textureSize, 0, gl .RGBA, gl .FLOAT, texCoordRamp);
3007
+ }
2328
3008
 
2329
- texCoordRamp .length = length;
3009
+ this .numTexCoords = this .texCoordRampNode ? numTexCoords : 0;
2330
3010
 
2331
- this .texCoordAnim = !! (texCoordKeys .length && this .texCoordRampNode);
3011
+ this .updateVertexArrays ();
2332
3012
  },
2333
- intersectsBox: function (box, clipPlanes)
3013
+ updateVertexArrays: function ()
3014
+ {
3015
+ this .inputParticles .vertexArrayObject .update ();
3016
+ this .inputParticles .shadowArrayObject .update ();
3017
+ this .inputParticles .emitterArrayObject .update ();
3018
+ this .outputParticles .vertexArrayObject .update ();
3019
+ this .outputParticles .shadowArrayObject .update ();
3020
+ this .outputParticles .emitterArrayObject .update ();
3021
+ },
3022
+ createTexture: function ()
3023
+ {
3024
+ const
3025
+ gl = this .getBrowser () .getContext (),
3026
+ texture = gl .createTexture ();
3027
+
3028
+ gl .bindTexture (gl .TEXTURE_2D, texture);
3029
+
3030
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_S, gl .CLAMP_TO_EDGE);
3031
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_WRAP_T, gl .CLAMP_TO_EDGE);
3032
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MAG_FILTER, gl .NEAREST);
3033
+ gl .texParameteri (gl .TEXTURE_2D, gl .TEXTURE_MIN_FILTER, gl .NEAREST);
3034
+
3035
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, 1, 1, 0, gl .RGBA, gl .FLOAT, new Float32Array (4));
3036
+
3037
+ return texture;
3038
+ },
3039
+ createBuffer: function ()
3040
+ {
3041
+ const
3042
+ gl = this .getBrowser () .getContext (),
3043
+ buffer = gl .createBuffer ();
3044
+
3045
+ gl .bindBuffer (gl .ARRAY_BUFFER, buffer);
3046
+ gl .bufferData (gl .ARRAY_BUFFER, new Uint32Array (), gl .DYNAMIC_DRAW);
3047
+
3048
+ return buffer;
3049
+ },
3050
+ resizeBuffers: function (lastNumParticles)
2334
3051
  {
2335
- // TODO: implement me.
3052
+ const
3053
+ gl = this .getBrowser () .getContext (),
3054
+ maxParticles = this .maxParticles,
3055
+ particleStride = this .particleStride,
3056
+ outputParticles = Object .assign (gl .createBuffer (), this .outputParticles),
3057
+ data = new Uint8Array (maxParticles * particleStride);
3058
+
3059
+ // Resize input buffer.
3060
+
3061
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .inputParticles);
3062
+ gl .bufferData (gl .ARRAY_BUFFER, data, gl .DYNAMIC_DRAW);
3063
+
3064
+ // Resize output buffer.
3065
+
3066
+ gl .bindBuffer (gl .COPY_READ_BUFFER, this .outputParticles);
3067
+ gl .bindBuffer (gl .ARRAY_BUFFER, outputParticles);
3068
+ gl .bufferData (gl .ARRAY_BUFFER, data, gl .DYNAMIC_DRAW);
3069
+ gl .copyBufferSubData (gl .COPY_READ_BUFFER, gl .ARRAY_BUFFER, 0, 0, Math .min (maxParticles * particleStride, lastNumParticles * particleStride));
3070
+ gl .deleteBuffer (this .outputParticles);
3071
+
3072
+ this .outputParticles = outputParticles;
2336
3073
  },
2337
3074
  animateParticles: function ()
2338
3075
  {
2339
- var emitterNode = this .emitterNode;
3076
+ const
3077
+ browser = this .getBrowser (),
3078
+ gl = browser .getContext (),
3079
+ emitterNode = this .emitterNode;
2340
3080
 
2341
3081
  // Determine delta time
2342
3082
 
2343
- var
2344
- DELAY = 15, // Delay in frames when dt full applys.
3083
+ const
3084
+ DELAY = 15, // Delay in frames when dt fully applies.
2345
3085
  dt = 1 / Math .max (10, this .getBrowser () .getCurrentFrameRate ());
2346
3086
 
2347
- // var deltaTime is only for the emitter, this.deltaTime is for the forces.
2348
- var deltaTime = this .deltaTime = ((DELAY - 1) * this .deltaTime + dt) / DELAY; // Moving average about DELAY frames.
3087
+ // let deltaTime is only for the emitter, this.deltaTime is for the forces.
3088
+ let deltaTime = this .deltaTime = ((DELAY - 1) * this .deltaTime + dt) / DELAY; // Moving average about DELAY frames.
2349
3089
 
2350
3090
  // Determine numParticles
2351
3091
 
2352
3092
  if (emitterNode .isExplosive ())
2353
3093
  {
2354
- var
3094
+ const
2355
3095
  now = performance .now () / 1000,
2356
3096
  particleLifetime = this .particleLifetime + this .particleLifetime * this .lifetimeVariation;
2357
3097
 
@@ -2370,7 +3110,7 @@ function (Fields,
2370
3110
  {
2371
3111
  if (this .numParticles < this .maxParticles)
2372
3112
  {
2373
- var
3113
+ const
2374
3114
  now = performance .now () / 1000,
2375
3115
  newParticles = Math .max (0, Math .floor ((now - this .creationTime) * this .maxParticles / this .particleLifetime));
2376
3116
 
@@ -2385,548 +3125,106 @@ function (Fields,
2385
3125
 
2386
3126
  if (emitterNode .getMass ())
2387
3127
  {
2388
- var
2389
- forcePhysicsModelNodes = this .forcePhysicsModelNodes,
2390
- velocities = this .velocities,
2391
- speeds = this .speeds,
2392
- turbulences = this .turbulences,
2393
- deltaMass = this .deltaTime / emitterNode .getMass ();
3128
+ const forcePhysicsModelNodes = this .forcePhysicsModelNodes;
2394
3129
 
2395
- // Collect forces in velocities and collect turbulences.
3130
+ let
3131
+ numForces = forcePhysicsModelNodes .length,
3132
+ forces = this .forces,
3133
+ timeByMass = deltaTime / emitterNode .getMass ();
2396
3134
 
2397
- for (var i = velocities .length, length = forcePhysicsModelNodes .length; i < length; ++ i)
2398
- velocities [i] = new Vector3 (0, 0, 0);
3135
+ // Collect forces in velocities and collect turbulences.
2399
3136
 
2400
- for (var i = 0, length = forcePhysicsModelNodes .length; i < length; ++ i)
2401
- forcePhysicsModelNodes [i] .addForce (i, emitterNode, velocities, turbulences);
3137
+ if (numForces * 4 > forces .length)
3138
+ forces = this .forces = new Float32Array (numForces * 4);
2402
3139
 
2403
- // Determine velocities from forces and determine speed.
3140
+ let disabledForces = 0;
2404
3141
 
2405
- for (var i = 0, length = velocities .length; i < length; ++ i)
3142
+ for (let i = 0; i < numForces; ++ i)
2406
3143
  {
2407
- velocities [i] .multiply (deltaMass);
2408
- speeds [i] = velocities [i] .abs ();
3144
+ disabledForces += !forcePhysicsModelNodes [i] .addForce (i - disabledForces, emitterNode, timeByMass, forces);
2409
3145
  }
2410
3146
 
2411
- this .numForces = length;
2412
- }
2413
- else
2414
- {
2415
- this .numForces = 0;
2416
- }
2417
-
2418
- // Determine particle position, velocity and colors
2419
-
2420
- emitterNode .animate (this, deltaTime);
2421
-
2422
- this .updateGeometry (null);
3147
+ this .numForces = numForces -= disabledForces;
2423
3148
 
2424
- this .getBrowser () .addBrowserEvent ();
2425
- },
2426
- updateGeometry: function (modelViewMatrix)
2427
- {
2428
- switch (this .geometryType)
2429
- {
2430
- case POINT:
2431
- if (! modelViewMatrix)
2432
- this .updatePoint ();
2433
- break;
2434
- case LINE:
2435
- if (! modelViewMatrix)
2436
- this .updateLine ();
2437
- break;
2438
- case TRIANGLE:
2439
- case QUAD:
2440
- case SPRITE:
2441
- this .updateQuad (modelViewMatrix);
2442
- break;
2443
- case GEOMETRY:
2444
- break;
2445
- }
2446
- },
2447
- updatePoint: function ()
2448
- {
2449
- var
2450
- gl = this .getBrowser () .getContext (),
2451
- particles = this .particles,
2452
- numParticles = this .numParticles,
2453
- positionArray = this .positionArray,
2454
- elapsedTimeArray = this .elapsedTimeArray,
2455
- lifeArray = this .lifeArray,
2456
- colorArray = this .colorArray,
2457
- vertexArray = this .vertexArray;
2458
-
2459
- // Colors
2460
-
2461
- if (this .geometryContext .colorMaterial)
2462
- {
2463
- for (var i = 0; i < numParticles; ++ i)
3149
+ if (numForces)
2464
3150
  {
2465
- var
2466
- color = particles [i] .color,
2467
- i4 = i * 4;
2468
-
2469
- colorArray [i4] = color .x;
2470
- colorArray [i4 + 1] = color .y;
2471
- colorArray [i4 + 2] = color .z;
2472
- colorArray [i4 + 3] = color .w;
3151
+ gl .bindTexture (gl .TEXTURE_2D, this .forcesTexture);
3152
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, numForces, 1, 0, gl .RGBA, gl .FLOAT, forces);
2473
3153
  }
2474
-
2475
- gl .bindBuffer (gl .ARRAY_BUFFER, this .colorBuffer);
2476
- gl .bufferData (gl .ARRAY_BUFFER, this .colorArray, gl .STATIC_DRAW);
2477
3154
  }
2478
-
2479
- // Vertices
2480
-
2481
- for (var i = 0; i < numParticles; ++ i)
3155
+ else
2482
3156
  {
2483
- var
2484
- position = particles [i] .position,
2485
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2486
- i3 = i * 3,
2487
- i4 = i * 4;
2488
-
2489
- positionArray [i3] = position .x;
2490
- positionArray [i3 + 1] = position .y;
2491
- positionArray [i3 + 2] = position .z;
2492
-
2493
- elapsedTimeArray [i] = elapsedTime;
2494
- lifeArray [i] = particles [i] .life;
2495
-
2496
- vertexArray [i4] = position .x;
2497
- vertexArray [i4 + 1] = position .y;
2498
- vertexArray [i4 + 2] = position .z;
3157
+ this .numForces = 0;
2499
3158
  }
2500
3159
 
2501
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2502
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2503
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2504
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2505
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2506
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2507
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2508
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
2509
- },
2510
- updateLine: function ()
2511
- {
2512
- var
2513
- gl = this .getBrowser () .getContext (),
2514
- particles = this .particles,
2515
- numParticles = this .numParticles,
2516
- positionArray = this .positionArray,
2517
- elapsedTimeArray = this .elapsedTimeArray,
2518
- lifeArray = this .lifeArray,
2519
- colorArray = this .colorArray,
2520
- vertexArray = this .vertexArray,
2521
- sy1_2 = this ._particleSize .y / 2;
2522
-
2523
- // Colors
2524
-
2525
- if (this .geometryContext .colorMaterial)
2526
- {
2527
- for (var i = 0; i < numParticles; ++ i)
2528
- {
2529
- var
2530
- color = particles [i] .color,
2531
- i8 = i * 8;
2532
-
2533
- colorArray [i8] = color .x;
2534
- colorArray [i8 + 1] = color .y;
2535
- colorArray [i8 + 2] = color .z;
2536
- colorArray [i8 + 3] = color .w;
2537
-
2538
- colorArray [i8 + 4] = color .x;
2539
- colorArray [i8 + 5] = color .y;
2540
- colorArray [i8 + 6] = color .z;
2541
- colorArray [i8 + 7] = color .w;
2542
- }
3160
+ // Swap buffers.
2543
3161
 
2544
- gl .bindBuffer (gl .ARRAY_BUFFER, this .colorBuffer);
2545
- gl .bufferData (gl .ARRAY_BUFFER, this .colorArray, gl .STATIC_DRAW);
2546
- }
3162
+ const inputParticles = this .outputParticles;
3163
+ this .outputParticles = this .inputParticles;
3164
+ this .inputParticles = inputParticles;
2547
3165
 
2548
- // Vertices
3166
+ // Determine particle position, velocity and colors.
2549
3167
 
2550
- for (var i = 0; i < numParticles; ++ i)
2551
- {
2552
- var
2553
- particle = particles [i],
2554
- position = particle .position,
2555
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2556
- life = particles [i] .life,
2557
- x = position .x,
2558
- y = position .y,
2559
- z = position .z,
2560
- i2 = i * 2,
2561
- i6 = i * 6,
2562
- i8 = i * 8;
2563
-
2564
- positionArray [i6] = x;
2565
- positionArray [i6 + 1] = y;
2566
- positionArray [i6 + 2] = z;
2567
- positionArray [i6 + 3] = x;
2568
- positionArray [i6 + 4] = y;
2569
- positionArray [i6 + 5] = z;
2570
-
2571
- elapsedTimeArray [i2] = elapsedTime;
2572
- elapsedTimeArray [i2 + 1] = elapsedTime;
2573
-
2574
- lifeArray [i2] = life;
2575
- lifeArray [i2 + 1] = life;
2576
-
2577
- // Length of line / 2.
2578
- normal .assign (particle .velocity) .normalize () .multiply (sy1_2);
2579
-
2580
- vertexArray [i8] = x - normal .x;
2581
- vertexArray [i8 + 1] = y - normal .y;
2582
- vertexArray [i8 + 2] = z - normal .z;
2583
-
2584
- vertexArray [i8 + 4] = x + normal .x;
2585
- vertexArray [i8 + 5] = y + normal .y;
2586
- vertexArray [i8 + 6] = z + normal .z;
2587
- }
3168
+ emitterNode .animate (this, deltaTime);
2588
3169
 
2589
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2590
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2591
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2592
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2593
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2594
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2595
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2596
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
3170
+ browser .addBrowserEvent ();
2597
3171
  },
2598
- updateQuad: function (modelViewMatrix)
3172
+ updateSprite: (function ()
2599
3173
  {
2600
- try
2601
- {
2602
- var
2603
- gl = this .getBrowser () .getContext (),
2604
- particles = this .particles,
2605
- maxParticles = this .maxParticles,
2606
- numParticles = this .numParticles,
2607
- positionArray = this .positionArray,
2608
- elapsedTimeArray = this .elapsedTimeArray,
2609
- lifeArray = this .lifeArray,
2610
- colorArray = this .colorArray,
2611
- texCoordArray = this .texCoordArray,
2612
- normalArray = this .normalArray,
2613
- vertexArray = this .vertexArray,
2614
- sx1_2 = this ._particleSize .x / 2,
2615
- sy1_2 = this ._particleSize .y / 2;
2616
-
2617
- // Sort particles
2618
-
2619
- // if (this .sortParticles) // always false
2620
- // {
2621
- // for (var i = 0; i < numParticles; ++ i)
2622
- // {
2623
- // var particle = particles [i];
2624
- // particle .distance = modelViewMatrix .getDepth (particle .position);
2625
- // }
2626
- //
2627
- // // Expensisive function!!!
2628
- // this .particleSorter .sort (0, numParticles);
2629
- // }
2630
-
2631
- // Colors
2632
-
2633
- if (! modelViewMatrix) // if called from animateParticles
2634
- {
2635
- if (this .geometryContext .colorMaterial)
2636
- {
2637
- for (var i = 0; i < maxParticles; ++ i)
2638
- {
2639
- var
2640
- color = particles [i] .color,
2641
- i24 = i * 24;
2642
-
2643
- // p4 ------ p3
2644
- // | / |
2645
- // | / |
2646
- // | / |
2647
- // | / |
2648
- // p1 ------ p2
2649
-
2650
- // p1, p2, p3; p1, p3, p4
2651
- colorArray [i24] = colorArray [i24 + 4] = colorArray [i24 + 8] = colorArray [i24 + 12] = colorArray [i24 + 16] = colorArray [i24 + 20] = color .x;
2652
- colorArray [i24 + 1] = colorArray [i24 + 5] = colorArray [i24 + 9] = colorArray [i24 + 13] = colorArray [i24 + 17] = colorArray [i24 + 21] = color .y;
2653
- colorArray [i24 + 2] = colorArray [i24 + 6] = colorArray [i24 + 10] = colorArray [i24 + 14] = colorArray [i24 + 18] = colorArray [i24 + 22] = color .z;
2654
- colorArray [i24 + 3] = colorArray [i24 + 7] = colorArray [i24 + 11] = colorArray [i24 + 15] = colorArray [i24 + 19] = colorArray [i24 + 23] = color .w;
2655
- }
2656
-
2657
- gl .bindBuffer (gl .ARRAY_BUFFER, this .colorBuffer);
2658
- gl .bufferData (gl .ARRAY_BUFFER, this .colorArray, gl .STATIC_DRAW);
2659
- }
2660
-
2661
- if (this .texCoordAnim && this .texCoordArray .length)
2662
- {
2663
- var
2664
- texCoordKeys = this .texCoordKeys,
2665
- texCoordRamp = this .texCoordRamp;
2666
-
2667
- var
2668
- length = texCoordKeys .length,
2669
- index0 = 0;
3174
+ const data = new Float32Array (QuadGeometry);
2670
3175
 
2671
- for (var i = 0; i < maxParticles; ++ i)
2672
- {
2673
- // Determine index0.
2674
-
2675
- var
2676
- particle = particles [i],
2677
- fraction = particle .elapsedTime / particle .lifetime;
2678
-
2679
- if (length == 1 || fraction <= texCoordKeys [0])
2680
- {
2681
- index0 = 0;
2682
- }
2683
- else if (fraction >= texCoordKeys .at (-1))
2684
- {
2685
- index0 = length - 2;
2686
- }
2687
- else
2688
- {
2689
- var index = Algorithm .upperBound (texCoordKeys, 0, length, fraction, Algorithm .less);
3176
+ const quad = [
3177
+ new Vector3 (-0.5, -0.5, 0),
3178
+ new Vector3 ( 0.5, -0.5, 0),
3179
+ new Vector3 ( 0.5, 0.5, 0),
3180
+ new Vector3 (-0.5, -0.5, 0),
3181
+ new Vector3 ( 0.5, 0.5, 0),
3182
+ new Vector3 (-0.5, 0.5, 0),
3183
+ ];
2690
3184
 
2691
- if (index < length)
2692
- index0 = index - 1;
2693
- else
2694
- index0 = 0;
2695
- }
3185
+ const
3186
+ vertex = new Vector3 (0, 0, 0),
3187
+ size = new Vector3 (0, 0, 0);
2696
3188
 
2697
- // Set texCoord.
2698
-
2699
- index0 *= this .texCoordCount;
2700
-
2701
- var
2702
- texCoord1 = texCoordRamp [index0],
2703
- texCoord2 = texCoordRamp [index0 + 1],
2704
- texCoord3 = texCoordRamp [index0 + 2],
2705
- texCoord4 = texCoordRamp [index0 + 3],
2706
- i24 = i * 24;
2707
-
2708
- // p4 ------ p3
2709
- // | / |
2710
- // | / |
2711
- // | / |
2712
- // | / |
2713
- // p1 ------ p2
2714
-
2715
- // p1
2716
- texCoordArray [i24] = texCoordArray [i24 + 12] = texCoord1 .x;
2717
- texCoordArray [i24 + 1] = texCoordArray [i24 + 13] = texCoord1 .y;
2718
- texCoordArray [i24 + 2] = texCoordArray [i24 + 14] = texCoord1 .z;
2719
- texCoordArray [i24 + 3] = texCoordArray [i24 + 15] = texCoord1 .w;
2720
-
2721
- // p2
2722
- texCoordArray [i24 + 4] = texCoord2 .x;
2723
- texCoordArray [i24 + 5] = texCoord2 .y;
2724
- texCoordArray [i24 + 6] = texCoord2 .z;
2725
- texCoordArray [i24 + 7] = texCoord2 .w;
2726
-
2727
- // p3
2728
- texCoordArray [i24 + 8] = texCoordArray [i24 + 16] = texCoord3 .x;
2729
- texCoordArray [i24 + 9] = texCoordArray [i24 + 17] = texCoord3 .y;
2730
- texCoordArray [i24 + 10] = texCoordArray [i24 + 18] = texCoord3 .z;
2731
- texCoordArray [i24 + 11] = texCoordArray [i24 + 19] = texCoord3 .w;
2732
-
2733
- // p4
2734
- texCoordArray [i24 + 20] = texCoord4 .x;
2735
- texCoordArray [i24 + 21] = texCoord4 .y;
2736
- texCoordArray [i24 + 22] = texCoord4 .z;
2737
- texCoordArray [i24 + 23] = texCoord4 .w;
2738
- }
3189
+ return function (gl, rotation)
3190
+ {
3191
+ // Normal
2739
3192
 
2740
- gl .bindBuffer (gl .ARRAY_BUFFER, this .texCoordBuffers [0]);
2741
- gl .bufferData (gl .ARRAY_BUFFER, this .texCoordArray, gl .STATIC_DRAW);
2742
- }
2743
- }
3193
+ for (let i = 0; i < 3; ++ i)
3194
+ data [24 + i] = rotation [6 + i];
2744
3195
 
2745
3196
  // Vertices
2746
3197
 
2747
- if (this .geometryType === SPRITE)
2748
- {
2749
- if (modelViewMatrix) // if called from depth or draw
2750
- {
2751
- // Normals
2752
-
2753
- var rotation = this .getScreenAlignedRotation (modelViewMatrix);
2754
-
2755
- normal
2756
- .set (rotation [0], rotation [1], rotation [2])
2757
- .cross (vector .set (rotation [3], rotation [4], rotation [5]))
2758
- .normalize ();
2759
-
2760
- var
2761
- nx = normal .x,
2762
- ny = normal .y,
2763
- nz = normal .z;
2764
-
2765
- for (var i = 0, length = 6 * 3 * maxParticles; i < length; i += 3)
2766
- {
2767
- normalArray [i] = nx;
2768
- normalArray [i + 1] = ny;
2769
- normalArray [i + 2] = nz;
2770
- }
2771
-
2772
- gl .bindBuffer (gl .ARRAY_BUFFER, this .normalBuffer);
2773
- gl .bufferData (gl .ARRAY_BUFFER, this .normalArray, gl .STATIC_DRAW);
2774
-
2775
- // Vertices
3198
+ size .set (this ._particleSize .x, this ._particleSize .y, 1);
2776
3199
 
2777
- s1 .set (-sx1_2, -sy1_2, 0);
2778
- s2 .set ( sx1_2, -sy1_2, 0);
2779
- s3 .set ( sx1_2, sy1_2, 0);
2780
- s4 .set (-sx1_2, sy1_2, 0);
2781
-
2782
- rotation .multVecMatrix (s1);
2783
- rotation .multVecMatrix (s2);
2784
- rotation .multVecMatrix (s3);
2785
- rotation .multVecMatrix (s4);
3200
+ for (let i = 0; i < 6; ++ i)
3201
+ {
3202
+ const index = 27 + i * 4;
2786
3203
 
2787
- for (var i = 0; i < numParticles; ++ i)
2788
- {
2789
- var
2790
- position = particles [i] .position,
2791
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2792
- x = position .x,
2793
- y = position .y,
2794
- z = position .z,
2795
- i6 = i * 6,
2796
- i18 = i * 18,
2797
- i24 = i * 24;
2798
-
2799
- // p4 ------ p3
2800
- // | / |
2801
- // | / |
2802
- // | / |
2803
- // | / |
2804
- // p1 ------ p2
2805
-
2806
-
2807
- positionArray [i18] = positionArray [i18 + 3] = positionArray [i18 + 6] = positionArray [i18 + 9] = positionArray [i18 + 12] = positionArray [i18 + 15] = x;
2808
- positionArray [i18 + 1] = positionArray [i18 + 4] = positionArray [i18 + 7] = positionArray [i18 + 10] = positionArray [i18 + 13] = positionArray [i18 + 16] = y;
2809
- positionArray [i18 + 2] = positionArray [i18 + 5] = positionArray [i18 + 8] = positionArray [i18 + 11] = positionArray [i18 + 14] = positionArray [i18 + 17] = z;
2810
-
2811
- elapsedTimeArray [i6] = elapsedTimeArray [i6 + 1] = elapsedTimeArray [i6 + 2] = elapsedTimeArray [i6 + 3] = elapsedTimeArray [i6 + 4] = elapsedTimeArray [i6 + 5] = elapsedTime;
2812
- lifeArray [i6] = lifeArray [i6 + 1] = lifeArray [i6 + 2] = lifeArray [i6 + 3] = lifeArray [i6 + 4] = lifeArray [i6 + 5] = particles [i] .life;
2813
-
2814
- // p1
2815
- vertexArray [i24] = vertexArray [i24 + 12] = x + s1 .x;
2816
- vertexArray [i24 + 1] = vertexArray [i24 + 13] = y + s1 .y;
2817
- vertexArray [i24 + 2] = vertexArray [i24 + 14] = z + s1 .z;
2818
-
2819
- // p2
2820
- vertexArray [i24 + 4] = x + s2 .x;
2821
- vertexArray [i24 + 5] = y + s2 .y;
2822
- vertexArray [i24 + 6] = z + s2 .z;
2823
-
2824
- // p3
2825
- vertexArray [i24 + 8] = vertexArray [i24 + 16] = x + s3 .x;
2826
- vertexArray [i24 + 9] = vertexArray [i24 + 17] = y + s3 .y;
2827
- vertexArray [i24 + 10] = vertexArray [i24 + 18] = z + s3 .z;
2828
-
2829
- // p4
2830
- vertexArray [i24 + 20] = x + s4 .x;
2831
- vertexArray [i24 + 21] = y + s4 .y;
2832
- vertexArray [i24 + 22] = z + s4 .z;
2833
- }
3204
+ rotation .multVecMatrix (vertex .assign (quad [i]) .multVec (size))
2834
3205
 
2835
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2836
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2837
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2838
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2839
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2840
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2841
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2842
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
2843
- }
3206
+ data [index + 0] = vertex .x;
3207
+ data [index + 1] = vertex .y;
3208
+ data [index + 2] = vertex .z;
2844
3209
  }
2845
- else
2846
- {
2847
- if (! modelViewMatrix) // if called from animateParticles
2848
- {
2849
- for (var i = 0; i < numParticles; ++ i)
2850
- {
2851
- var
2852
- position = particles [i] .position,
2853
- elapsedTime = particles [i] .elapsedTime / particles [i] .lifetime,
2854
- x = position .x,
2855
- y = position .y,
2856
- z = position .z,
2857
- i6 = i * 6,
2858
- i18 = i * 18,
2859
- i24 = i * 24;
2860
-
2861
- // p4 ------ p3
2862
- // | / |
2863
- // | / |
2864
- // | / |
2865
- // | / |
2866
- // p1 ------ p2
2867
-
2868
- positionArray [i18] = positionArray [i18 + 3] = positionArray [i18 + 6] = positionArray [i18 + 9] = positionArray [i18 + 12] = positionArray [i18 + 15] = x;
2869
- positionArray [i18 + 1] = positionArray [i18 + 4] = positionArray [i18 + 7] = positionArray [i18 + 10] = positionArray [i18 + 13] = positionArray [i18 + 16] = y;
2870
- positionArray [i18 + 2] = positionArray [i18 + 5] = positionArray [i18 + 8] = positionArray [i18 + 11] = positionArray [i18 + 14] = positionArray [i18 + 17] = z;
2871
-
2872
- elapsedTimeArray [i6] = elapsedTimeArray [i6 + 1] = elapsedTimeArray [i6 + 2] = elapsedTimeArray [i6 + 3] = elapsedTimeArray [i6 + 4] = elapsedTimeArray [i6 + 5] = elapsedTime;
2873
- lifeArray [i6] = lifeArray [i6 + 1] = lifeArray [i6 + 2] = lifeArray [i6 + 3] = lifeArray [i6 + 4] = lifeArray [i6 + 5] = particles [i] .life;
2874
-
2875
- // p1
2876
- vertexArray [i24] = vertexArray [i24 + 12] = x - sx1_2;
2877
- vertexArray [i24 + 1] = vertexArray [i24 + 13] = y - sy1_2;
2878
- vertexArray [i24 + 2] = vertexArray [i24 + 14] = z;
2879
-
2880
- // p2
2881
- vertexArray [i24 + 4] = x + sx1_2;
2882
- vertexArray [i24 + 5] = y - sy1_2;
2883
- vertexArray [i24 + 6] = z;
2884
-
2885
- // p3
2886
- vertexArray [i24 + 8] = vertexArray [i24 + 16] = x + sx1_2;
2887
- vertexArray [i24 + 9] = vertexArray [i24 + 17] = y + sy1_2;
2888
- vertexArray [i24 + 10] = vertexArray [i24 + 18] = z;
2889
-
2890
- // p4
2891
- vertexArray [i24 + 20] = x - sx1_2;
2892
- vertexArray [i24 + 21] = y + sy1_2;
2893
- vertexArray [i24 + 22] = z;
2894
- }
2895
3210
 
2896
- gl .bindBuffer (gl .ARRAY_BUFFER, this .positionBuffer);
2897
- gl .bufferData (gl .ARRAY_BUFFER, this .positionArray, gl .STATIC_DRAW);
2898
- gl .bindBuffer (gl .ARRAY_BUFFER, this .elapsedTimeBuffer);
2899
- gl .bufferData (gl .ARRAY_BUFFER, this .elapsedTimeArray, gl .STATIC_DRAW);
2900
- gl .bindBuffer (gl .ARRAY_BUFFER, this .lifeBuffer);
2901
- gl .bufferData (gl .ARRAY_BUFFER, this .lifeArray, gl .STATIC_DRAW);
2902
- gl .bindBuffer (gl .ARRAY_BUFFER, this .vertexBuffer);
2903
- gl .bufferData (gl .ARRAY_BUFFER, this .vertexArray, gl .STATIC_DRAW);
2904
- }
2905
- }
2906
- }
2907
- catch (error)
2908
- {
2909
- console .error (error);
2910
- }
2911
- },
3211
+ gl .bindBuffer (gl .ARRAY_BUFFER, this .geometryBuffer);
3212
+ gl .bufferData (gl .ARRAY_BUFFER, data, gl .DYNAMIC_DRAW);
3213
+ };
3214
+ })(),
3215
+ intersectsBox: function (box, clipPlanes)
3216
+ { },
2912
3217
  traverse: function (type, renderObject)
2913
3218
  {
2914
- if (! this ._isActive .getValue ())
3219
+ if (this .numParticles === 0)
2915
3220
  return;
2916
3221
 
2917
3222
  switch (type)
2918
3223
  {
2919
3224
  case TraverseType .POINTER:
2920
- {
2921
- break;
2922
- }
2923
3225
  case TraverseType .PICKING:
2924
- {
2925
- break;
2926
- }
2927
3226
  case TraverseType .COLLISION:
2928
3227
  {
2929
- // TODO: to be implemented.
2930
3228
  break;
2931
3229
  }
2932
3230
  case TraverseType .SHADOW:
@@ -2945,7 +3243,7 @@ function (Fields,
2945
3243
  }
2946
3244
  }
2947
3245
 
2948
- if (this .geometryType === GEOMETRY)
3246
+ if (this .geometryType === GeometryTypes .GEOMETRY)
2949
3247
  {
2950
3248
  if (this .getGeometry ())
2951
3249
  this .getGeometry () .traverse (type, renderObject); // Currently used for ScreenText.
@@ -2953,72 +3251,84 @@ function (Fields,
2953
3251
  },
2954
3252
  depth: function (gl, context, shaderNode)
2955
3253
  {
2956
- // Update geometry if SPRITE.
2957
-
2958
- this .updateGeometry (context .modelViewMatrix);
2959
-
2960
3254
  // Display geometry.
2961
3255
 
2962
- if (this .geometryType === GEOMETRY)
3256
+ switch (this .geometryType)
2963
3257
  {
2964
- var geometryNode = this .getGeometry ();
3258
+ case GeometryTypes .GEOMETRY:
3259
+ {
3260
+ const geometryNode = this .getGeometry ();
2965
3261
 
2966
- if (geometryNode)
2967
- geometryNode .displayParticlesDepth (gl, context, shaderNode, this .particles, this .numParticles);
2968
- }
2969
- else
2970
- {
2971
- if (this .numParticles <= 0)
2972
- return;
3262
+ if (geometryNode)
3263
+ geometryNode .displayParticlesDepth (gl, context, shaderNode, this);
2973
3264
 
2974
- if (shaderNode .getValid ())
3265
+ break;
3266
+ }
3267
+ case GeometryTypes .SPRITE:
3268
+ {
3269
+ this .updateSprite (gl, this .getScreenAlignedRotation (context .modelViewMatrix));
3270
+ // [fall trough]
3271
+ }
3272
+ default:
2975
3273
  {
2976
- // Setup vertex attributes.
3274
+ const outputParticles = this .outputParticles;
2977
3275
 
2978
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleId", this .idBuffer, 1);
2979
- shaderNode .enableFloatAttrib (gl, "x3d_ParticlePosition", this .positionBuffer, 3);
2980
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleElapsedTime", this .elapsedTimeBuffer, 1);
2981
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleLife", this .lifeBuffer, 1);
2982
- shaderNode .enableVertexAttribute (gl, this .vertexBuffer);
3276
+ if (outputParticles .shadowArrayObject .enable (gl, shaderNode))
3277
+ {
3278
+ const particleStride = this .particleStride;
3279
+
3280
+ shaderNode .enableParticleAttribute (gl, outputParticles, particleStride, this .particleOffset, 1);
3281
+ shaderNode .enableParticleMatrixAttribute (gl, outputParticles, particleStride, this .matrixOffset, 1);
3282
+ shaderNode .enableVertexAttribute (gl, this .geometryBuffer, 0, this .verticesOffset);
3283
+ }
2983
3284
 
2984
- gl .drawArrays (this .primitiveMode, 0, this .numParticles * this .vertexCount);
3285
+ gl .drawArraysInstanced (this .primitiveMode, 0, this .vertexCount, this .numParticles);
2985
3286
 
2986
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleId");
2987
- shaderNode .disableFloatAttrib (gl, "x3d_ParticlePosition");
2988
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleElapsedTime");
2989
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleLife");
3287
+ break;
2990
3288
  }
2991
3289
  }
2992
3290
  },
2993
3291
  display: function (gl, context)
2994
3292
  {
2995
- try
2996
- {
2997
- if (this .numParticles <= 0)
2998
- return;
2999
-
3000
- // Update geometry if SPRITE.
3001
-
3002
- this .updateGeometry (context .modelViewMatrix);
3003
-
3004
- // Display geometry.
3293
+ // Display geometry.
3005
3294
 
3006
- if (this .geometryType === GEOMETRY)
3295
+ switch (this .geometryType)
3296
+ {
3297
+ case GeometryTypes .GEOMETRY:
3007
3298
  {
3008
3299
  const geometryNode = this .getGeometry ();
3009
3300
 
3010
3301
  if (geometryNode)
3011
- geometryNode .displayParticles (gl, context, this .particles, this .numParticles);
3302
+ geometryNode .displayParticles (gl, context, this);
3303
+
3304
+ break;
3012
3305
  }
3013
- else
3306
+ case GeometryTypes .SPRITE:
3307
+ {
3308
+ this .updateSprite (gl, this .getScreenAlignedRotation (context .modelViewMatrix));
3309
+ // [fall trough]
3310
+ }
3311
+ case GeometryTypes .QUAD:
3312
+ case GeometryTypes .TRIANGLE:
3313
+ {
3314
+ const positiveScale = Matrix4 .prototype .determinant3 .call (context .modelViewMatrix) > 0;
3315
+
3316
+ gl .frontFace (positiveScale ? gl .CCW : gl .CW);
3317
+ gl .enable (gl .CULL_FACE);
3318
+ gl .cullFace (gl .BACK);
3319
+
3320
+ // [fall trough]
3321
+ }
3322
+ default:
3014
3323
  {
3015
3324
  const
3016
3325
  appearanceNode = this .getAppearance (),
3017
- shaderNode = appearanceNode .shaderNode || this .shaderNode || appearanceNode .materialNode .getShader (context .browser, context .shadow);
3326
+ shaderNode = appearanceNode .shaderNode || this .shaderNode || appearanceNode .materialNode .getShader (context .browser, context .shadow),
3327
+ primitiveMode = shaderNode .getPrimitiveMode (this .primitiveMode);
3018
3328
 
3019
3329
  // Setup shader.
3020
3330
 
3021
- if (shaderNode .getValid ())
3331
+ if (shaderNode .isValid ())
3022
3332
  {
3023
3333
  context .geometryContext = this .geometryContext;
3024
3334
 
@@ -3030,85 +3340,88 @@ function (Fields,
3030
3340
  shaderNode .enable (gl);
3031
3341
  shaderNode .setLocalUniforms (gl, context);
3032
3342
 
3033
- // Setup vertex attributes.
3343
+ if (this .numTexCoords)
3344
+ {
3345
+ const textureUnit = context .browser .getTexture2DUnit ();
3034
3346
 
3035
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleId", this .idBuffer, 1);
3036
- shaderNode .enableFloatAttrib (gl, "x3d_ParticlePosition", this .positionBuffer, 3);
3037
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleElapsedTime", this .elapsedTimeBuffer, 1);
3038
- shaderNode .enableFloatAttrib (gl, "x3d_ParticleLife", this .lifeBuffer, 1);
3347
+ gl .activeTexture (gl .TEXTURE0 + textureUnit);
3348
+ gl .bindTexture (gl .TEXTURE_2D, this .texCoordRampTexture);
3349
+ gl .uniform1i (shaderNode .x3d_TexCoordRamp, textureUnit);
3350
+ }
3039
3351
 
3040
- if (this .geometryContext .colorMaterial)
3041
- shaderNode .enableColorAttribute (gl, this .colorBuffer);
3352
+ // Setup vertex attributes.
3042
3353
 
3043
- if (this .texCoordArray .length)
3044
- shaderNode .enableTexCoordAttribute (gl, this .texCoordBuffers);
3354
+ const outputParticles = this .outputParticles;
3045
3355
 
3046
- if (this .normalArray .length)
3047
- shaderNode .enableNormalAttribute (gl, this .normalBuffer);
3356
+ if (outputParticles .vertexArrayObject .enable (gl, shaderNode))
3357
+ {
3358
+ const particleStride = this .particleStride;
3048
3359
 
3049
- shaderNode .enableVertexAttribute (gl, this .vertexBuffer);
3360
+ shaderNode .enableParticleAttribute (gl, outputParticles, particleStride, this .particleOffset, 1);
3361
+ shaderNode .enableParticleMatrixAttribute (gl, outputParticles, particleStride, this .matrixOffset, 1);
3050
3362
 
3051
- if (shaderNode .wireframe && this .testWireframe)
3052
- {
3053
- // Wireframes are always solid so only one drawing call is needed.
3363
+ if (this .geometryContext .colorMaterial)
3364
+ {
3365
+ shaderNode .enableColorAttribute (gl, outputParticles, particleStride, this .colorOffset);
3366
+ shaderNode .colorAttributeDivisor (gl, 1);
3367
+ }
3054
3368
 
3055
- for (var i = 0, length = this .numParticles * this .vertexCount; i < length; i += 3)
3056
- gl .drawArrays (shaderNode .primitiveMode, i, 3);
3057
- }
3058
- else
3059
- {
3060
- const positiveScale = Matrix4 .prototype .determinant3 .call (context .modelViewMatrix) > 0;
3369
+ if (this .texCoordCount)
3370
+ shaderNode .enableTexCoordAttribute (gl, this .texCoordBuffers, 0, this .texCoordOffset);
3061
3371
 
3062
- gl .frontFace (positiveScale ? gl .CCW : gl .CW);
3063
- gl .enable (gl .CULL_FACE);
3064
- gl .cullFace (gl .BACK);
3372
+ if (this .hasNormals)
3373
+ {
3374
+ shaderNode .enableNormalAttribute (gl, this .geometryBuffer, 0, this .normalOffset);
3375
+ shaderNode .normalAttributeDivisor (gl, this .maxParticles);
3376
+ }
3065
3377
 
3066
- gl .drawArrays (this .primitiveMode, 0, this .numParticles * this .vertexCount);
3378
+ shaderNode .enableVertexAttribute (gl, this .geometryBuffer, 0, this .verticesOffset);
3067
3379
  }
3068
3380
 
3069
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleId");
3070
- shaderNode .disableFloatAttrib (gl, "x3d_ParticlePosition");
3071
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleElapsedTime");
3072
- shaderNode .disableFloatAttrib (gl, "x3d_ParticleLife");
3073
-
3074
- shaderNode .disableColorAttribute (gl);
3075
- shaderNode .disableTexCoordAttribute (gl);
3076
- shaderNode .disableNormalAttribute (gl);
3381
+ gl .drawArraysInstanced (primitiveMode, 0, this .vertexCount, this .numParticles);
3077
3382
 
3078
3383
  if (blendModeNode)
3079
3384
  blendModeNode .disable (gl);
3080
3385
 
3081
- context .geometryContext = null;
3386
+ delete context .geometryContext;
3082
3387
  }
3388
+
3389
+ break;
3083
3390
  }
3084
3391
  }
3085
- catch (error)
3086
- {
3087
- // Catch error from setLocalUniforms.
3088
- console .error (error);
3089
- }
3090
3392
  },
3091
- getScreenAlignedRotation: function (modelViewMatrix)
3393
+ getScreenAlignedRotation: (function ()
3092
3394
  {
3093
- invModelViewMatrix .assign (modelViewMatrix) .inverse ();
3395
+ const
3396
+ invModelViewMatrix = new Matrix4 (),
3397
+ billboardToScreen = new Vector3 (0, 0, 0),
3398
+ viewerYAxis = new Vector3 (0, 0, 0),
3399
+ y = new Vector3 (0, 0, 0),
3400
+ rotation = new Matrix3 (9);
3401
+
3402
+ return function (modelViewMatrix)
3403
+ {
3404
+ invModelViewMatrix .assign (modelViewMatrix) .inverse ();
3405
+ invModelViewMatrix .multDirMatrix (billboardToScreen .assign (Vector3 .zAxis));
3406
+ invModelViewMatrix .multDirMatrix (viewerYAxis .assign (Vector3 .yAxis));
3094
3407
 
3095
- invModelViewMatrix .multDirMatrix (billboardToScreen .assign (Vector3 .zAxis));
3096
- invModelViewMatrix .multDirMatrix (viewerYAxis .assign (Vector3 .yAxis));
3408
+ const x = viewerYAxis .cross (billboardToScreen);
3409
+ y .assign (billboardToScreen) .cross (x);
3410
+ const z = billboardToScreen;
3097
3411
 
3098
- x .assign (viewerYAxis) .cross (billboardToScreen);
3099
- y .assign (billboardToScreen) .cross (x);
3100
- var z = billboardToScreen;
3412
+ // Compose rotation matrix.
3101
3413
 
3102
- // Compose rotation
3414
+ x .normalize ();
3415
+ y .normalize ();
3416
+ z .normalize ();
3103
3417
 
3104
- x .normalize ();
3105
- y .normalize ();
3106
- z .normalize ();
3418
+ rotation .set (x .x, x .y, x .z,
3419
+ y .x, y .y, y .z,
3420
+ z .x, z .y, z .z);
3107
3421
 
3108
- return this .rotation .set (x .x, x .y, x .z,
3109
- y .x, y .y, y .z,
3110
- z .x, z .y, z .z);
3111
- },
3422
+ return rotation;
3423
+ };
3424
+ })(),
3112
3425
  });
3113
3426
 
3114
3427
  return ParticleSystem;
@@ -3171,7 +3484,6 @@ define ('x_ite/Components/ParticleSystems/PolylineEmitter',[
3171
3484
  "x_ite/Components/Rendering/IndexedLineSet",
3172
3485
  "x_ite/Base/X3DConstants",
3173
3486
  "standard/Math/Numbers/Vector3",
3174
- "standard/Math/Algorithm",
3175
3487
  ],
3176
3488
  function (Fields,
3177
3489
  X3DFieldDefinition,
@@ -3179,8 +3491,7 @@ function (Fields,
3179
3491
  X3DParticleEmitterNode,
3180
3492
  IndexedLineSet,
3181
3493
  X3DConstants,
3182
- Vector3,
3183
- Algorithm)
3494
+ Vector3)
3184
3495
  {
3185
3496
  "use strict";
3186
3497
 
@@ -3190,28 +3501,69 @@ function (Fields,
3190
3501
 
3191
3502
  this .addType (X3DConstants .PolylineEmitter);
3192
3503
 
3193
- this ._speed .setUnit ("speed");
3194
- this ._mass .setUnit ("mass");
3195
- this ._surfaceArea .setUnit ("area");
3504
+ this .polylinesNode = new IndexedLineSet (executionContext);
3505
+ this .polylinesArray = new Float32Array ();
3506
+
3507
+ this .addSampler ("polylines");
3508
+
3509
+ this .addUniform ("direction", "uniform vec3 direction;");
3510
+ this .addUniform ("verticesIndex", "uniform int verticesIndex;");
3511
+ this .addUniform ("polylines", "uniform sampler2D polylines;");
3512
+
3513
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
3514
+ {
3515
+ if (direction == vec3 (0.0))
3516
+ return getRandomSphericalVelocity ();
3517
+
3518
+ else
3519
+ return direction * getRandomSpeed ();
3520
+ }`);
3521
+
3522
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
3523
+ {
3524
+ if (verticesIndex < 0)
3525
+ {
3526
+ return vec4 (NaN);
3527
+ }
3528
+ else
3529
+ {
3530
+ // Determine index0, index1 and weight.
3196
3531
 
3197
- this .direction = new Vector3 (0, 0, 0);
3198
- this .polylineNode = new IndexedLineSet (executionContext);
3199
- this .polylines = [ ];
3200
- this .lengthSoFarArray = [ 0 ];
3532
+ float lastLengthSoFar = texelFetch (polylines, verticesIndex - 1, 0) .x;
3533
+ float fraction = random () * lastLengthSoFar;
3534
+
3535
+ int index0 = 0;
3536
+ int index1 = 0;
3537
+ float weight = 0.0;
3538
+
3539
+ interpolate (polylines, verticesIndex, fraction, index0, index1, weight);
3540
+
3541
+ // Interpolate and return position.
3542
+
3543
+ index0 *= 2;
3544
+ index1 = index0 + 1;
3545
+
3546
+ vec4 vertex0 = texelFetch (polylines, verticesIndex + index0, 0);
3547
+ vec4 vertex1 = texelFetch (polylines, verticesIndex + index1, 0);
3548
+
3549
+ return mix (vertex0, vertex1, weight);
3550
+ }
3551
+ }`);
3201
3552
  }
3202
3553
 
3203
3554
  PolylineEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
3204
3555
  {
3205
3556
  constructor: PolylineEmitter,
3206
3557
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
3207
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3208
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
3209
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3210
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3211
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
3212
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
3213
- new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
3214
- new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
3558
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3559
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
3560
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
3561
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3562
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3563
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
3564
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
3565
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
3566
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
3215
3567
  ]),
3216
3568
  getTypeName: function ()
3217
3569
  {
@@ -3229,148 +3581,93 @@ function (Fields,
3229
3581
  {
3230
3582
  X3DParticleEmitterNode .prototype .initialize .call (this);
3231
3583
 
3584
+ const browser = this .getBrowser ();
3585
+
3586
+ if (browser .getContext () .getVersion () < 2)
3587
+ return;
3588
+
3589
+ // Create GL stuff.
3590
+
3591
+ this .polylinesTexture = this .createTexture ();
3592
+
3593
+ // Initialize fields.
3594
+
3232
3595
  this ._direction .addInterest ("set_direction__", this);
3233
3596
 
3234
- this ._coordIndex .addFieldInterest (this .polylineNode ._coordIndex);
3235
- this ._coord .addFieldInterest (this .polylineNode ._coord);
3597
+ this ._coordIndex .addFieldInterest (this .polylinesNode ._coordIndex);
3598
+ this ._coord .addFieldInterest (this .polylinesNode ._coord);
3236
3599
 
3237
- this .polylineNode ._coordIndex = this ._coordIndex;
3238
- this .polylineNode ._coord = this ._coord;
3600
+ this .polylinesNode ._coordIndex = this ._coordIndex;
3601
+ this .polylinesNode ._coord = this ._coord;
3239
3602
 
3240
- this .polylineNode ._rebuild .addInterest ("set_polyline", this);
3241
- this .polylineNode .setPrivate (true);
3242
- this .polylineNode .setup ();
3603
+ this .polylinesNode ._rebuild .addInterest ("set_polyline", this);
3604
+ this .polylinesNode .setPrivate (true);
3605
+ this .polylinesNode .setup ();
3243
3606
 
3244
3607
  this .set_direction__ ();
3245
3608
  this .set_polyline ();
3246
3609
  },
3247
- set_direction__: function ()
3610
+ set_direction__: (function ()
3248
3611
  {
3249
- this .direction .assign (this ._direction .getValue ()) .normalize ();
3612
+ const direction = new Vector3 (0, 0, 0);
3250
3613
 
3251
- if (this .direction .equals (Vector3 .Zero))
3252
- this .getRandomVelocity = this .getSphericalRandomVelocity;
3253
- else
3254
- delete this .getRandomVelocity;
3255
- },
3614
+ return function ()
3615
+ {
3616
+ direction .assign (this ._direction .getValue ()) .normalize ();
3617
+
3618
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
3619
+ };
3620
+ })(),
3256
3621
  set_polyline: (function ()
3257
3622
  {
3258
- var
3623
+ const
3259
3624
  vertex1 = new Vector3 (0, 0, 0),
3260
3625
  vertex2 = new Vector3 (0, 0, 0);
3261
3626
 
3262
3627
  return function ()
3263
3628
  {
3264
- var vertices = this .vertices = this .polylineNode .getVertices () .getValue ();
3629
+ const
3630
+ gl = this .getBrowser () .getContext (),
3631
+ vertices = this .polylinesNode .getVertices () .getValue (),
3632
+ numVertices = vertices .length / 4,
3633
+ numLengthSoFar = numVertices / 2 + 1,
3634
+ polylineArraySize = Math .ceil (Math .sqrt (numLengthSoFar + numVertices));
3265
3635
 
3266
- if (vertices .length)
3267
- {
3268
- delete this .getRandomPosition;
3636
+ const verticesIndex = numLengthSoFar;
3269
3637
 
3270
- var
3271
- lengthSoFar = 0,
3272
- lengthSoFarArray = this .lengthSoFarArray;
3638
+ let polylinesArray = this .polylinesArray;
3273
3639
 
3274
- lengthSoFarArray .length = 1;
3640
+ if (polylinesArray .length < polylineArraySize * polylineArraySize * 4)
3641
+ polylinesArray = this .polylinesArray = new Float32Array (polylineArraySize * polylineArraySize * 4);
3275
3642
 
3276
- for (var i = 0, length = vertices .length; i < length; i += 8)
3277
- {
3278
- vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3279
- vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3643
+ let lengthSoFar = 0;
3280
3644
 
3281
- lengthSoFar += vertex2 .subtract (vertex1) .abs ();
3282
- lengthSoFarArray .push (lengthSoFar);
3283
- }
3284
- }
3285
- else
3645
+ for (let i = 0, length = vertices .length; i < length; i += 8)
3286
3646
  {
3287
- this .getRandomPosition = getPosition;
3288
- }
3289
- };
3290
- })(),
3291
- getRandomPosition: function (position)
3292
- {
3293
- // Determine index0 and weight.
3294
-
3295
- var
3296
- lengthSoFarArray = this .lengthSoFarArray,
3297
- length = lengthSoFarArray .length,
3298
- fraction = Math .random () * lengthSoFarArray .at (-1),
3299
- index0 = 0,
3300
- index1 = 0,
3301
- weight = 0;
3647
+ vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3648
+ vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3302
3649
 
3303
- if (length == 1 || fraction <= lengthSoFarArray [0])
3304
- {
3305
- index0 = 0;
3306
- weight = 0;
3307
- }
3308
- else if (fraction >= lengthSoFarArray .at (-1))
3309
- {
3310
- index0 = length - 2;
3311
- weight = 1;
3312
- }
3313
- else
3314
- {
3315
- var index = Algorithm .upperBound (lengthSoFarArray, 0, length, fraction, Algorithm .less);
3650
+ polylinesArray [i / 2 + 4] = lengthSoFar += vertex2 .subtract (vertex1) .magnitude ();
3651
+ }
3316
3652
 
3317
- if (index < length)
3318
- {
3319
- index1 = index;
3320
- index0 = index - 1;
3653
+ polylinesArray .set (vertices, verticesIndex * 4);
3321
3654
 
3322
- var
3323
- key0 = lengthSoFarArray [index0],
3324
- key1 = lengthSoFarArray [index1];
3655
+ this .setUniform ("uniform1i", "verticesIndex", numVertices ? verticesIndex : -1);
3325
3656
 
3326
- weight = Algorithm .clamp ((fraction - key0) / (key1 - key0), 0, 1);
3327
- }
3328
- else
3657
+ if (polylineArraySize)
3329
3658
  {
3330
- index0 = 0;
3331
- weight = 0;
3659
+ gl .bindTexture (gl .TEXTURE_2D, this .polylinesTexture);
3660
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, polylineArraySize, polylineArraySize, 0, gl .RGBA, gl .FLOAT, polylinesArray);
3332
3661
  }
3333
- }
3334
-
3335
- // Interpolate and set position.
3336
-
3337
- index0 *= 8;
3338
- index1 = index0 + 4;
3339
-
3340
- var
3341
- vertices = this .vertices,
3342
- x1 = vertices [index0],
3343
- y1 = vertices [index0 + 1],
3344
- z1 = vertices [index0 + 2],
3345
- x2 = vertices [index1],
3346
- y2 = vertices [index1 + 1],
3347
- z2 = vertices [index1 + 2];
3348
-
3349
- position .x = x1 + weight * (x2 - x1);
3350
- position .y = y1 + weight * (y2 - y1);
3351
- position .z = z1 + weight * (z2 - z1);
3352
-
3353
- return position;
3354
- },
3355
- getRandomVelocity: function (velocity)
3662
+ };
3663
+ })(),
3664
+ activateTextures: function (gl, program)
3356
3665
  {
3357
- var
3358
- direction = this .direction,
3359
- speed = this .getRandomSpeed ();
3360
-
3361
- velocity .x = direction .x * speed;
3362
- velocity .y = direction .y * speed;
3363
- velocity .z = direction .z * speed;
3364
-
3365
- return velocity;
3366
- },
3666
+ gl .activeTexture (gl .TEXTURE0 + program .polylinesTextureUnit);
3667
+ gl .bindTexture (gl .TEXTURE_2D, this .polylinesTexture);
3668
+ },
3367
3669
  });
3368
3670
 
3369
- function getPosition (position)
3370
- {
3371
- return position .set (0, 0, 0);
3372
- }
3373
-
3374
3671
  return PolylineEmitter;
3375
3672
  });
3376
3673
 
@@ -3432,7 +3729,6 @@ define ('x_ite/Components/ParticleSystems/SurfaceEmitter',[
3432
3729
  "x_ite/Base/X3DCast",
3433
3730
  "standard/Math/Geometry/Triangle3",
3434
3731
  "standard/Math/Numbers/Vector3",
3435
- "standard/Math/Algorithm",
3436
3732
  ],
3437
3733
  function (Fields,
3438
3734
  X3DFieldDefinition,
@@ -3441,8 +3737,7 @@ function (Fields,
3441
3737
  X3DConstants,
3442
3738
  X3DCast,
3443
3739
  Triangle3,
3444
- Vector3,
3445
- Algorithm)
3740
+ Vector3)
3446
3741
  {
3447
3742
  "use strict";
3448
3743
 
@@ -3452,25 +3747,52 @@ function (Fields,
3452
3747
 
3453
3748
  this .addType (X3DConstants .SurfaceEmitter);
3454
3749
 
3455
- this ._speed .setUnit ("speed");
3456
- this ._mass .setUnit ("mass");
3457
- this ._surfaceArea .setUnit ("area");
3750
+ this .surfaceNode = null;
3751
+ this .surfaceArray = new Float32Array ();
3752
+
3753
+ this .addSampler ("surface");
3754
+
3755
+ this .addUniform ("solid", "uniform bool solid;");
3756
+ this .addUniform ("verticesIndex", "uniform int verticesIndex;");
3757
+ this .addUniform ("normalsIndex", "uniform int normalsIndex;");
3758
+ this .addUniform ("surface", "uniform sampler2D surface;");
3458
3759
 
3459
- this .surfaceNode = null;
3460
- this .areaSoFarArray = [ 0 ];
3461
- this .direction = new Vector3 (0, 0, 0);
3760
+ this .addFunction (/* glsl */ `vec4 position; vec3 getRandomVelocity ()
3761
+ {
3762
+ if (verticesIndex < 0)
3763
+ {
3764
+ return vec3 (0.0);
3765
+ }
3766
+ else
3767
+ {
3768
+ vec3 normal;
3769
+
3770
+ getRandomPointOnSurface (surface, verticesIndex, normalsIndex, position, normal);
3771
+
3772
+ if (solid == false && random () > 0.5)
3773
+ normal = -normal;
3774
+
3775
+ return normal * getRandomSpeed ();
3776
+ }
3777
+ }`);
3778
+
3779
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
3780
+ {
3781
+ return verticesIndex < 0 ? vec4 (NaN) : position;
3782
+ }`);
3462
3783
  }
3463
3784
 
3464
3785
  SurfaceEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
3465
3786
  {
3466
3787
  constructor: SurfaceEmitter,
3467
3788
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
3468
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3469
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3470
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3471
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
3472
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
3473
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surface", new Fields .SFNode ()),
3789
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3790
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
3791
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3792
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3793
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
3794
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
3795
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surface", new Fields .SFNode ()),
3474
3796
  ]),
3475
3797
  getTypeName: function ()
3476
3798
  {
@@ -3488,6 +3810,17 @@ function (Fields,
3488
3810
  {
3489
3811
  X3DParticleEmitterNode .prototype .initialize .call (this);
3490
3812
 
3813
+ const browser = this .getBrowser ();
3814
+
3815
+ if (browser .getContext () .getVersion () < 2)
3816
+ return;
3817
+
3818
+ // Create GL stuff.
3819
+
3820
+ this .surfaceTexture = this .createTexture ();
3821
+
3822
+ // Initialize fields.
3823
+
3491
3824
  this ._surface .addInterest ("set_surface__", this);
3492
3825
 
3493
3826
  this .set_surface__ ();
@@ -3495,142 +3828,99 @@ function (Fields,
3495
3828
  set_surface__: function ()
3496
3829
  {
3497
3830
  if (this .surfaceNode)
3831
+ {
3832
+ this .surfaceNode ._solid .removeInterest ("set_solid__", this);
3498
3833
  this .surfaceNode ._rebuild .removeInterest ("set_geometry__", this);
3834
+ }
3499
3835
 
3500
3836
  this .surfaceNode = X3DCast (X3DConstants .X3DGeometryNode, this ._surface);
3501
3837
 
3502
3838
  if (this .surfaceNode)
3839
+ {
3840
+ this .surfaceNode ._solid .addInterest ("set_solid__", this);
3503
3841
  this .surfaceNode ._rebuild .addInterest ("set_geometry__", this);
3842
+ }
3504
3843
 
3844
+ this .set_solid__ ();
3505
3845
  this .set_geometry__ ();
3506
3846
  },
3847
+ set_solid__: function ()
3848
+ {
3849
+ if (this .surfaceNode)
3850
+ this .setUniform ("uniform1i", "solid", this .surfaceNode ._solid .getValue ());
3851
+ },
3507
3852
  set_geometry__: (function ()
3508
3853
  {
3509
- var
3854
+ const
3510
3855
  vertex1 = new Vector3 (0, 0, 0),
3511
3856
  vertex2 = new Vector3 (0, 0, 0),
3512
3857
  vertex3 = new Vector3 (0, 0, 0);
3513
3858
 
3514
3859
  return function ()
3515
3860
  {
3861
+ const gl = this .getBrowser () .getContext ();
3862
+
3516
3863
  if (this .surfaceNode)
3517
3864
  {
3518
- delete this .getRandomPosition;
3519
- delete this .getRandomVelocity;
3865
+ const
3866
+ vertices = this .surfaceNode .getVertices () .getValue (),
3867
+ normals = this .surfaceNode .getNormals () .getValue (),
3868
+ numVertices = vertices .length / 4,
3869
+ numAreaSoFar = numVertices / 3 + 1,
3870
+ surfaceArraySize = Math .ceil (Math .sqrt (numAreaSoFar + numVertices + numVertices));
3871
+
3872
+ const
3873
+ verticesIndex = numAreaSoFar,
3874
+ normalsIndex = verticesIndex + numVertices;
3520
3875
 
3521
- var
3522
- areaSoFar = 0,
3523
- areaSoFarArray = this .areaSoFarArray,
3524
- vertices = this .surfaceNode .getVertices () .getValue ();
3876
+ let surfaceArray = this .surfaceArray;
3525
3877
 
3526
- this .normals = this .surfaceNode .getNormals () .getValue ();
3527
- this .vertices = vertices;
3878
+ if (surfaceArray .length < surfaceArraySize * surfaceArraySize * 4)
3879
+ surfaceArray = this .surfaceArray = new Float32Array (surfaceArraySize * surfaceArraySize * 4);
3528
3880
 
3529
- areaSoFarArray .length = 1;
3881
+ let areaSoFar = 0;
3530
3882
 
3531
- for (var i = 0, length = vertices .length; i < length; i += 12)
3883
+ for (let i = 0, length = vertices .length; i < length; i += 12)
3532
3884
  {
3533
3885
  vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3534
3886
  vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3535
3887
  vertex3 .set (vertices [i + 8], vertices [i + 9], vertices [i + 10]);
3536
3888
 
3537
- areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3538
- areaSoFarArray .push (areaSoFar);
3889
+ surfaceArray [i / 3 + 4] = areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3539
3890
  }
3540
- }
3541
- else
3542
- {
3543
- this .getRandomPosition = getPosition;
3544
- this .getRandomVelocity = this .getSphericalRandomVelocity;
3545
- }
3546
- };
3547
- })(),
3548
- getRandomPosition: function (position)
3549
- {
3550
- // Determine index0.
3551
3891
 
3552
- var
3553
- areaSoFarArray = this .areaSoFarArray,
3554
- length = areaSoFarArray .length,
3555
- fraction = Math .random () * areaSoFarArray .at (-1),
3556
- index0 = 0;
3892
+ surfaceArray .set (vertices, verticesIndex * 4);
3557
3893
 
3558
- if (length == 1 || fraction <= areaSoFarArray [0])
3559
- {
3560
- index0 = 0;
3561
- }
3562
- else if (fraction >= areaSoFarArray .at (-1))
3563
- {
3564
- index0 = length - 2;
3565
- }
3566
- else
3567
- {
3568
- var index = Algorithm .upperBound (areaSoFarArray, 0, length, fraction, Algorithm .less);
3894
+ for (let s = normalsIndex * 4, n = 0, l = normals .length; n < l; s += 4, n += 3)
3895
+ {
3896
+ surfaceArray [s + 0] = normals [n + 0];
3897
+ surfaceArray [s + 1] = normals [n + 1];
3898
+ surfaceArray [s + 2] = normals [n + 2];
3899
+ }
3569
3900
 
3570
- if (index < length)
3571
- {
3572
- index0 = index - 1;
3901
+ this .setUniform ("uniform1i", "verticesIndex", numVertices ? verticesIndex : -1);
3902
+ this .setUniform ("uniform1i", "normalsIndex", numVertices ? normalsIndex : -1);
3903
+
3904
+ if (surfaceArraySize)
3905
+ {
3906
+ gl .bindTexture (gl .TEXTURE_2D, this .surfaceTexture);
3907
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, surfaceArraySize, surfaceArraySize, 0, gl .RGBA, gl .FLOAT, surfaceArray);
3908
+ }
3573
3909
  }
3574
3910
  else
3575
3911
  {
3576
- index0 = 0;
3912
+ this .setUniform ("uniform1i", "verticesIndex", -1);
3913
+ this .setUniform ("uniform1i", "normalsIndex", -1);
3577
3914
  }
3578
- }
3579
-
3580
- // Random barycentric coordinates.
3581
-
3582
- var
3583
- u = Math .random (),
3584
- v = Math .random ();
3585
-
3586
- if (u + v > 1)
3587
- {
3588
- u = 1 - u;
3589
- v = 1 - v;
3590
- }
3591
-
3592
- var t = 1 - u - v;
3593
-
3594
- // Interpolate and set position.
3595
-
3596
- var
3597
- i = index0 * 12,
3598
- vertices = this .vertices;
3599
-
3600
- position .x = u * vertices [i] + v * vertices [i + 4] + t * vertices [i + 8];
3601
- position .y = u * vertices [i + 1] + v * vertices [i + 5] + t * vertices [i + 9];
3602
- position .z = u * vertices [i + 2] + v * vertices [i + 6] + t * vertices [i + 10];
3603
-
3604
- var
3605
- i = index0 * 9,
3606
- normals = this .normals,
3607
- direction = this .direction;
3608
-
3609
- direction .x = u * normals [i] + v * normals [i + 3] + t * normals [i + 6];
3610
- direction .y = u * normals [i + 1] + v * normals [i + 4] + t * normals [i + 7];
3611
- direction .z = u * normals [i + 2] + v * normals [i + 5] + t * normals [i + 8];
3612
-
3613
- return position;
3614
- },
3615
- getRandomVelocity: function (velocity)
3915
+ };
3916
+ })(),
3917
+ activateTextures: function (gl, program)
3616
3918
  {
3617
- var
3618
- speed = this .getRandomSpeed (),
3619
- direction = this .direction;
3620
-
3621
- velocity .x = direction .x * speed;
3622
- velocity .y = direction .y * speed;
3623
- velocity .z = direction .z * speed;
3624
-
3625
- return velocity;
3626
- },
3919
+ gl .activeTexture (gl .TEXTURE0 + program .surfaceTextureUnit);
3920
+ gl .bindTexture (gl .TEXTURE_2D, this .surfaceTexture);
3921
+ },
3627
3922
  });
3628
3923
 
3629
- function getPosition (position)
3630
- {
3631
- return position .set (0, 0, 0);
3632
- }
3633
-
3634
3924
  return SurfaceEmitter;
3635
3925
  });
3636
3926
 
@@ -3691,13 +3981,8 @@ define ('x_ite/Components/ParticleSystems/VolumeEmitter',[
3691
3981
  "x_ite/Components/Geometry3D/IndexedFaceSet",
3692
3982
  "x_ite/Base/X3DConstants",
3693
3983
  "standard/Math/Numbers/Vector3",
3694
- "standard/Math/Numbers/Rotation4",
3695
- "standard/Math/Geometry/Line3",
3696
- "standard/Math/Geometry/Plane3",
3697
3984
  "standard/Math/Geometry/Triangle3",
3698
- "standard/Math/Algorithm",
3699
3985
  "standard/Math/Utility/BVH",
3700
- "standard/Math/Algorithms/QuickSort",
3701
3986
  ],
3702
3987
  function (Fields,
3703
3988
  X3DFieldDefinition,
@@ -3706,13 +3991,8 @@ function (Fields,
3706
3991
  IndexedFaceSet,
3707
3992
  X3DConstants,
3708
3993
  Vector3,
3709
- Rotation4,
3710
- Line3,
3711
- Plane3,
3712
3994
  Triangle3,
3713
- Algorithm,
3714
- BVH,
3715
- QuickSort)
3995
+ BVH)
3716
3996
  {
3717
3997
  "use strict";
3718
3998
 
@@ -3722,28 +4002,87 @@ function (Fields,
3722
4002
 
3723
4003
  this .addType (X3DConstants .VolumeEmitter);
3724
4004
 
3725
- this ._speed .setUnit ("speed");
3726
- this ._mass .setUnit ("mass");
3727
- this ._surfaceArea .setUnit ("area");
4005
+ this .volumeNode = new IndexedFaceSet (executionContext);
4006
+ this .volumeArray = new Float32Array ();
4007
+
4008
+ this .addSampler ("volume");
4009
+
4010
+ this .addUniform ("direction", "uniform vec3 direction;");
4011
+ this .addUniform ("verticesIndex", "uniform int verticesIndex;");
4012
+ this .addUniform ("normalsIndex", "uniform int normalsIndex;");
4013
+ this .addUniform ("hierarchyIndex", "uniform int hierarchyIndex;");
4014
+ this .addUniform ("hierarchyRoot", "uniform int hierarchyRoot;");
4015
+ this .addUniform ("volume", "uniform sampler2D volume;");
4016
+
4017
+ this .addFunction (/* glsl */ `vec3 getRandomVelocity ()
4018
+ {
4019
+ if (hierarchyRoot < 0)
4020
+ {
4021
+ return vec3 (0.0);
4022
+ }
4023
+ else
4024
+ {
4025
+ if (direction == vec3 (0.0))
4026
+ return getRandomSphericalVelocity ();
4027
+
4028
+ else
4029
+ return direction * getRandomSpeed ();
4030
+ }
4031
+ }`);
4032
+
4033
+ this .addFunction (/* glsl */ `vec4 getRandomPosition ()
4034
+ {
4035
+ if (hierarchyRoot < 0)
4036
+ {
4037
+ return vec4 (NaN);
4038
+ }
4039
+ else
4040
+ {
4041
+ vec4 point;
4042
+ vec3 normal;
4043
+
4044
+ getRandomPointOnSurface (volume, verticesIndex, normalsIndex, point, normal);
4045
+
4046
+ Line3 line = Line3 (point .xyz, getRandomSurfaceNormal (normal));
4047
+
4048
+ vec4 points [ARRAY_SIZE];
4049
+
4050
+ int numIntersections = getIntersections (volume, verticesIndex, hierarchyIndex, hierarchyRoot, line, points);
4051
+
4052
+ numIntersections -= numIntersections % 2; // We need an even count of intersections.
3728
4053
 
3729
- this .direction = new Vector3 (0, 0, 0);
3730
- this .volumeNode = new IndexedFaceSet (executionContext);
3731
- this .areaSoFarArray = [ 0 ];
4054
+ switch (numIntersections)
4055
+ {
4056
+ case 0:
4057
+ return vec4 (0.0);
4058
+ case 2:
4059
+ break;
4060
+ default:
4061
+ sort (points, numIntersections, plane3 (line .point, line .direction));
4062
+ break;
4063
+ }
4064
+
4065
+ int index = int (fract (random ()) * float (numIntersections / 2)) * 2; // Select random intersection.
4066
+
4067
+ return mix (points [index], points [index + 1], random ());
4068
+ }
4069
+ }`);
3732
4070
  }
3733
4071
 
3734
4072
  VolumeEmitter .prototype = Object .assign (Object .create (X3DParticleEmitterNode .prototype),
3735
4073
  {
3736
4074
  constructor: VolumeEmitter,
3737
4075
  [Symbol .for ("X_ITE.X3DBaseNode.fieldDefinitions")]: new FieldDefinitionArray ([
3738
- new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
3739
- new X3DFieldDefinition (X3DConstants .initializeOnly, "internal", new Fields .SFBool (true)),
3740
- new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
3741
- new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
3742
- new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
3743
- new X3DFieldDefinition (X3DConstants .initializeOnly, "mass", new Fields .SFFloat ()),
3744
- new X3DFieldDefinition (X3DConstants .initializeOnly, "surfaceArea", new Fields .SFFloat ()),
3745
- new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
3746
- new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
4076
+ new X3DFieldDefinition (X3DConstants .inputOutput, "metadata", new Fields .SFNode ()),
4077
+ new X3DFieldDefinition (X3DConstants .inputOutput, "on", new Fields .SFBool (true)),
4078
+ new X3DFieldDefinition (X3DConstants .inputOutput, "internal", new Fields .SFBool (true)),
4079
+ new X3DFieldDefinition (X3DConstants .inputOutput, "direction", new Fields .SFVec3f (0, 1, 0)),
4080
+ new X3DFieldDefinition (X3DConstants .inputOutput, "speed", new Fields .SFFloat ()),
4081
+ new X3DFieldDefinition (X3DConstants .inputOutput, "variation", new Fields .SFFloat (0.25)),
4082
+ new X3DFieldDefinition (X3DConstants .inputOutput, "mass", new Fields .SFFloat ()),
4083
+ new X3DFieldDefinition (X3DConstants .inputOutput, "surfaceArea", new Fields .SFFloat ()),
4084
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coordIndex", new Fields .MFInt32 (-1)),
4085
+ new X3DFieldDefinition (X3DConstants .inputOutput, "coord", new Fields .SFNode ()),
3747
4086
  ]),
3748
4087
  getTypeName: function ()
3749
4088
  {
@@ -3761,6 +4100,17 @@ function (Fields,
3761
4100
  {
3762
4101
  X3DParticleEmitterNode .prototype .initialize .call (this);
3763
4102
 
4103
+ const browser = this .getBrowser ();
4104
+
4105
+ if (browser .getContext () .getVersion () < 2)
4106
+ return;
4107
+
4108
+ // Create GL stuff.
4109
+
4110
+ this .volumeTexture = this .createTexture ();
4111
+
4112
+ // Initialize fields.
4113
+
3764
4114
  this ._direction .addInterest ("set_direction__", this);
3765
4115
 
3766
4116
  this ._coordIndex .addFieldInterest (this .volumeNode ._coordIndex);
@@ -3778,184 +4128,86 @@ function (Fields,
3778
4128
  this .set_direction__ ();
3779
4129
  this .set_geometry__ ();
3780
4130
  },
3781
- set_direction__: function ()
4131
+ set_direction__: (function ()
3782
4132
  {
3783
- this .direction .assign (this ._direction .getValue ()) .normalize ();
4133
+ const direction = new Vector3 (0, 0, 0);
3784
4134
 
3785
- if (this .direction .equals (Vector3 .Zero))
3786
- this .getRandomVelocity = this .getSphericalRandomVelocity;
3787
- else
3788
- delete this .getRandomVelocity;
3789
- },
4135
+ return function ()
4136
+ {
4137
+ direction .assign (this ._direction .getValue ()) .normalize ();
4138
+
4139
+ this .setUniform ("uniform3f", "direction", direction .x, direction .y, direction .z);
4140
+ };
4141
+ })(),
3790
4142
  set_geometry__: (function ()
3791
4143
  {
3792
- var
4144
+ const
3793
4145
  vertex1 = new Vector3 (0, 0, 0),
3794
4146
  vertex2 = new Vector3 (0, 0, 0),
3795
4147
  vertex3 = new Vector3 (0, 0, 0);
3796
4148
 
3797
4149
  return function ()
3798
4150
  {
3799
- var
3800
- areaSoFar = 0,
3801
- areaSoFarArray = this .areaSoFarArray,
3802
- normals = this .volumeNode .getNormals () .getValue (),
3803
- vertices = this .volumeNode .getVertices () .getValue ();
4151
+ const
4152
+ gl = this .getBrowser () .getContext (),
4153
+ vertices = this .volumeNode .getVertices () .getValue (),
4154
+ normals = this .volumeNode .getNormals () .getValue (),
4155
+ hierarchy = new BVH (vertices, normals) .toArray ([ ]),
4156
+ numVertices = vertices .length / 4,
4157
+ numNormals = normals .length / 3,
4158
+ numAreaSoFar = numVertices / 3 + 1,
4159
+ hierarchyLength = hierarchy .length / 4,
4160
+ volumeArraySize = Math .ceil (Math .sqrt (numAreaSoFar + numVertices + numVertices + hierarchyLength));
3804
4161
 
3805
- this .normals = normals;
3806
- this .vertices = vertices;
4162
+ const
4163
+ verticesIndex = numAreaSoFar,
4164
+ normalsIndex = verticesIndex + numVertices,
4165
+ hierarchyIndex = normalsIndex + numNormals;
4166
+
4167
+ let volumeArray = this .volumeArray;
3807
4168
 
3808
- areaSoFarArray .length = 1;
4169
+ if (volumeArray .length < volumeArraySize * volumeArraySize * 4)
4170
+ volumeArray = this .volumeArray = new Float32Array (volumeArraySize * volumeArraySize * 4);
3809
4171
 
3810
- for (var i = 0, length = vertices .length; i < length; i += 12)
4172
+ let areaSoFar = 0;
4173
+
4174
+ for (let i = 0, length = vertices .length; i < length; i += 12)
3811
4175
  {
3812
4176
  vertex1 .set (vertices [i], vertices [i + 1], vertices [i + 2]);
3813
4177
  vertex2 .set (vertices [i + 4], vertices [i + 5], vertices [i + 6]);
3814
4178
  vertex3 .set (vertices [i + 8], vertices [i + 9], vertices [i + 10]);
3815
4179
 
3816
- areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3817
- areaSoFarArray .push (areaSoFar);
3818
- }
3819
-
3820
- this .bvh = new BVH (vertices, normals);
3821
- };
3822
- })(),
3823
- getRandomPosition: (function ()
3824
- {
3825
- var
3826
- point = new Vector3 (0, 0, 0),
3827
- normal = new Vector3 (0, 0, 0),
3828
- rotation = new Rotation4 (0, 0, 1, 0),
3829
- line = new Line3 (Vector3 .Zero, Vector3 .zAxis),
3830
- plane = new Plane3 (Vector3 .Zero, Vector3 .zAxis),
3831
- intersections = [ ],
3832
- sorter = new QuickSort (intersections, PlaneCompare);
3833
-
3834
- function PlaneCompare (a, b)
3835
- {
3836
- return plane .getDistanceToPoint (a) < plane .getDistanceToPoint (b);
3837
- }
3838
-
3839
- return function (position)
3840
- {
3841
- // Get random point on surface
3842
-
3843
- // Determine index0.
3844
-
3845
- var
3846
- areaSoFarArray = this .areaSoFarArray,
3847
- length = areaSoFarArray .length,
3848
- fraction = Math .random () * areaSoFarArray .at (-1),
3849
- index0 = 0;
3850
-
3851
- if (length == 1 || fraction <= areaSoFarArray [0])
3852
- {
3853
- index0 = 0;
3854
- }
3855
- else if (fraction >= areaSoFarArray .at (-1))
3856
- {
3857
- index0 = length - 2;
3858
- }
3859
- else
3860
- {
3861
- var index = Algorithm .upperBound (areaSoFarArray, 0, length, fraction, Algorithm .less);
3862
-
3863
- if (index < length)
3864
- {
3865
- index0 = index - 1;
3866
- }
3867
- else
3868
- {
3869
- index0 = 0;
3870
- }
4180
+ volumeArray [i / 3 + 4] = areaSoFar += Triangle3 .area (vertex1, vertex2, vertex3);
3871
4181
  }
3872
4182
 
3873
- // Random barycentric coordinates.
3874
-
3875
- var
3876
- u = Math .random (),
3877
- v = Math .random ();
4183
+ volumeArray .set (vertices, verticesIndex * 4);
3878
4184
 
3879
- if (u + v > 1)
4185
+ for (let s = normalsIndex * 4, n = 0, l = normals .length; n < l; s += 4, n += 3)
3880
4186
  {
3881
- u = 1 - u;
3882
- v = 1 - v;
4187
+ volumeArray [s + 0] = normals [n + 0];
4188
+ volumeArray [s + 1] = normals [n + 1];
4189
+ volumeArray [s + 2] = normals [n + 2];
3883
4190
  }
3884
4191
 
3885
- var t = 1 - u - v;
4192
+ volumeArray .set (hierarchy, hierarchyIndex * 4);
3886
4193
 
3887
- // Interpolate and determine random point on surface and normal.
4194
+ this .setUniform ("uniform1i", "verticesIndex", verticesIndex);
4195
+ this .setUniform ("uniform1i", "normalsIndex", normalsIndex);
4196
+ this .setUniform ("uniform1i", "hierarchyIndex", hierarchyIndex);
4197
+ this .setUniform ("uniform1i", "hierarchyRoot", hierarchyIndex + hierarchyLength - 1);
3888
4198
 
3889
- var
3890
- i = index0 * 12,
3891
- vertices = this .vertices;
3892
-
3893
- point .x = u * vertices [i] + v * vertices [i + 4] + t * vertices [i + 8];
3894
- point .y = u * vertices [i + 1] + v * vertices [i + 5] + t * vertices [i + 9];
3895
- point .z = u * vertices [i + 2] + v * vertices [i + 6] + t * vertices [i + 10];
3896
-
3897
- var
3898
- i = index0 * 9,
3899
- normals = this .normals;
3900
-
3901
- normal .x = u * normals [i] + v * normals [i + 3] + t * normals [i + 6];
3902
- normal .y = u * normals [i + 1] + v * normals [i + 4] + t * normals [i + 7];
3903
- normal .z = u * normals [i + 2] + v * normals [i + 5] + t * normals [i + 8];
3904
-
3905
- rotation .setFromToVec (Vector3 .zAxis, normal);
3906
- rotation .multVecRot (this .getRandomSurfaceNormal (normal));
3907
-
3908
- // Setup random line throu volume for intersection text
3909
- // and a plane corresponding to the line for intersection sorting.
3910
-
3911
- line .set (point, normal);
3912
- plane .set (point, normal);
3913
-
3914
- // Find random point in volume.
3915
-
3916
- var numIntersections = this .bvh .intersectsLine (line, intersections);
3917
-
3918
- numIntersections -= numIntersections % 2; // We need an even count of intersections.
3919
-
3920
- if (numIntersections)
4199
+ if (volumeArraySize)
3921
4200
  {
3922
- // Sort intersections along line with a little help from the plane.
3923
-
3924
- sorter .sort (0, numIntersections);
3925
-
3926
- // Select random intersection pair.
3927
-
3928
- var
3929
- index = Math .round (this .getRandomValue (0, numIntersections / 2 - 1)) * 2,
3930
- point0 = intersections [index],
3931
- point1 = intersections [index + 1],
3932
- t = Math .random ();
3933
-
3934
- // lerp
3935
- position .x = point0 .x + (point1 .x - point0 .x) * t;
3936
- position .y = point0 .y + (point1 .y - point0 .y) * t;
3937
- position .z = point0 .z + (point1 .z - point0 .z) * t;
3938
-
3939
- return position;
4201
+ gl .bindTexture (gl .TEXTURE_2D, this .volumeTexture);
4202
+ gl .texImage2D (gl .TEXTURE_2D, 0, gl .RGBA32F, volumeArraySize, volumeArraySize, 0, gl .RGBA, gl .FLOAT, volumeArray);
3940
4203
  }
3941
-
3942
- // Discard point.
3943
-
3944
- return position .set (Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY, Number .POSITIVE_INFINITY);
3945
4204
  };
3946
4205
  })(),
3947
- getRandomVelocity: function (velocity)
4206
+ activateTextures: function (gl, program)
3948
4207
  {
3949
- var
3950
- direction = this .direction,
3951
- speed = this .getRandomSpeed ();
3952
-
3953
- velocity .x = direction .x * speed;
3954
- velocity .y = direction .y * speed;
3955
- velocity .z = direction .z * speed;
3956
-
3957
- return velocity;
3958
- },
4208
+ gl .activeTexture (gl .TEXTURE0 + program .volumeTextureUnit);
4209
+ gl .bindTexture (gl .TEXTURE_2D, this .volumeTexture);
4210
+ },
3959
4211
  });
3960
4212
 
3961
4213
  return VolumeEmitter;
@@ -4063,7 +4315,7 @@ function (Fields,
4063
4315
  },
4064
4316
  getRandomSpeed: function (emitterNode)
4065
4317
  {
4066
- var
4318
+ const
4067
4319
  speed = Math .max (0, this ._speed .getValue ()),
4068
4320
  variation = speed * Math .max (0, this ._gustiness .getValue ());
4069
4321
 
@@ -4071,27 +4323,32 @@ function (Fields,
4071
4323
  },
4072
4324
  addForce: (function ()
4073
4325
  {
4074
- var force = new Vector3 (0, 0, 0);
4326
+ const force = new Vector3 (0, 0, 0);
4075
4327
 
4076
- return function (i, emitterNode, forces, turbulences)
4328
+ return function (i, emitterNode, timeByMass, forces)
4077
4329
  {
4078
- var surfaceArea = emitterNode ._surfaceArea .getValue ()
4079
-
4080
4330
  if (this ._enabled .getValue ())
4081
4331
  {
4082
- var
4083
- randomSpeed = this .getRandomSpeed (emitterNode),
4084
- pressure = Math .pow (10, 2 * Math .log (randomSpeed)) * 0.64615;
4332
+ const
4333
+ surfaceArea = emitterNode ._surfaceArea .getValue (),
4334
+ speed = this .getRandomSpeed (emitterNode),
4335
+ pressure = Math .pow (10, 2 * Math .log (speed)) * 0.64615;
4085
4336
 
4086
4337
  if (this ._direction .getValue () .equals (Vector3 .Zero))
4087
4338
  emitterNode .getRandomNormal (force);
4088
4339
  else
4089
4340
  force .assign (this ._direction .getValue ()) .normalize ();
4090
4341
 
4091
- forces [i] .assign (force .multiply (surfaceArea * pressure));
4092
- turbulences [i] = Math .PI * Algorithm .clamp (this ._turbulence .getValue (), 0, 1);
4342
+ forces .set (force .multiply (surfaceArea * pressure * timeByMass), i * 4);
4343
+ forces [i * 4 + 3] = Math .PI * Algorithm .clamp (this ._turbulence .getValue (), 0, 1);
4344
+
4345
+ return true;
4093
4346
  }
4094
- };
4347
+ else
4348
+ {
4349
+ return false;
4350
+ }
4351
+ }
4095
4352
  })(),
4096
4353
  });
4097
4354
 
@@ -4199,7 +4456,7 @@ function (Components,
4199
4456
  X3DParticleEmitterNode: X3DParticleEmitterNode,
4200
4457
  X3DParticlePhysicsModelNode: X3DParticlePhysicsModelNode,
4201
4458
  },
4202
- browser: X3DParticleSystemsContext,
4459
+ context: X3DParticleSystemsContext,
4203
4460
  });
4204
4461
  });
4205
4462