@lampdotdev/lamp 0.0.0-stage → 0.36.2-nightly.16

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 (470) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +397 -2
  3. package/Resources/Devices/roku.json +410 -0
  4. package/Resources/Devices/xbox-one.json +367 -0
  5. package/Resources/GameKit/NOTICE.md +63 -0
  6. package/Resources/GameKit/apple/LampPage.swift +1813 -0
  7. package/Resources/GameKit/apple/LampPlayer.swift +46 -0
  8. package/Resources/GameKit/apple/LampWebApp.swift +63 -0
  9. package/Resources/GameKit/apple/LampWebGame.swift +87 -0
  10. package/Resources/GameKit/apple/Native.swift +12 -0
  11. package/Resources/GameKit/build.sh +55 -0
  12. package/Resources/GameKit/lamp_game.h +116 -0
  13. package/Resources/GameKit/lamp_host.h +19 -0
  14. package/Resources/GameKit/lamp_kit.cpp +61 -0
  15. package/Resources/GameKit/lamp_sound.cpp +455 -0
  16. package/Resources/GameKit/lamp_xbox.cpp +374 -0
  17. package/Resources/GameKit/libraries/HandmadeMath.h +3940 -0
  18. package/Resources/GameKit/libraries/cgltf.h +7240 -0
  19. package/Resources/GameKit/libraries/dr_mp3.h +5430 -0
  20. package/Resources/GameKit/libraries/dr_wav.h +9209 -0
  21. package/Resources/GameKit/libraries/sokol_debugtext.h +4754 -0
  22. package/Resources/GameKit/libraries/sokol_gfx.h +29558 -0
  23. package/Resources/GameKit/libraries/sokol_gl.h +4538 -0
  24. package/Resources/GameKit/libraries/sokol_log.h +335 -0
  25. package/Resources/GameKit/libraries/sokol_shape.h +1531 -0
  26. package/Resources/GameKit/libraries/stb_image.h +7988 -0
  27. package/Resources/GameKit/libraries/stb_vorbis.c +5584 -0
  28. package/Resources/GameKit/page/lamp-live.js +672 -0
  29. package/Resources/GameKit/scaffold/Game/game.cpp +142 -0
  30. package/Resources/GameKit/scaffold/Game/scene.glsl +49 -0
  31. package/Resources/GameKit/scaffold-web/Web/game.js +31 -0
  32. package/Resources/GameKit/scaffold-web/Web/index.html +13 -0
  33. package/Resources/GameKit/scaffold-web/Web/making.js +33 -0
  34. package/Resources/GameKit/scaffold-web/Web/world.js +33 -0
  35. package/Resources/GameKit/web/lamp-game.js +3042 -0
  36. package/Resources/GameKit/web/lamp-phaser.js +128 -0
  37. package/Resources/WebHost/App.exe +0 -0
  38. package/Resources/WebHost/Microsoft.Web.WebView2.Core.dll +0 -0
  39. package/Resources/WebHost/WebView2-LICENSE.txt +27 -0
  40. package/Resources/WebHost/lamp_controllers.h +1506 -0
  41. package/Resources/WebHost/lamp_web_host.cpp +1173 -0
  42. package/Resources/WebLibraries/earlier.txt +318 -0
  43. package/Resources/WebLibraries/phaser/LICENSE.md +20 -0
  44. package/Resources/WebLibraries/phaser/NOTICE.md +2 -0
  45. package/Resources/WebLibraries/phaser/phaser.esm.min.js +1 -0
  46. package/Resources/WebLibraries/qrcode/LICENSE +21 -0
  47. package/Resources/WebLibraries/qrcode/NOTICE.md +4 -0
  48. package/Resources/WebLibraries/qrcode/qrcode.js +2297 -0
  49. package/Resources/WebLibraries/rapier/LICENSE +201 -0
  50. package/Resources/WebLibraries/rapier/NOTICE.md +3 -0
  51. package/Resources/WebLibraries/rapier/rapier.js +2 -0
  52. package/Resources/WebLibraries/three/LICENSE +21 -0
  53. package/Resources/WebLibraries/three/NOTICE.md +4 -0
  54. package/Resources/WebLibraries/three/addons/animation/AnimationClipCreator.js +168 -0
  55. package/Resources/WebLibraries/three/addons/animation/CCDIKSolver.js +607 -0
  56. package/Resources/WebLibraries/three/addons/controls/ArcballControls.js +3543 -0
  57. package/Resources/WebLibraries/three/addons/controls/DragControls.js +452 -0
  58. package/Resources/WebLibraries/three/addons/controls/FirstPersonControls.js +512 -0
  59. package/Resources/WebLibraries/three/addons/controls/FlyControls.js +384 -0
  60. package/Resources/WebLibraries/three/addons/controls/MapControls.js +116 -0
  61. package/Resources/WebLibraries/three/addons/controls/OrbitControls.js +1985 -0
  62. package/Resources/WebLibraries/three/addons/controls/PointerLockControls.js +264 -0
  63. package/Resources/WebLibraries/three/addons/controls/TrackballControls.js +1106 -0
  64. package/Resources/WebLibraries/three/addons/controls/TransformControls.js +2003 -0
  65. package/Resources/WebLibraries/three/addons/curves/CurveExtras.js +694 -0
  66. package/Resources/WebLibraries/three/addons/curves/NURBSCurve.js +169 -0
  67. package/Resources/WebLibraries/three/addons/curves/NURBSSurface.js +98 -0
  68. package/Resources/WebLibraries/three/addons/curves/NURBSUtils.js +532 -0
  69. package/Resources/WebLibraries/three/addons/curves/NURBSVolume.js +82 -0
  70. package/Resources/WebLibraries/three/addons/effects/AnaglyphEffect.js +274 -0
  71. package/Resources/WebLibraries/three/addons/effects/AsciiEffect.js +323 -0
  72. package/Resources/WebLibraries/three/addons/effects/OutlineEffect.js +489 -0
  73. package/Resources/WebLibraries/three/addons/effects/ParallaxBarrierEffect.js +155 -0
  74. package/Resources/WebLibraries/three/addons/effects/StereoEffect.js +91 -0
  75. package/Resources/WebLibraries/three/addons/environments/ColorEnvironment.js +59 -0
  76. package/Resources/WebLibraries/three/addons/environments/DebugEnvironment.js +102 -0
  77. package/Resources/WebLibraries/three/addons/environments/RoomEnvironment.js +185 -0
  78. package/Resources/WebLibraries/three/addons/geometries/BoxLineGeometry.js +92 -0
  79. package/Resources/WebLibraries/three/addons/geometries/ConvexGeometry.js +72 -0
  80. package/Resources/WebLibraries/three/addons/geometries/DecalGeometry.js +420 -0
  81. package/Resources/WebLibraries/three/addons/geometries/LoftGeometry.js +355 -0
  82. package/Resources/WebLibraries/three/addons/geometries/ParametricFunctions.js +100 -0
  83. package/Resources/WebLibraries/three/addons/geometries/ParametricGeometry.js +172 -0
  84. package/Resources/WebLibraries/three/addons/geometries/RoundedBoxGeometry.js +216 -0
  85. package/Resources/WebLibraries/three/addons/geometries/TeapotGeometry.js +689 -0
  86. package/Resources/WebLibraries/three/addons/geometries/TextGeometry.js +102 -0
  87. package/Resources/WebLibraries/three/addons/helpers/AnimationPathHelper.js +302 -0
  88. package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelper.js +166 -0
  89. package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelperWebGL.js +221 -0
  90. package/Resources/WebLibraries/three/addons/helpers/LightProbeHelper.js +166 -0
  91. package/Resources/WebLibraries/three/addons/helpers/LightProbeHelperGPU.js +102 -0
  92. package/Resources/WebLibraries/three/addons/helpers/OctreeHelper.js +109 -0
  93. package/Resources/WebLibraries/three/addons/helpers/PositionalAudioHelper.js +169 -0
  94. package/Resources/WebLibraries/three/addons/helpers/RapierHelper.js +59 -0
  95. package/Resources/WebLibraries/three/addons/helpers/RectAreaLightHelper.js +118 -0
  96. package/Resources/WebLibraries/three/addons/helpers/TextureHelper.js +265 -0
  97. package/Resources/WebLibraries/three/addons/helpers/TextureHelperGPU.js +214 -0
  98. package/Resources/WebLibraries/three/addons/helpers/VertexNormalsHelper.js +155 -0
  99. package/Resources/WebLibraries/three/addons/helpers/VertexTangentsHelper.js +133 -0
  100. package/Resources/WebLibraries/three/addons/helpers/ViewHelper.js +529 -0
  101. package/Resources/WebLibraries/three/addons/interactive/HTMLMesh.js +617 -0
  102. package/Resources/WebLibraries/three/addons/interactive/InteractiveGroup.js +224 -0
  103. package/Resources/WebLibraries/three/addons/interactive/SelectionBox.js +324 -0
  104. package/Resources/WebLibraries/three/addons/interactive/SelectionHelper.js +150 -0
  105. package/Resources/WebLibraries/three/addons/libs/fflate.module.js +2699 -0
  106. package/Resources/WebLibraries/three/addons/libs/lil-gui.module.min.js +8 -0
  107. package/Resources/WebLibraries/three/addons/libs/meshopt_decoder.module.js +196 -0
  108. package/Resources/WebLibraries/three/addons/libs/potpack.module.js +125 -0
  109. package/Resources/WebLibraries/three/addons/libs/stats.module.js +167 -0
  110. package/Resources/WebLibraries/three/addons/libs/tween.module.js +876 -0
  111. package/Resources/WebLibraries/three/addons/lighting/ClusteredLighting.js +153 -0
  112. package/Resources/WebLibraries/three/addons/lighting/DynamicLighting.js +82 -0
  113. package/Resources/WebLibraries/three/addons/lighting/LightMapper.js +295 -0
  114. package/Resources/WebLibraries/three/addons/lighting/LightProbeGrid.js +923 -0
  115. package/Resources/WebLibraries/three/addons/lighting/LightProbeGridUtils.js +107 -0
  116. package/Resources/WebLibraries/three/addons/lighting/LightProbeGridWebGL.js +846 -0
  117. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIConeTracer.js +243 -0
  118. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIIrradiance.js +43 -0
  119. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGINode.js +617 -0
  120. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGISceneCollector.js +793 -0
  121. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIVolume.js +1440 -0
  122. package/Resources/WebLibraries/three/addons/lights/LightProbeGenerator.js +337 -0
  123. package/Resources/WebLibraries/three/addons/lights/RectAreaLightTexturesLib.js +127 -0
  124. package/Resources/WebLibraries/three/addons/lights/RectAreaLightUniformsLib.js +40 -0
  125. package/Resources/WebLibraries/three/addons/lights/SunLight.js +100 -0
  126. package/Resources/WebLibraries/three/addons/lights/SunLightNode.js +56 -0
  127. package/Resources/WebLibraries/three/addons/lights/SunLightShadow.js +319 -0
  128. package/Resources/WebLibraries/three/addons/lights/SunShadowNode.js +312 -0
  129. package/Resources/WebLibraries/three/addons/lines/Line2.js +56 -0
  130. package/Resources/WebLibraries/three/addons/lines/LineGeometry.js +157 -0
  131. package/Resources/WebLibraries/three/addons/lines/LineMaterial.js +742 -0
  132. package/Resources/WebLibraries/three/addons/lines/LineSegments2.js +434 -0
  133. package/Resources/WebLibraries/three/addons/lines/LineSegmentsGeometry.js +298 -0
  134. package/Resources/WebLibraries/three/addons/lines/Wireframe.js +108 -0
  135. package/Resources/WebLibraries/three/addons/lines/WireframeGeometry2.js +49 -0
  136. package/Resources/WebLibraries/three/addons/lines/webgpu/Line2.js +46 -0
  137. package/Resources/WebLibraries/three/addons/lines/webgpu/LineSegments2.js +419 -0
  138. package/Resources/WebLibraries/three/addons/lines/webgpu/Wireframe.js +86 -0
  139. package/Resources/WebLibraries/three/addons/loaders/EXRLoader.js +3411 -0
  140. package/Resources/WebLibraries/three/addons/loaders/FBXLoader.js +4660 -0
  141. package/Resources/WebLibraries/three/addons/loaders/FontLoader.js +262 -0
  142. package/Resources/WebLibraries/three/addons/loaders/GLTFLoader.js +5006 -0
  143. package/Resources/WebLibraries/three/addons/loaders/HDRLoader.js +463 -0
  144. package/Resources/WebLibraries/three/addons/loaders/MTLLoader.js +601 -0
  145. package/Resources/WebLibraries/three/addons/loaders/OBJLoader.js +961 -0
  146. package/Resources/WebLibraries/three/addons/loaders/PLYLoader.js +992 -0
  147. package/Resources/WebLibraries/three/addons/loaders/RGBELoader.js +18 -0
  148. package/Resources/WebLibraries/three/addons/loaders/STLLoader.js +423 -0
  149. package/Resources/WebLibraries/three/addons/loaders/SVGLoader.js +3297 -0
  150. package/Resources/WebLibraries/three/addons/loaders/TGALoader.js +539 -0
  151. package/Resources/WebLibraries/three/addons/loaders/UltraHDRLoader.js +757 -0
  152. package/Resources/WebLibraries/three/addons/math/Capsule.js +159 -0
  153. package/Resources/WebLibraries/three/addons/math/ColorConverter.js +62 -0
  154. package/Resources/WebLibraries/three/addons/math/ColorSpaces.js +147 -0
  155. package/Resources/WebLibraries/three/addons/math/ConvexHull.js +1695 -0
  156. package/Resources/WebLibraries/three/addons/math/ImprovedNoise.js +88 -0
  157. package/Resources/WebLibraries/three/addons/math/Lut.js +317 -0
  158. package/Resources/WebLibraries/three/addons/math/MeshSurfaceSampler.js +315 -0
  159. package/Resources/WebLibraries/three/addons/math/OBB.js +535 -0
  160. package/Resources/WebLibraries/three/addons/math/Octree.js +825 -0
  161. package/Resources/WebLibraries/three/addons/math/SimplexNoise.js +470 -0
  162. package/Resources/WebLibraries/three/addons/misc/ConvexObjectBreaker.js +539 -0
  163. package/Resources/WebLibraries/three/addons/misc/GPUComputationRenderer.js +508 -0
  164. package/Resources/WebLibraries/three/addons/misc/Gyroscope.js +78 -0
  165. package/Resources/WebLibraries/three/addons/misc/MorphAnimMesh.js +119 -0
  166. package/Resources/WebLibraries/three/addons/misc/MorphBlendMesh.js +425 -0
  167. package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMap.js +370 -0
  168. package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMapGPU.js +322 -0
  169. package/Resources/WebLibraries/three/addons/misc/RollerCoaster.js +661 -0
  170. package/Resources/WebLibraries/three/addons/misc/Sculptor.js +1679 -0
  171. package/Resources/WebLibraries/three/addons/misc/SculptorMesh.js +1504 -0
  172. package/Resources/WebLibraries/three/addons/misc/SculptorTools.js +1180 -0
  173. package/Resources/WebLibraries/three/addons/misc/SculptorUtils.js +345 -0
  174. package/Resources/WebLibraries/three/addons/misc/TileCreasedNormalsPlugin.js +270 -0
  175. package/Resources/WebLibraries/three/addons/misc/TubePainter.js +611 -0
  176. package/Resources/WebLibraries/three/addons/misc/Volume.js +520 -0
  177. package/Resources/WebLibraries/three/addons/misc/VolumeSlice.js +275 -0
  178. package/Resources/WebLibraries/three/addons/modifiers/CurveModifier.js +374 -0
  179. package/Resources/WebLibraries/three/addons/modifiers/CurveModifierGPU.js +256 -0
  180. package/Resources/WebLibraries/three/addons/modifiers/EdgeSplitModifier.js +299 -0
  181. package/Resources/WebLibraries/three/addons/modifiers/TessellateModifier.js +340 -0
  182. package/Resources/WebLibraries/three/addons/objects/GroundedSkybox.js +69 -0
  183. package/Resources/WebLibraries/three/addons/objects/Lensflare.js +489 -0
  184. package/Resources/WebLibraries/three/addons/objects/LensflareMesh.js +376 -0
  185. package/Resources/WebLibraries/three/addons/objects/MarchingCubes.js +1261 -0
  186. package/Resources/WebLibraries/three/addons/objects/Reflector.js +390 -0
  187. package/Resources/WebLibraries/three/addons/objects/ReflectorForSSRPass.js +393 -0
  188. package/Resources/WebLibraries/three/addons/objects/Refractor.js +389 -0
  189. package/Resources/WebLibraries/three/addons/objects/ShadowMesh.js +130 -0
  190. package/Resources/WebLibraries/three/addons/objects/Sky.js +342 -0
  191. package/Resources/WebLibraries/three/addons/objects/SkyMesh.js +403 -0
  192. package/Resources/WebLibraries/three/addons/objects/Water.js +374 -0
  193. package/Resources/WebLibraries/three/addons/objects/Water2.js +403 -0
  194. package/Resources/WebLibraries/three/addons/objects/Water2Mesh.js +199 -0
  195. package/Resources/WebLibraries/three/addons/objects/WaterMesh.js +194 -0
  196. package/Resources/WebLibraries/three/addons/postprocessing/AfterimagePass.js +187 -0
  197. package/Resources/WebLibraries/three/addons/postprocessing/BloomPass.js +274 -0
  198. package/Resources/WebLibraries/three/addons/postprocessing/BokehPass.js +218 -0
  199. package/Resources/WebLibraries/three/addons/postprocessing/ClearPass.js +97 -0
  200. package/Resources/WebLibraries/three/addons/postprocessing/CubeTexturePass.js +146 -0
  201. package/Resources/WebLibraries/three/addons/postprocessing/DotScreenPass.js +114 -0
  202. package/Resources/WebLibraries/three/addons/postprocessing/EffectComposer.js +365 -0
  203. package/Resources/WebLibraries/three/addons/postprocessing/FXAAPass.js +40 -0
  204. package/Resources/WebLibraries/three/addons/postprocessing/FilmPass.js +113 -0
  205. package/Resources/WebLibraries/three/addons/postprocessing/GTAOPass.js +735 -0
  206. package/Resources/WebLibraries/three/addons/postprocessing/GlitchPass.js +177 -0
  207. package/Resources/WebLibraries/three/addons/postprocessing/HalftonePass.js +134 -0
  208. package/Resources/WebLibraries/three/addons/postprocessing/LUTPass.js +138 -0
  209. package/Resources/WebLibraries/three/addons/postprocessing/MaskPass.js +195 -0
  210. package/Resources/WebLibraries/three/addons/postprocessing/OutlinePass.js +776 -0
  211. package/Resources/WebLibraries/three/addons/postprocessing/OutputPass.js +148 -0
  212. package/Resources/WebLibraries/three/addons/postprocessing/Pass.js +191 -0
  213. package/Resources/WebLibraries/three/addons/postprocessing/RenderPass.js +193 -0
  214. package/Resources/WebLibraries/three/addons/postprocessing/RenderPixelatedPass.js +314 -0
  215. package/Resources/WebLibraries/three/addons/postprocessing/RenderTransitionPass.js +267 -0
  216. package/Resources/WebLibraries/three/addons/postprocessing/SAOPass.js +407 -0
  217. package/Resources/WebLibraries/three/addons/postprocessing/SMAAPass.js +230 -0
  218. package/Resources/WebLibraries/three/addons/postprocessing/SSAARenderPass.js +313 -0
  219. package/Resources/WebLibraries/three/addons/postprocessing/SSAOPass.js +527 -0
  220. package/Resources/WebLibraries/three/addons/postprocessing/SSRPass.js +858 -0
  221. package/Resources/WebLibraries/three/addons/postprocessing/SavePass.js +132 -0
  222. package/Resources/WebLibraries/three/addons/postprocessing/ShaderPass.js +135 -0
  223. package/Resources/WebLibraries/three/addons/postprocessing/TAARenderPass.js +243 -0
  224. package/Resources/WebLibraries/three/addons/postprocessing/TexturePass.js +131 -0
  225. package/Resources/WebLibraries/three/addons/postprocessing/UnrealBloomPass.js +541 -0
  226. package/Resources/WebLibraries/three/addons/shaders/ACESFilmicToneMappingShader.js +96 -0
  227. package/Resources/WebLibraries/three/addons/shaders/AfterimageShader.js +63 -0
  228. package/Resources/WebLibraries/three/addons/shaders/BasicShader.js +36 -0
  229. package/Resources/WebLibraries/three/addons/shaders/BleachBypassShader.js +68 -0
  230. package/Resources/WebLibraries/three/addons/shaders/BlendShader.js +56 -0
  231. package/Resources/WebLibraries/three/addons/shaders/BokehShader.js +151 -0
  232. package/Resources/WebLibraries/three/addons/shaders/BokehShader2.js +404 -0
  233. package/Resources/WebLibraries/three/addons/shaders/BrightnessContrastShader.js +62 -0
  234. package/Resources/WebLibraries/three/addons/shaders/ColorCorrectionShader.js +59 -0
  235. package/Resources/WebLibraries/three/addons/shaders/ColorifyShader.js +57 -0
  236. package/Resources/WebLibraries/three/addons/shaders/ConvolutionShader.js +74 -0
  237. package/Resources/WebLibraries/three/addons/shaders/CopyShader.js +52 -0
  238. package/Resources/WebLibraries/three/addons/shaders/DOFMipMapShader.js +63 -0
  239. package/Resources/WebLibraries/three/addons/shaders/DepthLimitedBlurShader.js +183 -0
  240. package/Resources/WebLibraries/three/addons/shaders/DigitalGlitch.js +104 -0
  241. package/Resources/WebLibraries/three/addons/shaders/DotScreenShader.js +75 -0
  242. package/Resources/WebLibraries/three/addons/shaders/ExposureShader.js +51 -0
  243. package/Resources/WebLibraries/three/addons/shaders/FXAAShader.js +298 -0
  244. package/Resources/WebLibraries/three/addons/shaders/FilmShader.js +73 -0
  245. package/Resources/WebLibraries/three/addons/shaders/FocusShader.js +94 -0
  246. package/Resources/WebLibraries/three/addons/shaders/FreiChenShader.js +103 -0
  247. package/Resources/WebLibraries/three/addons/shaders/GTAOShader.js +437 -0
  248. package/Resources/WebLibraries/three/addons/shaders/GammaCorrectionShader.js +52 -0
  249. package/Resources/WebLibraries/three/addons/shaders/HalftoneShader.js +332 -0
  250. package/Resources/WebLibraries/three/addons/shaders/HorizontalBlurShader.js +68 -0
  251. package/Resources/WebLibraries/three/addons/shaders/HorizontalTiltShiftShader.js +70 -0
  252. package/Resources/WebLibraries/three/addons/shaders/HueSaturationShader.js +74 -0
  253. package/Resources/WebLibraries/three/addons/shaders/KaleidoShader.js +65 -0
  254. package/Resources/WebLibraries/three/addons/shaders/LuminosityHighPassShader.js +68 -0
  255. package/Resources/WebLibraries/three/addons/shaders/LuminosityShader.js +54 -0
  256. package/Resources/WebLibraries/three/addons/shaders/MirrorShader.js +62 -0
  257. package/Resources/WebLibraries/three/addons/shaders/NormalMapShader.js +60 -0
  258. package/Resources/WebLibraries/three/addons/shaders/OutputShader.js +103 -0
  259. package/Resources/WebLibraries/three/addons/shaders/PoissonDenoiseShader.js +230 -0
  260. package/Resources/WebLibraries/three/addons/shaders/RGBShiftShader.js +61 -0
  261. package/Resources/WebLibraries/three/addons/shaders/SAOShader.js +201 -0
  262. package/Resources/WebLibraries/three/addons/shaders/SMAAShader.js +489 -0
  263. package/Resources/WebLibraries/three/addons/shaders/SSAOShader.js +331 -0
  264. package/Resources/WebLibraries/three/addons/shaders/SSRShader.js +396 -0
  265. package/Resources/WebLibraries/three/addons/shaders/SepiaShader.js +57 -0
  266. package/Resources/WebLibraries/three/addons/shaders/SobelOperatorShader.js +98 -0
  267. package/Resources/WebLibraries/three/addons/shaders/SubsurfaceScatteringShader.js +95 -0
  268. package/Resources/WebLibraries/three/addons/shaders/TechnicolorShader.js +51 -0
  269. package/Resources/WebLibraries/three/addons/shaders/ToonShader.js +349 -0
  270. package/Resources/WebLibraries/three/addons/shaders/TriangleBlurShader.js +79 -0
  271. package/Resources/WebLibraries/three/addons/shaders/UnpackDepthRGBAShader.js +60 -0
  272. package/Resources/WebLibraries/three/addons/shaders/VelocityShader.js +137 -0
  273. package/Resources/WebLibraries/three/addons/shaders/VerticalBlurShader.js +66 -0
  274. package/Resources/WebLibraries/three/addons/shaders/VerticalTiltShiftShader.js +70 -0
  275. package/Resources/WebLibraries/three/addons/shaders/VignetteShader.js +56 -0
  276. package/Resources/WebLibraries/three/addons/shaders/VolumeShader.js +285 -0
  277. package/Resources/WebLibraries/three/addons/shaders/WaterRefractionShader.js +106 -0
  278. package/Resources/WebLibraries/three/addons/textures/FlakesTexture.js +54 -0
  279. package/Resources/WebLibraries/three/addons/tsl/WebGLNodesHandler.js +607 -0
  280. package/Resources/WebLibraries/three/addons/tsl/display/AfterImageNode.js +256 -0
  281. package/Resources/WebLibraries/three/addons/tsl/display/AnaglyphPassNode.js +550 -0
  282. package/Resources/WebLibraries/three/addons/tsl/display/BilateralBlurNode.js +377 -0
  283. package/Resources/WebLibraries/three/addons/tsl/display/BleachBypass.js +33 -0
  284. package/Resources/WebLibraries/three/addons/tsl/display/BloomNode.js +599 -0
  285. package/Resources/WebLibraries/three/addons/tsl/display/CRT.js +150 -0
  286. package/Resources/WebLibraries/three/addons/tsl/display/ChromaticAberrationNode.js +163 -0
  287. package/Resources/WebLibraries/three/addons/tsl/display/DenoiseNode.js +354 -0
  288. package/Resources/WebLibraries/three/addons/tsl/display/DepthOfFieldNode.js +572 -0
  289. package/Resources/WebLibraries/three/addons/tsl/display/DotScreenNode.js +104 -0
  290. package/Resources/WebLibraries/three/addons/tsl/display/FSR1Node.js +481 -0
  291. package/Resources/WebLibraries/three/addons/tsl/display/FXAANode.js +357 -0
  292. package/Resources/WebLibraries/three/addons/tsl/display/FilmNode.js +101 -0
  293. package/Resources/WebLibraries/three/addons/tsl/display/GTAONode.js +727 -0
  294. package/Resources/WebLibraries/three/addons/tsl/display/GaussianBlurNode.js +412 -0
  295. package/Resources/WebLibraries/three/addons/tsl/display/GodraysNode.js +604 -0
  296. package/Resources/WebLibraries/three/addons/tsl/display/ImportanceSampledEnvironment.js +564 -0
  297. package/Resources/WebLibraries/three/addons/tsl/display/LensflareNode.js +282 -0
  298. package/Resources/WebLibraries/three/addons/tsl/display/Lut3DNode.js +109 -0
  299. package/Resources/WebLibraries/three/addons/tsl/display/MotionBlur.js +33 -0
  300. package/Resources/WebLibraries/three/addons/tsl/display/OITPassNode.js +341 -0
  301. package/Resources/WebLibraries/three/addons/tsl/display/OutlineNode.js +916 -0
  302. package/Resources/WebLibraries/three/addons/tsl/display/ParallaxBarrierPassNode.js +90 -0
  303. package/Resources/WebLibraries/three/addons/tsl/display/PixelationPassNode.js +227 -0
  304. package/Resources/WebLibraries/three/addons/tsl/display/RGBShiftNode.js +96 -0
  305. package/Resources/WebLibraries/three/addons/tsl/display/RecurrentDenoiseNode.js +812 -0
  306. package/Resources/WebLibraries/three/addons/tsl/display/RetroPassNode.js +263 -0
  307. package/Resources/WebLibraries/three/addons/tsl/display/SMAANode.js +729 -0
  308. package/Resources/WebLibraries/three/addons/tsl/display/SSAAPassNode.js +344 -0
  309. package/Resources/WebLibraries/three/addons/tsl/display/SSAONode.js +422 -0
  310. package/Resources/WebLibraries/three/addons/tsl/display/SSGINode.js +698 -0
  311. package/Resources/WebLibraries/three/addons/tsl/display/SSRNode.js +1430 -0
  312. package/Resources/WebLibraries/three/addons/tsl/display/SSSNode.js +479 -0
  313. package/Resources/WebLibraries/three/addons/tsl/display/Sepia.js +24 -0
  314. package/Resources/WebLibraries/three/addons/tsl/display/Shape.js +29 -0
  315. package/Resources/WebLibraries/three/addons/tsl/display/SharpenNode.js +284 -0
  316. package/Resources/WebLibraries/three/addons/tsl/display/SobelOperatorNode.js +168 -0
  317. package/Resources/WebLibraries/three/addons/tsl/display/StereoCompositePassNode.js +190 -0
  318. package/Resources/WebLibraries/three/addons/tsl/display/StereoPassNode.js +117 -0
  319. package/Resources/WebLibraries/three/addons/tsl/display/TAAUNode.js +700 -0
  320. package/Resources/WebLibraries/three/addons/tsl/display/TRAANode.js +609 -0
  321. package/Resources/WebLibraries/three/addons/tsl/display/TemporalReprojectNode.js +1024 -0
  322. package/Resources/WebLibraries/three/addons/tsl/display/TransitionNode.js +141 -0
  323. package/Resources/WebLibraries/three/addons/tsl/display/boxBlur.js +65 -0
  324. package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlend.js +80 -0
  325. package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlur.js +63 -0
  326. package/Resources/WebLibraries/three/addons/tsl/display/hashBlur.js +55 -0
  327. package/Resources/WebLibraries/three/addons/tsl/display/lensDirt.js +30 -0
  328. package/Resources/WebLibraries/three/addons/tsl/display/radialBlur.js +68 -0
  329. package/Resources/WebLibraries/three/addons/tsl/lighting/ClusteredLightsNode.js +994 -0
  330. package/Resources/WebLibraries/three/addons/tsl/lighting/DynamicLightsNode.js +201 -0
  331. package/Resources/WebLibraries/three/addons/tsl/lighting/LightProbeGridNode.js +183 -0
  332. package/Resources/WebLibraries/three/addons/tsl/lighting/data/AmbientLightDataNode.js +67 -0
  333. package/Resources/WebLibraries/three/addons/tsl/lighting/data/DirectionalLightDataNode.js +117 -0
  334. package/Resources/WebLibraries/three/addons/tsl/lighting/data/HemisphereLightDataNode.js +105 -0
  335. package/Resources/WebLibraries/three/addons/tsl/lighting/data/PointLightDataNode.js +140 -0
  336. package/Resources/WebLibraries/three/addons/tsl/lighting/data/SpotLightDataNode.js +167 -0
  337. package/Resources/WebLibraries/three/addons/tsl/math/Bayer.js +84 -0
  338. package/Resources/WebLibraries/three/addons/tsl/math/curlNoise.js +107 -0
  339. package/Resources/WebLibraries/three/addons/tsl/math/voronoiNoise.js +112 -0
  340. package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNode.js +542 -0
  341. package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNodeHelper.js +212 -0
  342. package/Resources/WebLibraries/three/addons/tsl/utils/GroundedSkybox.js +62 -0
  343. package/Resources/WebLibraries/three/addons/tsl/utils/RNoise.js +51 -0
  344. package/Resources/WebLibraries/three/addons/tsl/utils/Raymarching.js +70 -0
  345. package/Resources/WebLibraries/three/addons/tsl/utils/SoftParticles.js +53 -0
  346. package/Resources/WebLibraries/three/addons/tsl/utils/SpecularHelpers.js +302 -0
  347. package/Resources/WebLibraries/three/addons/tsl/utils/TAAUtils.js +184 -0
  348. package/Resources/WebLibraries/three/addons/utils/BufferGeometryUtils.js +1523 -0
  349. package/Resources/WebLibraries/three/addons/utils/CameraUtils.js +82 -0
  350. package/Resources/WebLibraries/three/addons/utils/ColorUtils.js +76 -0
  351. package/Resources/WebLibraries/three/addons/utils/GaussianSplatUtils.js +229 -0
  352. package/Resources/WebLibraries/three/addons/utils/GeometryCompressionUtils.js +547 -0
  353. package/Resources/WebLibraries/three/addons/utils/GeometryUtils.js +226 -0
  354. package/Resources/WebLibraries/three/addons/utils/LDrawUtils.js +211 -0
  355. package/Resources/WebLibraries/three/addons/utils/SceneOptimizer.js +459 -0
  356. package/Resources/WebLibraries/three/addons/utils/SceneUtils.js +363 -0
  357. package/Resources/WebLibraries/three/addons/utils/ShadowMapViewer.js +244 -0
  358. package/Resources/WebLibraries/three/addons/utils/ShadowMapViewerGPU.js +233 -0
  359. package/Resources/WebLibraries/three/addons/utils/SkeletonUtils.js +496 -0
  360. package/Resources/WebLibraries/three/addons/utils/SortUtils.js +175 -0
  361. package/Resources/WebLibraries/three/addons/utils/UVsDebug.js +173 -0
  362. package/Resources/WebLibraries/three/addons/utils/WebGLTextureUtils.js +115 -0
  363. package/Resources/WebLibraries/three/addons/utils/WebGPUTextureUtils.js +81 -0
  364. package/Resources/WebLibraries/three/addons/utils/WorkerPool.js +167 -0
  365. package/Resources/WebLibraries/three/addons/utils/unwrapUVs.js +865 -0
  366. package/Resources/WebLibraries/three/three.core.js +61162 -0
  367. package/Resources/WebLibraries/three/three.module.js +19537 -0
  368. package/Resources/WebLibraries/three/three.tsl.js +41903 -0
  369. package/Resources/WebLibraries/three/three.webgpu.js +53714 -0
  370. package/Resources/share-rules.json +64 -0
  371. package/Resources/skills/2d-game/SKILL.md +305 -0
  372. package/Resources/skills/3d-game/SKILL.md +274 -0
  373. package/Resources/skills/accounts/SKILL.md +41 -0
  374. package/Resources/skills/android-design/SKILL.md +159 -0
  375. package/Resources/skills/app-ai/SKILL.md +154 -0
  376. package/Resources/skills/app-intents/SKILL.md +31 -0
  377. package/Resources/skills/app-kinds/SKILL.md +122 -0
  378. package/Resources/skills/apple-watch/SKILL.md +43 -0
  379. package/Resources/skills/assets/SKILL.md +183 -0
  380. package/Resources/skills/building-blocks/SKILL.md +97 -0
  381. package/Resources/skills/device-control/SKILL.md +56 -0
  382. package/Resources/skills/device-integrations/SKILL.md +278 -0
  383. package/Resources/skills/finder-files/SKILL.md +19 -0
  384. package/Resources/skills/game/SKILL.md +416 -0
  385. package/Resources/skills/game-3d/SKILL.md +12 -0
  386. package/Resources/skills/game-art/SKILL.md +11 -0
  387. package/Resources/skills/game-feel/SKILL.md +13 -0
  388. package/Resources/skills/game-levels/SKILL.md +12 -0
  389. package/Resources/skills/game-live/SKILL.md +12 -0
  390. package/Resources/skills/game-physics/SKILL.md +13 -0
  391. package/Resources/skills/game-playtest/SKILL.md +26 -0
  392. package/Resources/skills/game-ui/SKILL.md +278 -0
  393. package/Resources/skills/github-projects/SKILL.md +62 -0
  394. package/Resources/skills/icloud-sync/SKILL.md +30 -0
  395. package/Resources/skills/iphone-hardware/SKILL.md +57 -0
  396. package/Resources/skills/iphone-widgets/SKILL.md +53 -0
  397. package/Resources/skills/lg-developer-mode/SKILL.md +152 -0
  398. package/Resources/skills/mac-widgets/SKILL.md +60 -0
  399. package/Resources/skills/maps/SKILL.md +8 -0
  400. package/Resources/skills/menu-bar/SKILL.md +36 -0
  401. package/Resources/skills/more-apps/SKILL.md +53 -0
  402. package/Resources/skills/phone-controllers/SKILL.md +79 -0
  403. package/Resources/skills/phone-pages/SKILL.md +173 -0
  404. package/Resources/skills/roku-developer-mode/SKILL.md +106 -0
  405. package/Resources/skills/scene-3d/SKILL.md +27 -0
  406. package/Resources/skills/scripting/SKILL.md +17 -0
  407. package/Resources/skills/share-extension/SKILL.md +22 -0
  408. package/Resources/skills/tv-design/SKILL.md +72 -0
  409. package/Resources/skills/web-app/SKILL.md +170 -0
  410. package/Resources/skills/web-game/SKILL.md +95 -0
  411. package/Resources/skills/web-or-native/SKILL.md +108 -0
  412. package/Resources/skills/wish-links/SKILL.md +156 -0
  413. package/THIRD_PARTY_NOTICES.md +170 -0
  414. package/cli/ai.mjs +237 -0
  415. package/cli/android.mjs +941 -0
  416. package/cli/app-ai.mjs +473 -0
  417. package/cli/browser.mjs +284 -0
  418. package/cli/calls.mjs +594 -0
  419. package/cli/dev.mjs +820 -0
  420. package/cli/devices.mjs +984 -0
  421. package/cli/lamp.mjs +1326 -0
  422. package/cli/lampapp.mjs +332 -0
  423. package/cli/lamps/android-host/LampPageGateway.kt +345 -0
  424. package/cli/lamps/android-host/app/build.gradle.kts +40 -0
  425. package/cli/lamps/android-host/build.gradle.kts +4 -0
  426. package/cli/lamps/android-host/game/AndroidManifest.xml +33 -0
  427. package/cli/lamps/android-host/game/MainActivity.kt +173 -0
  428. package/cli/lamps/android-host/gradle/libs.versions.toml +39 -0
  429. package/cli/lamps/android-host/gradle.properties +8 -0
  430. package/cli/lamps/android-host/page/AndroidManifest.xml +35 -0
  431. package/cli/lamps/android-host/page/MainActivity.kt +193 -0
  432. package/cli/lamps/android-host/settings.gradle.kts +30 -0
  433. package/cli/lamps/android-host/tools.json +43 -0
  434. package/cli/lamps/lamp-controllers.js +2 -0
  435. package/cli/lamps/lamp-for-games.js +6922 -0
  436. package/cli/lamps/lamp.js +7082 -0
  437. package/cli/lamps/mac-starter/.lamp/meta.json +1 -0
  438. package/cli/lamps/mac-starter/APP.md +12 -0
  439. package/cli/lamps/mac-starter/Package.swift +8 -0
  440. package/cli/lamps/mac-starter/Sources/App.swift +11 -0
  441. package/cli/lamps/mac-starter/Sources/ContentView.swift +17 -0
  442. package/cli/lamps/mac-starter/Sources/LampSupport.swift +18215 -0
  443. package/cli/lamps/mac-starter/build.sh +336 -0
  444. package/cli/lamps/mac-starter/gitignore +3 -0
  445. package/cli/lamps/mac-starter/lamp-starter.json +6 -0
  446. package/cli/lamps/web-starter/APP.md +8 -0
  447. package/cli/lamps/web-starter/app.js +1 -0
  448. package/cli/lamps/web-starter/index.html +17 -0
  449. package/cli/lamps/web-starter/lamp-starter.json +5 -0
  450. package/cli/lamps/web-starter/lamp.js +7082 -0
  451. package/cli/lamps/web-starter/style.css +25 -0
  452. package/cli/link.mjs +202 -0
  453. package/cli/local-ai.mjs +193 -0
  454. package/cli/mac.mjs +621 -0
  455. package/cli/mdns.mjs +205 -0
  456. package/cli/msix.mjs +413 -0
  457. package/cli/network.mjs +209 -0
  458. package/cli/openrouter.mjs +133 -0
  459. package/cli/outside.mjs +203 -0
  460. package/cli/page.js +317 -0
  461. package/cli/place.mjs +298 -0
  462. package/cli/png.mjs +184 -0
  463. package/cli/share.mjs +270 -0
  464. package/cli/skill/SKILL.md +280 -0
  465. package/cli/skills.mjs +71 -0
  466. package/cli/state.mjs +176 -0
  467. package/cli/update.mjs +162 -0
  468. package/package.json +20 -4
  469. package/site/lib/quota.js +59 -0
  470. package/site/lib/shared-wishes.js +1727 -0
@@ -0,0 +1,3297 @@
1
+ import {
2
+ Box2,
3
+ BufferGeometry,
4
+ CanvasTexture,
5
+ ClampToEdgeWrapping,
6
+ Color,
7
+ DoubleSide,
8
+ FileLoader,
9
+ Float32BufferAttribute,
10
+ Loader,
11
+ Matrix3,
12
+ MeshBasicMaterial,
13
+ MirroredRepeatWrapping,
14
+ Path,
15
+ RepeatWrapping,
16
+ ShapePath,
17
+ ShapeUtils,
18
+ SRGBColorSpace,
19
+ Vector2,
20
+ Vector3
21
+ } from 'three';
22
+
23
+ const COLOR_SPACE_SVG = SRGBColorSpace;
24
+
25
+ /**
26
+ * A loader for the SVG format.
27
+ *
28
+ * Scalable Vector Graphics is an XML-based vector image format for two-dimensional graphics
29
+ * with support for interactivity and animation.
30
+ *
31
+ * ```js
32
+ * const loader = new SVGLoader();
33
+ * const data = await loader.loadAsync( 'data/svgSample.svg' );
34
+ *
35
+ * const paths = data.paths;
36
+ * const group = new THREE.Group();
37
+ *
38
+ * for ( let i = 0; i < paths.length; i ++ ) {
39
+ *
40
+ * const path = paths[ i ];
41
+ * const material = new THREE.MeshBasicMaterial( {
42
+ * color: path.color,
43
+ * side: THREE.DoubleSide,
44
+ * depthWrite: false
45
+ * } );
46
+ *
47
+ * const shapes = SVGLoader.createShapes( path );
48
+ *
49
+ * for ( let j = 0; j < shapes.length; j ++ ) {
50
+ *
51
+ * const shape = shapes[ j ];
52
+ * const geometry = new THREE.ShapeGeometry( shape );
53
+ * const mesh = new THREE.Mesh( geometry, material );
54
+ * group.add( mesh );
55
+ *
56
+ * }
57
+ *
58
+ * }
59
+ *
60
+ * scene.add( group );
61
+ * ```
62
+ *
63
+ * @augments Loader
64
+ * @three_import import { SVGLoader } from 'three/addons/loaders/SVGLoader.js';
65
+ */
66
+ class SVGLoader extends Loader {
67
+
68
+ /**
69
+ * Constructs a new SVG loader.
70
+ *
71
+ * @param {LoadingManager} [manager] - The loading manager.
72
+ */
73
+ constructor( manager ) {
74
+
75
+ super( manager );
76
+
77
+ /**
78
+ * Default dots per inch.
79
+ *
80
+ * @type {number}
81
+ * @default 90
82
+ */
83
+ this.defaultDPI = 90;
84
+
85
+ /**
86
+ * Default unit.
87
+ *
88
+ * @type {('mm'|'cm'|'in'|'pt'|'pc'|'px')}
89
+ * @default 'px'
90
+ */
91
+ this.defaultUnit = 'px';
92
+
93
+ }
94
+
95
+ /**
96
+ * Starts loading from the given URL and passes the loaded SVG asset
97
+ * to the `onLoad()` callback.
98
+ *
99
+ * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
100
+ * @param {function({paths:Array<ShapePath>,xml:string})} onLoad - Executed when the loading process has been finished.
101
+ * @param {onProgressCallback} onProgress - Executed while the loading is in progress.
102
+ * @param {onErrorCallback} onError - Executed when errors occur.
103
+ */
104
+ load( url, onLoad, onProgress, onError ) {
105
+
106
+ const scope = this;
107
+
108
+ const loader = new FileLoader( scope.manager );
109
+ loader.setPriority( scope.priority );
110
+ loader.setCache( scope.cache );
111
+ loader.setPath( scope.path );
112
+ loader.setRequestHeader( scope.requestHeader );
113
+ loader.setWithCredentials( scope.withCredentials );
114
+ loader.load( url, function ( text ) {
115
+
116
+ try {
117
+
118
+ onLoad( scope.parse( text ) );
119
+
120
+ } catch ( e ) {
121
+
122
+ if ( onError ) {
123
+
124
+ onError( e );
125
+
126
+ } else {
127
+
128
+ console.error( e );
129
+
130
+ }
131
+
132
+ scope.manager.itemError( url );
133
+
134
+ }
135
+
136
+ }, onProgress, onError );
137
+
138
+ }
139
+
140
+ /**
141
+ * Parses the given SVG data and returns the resulting data.
142
+ *
143
+ * @param {string} text - The raw SVG data as a string.
144
+ * @return {{paths:Array<ShapePath>,xml:string}} An object holding an array of shape paths and the
145
+ * SVG XML document.
146
+ */
147
+ parse( text ) {
148
+
149
+ const scope = this;
150
+
151
+ function parseNode( node, style ) {
152
+
153
+ if ( node.nodeType !== 1 ) return;
154
+
155
+ if ( node.hasAttribute( 'filter' ) ) {
156
+
157
+ console.warn( 'THREE.SVGLoader: Filters are not supported.' );
158
+
159
+ }
160
+
161
+ const transform = getNodeTransform( node );
162
+
163
+ let isDefsNode = false;
164
+
165
+ let path = null;
166
+
167
+ switch ( node.nodeName ) {
168
+
169
+ case 'svg':
170
+ style = parseStyle( node, style );
171
+ break;
172
+
173
+ case 'style':
174
+ parseCSSStylesheet( node );
175
+ break;
176
+
177
+ case 'g':
178
+ style = parseStyle( node, style );
179
+ break;
180
+
181
+ case 'path':
182
+ style = parseStyle( node, style );
183
+ if ( node.hasAttribute( 'd' ) ) path = parsePathNode( node );
184
+ break;
185
+
186
+ case 'rect':
187
+ style = parseStyle( node, style );
188
+ path = parseRectNode( node );
189
+ break;
190
+
191
+ case 'polygon':
192
+ style = parseStyle( node, style );
193
+ path = parsePolygonNode( node );
194
+ break;
195
+
196
+ case 'polyline':
197
+ style = parseStyle( node, style );
198
+ path = parsePolylineNode( node );
199
+ break;
200
+
201
+ case 'circle':
202
+ style = parseStyle( node, style );
203
+ path = parseCircleNode( node );
204
+ break;
205
+
206
+ case 'ellipse':
207
+ style = parseStyle( node, style );
208
+ path = parseEllipseNode( node );
209
+ break;
210
+
211
+ case 'line':
212
+ style = parseStyle( node, style );
213
+ path = parseLineNode( node );
214
+ break;
215
+
216
+ case 'defs':
217
+ isDefsNode = true;
218
+ break;
219
+
220
+ case 'use':
221
+ style = parseStyle( node, style );
222
+
223
+ const href = node.getAttributeNS( 'http://www.w3.org/1999/xlink', 'href' ) || node.getAttribute( 'href' ) || '';
224
+ const usedNodeId = href.substring( 1 );
225
+ const usedNode = node.viewportElement.getElementById( usedNodeId );
226
+ if ( usedNode ) {
227
+
228
+ parseNode( usedNode, style );
229
+
230
+ } else {
231
+
232
+ console.warn( 'SVGLoader: \'use node\' references non-existent node id: ' + usedNodeId );
233
+
234
+ }
235
+
236
+ break;
237
+
238
+ default:
239
+ // console.log( node );
240
+
241
+ }
242
+
243
+ if ( path ) {
244
+
245
+ if ( style.fill !== undefined && style.fill !== 'none' && ! style.fill.startsWith( 'url' ) ) {
246
+
247
+ path.color.setStyle( style.fill, COLOR_SPACE_SVG );
248
+
249
+ }
250
+
251
+ transformPath( path, currentTransform );
252
+
253
+ paths.push( path );
254
+
255
+ const pathStyle = Object.assign( {}, style );
256
+ pathStyle.strokeWidth = style.strokeWidth * getTransformScale( currentTransform );
257
+
258
+ path.userData = { node: node, style: pathStyle, transform: currentTransform.clone(), gradients: gradients };
259
+
260
+ }
261
+
262
+ const childNodes = node.childNodes;
263
+
264
+ for ( let i = 0; i < childNodes.length; i ++ ) {
265
+
266
+ const node = childNodes[ i ];
267
+
268
+ if ( isDefsNode && node.nodeName !== 'style' && node.nodeName !== 'defs' ) {
269
+
270
+ // Ignore everything in defs except CSS style definitions
271
+ // and nested defs, because it is OK by the standard to have
272
+ // <style/> there.
273
+ continue;
274
+
275
+ }
276
+
277
+ parseNode( node, style );
278
+
279
+ }
280
+
281
+
282
+ if ( transform ) {
283
+
284
+ transformStack.pop();
285
+
286
+ if ( transformStack.length > 0 ) {
287
+
288
+ currentTransform.copy( transformStack[ transformStack.length - 1 ] );
289
+
290
+ } else {
291
+
292
+ currentTransform.identity();
293
+
294
+ }
295
+
296
+ }
297
+
298
+ }
299
+
300
+ function parsePathNode( node ) {
301
+
302
+ const path = new ShapePath();
303
+
304
+ const point = new Vector2();
305
+ const control = new Vector2();
306
+
307
+ const firstPoint = new Vector2();
308
+ let isPathClosed = false;
309
+
310
+ const d = node.getAttribute( 'd' );
311
+
312
+ if ( d === '' || d === 'none' ) return null;
313
+
314
+ // console.log( d );
315
+
316
+ const commands = d.match( /[a-df-z][^a-df-z]*/ig );
317
+
318
+ for ( let i = 0, l = commands.length; i < l; i ++ ) {
319
+
320
+ const command = commands[ i ];
321
+
322
+ const type = command.charAt( 0 );
323
+ const data = command.slice( 1 ).trim();
324
+
325
+ if ( isPathClosed === true ) {
326
+
327
+ // commands after Z without M start a new subpath at the initial point
328
+
329
+ if ( type !== 'M' && type !== 'm' && type !== 'Z' && type !== 'z' ) {
330
+
331
+ path.moveTo( firstPoint.x, firstPoint.y );
332
+
333
+ }
334
+
335
+ isPathClosed = false;
336
+
337
+ }
338
+
339
+ let numbers;
340
+
341
+ switch ( type ) {
342
+
343
+ case 'M':
344
+ numbers = parseFloats( data );
345
+ for ( let j = 0, jl = numbers.length; j < jl; j += 2 ) {
346
+
347
+ point.x = numbers[ j + 0 ];
348
+ point.y = numbers[ j + 1 ];
349
+ control.x = point.x;
350
+ control.y = point.y;
351
+
352
+ if ( j === 0 ) {
353
+
354
+ path.moveTo( point.x, point.y );
355
+
356
+ } else {
357
+
358
+ path.lineTo( point.x, point.y );
359
+
360
+ }
361
+
362
+ if ( j === 0 ) firstPoint.copy( point );
363
+
364
+ }
365
+
366
+ break;
367
+
368
+ case 'H':
369
+ numbers = parseFloats( data );
370
+
371
+ for ( let j = 0, jl = numbers.length; j < jl; j ++ ) {
372
+
373
+ point.x = numbers[ j ];
374
+ control.x = point.x;
375
+ control.y = point.y;
376
+ path.lineTo( point.x, point.y );
377
+
378
+ }
379
+
380
+ break;
381
+
382
+ case 'V':
383
+ numbers = parseFloats( data );
384
+
385
+ for ( let j = 0, jl = numbers.length; j < jl; j ++ ) {
386
+
387
+ point.y = numbers[ j ];
388
+ control.x = point.x;
389
+ control.y = point.y;
390
+ path.lineTo( point.x, point.y );
391
+
392
+ }
393
+
394
+ break;
395
+
396
+ case 'L':
397
+ numbers = parseFloats( data );
398
+
399
+ for ( let j = 0, jl = numbers.length; j < jl; j += 2 ) {
400
+
401
+ point.x = numbers[ j + 0 ];
402
+ point.y = numbers[ j + 1 ];
403
+ control.x = point.x;
404
+ control.y = point.y;
405
+ path.lineTo( point.x, point.y );
406
+
407
+ }
408
+
409
+ break;
410
+
411
+ case 'C':
412
+ numbers = parseFloats( data );
413
+
414
+ for ( let j = 0, jl = numbers.length; j < jl; j += 6 ) {
415
+
416
+ path.bezierCurveTo(
417
+ numbers[ j + 0 ],
418
+ numbers[ j + 1 ],
419
+ numbers[ j + 2 ],
420
+ numbers[ j + 3 ],
421
+ numbers[ j + 4 ],
422
+ numbers[ j + 5 ]
423
+ );
424
+ control.x = numbers[ j + 2 ];
425
+ control.y = numbers[ j + 3 ];
426
+ point.x = numbers[ j + 4 ];
427
+ point.y = numbers[ j + 5 ];
428
+
429
+ }
430
+
431
+ break;
432
+
433
+ case 'S':
434
+ numbers = parseFloats( data );
435
+
436
+ for ( let j = 0, jl = numbers.length; j < jl; j += 4 ) {
437
+
438
+ path.bezierCurveTo(
439
+ getReflection( point.x, control.x ),
440
+ getReflection( point.y, control.y ),
441
+ numbers[ j + 0 ],
442
+ numbers[ j + 1 ],
443
+ numbers[ j + 2 ],
444
+ numbers[ j + 3 ]
445
+ );
446
+ control.x = numbers[ j + 0 ];
447
+ control.y = numbers[ j + 1 ];
448
+ point.x = numbers[ j + 2 ];
449
+ point.y = numbers[ j + 3 ];
450
+
451
+ }
452
+
453
+ break;
454
+
455
+ case 'Q':
456
+ numbers = parseFloats( data );
457
+
458
+ for ( let j = 0, jl = numbers.length; j < jl; j += 4 ) {
459
+
460
+ path.quadraticCurveTo(
461
+ numbers[ j + 0 ],
462
+ numbers[ j + 1 ],
463
+ numbers[ j + 2 ],
464
+ numbers[ j + 3 ]
465
+ );
466
+ control.x = numbers[ j + 0 ];
467
+ control.y = numbers[ j + 1 ];
468
+ point.x = numbers[ j + 2 ];
469
+ point.y = numbers[ j + 3 ];
470
+
471
+ }
472
+
473
+ break;
474
+
475
+ case 'T':
476
+ numbers = parseFloats( data );
477
+
478
+ for ( let j = 0, jl = numbers.length; j < jl; j += 2 ) {
479
+
480
+ const rx = getReflection( point.x, control.x );
481
+ const ry = getReflection( point.y, control.y );
482
+ path.quadraticCurveTo(
483
+ rx,
484
+ ry,
485
+ numbers[ j + 0 ],
486
+ numbers[ j + 1 ]
487
+ );
488
+ control.x = rx;
489
+ control.y = ry;
490
+ point.x = numbers[ j + 0 ];
491
+ point.y = numbers[ j + 1 ];
492
+
493
+ }
494
+
495
+ break;
496
+
497
+ case 'A':
498
+ numbers = parseFloats( data, [ 3, 4 ], 7 );
499
+
500
+ for ( let j = 0, jl = numbers.length; j < jl; j += 7 ) {
501
+
502
+ // skip command if start point == end point
503
+ if ( numbers[ j + 5 ] == point.x && numbers[ j + 6 ] == point.y ) continue;
504
+
505
+ const start = point.clone();
506
+ point.x = numbers[ j + 5 ];
507
+ point.y = numbers[ j + 6 ];
508
+ control.x = point.x;
509
+ control.y = point.y;
510
+ parseArcCommand(
511
+ path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
512
+ );
513
+
514
+ }
515
+
516
+ break;
517
+
518
+ case 'm':
519
+ numbers = parseFloats( data );
520
+
521
+ for ( let j = 0, jl = numbers.length; j < jl; j += 2 ) {
522
+
523
+ point.x += numbers[ j + 0 ];
524
+ point.y += numbers[ j + 1 ];
525
+ control.x = point.x;
526
+ control.y = point.y;
527
+
528
+ if ( j === 0 ) {
529
+
530
+ path.moveTo( point.x, point.y );
531
+
532
+ } else {
533
+
534
+ path.lineTo( point.x, point.y );
535
+
536
+ }
537
+
538
+ if ( j === 0 ) firstPoint.copy( point );
539
+
540
+ }
541
+
542
+ break;
543
+
544
+ case 'h':
545
+ numbers = parseFloats( data );
546
+
547
+ for ( let j = 0, jl = numbers.length; j < jl; j ++ ) {
548
+
549
+ point.x += numbers[ j ];
550
+ control.x = point.x;
551
+ control.y = point.y;
552
+ path.lineTo( point.x, point.y );
553
+
554
+ }
555
+
556
+ break;
557
+
558
+ case 'v':
559
+ numbers = parseFloats( data );
560
+
561
+ for ( let j = 0, jl = numbers.length; j < jl; j ++ ) {
562
+
563
+ point.y += numbers[ j ];
564
+ control.x = point.x;
565
+ control.y = point.y;
566
+ path.lineTo( point.x, point.y );
567
+
568
+ }
569
+
570
+ break;
571
+
572
+ case 'l':
573
+ numbers = parseFloats( data );
574
+
575
+ for ( let j = 0, jl = numbers.length; j < jl; j += 2 ) {
576
+
577
+ point.x += numbers[ j + 0 ];
578
+ point.y += numbers[ j + 1 ];
579
+ control.x = point.x;
580
+ control.y = point.y;
581
+ path.lineTo( point.x, point.y );
582
+
583
+ }
584
+
585
+ break;
586
+
587
+ case 'c':
588
+ numbers = parseFloats( data );
589
+
590
+ for ( let j = 0, jl = numbers.length; j < jl; j += 6 ) {
591
+
592
+ path.bezierCurveTo(
593
+ point.x + numbers[ j + 0 ],
594
+ point.y + numbers[ j + 1 ],
595
+ point.x + numbers[ j + 2 ],
596
+ point.y + numbers[ j + 3 ],
597
+ point.x + numbers[ j + 4 ],
598
+ point.y + numbers[ j + 5 ]
599
+ );
600
+ control.x = point.x + numbers[ j + 2 ];
601
+ control.y = point.y + numbers[ j + 3 ];
602
+ point.x += numbers[ j + 4 ];
603
+ point.y += numbers[ j + 5 ];
604
+
605
+ }
606
+
607
+ break;
608
+
609
+ case 's':
610
+ numbers = parseFloats( data );
611
+
612
+ for ( let j = 0, jl = numbers.length; j < jl; j += 4 ) {
613
+
614
+ path.bezierCurveTo(
615
+ getReflection( point.x, control.x ),
616
+ getReflection( point.y, control.y ),
617
+ point.x + numbers[ j + 0 ],
618
+ point.y + numbers[ j + 1 ],
619
+ point.x + numbers[ j + 2 ],
620
+ point.y + numbers[ j + 3 ]
621
+ );
622
+ control.x = point.x + numbers[ j + 0 ];
623
+ control.y = point.y + numbers[ j + 1 ];
624
+ point.x += numbers[ j + 2 ];
625
+ point.y += numbers[ j + 3 ];
626
+
627
+ }
628
+
629
+ break;
630
+
631
+ case 'q':
632
+ numbers = parseFloats( data );
633
+
634
+ for ( let j = 0, jl = numbers.length; j < jl; j += 4 ) {
635
+
636
+ path.quadraticCurveTo(
637
+ point.x + numbers[ j + 0 ],
638
+ point.y + numbers[ j + 1 ],
639
+ point.x + numbers[ j + 2 ],
640
+ point.y + numbers[ j + 3 ]
641
+ );
642
+ control.x = point.x + numbers[ j + 0 ];
643
+ control.y = point.y + numbers[ j + 1 ];
644
+ point.x += numbers[ j + 2 ];
645
+ point.y += numbers[ j + 3 ];
646
+
647
+ }
648
+
649
+ break;
650
+
651
+ case 't':
652
+ numbers = parseFloats( data );
653
+
654
+ for ( let j = 0, jl = numbers.length; j < jl; j += 2 ) {
655
+
656
+ const rx = getReflection( point.x, control.x );
657
+ const ry = getReflection( point.y, control.y );
658
+ path.quadraticCurveTo(
659
+ rx,
660
+ ry,
661
+ point.x + numbers[ j + 0 ],
662
+ point.y + numbers[ j + 1 ]
663
+ );
664
+ control.x = rx;
665
+ control.y = ry;
666
+ point.x = point.x + numbers[ j + 0 ];
667
+ point.y = point.y + numbers[ j + 1 ];
668
+
669
+ }
670
+
671
+ break;
672
+
673
+ case 'a':
674
+ numbers = parseFloats( data, [ 3, 4 ], 7 );
675
+
676
+ for ( let j = 0, jl = numbers.length; j < jl; j += 7 ) {
677
+
678
+ // skip command if no displacement
679
+ if ( numbers[ j + 5 ] == 0 && numbers[ j + 6 ] == 0 ) continue;
680
+
681
+ const start = point.clone();
682
+ point.x += numbers[ j + 5 ];
683
+ point.y += numbers[ j + 6 ];
684
+ control.x = point.x;
685
+ control.y = point.y;
686
+ parseArcCommand(
687
+ path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
688
+ );
689
+
690
+ }
691
+
692
+ break;
693
+
694
+ case 'Z':
695
+ case 'z':
696
+ path.currentPath.autoClose = true;
697
+
698
+ if ( path.currentPath.curves.length > 0 ) {
699
+
700
+ // Reset point to beginning of Path
701
+ point.copy( firstPoint );
702
+ path.currentPath.currentPoint.copy( point );
703
+ isPathClosed = true;
704
+
705
+ }
706
+
707
+ break;
708
+
709
+ default:
710
+ console.warn( command );
711
+
712
+ }
713
+
714
+ // console.log( type, parseFloats( data ), parseFloats( data ).length )
715
+
716
+ }
717
+
718
+ return path;
719
+
720
+ }
721
+
722
+ function parseCSSStylesheet( node ) {
723
+
724
+ if ( ! node.sheet || ! node.sheet.cssRules || ! node.sheet.cssRules.length ) return;
725
+
726
+ for ( let i = 0; i < node.sheet.cssRules.length; i ++ ) {
727
+
728
+ const stylesheet = node.sheet.cssRules[ i ];
729
+
730
+ if ( stylesheet.type !== 1 ) continue;
731
+
732
+ const selectorList = stylesheet.selectorText
733
+ .split( /,/gm )
734
+ .filter( Boolean )
735
+ .map( i => i.trim() );
736
+
737
+ const definitions = {};
738
+
739
+ for ( let j = 0; j < stylesheet.style.length; j ++ ) {
740
+
741
+ const property = stylesheet.style[ j ];
742
+ definitions[ property ] = stylesheet.style.getPropertyValue( property );
743
+
744
+ }
745
+
746
+ for ( let j = 0; j < selectorList.length; j ++ ) {
747
+
748
+ stylesheets[ selectorList[ j ] ] = Object.assign(
749
+ stylesheets[ selectorList[ j ] ] || {},
750
+ definitions
751
+ );
752
+
753
+ }
754
+
755
+ }
756
+
757
+ }
758
+
759
+ /**
760
+ * https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
761
+ * https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ Appendix: Endpoint to center arc conversion
762
+ * From
763
+ * rx ry x-axis-rotation large-arc-flag sweep-flag x y
764
+ * To
765
+ * aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation
766
+ */
767
+
768
+ function parseArcCommand( path, rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, start, end ) {
769
+
770
+ if ( rx == 0 || ry == 0 ) {
771
+
772
+ // draw a line if either of the radii == 0
773
+ path.lineTo( end.x, end.y );
774
+ return;
775
+
776
+ }
777
+
778
+ x_axis_rotation = x_axis_rotation * Math.PI / 180;
779
+
780
+ // Ensure radii are positive
781
+ rx = Math.abs( rx );
782
+ ry = Math.abs( ry );
783
+
784
+ // Compute (x1', y1')
785
+ const dx2 = ( start.x - end.x ) / 2.0;
786
+ const dy2 = ( start.y - end.y ) / 2.0;
787
+ const x1p = Math.cos( x_axis_rotation ) * dx2 + Math.sin( x_axis_rotation ) * dy2;
788
+ const y1p = - Math.sin( x_axis_rotation ) * dx2 + Math.cos( x_axis_rotation ) * dy2;
789
+
790
+ // Compute (cx', cy')
791
+ let rxs = rx * rx;
792
+ let rys = ry * ry;
793
+ const x1ps = x1p * x1p;
794
+ const y1ps = y1p * y1p;
795
+
796
+ // Ensure radii are large enough
797
+ const cr = x1ps / rxs + y1ps / rys;
798
+
799
+ if ( cr > 1 ) {
800
+
801
+ // scale up rx,ry equally so cr == 1
802
+ const s = Math.sqrt( cr );
803
+ rx = s * rx;
804
+ ry = s * ry;
805
+ rxs = rx * rx;
806
+ rys = ry * ry;
807
+
808
+ }
809
+
810
+ const dq = ( rxs * y1ps + rys * x1ps );
811
+ const pq = ( rxs * rys - dq ) / dq;
812
+ let q = Math.sqrt( Math.max( 0, pq ) );
813
+ if ( large_arc_flag === sweep_flag ) q = - q;
814
+ const cxp = q * rx * y1p / ry;
815
+ const cyp = - q * ry * x1p / rx;
816
+
817
+ // Step 3: Compute (cx, cy) from (cx', cy')
818
+ const cx = Math.cos( x_axis_rotation ) * cxp - Math.sin( x_axis_rotation ) * cyp + ( start.x + end.x ) / 2;
819
+ const cy = Math.sin( x_axis_rotation ) * cxp + Math.cos( x_axis_rotation ) * cyp + ( start.y + end.y ) / 2;
820
+
821
+ // Step 4: Compute θ1 and Δθ
822
+ const theta = svgAngle( 1, 0, ( x1p - cxp ) / rx, ( y1p - cyp ) / ry );
823
+ const delta = svgAngle( ( x1p - cxp ) / rx, ( y1p - cyp ) / ry, ( - x1p - cxp ) / rx, ( - y1p - cyp ) / ry ) % ( Math.PI * 2 );
824
+
825
+ path.currentPath.absellipse( cx, cy, rx, ry, theta, theta + delta, sweep_flag === 0, x_axis_rotation );
826
+
827
+ }
828
+
829
+ function svgAngle( ux, uy, vx, vy ) {
830
+
831
+ const dot = ux * vx + uy * vy;
832
+ const len = Math.sqrt( ux * ux + uy * uy ) * Math.sqrt( vx * vx + vy * vy );
833
+ let ang = Math.acos( Math.max( - 1, Math.min( 1, dot / len ) ) ); // floating point precision, slightly over values appear
834
+ if ( ( ux * vy - uy * vx ) < 0 ) ang = - ang;
835
+ return ang;
836
+
837
+ }
838
+
839
+ /*
840
+ * According to https://www.w3.org/TR/SVG/shapes.html#RectElementRXAttribute
841
+ * rounded corner should be rendered to elliptical arc, but bezier curve does the job well enough
842
+ */
843
+
844
+ function parseRectNode( node ) {
845
+
846
+ const x = parseFloatWithUnits( node.getAttribute( 'x' ) || 0 );
847
+ const y = parseFloatWithUnits( node.getAttribute( 'y' ) || 0 );
848
+ const rx = parseFloatWithUnits( node.getAttribute( 'rx' ) || node.getAttribute( 'ry' ) || 0 );
849
+ const ry = parseFloatWithUnits( node.getAttribute( 'ry' ) || node.getAttribute( 'rx' ) || 0 );
850
+ const w = parseFloatWithUnits( node.getAttribute( 'width' ) );
851
+ const h = parseFloatWithUnits( node.getAttribute( 'height' ) );
852
+
853
+ // Ellipse arc to Bezier approximation Coefficient (Inversed). See:
854
+ // https://spencermortensen.com/articles/bezier-circle/
855
+ const bci = 1 - 0.551915024494;
856
+
857
+ const path = new ShapePath();
858
+
859
+ // top left
860
+ path.moveTo( x + rx, y );
861
+
862
+ // top right
863
+ path.lineTo( x + w - rx, y );
864
+ if ( rx !== 0 || ry !== 0 ) {
865
+
866
+ path.bezierCurveTo(
867
+ x + w - rx * bci,
868
+ y,
869
+ x + w,
870
+ y + ry * bci,
871
+ x + w,
872
+ y + ry
873
+ );
874
+
875
+ }
876
+
877
+ // bottom right
878
+ path.lineTo( x + w, y + h - ry );
879
+ if ( rx !== 0 || ry !== 0 ) {
880
+
881
+ path.bezierCurveTo(
882
+ x + w,
883
+ y + h - ry * bci,
884
+ x + w - rx * bci,
885
+ y + h,
886
+ x + w - rx,
887
+ y + h
888
+ );
889
+
890
+ }
891
+
892
+ // bottom left
893
+ path.lineTo( x + rx, y + h );
894
+ if ( rx !== 0 || ry !== 0 ) {
895
+
896
+ path.bezierCurveTo(
897
+ x + rx * bci,
898
+ y + h,
899
+ x,
900
+ y + h - ry * bci,
901
+ x,
902
+ y + h - ry
903
+ );
904
+
905
+ }
906
+
907
+ // back to top left
908
+ path.lineTo( x, y + ry );
909
+ if ( rx !== 0 || ry !== 0 ) {
910
+
911
+ path.bezierCurveTo( x, y + ry * bci, x + rx * bci, y, x + rx, y );
912
+
913
+ }
914
+
915
+ return path;
916
+
917
+ }
918
+
919
+ function parsePolygonNode( node ) {
920
+
921
+ function iterator( match, a, b ) {
922
+
923
+ const x = parseFloatWithUnits( a );
924
+ const y = parseFloatWithUnits( b );
925
+
926
+ if ( index === 0 ) {
927
+
928
+ path.moveTo( x, y );
929
+
930
+ } else {
931
+
932
+ path.lineTo( x, y );
933
+
934
+ }
935
+
936
+ index ++;
937
+
938
+ }
939
+
940
+ const regex = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)/g;
941
+
942
+ const path = new ShapePath();
943
+
944
+ let index = 0;
945
+
946
+ node.getAttribute( 'points' ).replace( regex, iterator );
947
+
948
+ path.currentPath.autoClose = true;
949
+
950
+ return path;
951
+
952
+ }
953
+
954
+ function parsePolylineNode( node ) {
955
+
956
+ function iterator( match, a, b ) {
957
+
958
+ const x = parseFloatWithUnits( a );
959
+ const y = parseFloatWithUnits( b );
960
+
961
+ if ( index === 0 ) {
962
+
963
+ path.moveTo( x, y );
964
+
965
+ } else {
966
+
967
+ path.lineTo( x, y );
968
+
969
+ }
970
+
971
+ index ++;
972
+
973
+ }
974
+
975
+ const regex = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)/g;
976
+
977
+ const path = new ShapePath();
978
+
979
+ let index = 0;
980
+
981
+ node.getAttribute( 'points' ).replace( regex, iterator );
982
+
983
+ path.currentPath.autoClose = false;
984
+
985
+ return path;
986
+
987
+ }
988
+
989
+ function parseCircleNode( node ) {
990
+
991
+ const x = parseFloatWithUnits( node.getAttribute( 'cx' ) || 0 );
992
+ const y = parseFloatWithUnits( node.getAttribute( 'cy' ) || 0 );
993
+ const r = parseFloatWithUnits( node.getAttribute( 'r' ) || 0 );
994
+
995
+ const subpath = new Path();
996
+ subpath.absarc( x, y, r, 0, Math.PI * 2 );
997
+
998
+ const path = new ShapePath();
999
+ path.subPaths.push( subpath );
1000
+
1001
+ return path;
1002
+
1003
+ }
1004
+
1005
+ function parseEllipseNode( node ) {
1006
+
1007
+ const x = parseFloatWithUnits( node.getAttribute( 'cx' ) || 0 );
1008
+ const y = parseFloatWithUnits( node.getAttribute( 'cy' ) || 0 );
1009
+ const rx = parseFloatWithUnits( node.getAttribute( 'rx' ) || 0 );
1010
+ const ry = parseFloatWithUnits( node.getAttribute( 'ry' ) || 0 );
1011
+
1012
+ const subpath = new Path();
1013
+ subpath.absellipse( x, y, rx, ry, 0, Math.PI * 2 );
1014
+
1015
+ const path = new ShapePath();
1016
+ path.subPaths.push( subpath );
1017
+
1018
+ return path;
1019
+
1020
+ }
1021
+
1022
+ function parseLineNode( node ) {
1023
+
1024
+ const x1 = parseFloatWithUnits( node.getAttribute( 'x1' ) || 0 );
1025
+ const y1 = parseFloatWithUnits( node.getAttribute( 'y1' ) || 0 );
1026
+ const x2 = parseFloatWithUnits( node.getAttribute( 'x2' ) || 0 );
1027
+ const y2 = parseFloatWithUnits( node.getAttribute( 'y2' ) || 0 );
1028
+
1029
+ const path = new ShapePath();
1030
+ path.moveTo( x1, y1 );
1031
+ path.lineTo( x2, y2 );
1032
+ path.currentPath.autoClose = false;
1033
+
1034
+ return path;
1035
+
1036
+ }
1037
+
1038
+ //
1039
+
1040
+ function parseGradients( xml ) {
1041
+
1042
+ const HREF_NS = 'http://www.w3.org/1999/xlink';
1043
+ const gradientNodes = xml.querySelectorAll( 'linearGradient, radialGradient' );
1044
+ const ATTRS = [ 'x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'r', 'fx', 'fy', 'gradientUnits', 'gradientTransform', 'spreadMethod' ];
1045
+
1046
+ const parsed = {};
1047
+
1048
+ for ( const node of gradientNodes ) {
1049
+
1050
+ const id = node.getAttribute( 'id' );
1051
+ if ( ! id ) continue;
1052
+
1053
+ const entry = {
1054
+ type: node.nodeName === 'radialGradient' ? 'radialGradient' : 'linearGradient',
1055
+ attrs: {},
1056
+ stops: null,
1057
+ href: null,
1058
+ };
1059
+
1060
+ const href = node.getAttributeNS( HREF_NS, 'href' ) || node.getAttribute( 'href' ) || '';
1061
+ if ( href.startsWith( '#' ) ) entry.href = href.substring( 1 );
1062
+
1063
+ for ( const name of ATTRS ) {
1064
+
1065
+ if ( node.hasAttribute( name ) ) entry.attrs[ name ] = node.getAttribute( name );
1066
+
1067
+ }
1068
+
1069
+ const stopNodes = node.querySelectorAll( 'stop' );
1070
+ if ( stopNodes.length > 0 ) {
1071
+
1072
+ entry.stops = [];
1073
+ for ( const s of stopNodes ) {
1074
+
1075
+ let color = s.getAttribute( 'stop-color' );
1076
+ if ( ! color && s.style ) color = s.style[ 'stop-color' ];
1077
+ if ( ! color ) color = '#000';
1078
+
1079
+ let opacity = s.getAttribute( 'stop-opacity' );
1080
+ if ( ( opacity === null || opacity === '' ) && s.style ) opacity = s.style[ 'stop-opacity' ];
1081
+ opacity = ( opacity === null || opacity === '' || opacity === undefined )
1082
+ ? 1
1083
+ : Math.max( 0, Math.min( 1, parseFloat( opacity ) ) );
1084
+
1085
+ const offset = Math.max( 0, Math.min( 1, parseFloat( s.getAttribute( 'offset' ) || '0' ) ) );
1086
+ entry.stops.push( { offset, color, opacity } );
1087
+
1088
+ }
1089
+
1090
+ }
1091
+
1092
+ parsed[ id ] = entry;
1093
+
1094
+ }
1095
+
1096
+ function inherit( id, visited ) {
1097
+
1098
+ const entry = parsed[ id ];
1099
+ if ( ! entry || visited.has( id ) ) return entry;
1100
+ visited.add( id );
1101
+
1102
+ if ( entry.href && parsed[ entry.href ] ) {
1103
+
1104
+ const parent = inherit( entry.href, visited );
1105
+ if ( parent ) {
1106
+
1107
+ if ( ! entry.stops ) entry.stops = parent.stops;
1108
+ for ( const key in parent.attrs ) {
1109
+
1110
+ if ( ! ( key in entry.attrs ) ) entry.attrs[ key ] = parent.attrs[ key ];
1111
+
1112
+ }
1113
+
1114
+ }
1115
+
1116
+ }
1117
+
1118
+ return entry;
1119
+
1120
+ }
1121
+
1122
+ for ( const id in parsed ) inherit( id, new Set() );
1123
+
1124
+ for ( const id in parsed ) {
1125
+
1126
+ const entry = parsed[ id ];
1127
+ const a = entry.attrs;
1128
+ const units = a.gradientUnits === 'userSpaceOnUse' ? 'userSpaceOnUse' : 'objectBoundingBox';
1129
+
1130
+ const gradient = {
1131
+ type: entry.type,
1132
+ gradientUnits: units,
1133
+ spreadMethod: a.spreadMethod === 'reflect' || a.spreadMethod === 'repeat' ? a.spreadMethod : 'pad',
1134
+ gradientTransform: null,
1135
+ stops: ( entry.stops || [] ).slice().sort( ( x, y ) => x.offset - y.offset ),
1136
+ };
1137
+
1138
+ if ( a.gradientTransform ) {
1139
+
1140
+ gradient.gradientTransform = new Matrix3();
1141
+ parseTransformString( a.gradientTransform, gradient.gradientTransform );
1142
+
1143
+ }
1144
+
1145
+ function coord( str ) {
1146
+
1147
+ if ( typeof str !== 'string' ) return 0;
1148
+ if ( str.endsWith( '%' ) ) return parseFloat( str ) / 100;
1149
+ return parseFloatWithUnits( str );
1150
+
1151
+ }
1152
+
1153
+ if ( entry.type === 'linearGradient' ) {
1154
+
1155
+ gradient.x1 = a.x1 !== undefined ? coord( a.x1 ) : 0;
1156
+ gradient.y1 = a.y1 !== undefined ? coord( a.y1 ) : 0;
1157
+ gradient.x2 = a.x2 !== undefined ? coord( a.x2 ) : ( units === 'objectBoundingBox' ? 1 : 0 );
1158
+ gradient.y2 = a.y2 !== undefined ? coord( a.y2 ) : 0;
1159
+
1160
+ } else {
1161
+
1162
+ const defCenter = units === 'objectBoundingBox' ? 0.5 : 0;
1163
+ const defR = units === 'objectBoundingBox' ? 0.5 : 0;
1164
+ gradient.cx = a.cx !== undefined ? coord( a.cx ) : defCenter;
1165
+ gradient.cy = a.cy !== undefined ? coord( a.cy ) : defCenter;
1166
+ gradient.r = a.r !== undefined ? coord( a.r ) : defR;
1167
+ gradient.fx = a.fx !== undefined ? coord( a.fx ) : gradient.cx;
1168
+ gradient.fy = a.fy !== undefined ? coord( a.fy ) : gradient.cy;
1169
+
1170
+ }
1171
+
1172
+ gradients[ id ] = gradient;
1173
+
1174
+ }
1175
+
1176
+ }
1177
+
1178
+ //
1179
+
1180
+ function parseStyle( node, style ) {
1181
+
1182
+ style = Object.assign( {}, style ); // clone style
1183
+
1184
+ let stylesheetStyles = {};
1185
+
1186
+ if ( node.hasAttribute( 'class' ) ) {
1187
+
1188
+ const classSelectors = node.getAttribute( 'class' )
1189
+ .split( /\s/ )
1190
+ .filter( Boolean )
1191
+ .map( i => i.trim() );
1192
+
1193
+ for ( let i = 0; i < classSelectors.length; i ++ ) {
1194
+
1195
+ stylesheetStyles = Object.assign( stylesheetStyles, stylesheets[ '.' + classSelectors[ i ] ] );
1196
+
1197
+ }
1198
+
1199
+ }
1200
+
1201
+ if ( node.hasAttribute( 'id' ) ) {
1202
+
1203
+ stylesheetStyles = Object.assign( stylesheetStyles, stylesheets[ '#' + node.getAttribute( 'id' ) ] );
1204
+
1205
+ }
1206
+
1207
+ function addStyle( svgName, jsName, adjustFunction ) {
1208
+
1209
+ if ( adjustFunction === undefined ) adjustFunction = function copy( v ) {
1210
+
1211
+ return v;
1212
+
1213
+ };
1214
+
1215
+ if ( node.hasAttribute( svgName ) ) style[ jsName ] = adjustFunction( node.getAttribute( svgName ) );
1216
+ if ( stylesheetStyles[ svgName ] ) style[ jsName ] = adjustFunction( stylesheetStyles[ svgName ] );
1217
+ if ( node.style && node.style[ svgName ] !== '' ) style[ jsName ] = adjustFunction( node.style[ svgName ] );
1218
+
1219
+ }
1220
+
1221
+ function clamp( v ) {
1222
+
1223
+ return Math.max( 0, Math.min( 1, parseFloatWithUnits( v ) ) );
1224
+
1225
+ }
1226
+
1227
+ function positive( v ) {
1228
+
1229
+ return Math.max( 0, parseFloatWithUnits( v ) );
1230
+
1231
+ }
1232
+
1233
+ addStyle( 'fill', 'fill' );
1234
+ addStyle( 'fill-opacity', 'fillOpacity', clamp );
1235
+ addStyle( 'fill-rule', 'fillRule' );
1236
+ addStyle( 'opacity', 'opacity', clamp );
1237
+ addStyle( 'stroke', 'stroke' );
1238
+ addStyle( 'stroke-opacity', 'strokeOpacity', clamp );
1239
+ addStyle( 'stroke-width', 'strokeWidth', positive );
1240
+ addStyle( 'stroke-linejoin', 'strokeLineJoin' );
1241
+ addStyle( 'stroke-linecap', 'strokeLineCap' );
1242
+ addStyle( 'stroke-miterlimit', 'strokeMiterLimit', positive );
1243
+ addStyle( 'visibility', 'visibility' );
1244
+
1245
+ return style;
1246
+
1247
+ }
1248
+
1249
+ // http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
1250
+
1251
+ function getReflection( a, b ) {
1252
+
1253
+ return a - ( b - a );
1254
+
1255
+ }
1256
+
1257
+ // from https://github.com/ppvg/svg-numbers (MIT License)
1258
+
1259
+ function parseFloats( input, flags, stride ) {
1260
+
1261
+ if ( typeof input !== 'string' ) {
1262
+
1263
+ throw new TypeError( 'Invalid input: ' + typeof input );
1264
+
1265
+ }
1266
+
1267
+ // Character groups
1268
+ const RE = {
1269
+ SEPARATOR: /[ \t\r\n\,.\-+]/,
1270
+ WHITESPACE: /[ \t\r\n]/,
1271
+ DIGIT: /[\d]/,
1272
+ SIGN: /[-+]/,
1273
+ POINT: /\./,
1274
+ COMMA: /,/,
1275
+ EXP: /e/i,
1276
+ FLAGS: /[01]/
1277
+ };
1278
+
1279
+ // States
1280
+ const SEP = 0;
1281
+ const INT = 1;
1282
+ const FLOAT = 2;
1283
+ const EXP = 3;
1284
+
1285
+ let state = SEP;
1286
+ let seenComma = true;
1287
+ let number = '', exponent = '';
1288
+ const result = [];
1289
+
1290
+ function throwSyntaxError( current, i, partial ) {
1291
+
1292
+ const error = new SyntaxError( 'Unexpected character "' + current + '" at index ' + i + '.' );
1293
+ error.partial = partial;
1294
+ throw error;
1295
+
1296
+ }
1297
+
1298
+ function newNumber() {
1299
+
1300
+ if ( number !== '' ) {
1301
+
1302
+ if ( exponent === '' ) result.push( Number( number ) );
1303
+ else result.push( Number( number ) * Math.pow( 10, Number( exponent ) ) );
1304
+
1305
+ }
1306
+
1307
+ number = '';
1308
+ exponent = '';
1309
+
1310
+ }
1311
+
1312
+ let current;
1313
+ const length = input.length;
1314
+
1315
+ for ( let i = 0; i < length; i ++ ) {
1316
+
1317
+ current = input[ i ];
1318
+
1319
+ // check for flags
1320
+ if ( Array.isArray( flags ) && flags.includes( result.length % stride ) && RE.FLAGS.test( current ) ) {
1321
+
1322
+ state = INT;
1323
+ number = current;
1324
+ newNumber();
1325
+ continue;
1326
+
1327
+ }
1328
+
1329
+ // parse until next number
1330
+ if ( state === SEP ) {
1331
+
1332
+ // eat whitespace
1333
+ if ( RE.WHITESPACE.test( current ) ) {
1334
+
1335
+ continue;
1336
+
1337
+ }
1338
+
1339
+ // start new number
1340
+ if ( RE.DIGIT.test( current ) || RE.SIGN.test( current ) ) {
1341
+
1342
+ state = INT;
1343
+ number = current;
1344
+ continue;
1345
+
1346
+ }
1347
+
1348
+ if ( RE.POINT.test( current ) ) {
1349
+
1350
+ state = FLOAT;
1351
+ number = current;
1352
+ continue;
1353
+
1354
+ }
1355
+
1356
+ // throw on double commas (e.g. "1, , 2")
1357
+ if ( RE.COMMA.test( current ) ) {
1358
+
1359
+ if ( seenComma ) {
1360
+
1361
+ throwSyntaxError( current, i, result );
1362
+
1363
+ }
1364
+
1365
+ seenComma = true;
1366
+
1367
+ }
1368
+
1369
+ }
1370
+
1371
+ // parse integer part
1372
+ if ( state === INT ) {
1373
+
1374
+ if ( RE.DIGIT.test( current ) ) {
1375
+
1376
+ number += current;
1377
+ continue;
1378
+
1379
+ }
1380
+
1381
+ if ( RE.POINT.test( current ) ) {
1382
+
1383
+ number += current;
1384
+ state = FLOAT;
1385
+ continue;
1386
+
1387
+ }
1388
+
1389
+ if ( RE.EXP.test( current ) ) {
1390
+
1391
+ state = EXP;
1392
+ continue;
1393
+
1394
+ }
1395
+
1396
+ // throw on double signs ("-+1"), but not on sign as separator ("-1-2")
1397
+ if ( RE.SIGN.test( current )
1398
+ && number.length === 1
1399
+ && RE.SIGN.test( number[ 0 ] ) ) {
1400
+
1401
+ throwSyntaxError( current, i, result );
1402
+
1403
+ }
1404
+
1405
+ }
1406
+
1407
+ // parse decimal part
1408
+ if ( state === FLOAT ) {
1409
+
1410
+ if ( RE.DIGIT.test( current ) ) {
1411
+
1412
+ number += current;
1413
+ continue;
1414
+
1415
+ }
1416
+
1417
+ if ( RE.EXP.test( current ) ) {
1418
+
1419
+ state = EXP;
1420
+ continue;
1421
+
1422
+ }
1423
+
1424
+ // throw on double decimal points (e.g. "1..2")
1425
+ if ( RE.POINT.test( current ) && number[ number.length - 1 ] === '.' ) {
1426
+
1427
+ throwSyntaxError( current, i, result );
1428
+
1429
+ }
1430
+
1431
+ }
1432
+
1433
+ // parse exponent part
1434
+ if ( state === EXP ) {
1435
+
1436
+ if ( RE.DIGIT.test( current ) ) {
1437
+
1438
+ exponent += current;
1439
+ continue;
1440
+
1441
+ }
1442
+
1443
+ if ( RE.SIGN.test( current ) ) {
1444
+
1445
+ if ( exponent === '' ) {
1446
+
1447
+ exponent += current;
1448
+ continue;
1449
+
1450
+ }
1451
+
1452
+ if ( exponent.length === 1 && RE.SIGN.test( exponent ) ) {
1453
+
1454
+ throwSyntaxError( current, i, result );
1455
+
1456
+ }
1457
+
1458
+ }
1459
+
1460
+ }
1461
+
1462
+
1463
+ // end of number
1464
+ if ( RE.WHITESPACE.test( current ) ) {
1465
+
1466
+ newNumber();
1467
+ state = SEP;
1468
+ seenComma = false;
1469
+
1470
+ } else if ( RE.COMMA.test( current ) ) {
1471
+
1472
+ newNumber();
1473
+ state = SEP;
1474
+ seenComma = true;
1475
+
1476
+ } else if ( RE.SIGN.test( current ) ) {
1477
+
1478
+ newNumber();
1479
+ state = INT;
1480
+ number = current;
1481
+
1482
+ } else if ( RE.POINT.test( current ) ) {
1483
+
1484
+ newNumber();
1485
+ state = FLOAT;
1486
+ number = current;
1487
+
1488
+ } else {
1489
+
1490
+ throwSyntaxError( current, i, result );
1491
+
1492
+ }
1493
+
1494
+ }
1495
+
1496
+ // add the last number found (if any)
1497
+ newNumber();
1498
+
1499
+ return result;
1500
+
1501
+ }
1502
+
1503
+ // Units
1504
+
1505
+ const units = [ 'mm', 'cm', 'in', 'pt', 'pc', 'px' ];
1506
+
1507
+ // Conversion: [ fromUnit ][ toUnit ] (-1 means dpi dependent)
1508
+ const unitConversion = {
1509
+
1510
+ 'mm': {
1511
+ 'mm': 1,
1512
+ 'cm': 0.1,
1513
+ 'in': 1 / 25.4,
1514
+ 'pt': 72 / 25.4,
1515
+ 'pc': 6 / 25.4,
1516
+ 'px': - 1
1517
+ },
1518
+ 'cm': {
1519
+ 'mm': 10,
1520
+ 'cm': 1,
1521
+ 'in': 1 / 2.54,
1522
+ 'pt': 72 / 2.54,
1523
+ 'pc': 6 / 2.54,
1524
+ 'px': - 1
1525
+ },
1526
+ 'in': {
1527
+ 'mm': 25.4,
1528
+ 'cm': 2.54,
1529
+ 'in': 1,
1530
+ 'pt': 72,
1531
+ 'pc': 6,
1532
+ 'px': - 1
1533
+ },
1534
+ 'pt': {
1535
+ 'mm': 25.4 / 72,
1536
+ 'cm': 2.54 / 72,
1537
+ 'in': 1 / 72,
1538
+ 'pt': 1,
1539
+ 'pc': 6 / 72,
1540
+ 'px': - 1
1541
+ },
1542
+ 'pc': {
1543
+ 'mm': 25.4 / 6,
1544
+ 'cm': 2.54 / 6,
1545
+ 'in': 1 / 6,
1546
+ 'pt': 72 / 6,
1547
+ 'pc': 1,
1548
+ 'px': - 1
1549
+ },
1550
+ 'px': {
1551
+ 'px': 1
1552
+ }
1553
+
1554
+ };
1555
+
1556
+ function parseFloatWithUnits( string ) {
1557
+
1558
+ let theUnit = 'px';
1559
+
1560
+ if ( typeof string === 'string' || string instanceof String ) {
1561
+
1562
+ for ( let i = 0, n = units.length; i < n; i ++ ) {
1563
+
1564
+ const u = units[ i ];
1565
+
1566
+ if ( string.endsWith( u ) ) {
1567
+
1568
+ theUnit = u;
1569
+ string = string.substring( 0, string.length - u.length );
1570
+ break;
1571
+
1572
+ }
1573
+
1574
+ }
1575
+
1576
+ }
1577
+
1578
+ let scale = undefined;
1579
+
1580
+ if ( theUnit === 'px' && scope.defaultUnit !== 'px' ) {
1581
+
1582
+ // Conversion scale from pixels to inches, then to default units
1583
+
1584
+ scale = unitConversion[ 'in' ][ scope.defaultUnit ] / scope.defaultDPI;
1585
+
1586
+ } else {
1587
+
1588
+ scale = unitConversion[ theUnit ][ scope.defaultUnit ];
1589
+
1590
+ if ( scale < 0 ) {
1591
+
1592
+ // Conversion scale to pixels
1593
+
1594
+ scale = unitConversion[ theUnit ][ 'in' ] * scope.defaultDPI;
1595
+
1596
+ }
1597
+
1598
+ }
1599
+
1600
+ return scale * parseFloat( string );
1601
+
1602
+ }
1603
+
1604
+ // Transforms
1605
+
1606
+ function getNodeTransform( node ) {
1607
+
1608
+ if ( ! ( node.hasAttribute( 'transform' ) || ( node.nodeName === 'use' && ( node.hasAttribute( 'x' ) || node.hasAttribute( 'y' ) ) ) ) ) {
1609
+
1610
+ return null;
1611
+
1612
+ }
1613
+
1614
+ const transform = parseNodeTransform( node );
1615
+
1616
+ if ( transformStack.length > 0 ) {
1617
+
1618
+ transform.premultiply( transformStack[ transformStack.length - 1 ] );
1619
+
1620
+ }
1621
+
1622
+ currentTransform.copy( transform );
1623
+ transformStack.push( transform );
1624
+
1625
+ return transform;
1626
+
1627
+ }
1628
+
1629
+ function parseNodeTransform( node ) {
1630
+
1631
+ const transform = new Matrix3();
1632
+
1633
+ if ( node.nodeName === 'use' && ( node.hasAttribute( 'x' ) || node.hasAttribute( 'y' ) ) ) {
1634
+
1635
+ const tx = parseFloatWithUnits( node.getAttribute( 'x' ) || 0 );
1636
+ const ty = parseFloatWithUnits( node.getAttribute( 'y' ) || 0 );
1637
+
1638
+ transform.makeTranslation( tx, ty );
1639
+
1640
+ }
1641
+
1642
+ if ( node.hasAttribute( 'transform' ) ) {
1643
+
1644
+ parseTransformString( node.getAttribute( 'transform' ), transform );
1645
+
1646
+ }
1647
+
1648
+ return transform;
1649
+
1650
+ }
1651
+
1652
+ function parseTransformString( text, transform ) {
1653
+
1654
+ const currentTransform = tempTransform0;
1655
+
1656
+ const transformsTexts = text.split( ')' );
1657
+
1658
+ for ( let tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex -- ) {
1659
+
1660
+ const transformText = transformsTexts[ tIndex ].trim();
1661
+
1662
+ if ( transformText === '' ) continue;
1663
+
1664
+ const openParPos = transformText.indexOf( '(' );
1665
+ const closeParPos = transformText.length;
1666
+
1667
+ if ( openParPos > 0 && openParPos < closeParPos ) {
1668
+
1669
+ const transformType = transformText.slice( 0, openParPos );
1670
+
1671
+ const array = parseFloats( transformText.slice( openParPos + 1 ) );
1672
+
1673
+ currentTransform.identity();
1674
+
1675
+ switch ( transformType ) {
1676
+
1677
+ case 'translate':
1678
+
1679
+ if ( array.length >= 1 ) {
1680
+
1681
+ const tx = array[ 0 ];
1682
+ let ty = 0;
1683
+
1684
+ if ( array.length >= 2 ) {
1685
+
1686
+ ty = array[ 1 ];
1687
+
1688
+ }
1689
+
1690
+ currentTransform.makeTranslation( tx, ty );
1691
+
1692
+ }
1693
+
1694
+ break;
1695
+
1696
+ case 'rotate':
1697
+
1698
+ if ( array.length >= 1 ) {
1699
+
1700
+ let angle = 0;
1701
+ let cx = 0;
1702
+ let cy = 0;
1703
+
1704
+ // Angle
1705
+ angle = array[ 0 ] * Math.PI / 180;
1706
+
1707
+ if ( array.length >= 3 ) {
1708
+
1709
+ // Center x, y
1710
+ cx = array[ 1 ];
1711
+ cy = array[ 2 ];
1712
+
1713
+ }
1714
+
1715
+ // Rotate around center (cx, cy)
1716
+ tempTransform1.makeTranslation( - cx, - cy );
1717
+ tempTransform2.makeRotation( angle );
1718
+ tempTransform3.multiplyMatrices( tempTransform2, tempTransform1 );
1719
+ tempTransform1.makeTranslation( cx, cy );
1720
+ currentTransform.multiplyMatrices( tempTransform1, tempTransform3 );
1721
+
1722
+ }
1723
+
1724
+ break;
1725
+
1726
+ case 'scale':
1727
+
1728
+ if ( array.length >= 1 ) {
1729
+
1730
+ const scaleX = array[ 0 ];
1731
+ let scaleY = scaleX;
1732
+
1733
+ if ( array.length >= 2 ) {
1734
+
1735
+ scaleY = array[ 1 ];
1736
+
1737
+ }
1738
+
1739
+ currentTransform.makeScale( scaleX, scaleY );
1740
+
1741
+ }
1742
+
1743
+ break;
1744
+
1745
+ case 'skewX':
1746
+
1747
+ if ( array.length === 1 ) {
1748
+
1749
+ currentTransform.set(
1750
+ 1, Math.tan( array[ 0 ] * Math.PI / 180 ), 0,
1751
+ 0, 1, 0,
1752
+ 0, 0, 1
1753
+ );
1754
+
1755
+ }
1756
+
1757
+ break;
1758
+
1759
+ case 'skewY':
1760
+
1761
+ if ( array.length === 1 ) {
1762
+
1763
+ currentTransform.set(
1764
+ 1, 0, 0,
1765
+ Math.tan( array[ 0 ] * Math.PI / 180 ), 1, 0,
1766
+ 0, 0, 1
1767
+ );
1768
+
1769
+ }
1770
+
1771
+ break;
1772
+
1773
+ case 'matrix':
1774
+
1775
+ if ( array.length === 6 ) {
1776
+
1777
+ currentTransform.set(
1778
+ array[ 0 ], array[ 2 ], array[ 4 ],
1779
+ array[ 1 ], array[ 3 ], array[ 5 ],
1780
+ 0, 0, 1
1781
+ );
1782
+
1783
+ }
1784
+
1785
+ break;
1786
+
1787
+ }
1788
+
1789
+ transform.premultiply( currentTransform );
1790
+
1791
+ }
1792
+
1793
+ }
1794
+
1795
+ return transform;
1796
+
1797
+ }
1798
+
1799
+ function transformPath( path, m ) {
1800
+
1801
+ function transfVec2( v2 ) {
1802
+
1803
+ tempV3.set( v2.x, v2.y, 1 ).applyMatrix3( m );
1804
+
1805
+ v2.set( tempV3.x, tempV3.y );
1806
+
1807
+ }
1808
+
1809
+ function transfEllipseGeneric( curve ) {
1810
+
1811
+ // For math description see:
1812
+ // https://math.stackexchange.com/questions/4544164
1813
+
1814
+ const a = curve.xRadius;
1815
+ const b = curve.yRadius;
1816
+
1817
+ const cosTheta = Math.cos( curve.aRotation );
1818
+ const sinTheta = Math.sin( curve.aRotation );
1819
+
1820
+ const v1 = new Vector3( a * cosTheta, a * sinTheta, 0 );
1821
+ const v2 = new Vector3( - b * sinTheta, b * cosTheta, 0 );
1822
+
1823
+ const f1 = v1.applyMatrix3( m );
1824
+ const f2 = v2.applyMatrix3( m );
1825
+
1826
+ const mF = tempTransform0.set(
1827
+ f1.x, f2.x, 0,
1828
+ f1.y, f2.y, 0,
1829
+ 0, 0, 1,
1830
+ );
1831
+
1832
+ const mFInv = tempTransform1.copy( mF ).invert();
1833
+ const mFInvT = tempTransform2.copy( mFInv ).transpose();
1834
+ const mQ = mFInvT.multiply( mFInv );
1835
+ const mQe = mQ.elements;
1836
+
1837
+ const ed = eigenDecomposition( mQe[ 0 ], mQe[ 1 ], mQe[ 4 ] );
1838
+ const rt1sqrt = Math.sqrt( ed.rt1 );
1839
+ const rt2sqrt = Math.sqrt( ed.rt2 );
1840
+
1841
+ curve.xRadius = 1 / rt1sqrt;
1842
+ curve.yRadius = 1 / rt2sqrt;
1843
+ curve.aRotation = Math.atan2( ed.sn, ed.cs );
1844
+
1845
+ const isFullEllipse =
1846
+ ( curve.aEndAngle - curve.aStartAngle ) % ( 2 * Math.PI ) < Number.EPSILON;
1847
+
1848
+ // Do not touch angles of a full ellipse because after transformation they
1849
+ // would converge to a single value effectively removing the whole curve
1850
+
1851
+ if ( ! isFullEllipse ) {
1852
+
1853
+ const mDsqrt = tempTransform1.set(
1854
+ rt1sqrt, 0, 0,
1855
+ 0, rt2sqrt, 0,
1856
+ 0, 0, 1,
1857
+ );
1858
+
1859
+ const mRT = tempTransform2.set(
1860
+ ed.cs, ed.sn, 0,
1861
+ - ed.sn, ed.cs, 0,
1862
+ 0, 0, 1,
1863
+ );
1864
+
1865
+ const mDRF = mDsqrt.multiply( mRT ).multiply( mF );
1866
+
1867
+ const transformAngle = phi => {
1868
+
1869
+ const { x: cosR, y: sinR } =
1870
+ new Vector3( Math.cos( phi ), Math.sin( phi ), 0 ).applyMatrix3( mDRF );
1871
+
1872
+ return Math.atan2( sinR, cosR );
1873
+
1874
+ };
1875
+
1876
+ curve.aStartAngle = transformAngle( curve.aStartAngle );
1877
+ curve.aEndAngle = transformAngle( curve.aEndAngle );
1878
+
1879
+ if ( isTransformFlipped( m ) ) {
1880
+
1881
+ curve.aClockwise = ! curve.aClockwise;
1882
+
1883
+ }
1884
+
1885
+ }
1886
+
1887
+ }
1888
+
1889
+ function transfEllipseNoSkew( curve ) {
1890
+
1891
+ // Faster shortcut if no skew is applied
1892
+ // (e.g, a euclidean transform of a group containing the ellipse)
1893
+
1894
+ const sx = getTransformScaleX( m );
1895
+ const sy = getTransformScaleY( m );
1896
+
1897
+ curve.xRadius *= sx;
1898
+ curve.yRadius *= sy;
1899
+
1900
+ // Extract rotation angle from the matrix of form:
1901
+ //
1902
+ // | cosθ sx -sinθ sy |
1903
+ // | sinθ sx cosθ sy |
1904
+ //
1905
+ // Remembering that tanθ = sinθ / cosθ; and that
1906
+ // `sx`, `sy`, or both might be zero.
1907
+ const theta =
1908
+ sx > Number.EPSILON
1909
+ ? Math.atan2( m.elements[ 1 ], m.elements[ 0 ] )
1910
+ : Math.atan2( - m.elements[ 3 ], m.elements[ 4 ] );
1911
+
1912
+ curve.aRotation += theta;
1913
+
1914
+ if ( isTransformFlipped( m ) ) {
1915
+
1916
+ curve.aStartAngle *= - 1;
1917
+ curve.aEndAngle *= - 1;
1918
+ curve.aClockwise = ! curve.aClockwise;
1919
+
1920
+ }
1921
+
1922
+ }
1923
+
1924
+ const subPaths = path.subPaths;
1925
+
1926
+ for ( let i = 0, n = subPaths.length; i < n; i ++ ) {
1927
+
1928
+ const subPath = subPaths[ i ];
1929
+ const curves = subPath.curves;
1930
+
1931
+ for ( let j = 0; j < curves.length; j ++ ) {
1932
+
1933
+ const curve = curves[ j ];
1934
+
1935
+ if ( curve.isLineCurve ) {
1936
+
1937
+ transfVec2( curve.v1 );
1938
+ transfVec2( curve.v2 );
1939
+
1940
+ } else if ( curve.isCubicBezierCurve ) {
1941
+
1942
+ transfVec2( curve.v0 );
1943
+ transfVec2( curve.v1 );
1944
+ transfVec2( curve.v2 );
1945
+ transfVec2( curve.v3 );
1946
+
1947
+ } else if ( curve.isQuadraticBezierCurve ) {
1948
+
1949
+ transfVec2( curve.v0 );
1950
+ transfVec2( curve.v1 );
1951
+ transfVec2( curve.v2 );
1952
+
1953
+ } else if ( curve.isEllipseCurve ) {
1954
+
1955
+ // Transform ellipse center point
1956
+
1957
+ tempV2.set( curve.aX, curve.aY );
1958
+ transfVec2( tempV2 );
1959
+ curve.aX = tempV2.x;
1960
+ curve.aY = tempV2.y;
1961
+
1962
+ // Transform ellipse shape parameters
1963
+
1964
+ if ( isTransformSkewed( m ) ) {
1965
+
1966
+ transfEllipseGeneric( curve );
1967
+
1968
+ } else {
1969
+
1970
+ transfEllipseNoSkew( curve );
1971
+
1972
+ }
1973
+
1974
+ }
1975
+
1976
+ }
1977
+
1978
+ }
1979
+
1980
+ }
1981
+
1982
+ function isTransformFlipped( m ) {
1983
+
1984
+ const te = m.elements;
1985
+ return te[ 0 ] * te[ 4 ] - te[ 1 ] * te[ 3 ] < 0;
1986
+
1987
+ }
1988
+
1989
+ function isTransformSkewed( m ) {
1990
+
1991
+ const te = m.elements;
1992
+ const basisDot = te[ 0 ] * te[ 3 ] + te[ 1 ] * te[ 4 ];
1993
+
1994
+ // Shortcut for trivial rotations and transformations
1995
+ if ( basisDot === 0 ) return false;
1996
+
1997
+ const sx = getTransformScaleX( m );
1998
+ const sy = getTransformScaleY( m );
1999
+
2000
+ return Math.abs( basisDot / ( sx * sy ) ) > Number.EPSILON;
2001
+
2002
+ }
2003
+
2004
+ function getTransformScaleX( m ) {
2005
+
2006
+ const te = m.elements;
2007
+ return Math.sqrt( te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] );
2008
+
2009
+ }
2010
+
2011
+ function getTransformScaleY( m ) {
2012
+
2013
+ const te = m.elements;
2014
+ return Math.sqrt( te[ 3 ] * te[ 3 ] + te[ 4 ] * te[ 4 ] );
2015
+
2016
+ }
2017
+
2018
+ function getTransformScale( m ) {
2019
+
2020
+ const te = m.elements;
2021
+ const det = te[ 0 ] * te[ 4 ] - te[ 1 ] * te[ 3 ];
2022
+ return Math.sqrt( Math.abs( det ) );
2023
+
2024
+ }
2025
+
2026
+ // Calculates the eigensystem of a real symmetric 2x2 matrix
2027
+ // [ A B ]
2028
+ // [ B C ]
2029
+ // in the form
2030
+ // [ A B ] = [ cs -sn ] [ rt1 0 ] [ cs sn ]
2031
+ // [ B C ] [ sn cs ] [ 0 rt2 ] [ -sn cs ]
2032
+ // where rt1 >= rt2.
2033
+ //
2034
+ // Adapted from: https://www.mpi-hd.mpg.de/personalhomes/globes/3x3/index.html
2035
+ // -> Algorithms for real symmetric matrices -> Analytical (2x2 symmetric)
2036
+ function eigenDecomposition( A, B, C ) {
2037
+
2038
+ let rt1, rt2, cs, sn, t;
2039
+ const sm = A + C;
2040
+ const df = A - C;
2041
+ const rt = Math.sqrt( df * df + 4 * B * B );
2042
+
2043
+ if ( sm > 0 ) {
2044
+
2045
+ rt1 = 0.5 * ( sm + rt );
2046
+ t = 1 / rt1;
2047
+ rt2 = A * t * C - B * t * B;
2048
+
2049
+ } else if ( sm < 0 ) {
2050
+
2051
+ rt2 = 0.5 * ( sm - rt );
2052
+
2053
+ } else {
2054
+
2055
+ // This case needs to be treated separately to avoid div by 0
2056
+
2057
+ rt1 = 0.5 * rt;
2058
+ rt2 = - 0.5 * rt;
2059
+
2060
+ }
2061
+
2062
+ // Calculate eigenvectors
2063
+
2064
+ if ( df > 0 ) {
2065
+
2066
+ cs = df + rt;
2067
+
2068
+ } else {
2069
+
2070
+ cs = df - rt;
2071
+
2072
+ }
2073
+
2074
+ if ( Math.abs( cs ) > 2 * Math.abs( B ) ) {
2075
+
2076
+ t = - 2 * B / cs;
2077
+ sn = 1 / Math.sqrt( 1 + t * t );
2078
+ cs = t * sn;
2079
+
2080
+ } else if ( Math.abs( B ) === 0 ) {
2081
+
2082
+ cs = 1;
2083
+ sn = 0;
2084
+
2085
+ } else {
2086
+
2087
+ t = - 0.5 * cs / B;
2088
+ cs = 1 / Math.sqrt( 1 + t * t );
2089
+ sn = t * cs;
2090
+
2091
+ }
2092
+
2093
+ if ( df > 0 ) {
2094
+
2095
+ t = cs;
2096
+ cs = - sn;
2097
+ sn = t;
2098
+
2099
+ }
2100
+
2101
+ return { rt1, rt2, cs, sn };
2102
+
2103
+ }
2104
+
2105
+ //
2106
+
2107
+ const paths = [];
2108
+ const stylesheets = {};
2109
+ const gradients = {};
2110
+
2111
+ const transformStack = [];
2112
+
2113
+ const tempTransform0 = new Matrix3();
2114
+ const tempTransform1 = new Matrix3();
2115
+ const tempTransform2 = new Matrix3();
2116
+ const tempTransform3 = new Matrix3();
2117
+ const tempV2 = new Vector2();
2118
+ const tempV3 = new Vector3();
2119
+
2120
+ const currentTransform = new Matrix3();
2121
+
2122
+ const xml = new DOMParser().parseFromString( text, 'image/svg+xml' ); // application/xml
2123
+
2124
+ parseGradients( xml );
2125
+
2126
+ parseNode( xml.documentElement, {
2127
+ fill: '#000',
2128
+ fillOpacity: 1,
2129
+ strokeOpacity: 1,
2130
+ strokeWidth: 1,
2131
+ strokeLineJoin: 'miter',
2132
+ strokeLineCap: 'butt',
2133
+ strokeMiterLimit: 4
2134
+ } );
2135
+
2136
+ const data = { paths: paths, gradients: gradients, xml: xml.documentElement };
2137
+
2138
+ // console.log( paths );
2139
+ return data;
2140
+
2141
+ }
2142
+
2143
+ /**
2144
+ * Creates a material for rendering the fill of the given path.
2145
+ *
2146
+ * @param {ShapePath} shapePath - The shape path.
2147
+ * @return {?MeshBasicMaterial} The fill material. `null` if the path has no fill.
2148
+ */
2149
+ static createFillMaterial( shapePath ) {
2150
+
2151
+ const style = shapePath.userData.style;
2152
+ if ( style.fill === undefined || style.fill === 'none' ) return null;
2153
+
2154
+ const color = shapePath.color;
2155
+ let texture = null;
2156
+
2157
+ const urlMatch = GRADIENT_URL_RE.exec( style.fill );
2158
+
2159
+ if ( urlMatch ) {
2160
+
2161
+ const gradient = shapePath.userData.gradients && shapePath.userData.gradients[ urlMatch[ 1 ] ];
2162
+ texture = buildGradientTexture( gradient, shapePath );
2163
+
2164
+ }
2165
+
2166
+ const material = new MeshBasicMaterial( {
2167
+ opacity: style.fillOpacity * ( style.opacity || 1 ),
2168
+ transparent: true,
2169
+ side: DoubleSide,
2170
+ depthWrite: false,
2171
+ } );
2172
+
2173
+ if ( texture !== null ) {
2174
+
2175
+ material.map = texture;
2176
+
2177
+ } else {
2178
+
2179
+ material.color = color;
2180
+
2181
+ }
2182
+
2183
+ return material;
2184
+
2185
+ }
2186
+
2187
+ /**
2188
+ * Creates a material for rendering the stroke of the given path.
2189
+ *
2190
+ * @param {ShapePath} shapePath - The shape path.
2191
+ * @return {?MeshBasicMaterial} The stroke material. `null` if the path has no stroke.
2192
+ */
2193
+ static createStrokeMaterial( shapePath ) {
2194
+
2195
+ const style = shapePath.userData.style;
2196
+
2197
+ if ( style.stroke === undefined || style.stroke === 'none' ) return null;
2198
+
2199
+ if ( GRADIENT_URL_RE.test( style.stroke ) ) {
2200
+
2201
+ console.warn( 'THREE.SVGLoader: Gradient strokes are not supported.' );
2202
+
2203
+ }
2204
+
2205
+ return new MeshBasicMaterial( {
2206
+ color: new Color().setStyle( style.stroke, COLOR_SPACE_SVG ),
2207
+ opacity: style.strokeOpacity * ( style.opacity || 1 ),
2208
+ transparent: true,
2209
+ side: DoubleSide,
2210
+ depthWrite: false,
2211
+ } );
2212
+
2213
+ }
2214
+
2215
+ /**
2216
+ * Creates from the given shape path and array of shapes.
2217
+ *
2218
+ * @deprecated since 185.
2219
+ * @param {ShapePath} shapePath - The shape path.
2220
+ * @return {Array<Shape>} An array of shapes.
2221
+ */
2222
+ static createShapes( shapePath ) {
2223
+
2224
+ console.warn( 'SVGLoader: createShapes() is deprecated. Use shapePath.toShapes() instead.' ); // @deprecated, r185
2225
+
2226
+ return shapePath.toShapes();
2227
+
2228
+ }
2229
+
2230
+ /**
2231
+ * Returns a stroke style object from the given parameters.
2232
+ *
2233
+ * @param {number} [width=1] - The stroke width.
2234
+ * @param {string} [color='#000'] - The stroke color, as returned by {@link Color#getStyle}.
2235
+ * @param {'round'|'bevel'|'miter'|'miter-limit'} [lineJoin='miter'] - The line join style.
2236
+ * @param {'round'|'square'|'butt'} [lineCap='butt'] - The line cap style.
2237
+ * @param {number} [miterLimit=4] - Maximum join length, in multiples of the `width` parameter (join is truncated if it exceeds that distance).
2238
+ * @return {Object} The style object.
2239
+ */
2240
+ static getStrokeStyle( width, color, lineJoin, lineCap, miterLimit ) {
2241
+
2242
+ width = width !== undefined ? width : 1;
2243
+ color = color !== undefined ? color : '#000';
2244
+ lineJoin = lineJoin !== undefined ? lineJoin : 'miter';
2245
+ lineCap = lineCap !== undefined ? lineCap : 'butt';
2246
+ miterLimit = miterLimit !== undefined ? miterLimit : 4;
2247
+
2248
+ return {
2249
+ strokeColor: color,
2250
+ strokeWidth: width,
2251
+ strokeLineJoin: lineJoin,
2252
+ strokeLineCap: lineCap,
2253
+ strokeMiterLimit: miterLimit
2254
+ };
2255
+
2256
+ }
2257
+
2258
+ /**
2259
+ * Creates a stroke from an array of points.
2260
+ *
2261
+ * @param {Array<Vector2>} points - The points in 2D space. Minimum 2 points. The path can be open or closed (last point equals to first point).
2262
+ * @param {Object} style - Object with SVG properties as returned by `SVGLoader.getStrokeStyle()`, or `SVGLoader.parse()` in the `path.userData.style` object.
2263
+ * @param {number} [arcDivisions=12] - Arc divisions for round joins and endcaps.
2264
+ * @param {number} [minDistance=0.001] - Points closer to this distance will be merged.
2265
+ * @return {?BufferGeometry} The stroke geometry. UV coordinates are generated ('u' along path. 'v' across it, from left to right).
2266
+ * Returns `null` if not geometry was generated.
2267
+ */
2268
+ static pointsToStroke( points, style, arcDivisions, minDistance ) {
2269
+
2270
+ const vertices = [];
2271
+ const normals = [];
2272
+ const uvs = [];
2273
+
2274
+ if ( SVGLoader.pointsToStrokeWithBuffers( points, style, arcDivisions, minDistance, vertices, normals, uvs ) === 0 ) {
2275
+
2276
+ return null;
2277
+
2278
+ }
2279
+
2280
+ const geometry = new BufferGeometry();
2281
+ geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
2282
+ geometry.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
2283
+ geometry.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
2284
+
2285
+ return geometry;
2286
+
2287
+ }
2288
+
2289
+ /**
2290
+ * Creates a stroke from an array of points.
2291
+ *
2292
+ * @param {Array<Vector2>} points - The points in 2D space. Minimum 2 points.
2293
+ * @param {Object} style - Object with SVG properties as returned by `SVGLoader.getStrokeStyle()`, or `SVGLoader.parse()` in the `path.userData.style` object.
2294
+ * @param {number} [arcDivisions=12] - Arc divisions for round joins and endcaps.
2295
+ * @param {number} [minDistance=0.001] - Points closer to this distance will be merged.
2296
+ * @param {Array<number>} vertices - An array holding vertices.
2297
+ * @param {Array<number>} normals - An array holding normals.
2298
+ * @param {Array<number>} uvs - An array holding uvs.
2299
+ * @param {number} [vertexOffset=0] - The vertex offset.
2300
+ * @return {number} The number of vertices.
2301
+ */
2302
+ static pointsToStrokeWithBuffers( points, style, arcDivisions, minDistance, vertices, normals, uvs, vertexOffset ) {
2303
+
2304
+ // This function can be called to update existing arrays or buffers.
2305
+ // Accepts same parameters as pointsToStroke, plus the buffers and optional offset.
2306
+ // Param vertexOffset: Offset vertices to start writing in the buffers (3 elements/vertex for vertices and normals, and 2 elements/vertex for uvs)
2307
+ // Returns number of written vertices / normals / uvs pairs
2308
+ // if 'vertices' parameter is undefined no triangles will be generated, but the returned vertices count will still be valid (useful to preallocate the buffers)
2309
+ // 'normals' and 'uvs' buffers are optional
2310
+
2311
+ const tempV2_1 = new Vector2();
2312
+ const tempV2_2 = new Vector2();
2313
+ const tempV2_3 = new Vector2();
2314
+ const tempV2_4 = new Vector2();
2315
+ const tempV2_5 = new Vector2();
2316
+ const tempV2_6 = new Vector2();
2317
+ const tempV2_7 = new Vector2();
2318
+ const lastPointL = new Vector2();
2319
+ const lastPointR = new Vector2();
2320
+ const point0L = new Vector2();
2321
+ const point0R = new Vector2();
2322
+ const currentPointL = new Vector2();
2323
+ const currentPointR = new Vector2();
2324
+ const nextPointL = new Vector2();
2325
+ const nextPointR = new Vector2();
2326
+ const innerPoint = new Vector2();
2327
+ const outerPoint = new Vector2();
2328
+
2329
+ arcDivisions = arcDivisions !== undefined ? arcDivisions : 12;
2330
+ minDistance = minDistance !== undefined ? minDistance : 0.001;
2331
+ vertexOffset = vertexOffset !== undefined ? vertexOffset : 0;
2332
+
2333
+ // First ensure there are no duplicated points
2334
+ points = removeDuplicatedPoints( points );
2335
+
2336
+ const numPoints = points.length;
2337
+
2338
+ if ( numPoints < 2 ) return 0;
2339
+
2340
+ const isClosed = points[ 0 ].equals( points[ numPoints - 1 ] );
2341
+
2342
+ let currentPoint;
2343
+ let previousPoint = points[ 0 ];
2344
+ let nextPoint;
2345
+
2346
+ const strokeWidth2 = style.strokeWidth / 2;
2347
+
2348
+ const deltaU = 1 / ( numPoints - 1 );
2349
+ let u0 = 0, u1;
2350
+
2351
+ let innerSideModified;
2352
+ let joinIsOnLeftSide;
2353
+ let isMiter;
2354
+ let initialJoinIsOnLeftSide = false;
2355
+
2356
+ let numVertices = 0;
2357
+ let currentCoordinate = vertexOffset * 3;
2358
+ let currentCoordinateUV = vertexOffset * 2;
2359
+
2360
+ // Get initial left and right stroke points
2361
+ getNormal( points[ 0 ], points[ 1 ], tempV2_1 ).multiplyScalar( strokeWidth2 );
2362
+ lastPointL.copy( points[ 0 ] ).sub( tempV2_1 );
2363
+ lastPointR.copy( points[ 0 ] ).add( tempV2_1 );
2364
+ point0L.copy( lastPointL );
2365
+ point0R.copy( lastPointR );
2366
+
2367
+ for ( let iPoint = 1; iPoint < numPoints; iPoint ++ ) {
2368
+
2369
+ currentPoint = points[ iPoint ];
2370
+
2371
+ // Get next point
2372
+ if ( iPoint === numPoints - 1 ) {
2373
+
2374
+ if ( isClosed ) {
2375
+
2376
+ // Skip duplicated initial point
2377
+ nextPoint = points[ 1 ];
2378
+
2379
+ } else nextPoint = undefined;
2380
+
2381
+ } else {
2382
+
2383
+ nextPoint = points[ iPoint + 1 ];
2384
+
2385
+ }
2386
+
2387
+ // Normal of previous segment in tempV2_1
2388
+ const normal1 = tempV2_1;
2389
+ getNormal( previousPoint, currentPoint, normal1 );
2390
+
2391
+ tempV2_3.copy( normal1 ).multiplyScalar( strokeWidth2 );
2392
+ currentPointL.copy( currentPoint ).sub( tempV2_3 );
2393
+ currentPointR.copy( currentPoint ).add( tempV2_3 );
2394
+
2395
+ u1 = u0 + deltaU;
2396
+
2397
+ innerSideModified = false;
2398
+
2399
+ if ( nextPoint !== undefined ) {
2400
+
2401
+ // Normal of next segment in tempV2_2
2402
+ getNormal( currentPoint, nextPoint, tempV2_2 );
2403
+
2404
+ tempV2_3.copy( tempV2_2 ).multiplyScalar( strokeWidth2 );
2405
+ nextPointL.copy( currentPoint ).sub( tempV2_3 );
2406
+ nextPointR.copy( currentPoint ).add( tempV2_3 );
2407
+
2408
+ joinIsOnLeftSide = true;
2409
+ tempV2_3.subVectors( nextPoint, previousPoint );
2410
+ if ( normal1.dot( tempV2_3 ) < 0 ) {
2411
+
2412
+ joinIsOnLeftSide = false;
2413
+
2414
+ }
2415
+
2416
+ if ( iPoint === 1 ) initialJoinIsOnLeftSide = joinIsOnLeftSide;
2417
+
2418
+ tempV2_3.subVectors( nextPoint, currentPoint );
2419
+ tempV2_3.normalize();
2420
+ const dot = Math.abs( normal1.dot( tempV2_3 ) );
2421
+
2422
+ // If path is straight, don't create join
2423
+ if ( dot > Number.EPSILON ) {
2424
+
2425
+ // Compute inner and outer segment intersections
2426
+ const miterSide = strokeWidth2 / dot;
2427
+ tempV2_3.multiplyScalar( - miterSide );
2428
+ tempV2_4.subVectors( currentPoint, previousPoint );
2429
+ tempV2_5.copy( tempV2_4 ).setLength( miterSide ).add( tempV2_3 );
2430
+ innerPoint.copy( tempV2_5 ).negate();
2431
+ const miterLength2 = tempV2_5.length();
2432
+ const segmentLengthPrev = tempV2_4.length();
2433
+ tempV2_4.divideScalar( segmentLengthPrev );
2434
+ tempV2_6.subVectors( nextPoint, currentPoint );
2435
+ const segmentLengthNext = tempV2_6.length();
2436
+ tempV2_6.divideScalar( segmentLengthNext );
2437
+ // Check that previous and next segments doesn't overlap with the innerPoint of intersection
2438
+ if ( tempV2_4.dot( innerPoint ) < segmentLengthPrev && tempV2_6.dot( innerPoint ) < segmentLengthNext ) {
2439
+
2440
+ innerSideModified = true;
2441
+
2442
+ }
2443
+
2444
+ outerPoint.copy( tempV2_5 ).add( currentPoint );
2445
+ innerPoint.add( currentPoint );
2446
+
2447
+ // in-loop fold detection to mitigate #25326
2448
+ if ( innerSideModified ) {
2449
+
2450
+ // when the second triangle's signed area would flip, snap innerPoint to the previous inner-side vertex
2451
+
2452
+ const refPt = joinIsOnLeftSide ? lastPointR : lastPointL;
2453
+ const foldCross = ( outerPoint.x - refPt.x ) * ( innerPoint.y - refPt.y )
2454
+ - ( outerPoint.y - refPt.y ) * ( innerPoint.x - refPt.x );
2455
+ if ( ( joinIsOnLeftSide && foldCross < 0 ) || ( ! joinIsOnLeftSide && foldCross > 0 ) ) {
2456
+
2457
+ innerPoint.copy( refPt );
2458
+
2459
+ }
2460
+
2461
+ }
2462
+
2463
+ isMiter = false;
2464
+
2465
+ if ( innerSideModified ) {
2466
+
2467
+ if ( joinIsOnLeftSide ) {
2468
+
2469
+ nextPointR.copy( innerPoint );
2470
+ currentPointR.copy( innerPoint );
2471
+
2472
+ } else {
2473
+
2474
+ nextPointL.copy( innerPoint );
2475
+ currentPointL.copy( innerPoint );
2476
+
2477
+ }
2478
+
2479
+ } else {
2480
+
2481
+ // The segment triangles are generated here if there was overlapping
2482
+
2483
+ makeSegmentTriangles();
2484
+
2485
+ }
2486
+
2487
+ switch ( style.strokeLineJoin ) {
2488
+
2489
+ case 'bevel':
2490
+
2491
+ makeSegmentWithBevelJoin( joinIsOnLeftSide, innerSideModified, u1 );
2492
+
2493
+ break;
2494
+
2495
+ case 'round':
2496
+
2497
+ // Segment triangles
2498
+
2499
+ createSegmentTrianglesWithMiddleSection( joinIsOnLeftSide, innerSideModified );
2500
+
2501
+ // Join triangles
2502
+
2503
+ if ( joinIsOnLeftSide ) {
2504
+
2505
+ makeCircularSector( currentPoint, currentPointL, nextPointL, u1, 0 );
2506
+
2507
+ } else {
2508
+
2509
+ makeCircularSector( currentPoint, nextPointR, currentPointR, u1, 1 );
2510
+
2511
+ }
2512
+
2513
+ break;
2514
+
2515
+ case 'miter':
2516
+ case 'miter-clip':
2517
+ default:
2518
+
2519
+ const miterFraction = ( strokeWidth2 * style.strokeMiterLimit ) / miterLength2;
2520
+
2521
+ if ( miterFraction < 1 ) {
2522
+
2523
+ // The join miter length exceeds the miter limit
2524
+
2525
+ if ( style.strokeLineJoin !== 'miter-clip' ) {
2526
+
2527
+ makeSegmentWithBevelJoin( joinIsOnLeftSide, innerSideModified, u1 );
2528
+ break;
2529
+
2530
+ } else {
2531
+
2532
+ // Segment triangles
2533
+
2534
+ createSegmentTrianglesWithMiddleSection( joinIsOnLeftSide, innerSideModified );
2535
+
2536
+ // Miter-clip join triangles
2537
+
2538
+ if ( joinIsOnLeftSide ) {
2539
+
2540
+ tempV2_6.subVectors( outerPoint, currentPointL ).multiplyScalar( miterFraction ).add( currentPointL );
2541
+ tempV2_7.subVectors( outerPoint, nextPointL ).multiplyScalar( miterFraction ).add( nextPointL );
2542
+
2543
+ addVertex( currentPointL, u1, 0 );
2544
+ addVertex( tempV2_6, u1, 0 );
2545
+ addVertex( currentPoint, u1, 0.5 );
2546
+
2547
+ addVertex( currentPoint, u1, 0.5 );
2548
+ addVertex( tempV2_6, u1, 0 );
2549
+ addVertex( tempV2_7, u1, 0 );
2550
+
2551
+ addVertex( currentPoint, u1, 0.5 );
2552
+ addVertex( tempV2_7, u1, 0 );
2553
+ addVertex( nextPointL, u1, 0 );
2554
+
2555
+ } else {
2556
+
2557
+ tempV2_6.subVectors( outerPoint, currentPointR ).multiplyScalar( miterFraction ).add( currentPointR );
2558
+ tempV2_7.subVectors( outerPoint, nextPointR ).multiplyScalar( miterFraction ).add( nextPointR );
2559
+
2560
+ addVertex( currentPointR, u1, 1 );
2561
+ addVertex( tempV2_6, u1, 1 );
2562
+ addVertex( currentPoint, u1, 0.5 );
2563
+
2564
+ addVertex( currentPoint, u1, 0.5 );
2565
+ addVertex( tempV2_6, u1, 1 );
2566
+ addVertex( tempV2_7, u1, 1 );
2567
+
2568
+ addVertex( currentPoint, u1, 0.5 );
2569
+ addVertex( tempV2_7, u1, 1 );
2570
+ addVertex( nextPointR, u1, 1 );
2571
+
2572
+ }
2573
+
2574
+ }
2575
+
2576
+ } else {
2577
+
2578
+ // Miter join segment triangles
2579
+
2580
+ if ( innerSideModified ) {
2581
+
2582
+ // Optimized segment + join triangles
2583
+
2584
+ if ( joinIsOnLeftSide ) {
2585
+
2586
+ addVertex( lastPointR, u0, 1 );
2587
+ addVertex( lastPointL, u0, 0 );
2588
+ addVertex( outerPoint, u1, 0 );
2589
+
2590
+ addVertex( lastPointR, u0, 1 );
2591
+ addVertex( outerPoint, u1, 0 );
2592
+ addVertex( innerPoint, u1, 1 );
2593
+
2594
+ } else {
2595
+
2596
+ addVertex( lastPointR, u0, 1 );
2597
+ addVertex( lastPointL, u0, 0 );
2598
+ addVertex( outerPoint, u1, 1 );
2599
+
2600
+ addVertex( lastPointL, u0, 0 );
2601
+ addVertex( innerPoint, u1, 0 );
2602
+ addVertex( outerPoint, u1, 1 );
2603
+
2604
+ }
2605
+
2606
+
2607
+ if ( joinIsOnLeftSide ) {
2608
+
2609
+ nextPointL.copy( outerPoint );
2610
+
2611
+ } else {
2612
+
2613
+ nextPointR.copy( outerPoint );
2614
+
2615
+ }
2616
+
2617
+
2618
+ } else {
2619
+
2620
+ // Add extra miter join triangles
2621
+
2622
+ if ( joinIsOnLeftSide ) {
2623
+
2624
+ addVertex( currentPointL, u1, 0 );
2625
+ addVertex( outerPoint, u1, 0 );
2626
+ addVertex( currentPoint, u1, 0.5 );
2627
+
2628
+ addVertex( currentPoint, u1, 0.5 );
2629
+ addVertex( outerPoint, u1, 0 );
2630
+ addVertex( nextPointL, u1, 0 );
2631
+
2632
+ } else {
2633
+
2634
+ addVertex( currentPointR, u1, 1 );
2635
+ addVertex( outerPoint, u1, 1 );
2636
+ addVertex( currentPoint, u1, 0.5 );
2637
+
2638
+ addVertex( currentPoint, u1, 0.5 );
2639
+ addVertex( outerPoint, u1, 1 );
2640
+ addVertex( nextPointR, u1, 1 );
2641
+
2642
+ }
2643
+
2644
+ }
2645
+
2646
+ isMiter = true;
2647
+
2648
+ }
2649
+
2650
+ break;
2651
+
2652
+ }
2653
+
2654
+ } else {
2655
+
2656
+ // The segment triangles are generated here when two consecutive points are collinear
2657
+
2658
+ makeSegmentTriangles();
2659
+
2660
+ }
2661
+
2662
+ } else {
2663
+
2664
+ // The segment triangles are generated here if it is the ending segment
2665
+
2666
+ makeSegmentTriangles();
2667
+
2668
+ }
2669
+
2670
+ if ( ! isClosed && iPoint === numPoints - 1 ) {
2671
+
2672
+ // Start line endcap
2673
+ addCapGeometry( points[ 0 ], point0L, point0R, joinIsOnLeftSide, true, u0 );
2674
+
2675
+ }
2676
+
2677
+ // Increment loop variables
2678
+
2679
+ u0 = u1;
2680
+
2681
+ previousPoint = currentPoint;
2682
+
2683
+ lastPointL.copy( nextPointL );
2684
+ lastPointR.copy( nextPointR );
2685
+
2686
+ }
2687
+
2688
+ if ( ! isClosed ) {
2689
+
2690
+ // Ending line endcap
2691
+ addCapGeometry( currentPoint, currentPointL, currentPointR, joinIsOnLeftSide, false, u1 );
2692
+
2693
+ } else if ( innerSideModified && vertices ) {
2694
+
2695
+ // Modify path first segment vertices to adjust to the segments inner and outer intersections
2696
+
2697
+ let lastOuter = outerPoint;
2698
+ let lastInner = innerPoint;
2699
+
2700
+ if ( initialJoinIsOnLeftSide !== joinIsOnLeftSide ) {
2701
+
2702
+ lastOuter = innerPoint;
2703
+ lastInner = outerPoint;
2704
+
2705
+ }
2706
+
2707
+ if ( joinIsOnLeftSide ) {
2708
+
2709
+ if ( isMiter || initialJoinIsOnLeftSide ) {
2710
+
2711
+ lastInner.toArray( vertices, 0 * 3 );
2712
+ lastInner.toArray( vertices, 3 * 3 );
2713
+
2714
+ if ( isMiter ) {
2715
+
2716
+ lastOuter.toArray( vertices, 1 * 3 );
2717
+
2718
+ }
2719
+
2720
+ }
2721
+
2722
+ } else {
2723
+
2724
+ if ( isMiter || ! initialJoinIsOnLeftSide ) {
2725
+
2726
+ lastInner.toArray( vertices, 1 * 3 );
2727
+ lastInner.toArray( vertices, 3 * 3 );
2728
+
2729
+ if ( isMiter ) {
2730
+
2731
+ lastOuter.toArray( vertices, 0 * 3 );
2732
+
2733
+ }
2734
+
2735
+ }
2736
+
2737
+ }
2738
+
2739
+ }
2740
+
2741
+ // Second fix for #25326: Scan for reamining flipped (CW) triangles and collapse them to
2742
+ // degenerated ones. This is safe and leaves no "holes" in the stroke because the flipped
2743
+ // triangle's area is covered by neighbouring (CCW) triangles.
2744
+
2745
+ if ( vertices ) {
2746
+
2747
+ const tri = [ new Vector2(), new Vector2(), new Vector2() ];
2748
+ const startFloat = vertexOffset * 3;
2749
+
2750
+ for ( let t = startFloat; t < currentCoordinate; t += 9 ) {
2751
+
2752
+ tri[ 0 ].set( vertices[ t ], vertices[ t + 1 ] );
2753
+ tri[ 1 ].set( vertices[ t + 3 ], vertices[ t + 4 ] );
2754
+ tri[ 2 ].set( vertices[ t + 6 ], vertices[ t + 7 ] );
2755
+
2756
+ if ( ShapeUtils.area( tri ) < 0 ) {
2757
+
2758
+ vertices[ t + 3 ] = tri[ 0 ].x;
2759
+ vertices[ t + 4 ] = tri[ 0 ].y;
2760
+
2761
+ }
2762
+
2763
+ }
2764
+
2765
+ }
2766
+
2767
+ return numVertices;
2768
+
2769
+ // -- End of algorithm
2770
+
2771
+ // -- Functions
2772
+
2773
+ function getNormal( p1, p2, result ) {
2774
+
2775
+ result.subVectors( p2, p1 );
2776
+ return result.set( - result.y, result.x ).normalize();
2777
+
2778
+ }
2779
+
2780
+ function addVertex( position, u, v ) {
2781
+
2782
+ if ( vertices ) {
2783
+
2784
+ vertices[ currentCoordinate ] = position.x;
2785
+ vertices[ currentCoordinate + 1 ] = position.y;
2786
+ vertices[ currentCoordinate + 2 ] = 0;
2787
+
2788
+ if ( normals ) {
2789
+
2790
+ normals[ currentCoordinate ] = 0;
2791
+ normals[ currentCoordinate + 1 ] = 0;
2792
+ normals[ currentCoordinate + 2 ] = 1;
2793
+
2794
+ }
2795
+
2796
+ currentCoordinate += 3;
2797
+
2798
+ if ( uvs ) {
2799
+
2800
+ uvs[ currentCoordinateUV ] = u;
2801
+ uvs[ currentCoordinateUV + 1 ] = v;
2802
+
2803
+ currentCoordinateUV += 2;
2804
+
2805
+ }
2806
+
2807
+ }
2808
+
2809
+ numVertices += 3;
2810
+
2811
+ }
2812
+
2813
+ function makeCircularSector( center, p1, p2, u, v ) {
2814
+
2815
+ // param p1, p2: Points in the circle arc.
2816
+ // p1 and p2 are in clockwise direction.
2817
+
2818
+ tempV2_1.copy( p1 ).sub( center ).normalize();
2819
+ tempV2_2.copy( p2 ).sub( center ).normalize();
2820
+
2821
+ let angle = Math.PI;
2822
+ const dot = tempV2_1.dot( tempV2_2 );
2823
+ if ( Math.abs( dot ) < 1 ) angle = Math.abs( Math.acos( dot ) );
2824
+
2825
+ angle /= arcDivisions;
2826
+
2827
+ tempV2_3.copy( p1 );
2828
+
2829
+ for ( let i = 0, il = arcDivisions - 1; i < il; i ++ ) {
2830
+
2831
+ tempV2_4.copy( tempV2_3 ).rotateAround( center, angle );
2832
+
2833
+ addVertex( tempV2_3, u, v );
2834
+ addVertex( tempV2_4, u, v );
2835
+ addVertex( center, u, 0.5 );
2836
+
2837
+ tempV2_3.copy( tempV2_4 );
2838
+
2839
+ }
2840
+
2841
+ addVertex( tempV2_3, u, v );
2842
+ addVertex( p2, u, v );
2843
+ addVertex( center, u, 0.5 );
2844
+
2845
+ }
2846
+
2847
+ function makeSegmentTriangles() {
2848
+
2849
+ addVertex( lastPointR, u0, 1 );
2850
+ addVertex( lastPointL, u0, 0 );
2851
+ addVertex( currentPointL, u1, 0 );
2852
+
2853
+ addVertex( lastPointR, u0, 1 );
2854
+ addVertex( currentPointL, u1, 0 );
2855
+ addVertex( currentPointR, u1, 1 );
2856
+
2857
+ }
2858
+
2859
+ function makeSegmentWithBevelJoin( joinIsOnLeftSide, innerSideModified, u ) {
2860
+
2861
+ if ( innerSideModified ) {
2862
+
2863
+ // Optimized segment + bevel triangles
2864
+
2865
+ if ( joinIsOnLeftSide ) {
2866
+
2867
+ // Path segments triangles
2868
+
2869
+ addVertex( lastPointR, u0, 1 );
2870
+ addVertex( lastPointL, u0, 0 );
2871
+ addVertex( currentPointL, u1, 0 );
2872
+
2873
+ addVertex( lastPointR, u0, 1 );
2874
+ addVertex( currentPointL, u1, 0 );
2875
+ addVertex( innerPoint, u1, 1 );
2876
+
2877
+ // Bevel join triangle
2878
+
2879
+ addVertex( currentPointL, u, 0 );
2880
+ addVertex( nextPointL, u, 0 );
2881
+ addVertex( innerPoint, u, 0.5 );
2882
+
2883
+ } else {
2884
+
2885
+ // Path segments triangles
2886
+
2887
+ addVertex( lastPointR, u0, 1 );
2888
+ addVertex( lastPointL, u0, 0 );
2889
+ addVertex( currentPointR, u1, 1 );
2890
+
2891
+ addVertex( lastPointL, u0, 0 );
2892
+ addVertex( innerPoint, u1, 0 );
2893
+ addVertex( currentPointR, u1, 1 );
2894
+
2895
+ // Bevel join triangle
2896
+
2897
+ addVertex( currentPointR, u, 1 );
2898
+ addVertex( innerPoint, u, 0 );
2899
+ addVertex( nextPointR, u, 1 );
2900
+
2901
+ }
2902
+
2903
+ } else {
2904
+
2905
+ // Bevel join triangle. The segment triangles are done in the main loop
2906
+
2907
+ if ( joinIsOnLeftSide ) {
2908
+
2909
+ addVertex( currentPointL, u, 0 );
2910
+ addVertex( nextPointL, u, 0 );
2911
+ addVertex( currentPoint, u, 0.5 );
2912
+
2913
+ } else {
2914
+
2915
+ addVertex( currentPointR, u, 1 );
2916
+ addVertex( nextPointR, u, 0 );
2917
+ addVertex( currentPoint, u, 0.5 );
2918
+
2919
+ }
2920
+
2921
+ }
2922
+
2923
+ }
2924
+
2925
+ function createSegmentTrianglesWithMiddleSection( joinIsOnLeftSide, innerSideModified ) {
2926
+
2927
+ if ( innerSideModified ) {
2928
+
2929
+ if ( joinIsOnLeftSide ) {
2930
+
2931
+ addVertex( lastPointR, u0, 1 );
2932
+ addVertex( lastPointL, u0, 0 );
2933
+ addVertex( currentPointL, u1, 0 );
2934
+
2935
+ addVertex( lastPointR, u0, 1 );
2936
+ addVertex( currentPointL, u1, 0 );
2937
+ addVertex( innerPoint, u1, 1 );
2938
+
2939
+ addVertex( currentPointL, u0, 0 );
2940
+ addVertex( currentPoint, u1, 0.5 );
2941
+ addVertex( innerPoint, u1, 1 );
2942
+
2943
+ addVertex( currentPoint, u1, 0.5 );
2944
+ addVertex( nextPointL, u0, 0 );
2945
+ addVertex( innerPoint, u1, 1 );
2946
+
2947
+ } else {
2948
+
2949
+ addVertex( lastPointR, u0, 1 );
2950
+ addVertex( lastPointL, u0, 0 );
2951
+ addVertex( currentPointR, u1, 1 );
2952
+
2953
+ addVertex( lastPointL, u0, 0 );
2954
+ addVertex( innerPoint, u1, 0 );
2955
+ addVertex( currentPointR, u1, 1 );
2956
+
2957
+ addVertex( currentPointR, u0, 1 );
2958
+ addVertex( innerPoint, u1, 0 );
2959
+ addVertex( currentPoint, u1, 0.5 );
2960
+
2961
+ addVertex( currentPoint, u1, 0.5 );
2962
+ addVertex( innerPoint, u1, 0 );
2963
+ addVertex( nextPointR, u0, 1 );
2964
+
2965
+ }
2966
+
2967
+ }
2968
+
2969
+ }
2970
+
2971
+ function addCapGeometry( center, p1, p2, joinIsOnLeftSide, start, u ) {
2972
+
2973
+ // param center: End point of the path
2974
+ // param p1, p2: Left and right cap points
2975
+
2976
+ switch ( style.strokeLineCap ) {
2977
+
2978
+ case 'round':
2979
+
2980
+ if ( start ) {
2981
+
2982
+ makeCircularSector( center, p2, p1, u, 0.5 );
2983
+
2984
+ } else {
2985
+
2986
+ makeCircularSector( center, p1, p2, u, 0.5 );
2987
+
2988
+ }
2989
+
2990
+ break;
2991
+
2992
+ case 'square':
2993
+
2994
+ if ( start ) {
2995
+
2996
+ tempV2_1.subVectors( p1, center );
2997
+ tempV2_2.set( tempV2_1.y, - tempV2_1.x );
2998
+
2999
+ tempV2_3.addVectors( tempV2_1, tempV2_2 ).add( center );
3000
+ tempV2_4.subVectors( tempV2_2, tempV2_1 ).add( center );
3001
+
3002
+ // Modify already existing vertices
3003
+ if ( joinIsOnLeftSide ) {
3004
+
3005
+ tempV2_3.toArray( vertices, 1 * 3 );
3006
+ tempV2_4.toArray( vertices, 0 * 3 );
3007
+ tempV2_4.toArray( vertices, 3 * 3 );
3008
+
3009
+ } else {
3010
+
3011
+ tempV2_3.toArray( vertices, 1 * 3 );
3012
+ // using tempV2_4 to update 3rd vertex if the uv.y of 3rd vertex is 1
3013
+ uvs[ 3 * 2 + 1 ] === 1 ? tempV2_4.toArray( vertices, 3 * 3 ) : tempV2_3.toArray( vertices, 3 * 3 );
3014
+ tempV2_4.toArray( vertices, 0 * 3 );
3015
+
3016
+ }
3017
+
3018
+ } else {
3019
+
3020
+ tempV2_1.subVectors( p2, center );
3021
+ tempV2_2.set( tempV2_1.y, - tempV2_1.x );
3022
+
3023
+ tempV2_3.addVectors( tempV2_1, tempV2_2 ).add( center );
3024
+ tempV2_4.subVectors( tempV2_2, tempV2_1 ).add( center );
3025
+
3026
+ const vl = vertices.length;
3027
+
3028
+ // Modify already existing vertices
3029
+ if ( joinIsOnLeftSide ) {
3030
+
3031
+ tempV2_3.toArray( vertices, vl - 1 * 3 );
3032
+ tempV2_4.toArray( vertices, vl - 2 * 3 );
3033
+ tempV2_4.toArray( vertices, vl - 4 * 3 );
3034
+
3035
+ } else {
3036
+
3037
+ tempV2_4.toArray( vertices, vl - 2 * 3 );
3038
+ tempV2_3.toArray( vertices, vl - 1 * 3 );
3039
+ tempV2_4.toArray( vertices, vl - 4 * 3 );
3040
+
3041
+ }
3042
+
3043
+ }
3044
+
3045
+ break;
3046
+
3047
+ case 'butt':
3048
+ default:
3049
+
3050
+ // Nothing to do here
3051
+ break;
3052
+
3053
+ }
3054
+
3055
+ }
3056
+
3057
+ function removeDuplicatedPoints( points ) {
3058
+
3059
+ // Creates a new array if necessary with duplicated points removed.
3060
+ // This does not remove duplicated initial and ending points of a closed path.
3061
+
3062
+ let dupPoints = false;
3063
+ for ( let i = 1, n = points.length - 1; i < n; i ++ ) {
3064
+
3065
+ if ( points[ i ].distanceTo( points[ i + 1 ] ) < minDistance ) {
3066
+
3067
+ dupPoints = true;
3068
+ break;
3069
+
3070
+ }
3071
+
3072
+ }
3073
+
3074
+ if ( ! dupPoints ) return points;
3075
+
3076
+ const newPoints = [];
3077
+ newPoints.push( points[ 0 ] );
3078
+
3079
+ for ( let i = 1, n = points.length - 1; i < n; i ++ ) {
3080
+
3081
+ if ( points[ i ].distanceTo( points[ i + 1 ] ) >= minDistance ) {
3082
+
3083
+ newPoints.push( points[ i ] );
3084
+
3085
+ }
3086
+
3087
+ }
3088
+
3089
+ newPoints.push( points[ points.length - 1 ] );
3090
+
3091
+ return newPoints;
3092
+
3093
+ }
3094
+
3095
+ }
3096
+
3097
+ }
3098
+
3099
+ const GRADIENT_URL_RE = /^\s*url\(\s*(?:["']\s*)?#([^)'"\s]+)(?:\s*["'])?\s*\)\s*$/;
3100
+
3101
+ // Bakes a gradient into a CanvasTexture in its own local frame and configures
3102
+ // `texture.matrix` (with `matrixAutoUpdate = false`) so that shape-space UVs —
3103
+ // which, because transformPath bakes the world matrix into geometry vertex
3104
+ // positions, equal world xy — sample the correct gradient color. The caller
3105
+ // just sets `material.map = texture`; no bounding box, no geometry, no
3106
+ // per-vertex UV work required.
3107
+ function buildGradientTexture( gradient, shapePath, resolution = 256 ) {
3108
+
3109
+ if ( ! gradient || ! Array.isArray( gradient.stops ) || gradient.stops.length === 0 ) return null;
3110
+
3111
+ const worldTransform = shapePath.userData.transform;
3112
+ const isBBoxUnits = gradient.gradientUnits === 'objectBoundingBox';
3113
+
3114
+ // For objectBoundingBox gradients we need the element's local bounding
3115
+ // box. Path points are in world space (transformPath already applied the
3116
+ // world transform), so invert that first.
3117
+ let localBBox = null;
3118
+
3119
+ if ( isBBoxUnits ) {
3120
+
3121
+ localBBox = computeLocalBBox( shapePath, worldTransform );
3122
+ if ( localBBox === null ) return null;
3123
+
3124
+ }
3125
+
3126
+ // Resolves a gradient-space point to the geometry's (world) coordinate
3127
+ // space: gradient coord → gradientTransform → target coord → (for
3128
+ // objectBoundingBox: bbox → local) → worldTransform → world.
3129
+ function resolvePoint( x, y, out ) {
3130
+
3131
+ out.set( x, y, 1 );
3132
+ if ( gradient.gradientTransform ) out.applyMatrix3( gradient.gradientTransform );
3133
+ if ( isBBoxUnits ) out.set(
3134
+ localBBox.minX + out.x * localBBox.width,
3135
+ localBBox.minY + out.y * localBBox.height,
3136
+ 1,
3137
+ );
3138
+ if ( worldTransform ) out.applyMatrix3( worldTransform );
3139
+
3140
+ }
3141
+
3142
+ const canvas = document.createElement( 'canvas' );
3143
+ let textureMatrix;
3144
+
3145
+ if ( gradient.type === 'linearGradient' ) {
3146
+
3147
+ // 1D bake along the gradient vector.
3148
+ canvas.width = resolution;
3149
+ canvas.height = 1;
3150
+ const ctx = canvas.getContext( '2d' );
3151
+
3152
+ const grad = ctx.createLinearGradient( 0, 0, resolution, 0 );
3153
+ addStops( grad, gradient.stops );
3154
+ ctx.fillStyle = grad;
3155
+ ctx.fillRect( 0, 0, resolution, 1 );
3156
+
3157
+ const p1 = new Vector3();
3158
+ const p2 = new Vector3();
3159
+ resolvePoint( gradient.x1, gradient.y1, p1 );
3160
+ resolvePoint( gradient.x2, gradient.y2, p2 );
3161
+
3162
+ const dx = p2.x - p1.x;
3163
+ const dy = p2.y - p1.y;
3164
+ const len2 = dx * dx + dy * dy || 1e-20;
3165
+ const a = dx / len2;
3166
+ const b = dy / len2;
3167
+ const c = - ( a * p1.x + b * p1.y );
3168
+
3169
+ // M * (vx, vy, 1) = (t, 0.5, 1)
3170
+ textureMatrix = new Matrix3().set(
3171
+ a, b, c,
3172
+ 0, 0, 0.5,
3173
+ 0, 0, 1,
3174
+ );
3175
+
3176
+ } else {
3177
+
3178
+ // Resolve cx/cy/fx/fy into local space and scale r per the SVG spec
3179
+ // (objectBoundingBox scales lengths by sqrt((w² + h²) / 2)). The canvas
3180
+ // only draws circular radial gradients, so any ellipticity induced by
3181
+ // a non-uniform world transform is picked up later via the UV matrix.
3182
+ let cx = gradient.cx, cy = gradient.cy;
3183
+ let fx = gradient.fx, fy = gradient.fy;
3184
+ let r = gradient.r;
3185
+
3186
+ if ( gradient.gradientTransform ) {
3187
+
3188
+ const tmp = new Vector3();
3189
+ tmp.set( cx, cy, 1 ).applyMatrix3( gradient.gradientTransform );
3190
+ cx = tmp.x; cy = tmp.y;
3191
+ tmp.set( fx, fy, 1 ).applyMatrix3( gradient.gradientTransform );
3192
+ fx = tmp.x; fy = tmp.y;
3193
+
3194
+ }
3195
+
3196
+ if ( isBBoxUnits ) {
3197
+
3198
+ cx = localBBox.minX + cx * localBBox.width;
3199
+ cy = localBBox.minY + cy * localBBox.height;
3200
+ fx = localBBox.minX + fx * localBBox.width;
3201
+ fy = localBBox.minY + fy * localBBox.height;
3202
+ r = r * Math.sqrt( ( localBBox.width * localBBox.width + localBBox.height * localBBox.height ) / 2 );
3203
+
3204
+ }
3205
+
3206
+ if ( r <= 0 ) return null;
3207
+
3208
+ // 2D bake in the gradient's local frame, covering [cx-r, cx+r]².
3209
+ canvas.width = resolution;
3210
+ canvas.height = resolution;
3211
+ const ctx = canvas.getContext( '2d' );
3212
+
3213
+ const localMinX = cx - r;
3214
+ const localMinY = cy - r;
3215
+ const localSpan = 2 * r;
3216
+ const scale = resolution / localSpan;
3217
+
3218
+ // Canvas pixel = (local - localMin) * scale.
3219
+ ctx.setTransform( scale, 0, 0, scale, - localMinX * scale, - localMinY * scale );
3220
+
3221
+ const grad = ctx.createRadialGradient( fx, fy, 0, cx, cy, r );
3222
+ addStops( grad, gradient.stops );
3223
+ ctx.fillStyle = grad;
3224
+ ctx.fillRect( localMinX, localMinY, localSpan, localSpan );
3225
+
3226
+ // UV matrix: world → local (via worldTransform⁻¹) → normalized canvas UV.
3227
+ const inv = worldTransform ? worldTransform.clone().invert() : new Matrix3();
3228
+ const norm = new Matrix3().set(
3229
+ 1 / localSpan, 0, - localMinX / localSpan,
3230
+ 0, 1 / localSpan, - localMinY / localSpan,
3231
+ 0, 0, 1,
3232
+ );
3233
+ textureMatrix = norm.multiply( inv );
3234
+
3235
+ }
3236
+
3237
+ const texture = new CanvasTexture( canvas );
3238
+ texture.colorSpace = COLOR_SPACE_SVG;
3239
+ texture.flipY = false;
3240
+ texture.matrixAutoUpdate = false;
3241
+ texture.matrix = textureMatrix;
3242
+
3243
+ const wrap = gradient.spreadMethod === 'reflect' ? MirroredRepeatWrapping
3244
+ : gradient.spreadMethod === 'repeat' ? RepeatWrapping
3245
+ : ClampToEdgeWrapping;
3246
+ texture.wrapS = wrap;
3247
+ texture.wrapT = wrap;
3248
+
3249
+ return texture;
3250
+
3251
+ }
3252
+
3253
+ function computeLocalBBox( shapePath, worldTransform ) {
3254
+
3255
+ const inv = worldTransform ? worldTransform.clone().invert() : null;
3256
+ const tmp = new Vector2();
3257
+ const box = new Box2();
3258
+
3259
+ for ( const subPath of shapePath.subPaths ) {
3260
+
3261
+ for ( const p of subPath.getPoints() ) {
3262
+
3263
+ tmp.copy( p );
3264
+ if ( inv ) tmp.applyMatrix3( inv );
3265
+ box.expandByPoint( tmp );
3266
+
3267
+ }
3268
+
3269
+ }
3270
+
3271
+ if ( box.isEmpty() ) return null;
3272
+
3273
+ return { minX: box.min.x, minY: box.min.y, width: box.max.x - box.min.x, height: box.max.y - box.min.y };
3274
+
3275
+ }
3276
+
3277
+ function addStops( canvasGradient, stops ) {
3278
+
3279
+ const tmpColor = new Color();
3280
+ for ( const stop of stops ) {
3281
+
3282
+ let css = stop.color;
3283
+ if ( stop.opacity < 1 ) {
3284
+
3285
+ tmpColor.setStyle( stop.color, COLOR_SPACE_SVG );
3286
+ const m = /rgb\(([^)]+)\)/.exec( tmpColor.getStyle( COLOR_SPACE_SVG ) );
3287
+ if ( m ) css = `rgba(${m[ 1 ]},${stop.opacity})`;
3288
+
3289
+ }
3290
+
3291
+ canvasGradient.addColorStop( Math.max( 0, Math.min( 1, stop.offset ) ), css );
3292
+
3293
+ }
3294
+
3295
+ }
3296
+
3297
+ export { SVGLoader };