@lampdotdev/lamp 0.0.0-stage → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -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 +1646 -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/scaffold/Game/game.cpp +142 -0
  29. package/Resources/GameKit/scaffold/Game/scene.glsl +49 -0
  30. package/Resources/GameKit/scaffold-web/Web/game.js +31 -0
  31. package/Resources/GameKit/scaffold-web/Web/index.html +13 -0
  32. package/Resources/GameKit/scaffold-web/Web/making.js +33 -0
  33. package/Resources/GameKit/scaffold-web/Web/world.js +33 -0
  34. package/Resources/GameKit/web/lamp-game.js +3036 -0
  35. package/Resources/GameKit/web/lamp-phaser.js +128 -0
  36. package/Resources/WebHost/App.exe +0 -0
  37. package/Resources/WebHost/Microsoft.Web.WebView2.Core.dll +0 -0
  38. package/Resources/WebHost/WebView2-LICENSE.txt +27 -0
  39. package/Resources/WebHost/lamp_controllers.h +1506 -0
  40. package/Resources/WebHost/lamp_web_host.cpp +1173 -0
  41. package/Resources/WebLibraries/earlier.txt +318 -0
  42. package/Resources/WebLibraries/phaser/LICENSE.md +20 -0
  43. package/Resources/WebLibraries/phaser/NOTICE.md +2 -0
  44. package/Resources/WebLibraries/phaser/phaser.esm.min.js +1 -0
  45. package/Resources/WebLibraries/qrcode/LICENSE +21 -0
  46. package/Resources/WebLibraries/qrcode/NOTICE.md +4 -0
  47. package/Resources/WebLibraries/qrcode/qrcode.js +2297 -0
  48. package/Resources/WebLibraries/rapier/LICENSE +201 -0
  49. package/Resources/WebLibraries/rapier/NOTICE.md +3 -0
  50. package/Resources/WebLibraries/rapier/rapier.js +2 -0
  51. package/Resources/WebLibraries/three/LICENSE +21 -0
  52. package/Resources/WebLibraries/three/NOTICE.md +4 -0
  53. package/Resources/WebLibraries/three/addons/animation/AnimationClipCreator.js +168 -0
  54. package/Resources/WebLibraries/three/addons/animation/CCDIKSolver.js +607 -0
  55. package/Resources/WebLibraries/three/addons/controls/ArcballControls.js +3543 -0
  56. package/Resources/WebLibraries/three/addons/controls/DragControls.js +452 -0
  57. package/Resources/WebLibraries/three/addons/controls/FirstPersonControls.js +512 -0
  58. package/Resources/WebLibraries/three/addons/controls/FlyControls.js +384 -0
  59. package/Resources/WebLibraries/three/addons/controls/MapControls.js +116 -0
  60. package/Resources/WebLibraries/three/addons/controls/OrbitControls.js +1985 -0
  61. package/Resources/WebLibraries/three/addons/controls/PointerLockControls.js +264 -0
  62. package/Resources/WebLibraries/three/addons/controls/TrackballControls.js +1106 -0
  63. package/Resources/WebLibraries/three/addons/controls/TransformControls.js +2003 -0
  64. package/Resources/WebLibraries/three/addons/curves/CurveExtras.js +694 -0
  65. package/Resources/WebLibraries/three/addons/curves/NURBSCurve.js +169 -0
  66. package/Resources/WebLibraries/three/addons/curves/NURBSSurface.js +98 -0
  67. package/Resources/WebLibraries/three/addons/curves/NURBSUtils.js +532 -0
  68. package/Resources/WebLibraries/three/addons/curves/NURBSVolume.js +82 -0
  69. package/Resources/WebLibraries/three/addons/effects/AnaglyphEffect.js +274 -0
  70. package/Resources/WebLibraries/three/addons/effects/AsciiEffect.js +323 -0
  71. package/Resources/WebLibraries/three/addons/effects/OutlineEffect.js +489 -0
  72. package/Resources/WebLibraries/three/addons/effects/ParallaxBarrierEffect.js +155 -0
  73. package/Resources/WebLibraries/three/addons/effects/StereoEffect.js +91 -0
  74. package/Resources/WebLibraries/three/addons/environments/ColorEnvironment.js +59 -0
  75. package/Resources/WebLibraries/three/addons/environments/DebugEnvironment.js +102 -0
  76. package/Resources/WebLibraries/three/addons/environments/RoomEnvironment.js +185 -0
  77. package/Resources/WebLibraries/three/addons/geometries/BoxLineGeometry.js +92 -0
  78. package/Resources/WebLibraries/three/addons/geometries/ConvexGeometry.js +72 -0
  79. package/Resources/WebLibraries/three/addons/geometries/DecalGeometry.js +420 -0
  80. package/Resources/WebLibraries/three/addons/geometries/LoftGeometry.js +355 -0
  81. package/Resources/WebLibraries/three/addons/geometries/ParametricFunctions.js +100 -0
  82. package/Resources/WebLibraries/three/addons/geometries/ParametricGeometry.js +172 -0
  83. package/Resources/WebLibraries/three/addons/geometries/RoundedBoxGeometry.js +216 -0
  84. package/Resources/WebLibraries/three/addons/geometries/TeapotGeometry.js +689 -0
  85. package/Resources/WebLibraries/three/addons/geometries/TextGeometry.js +102 -0
  86. package/Resources/WebLibraries/three/addons/helpers/AnimationPathHelper.js +302 -0
  87. package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelper.js +166 -0
  88. package/Resources/WebLibraries/three/addons/helpers/LightProbeGridHelperWebGL.js +221 -0
  89. package/Resources/WebLibraries/three/addons/helpers/LightProbeHelper.js +166 -0
  90. package/Resources/WebLibraries/three/addons/helpers/LightProbeHelperGPU.js +102 -0
  91. package/Resources/WebLibraries/three/addons/helpers/OctreeHelper.js +109 -0
  92. package/Resources/WebLibraries/three/addons/helpers/PositionalAudioHelper.js +169 -0
  93. package/Resources/WebLibraries/three/addons/helpers/RapierHelper.js +59 -0
  94. package/Resources/WebLibraries/three/addons/helpers/RectAreaLightHelper.js +118 -0
  95. package/Resources/WebLibraries/three/addons/helpers/TextureHelper.js +265 -0
  96. package/Resources/WebLibraries/three/addons/helpers/TextureHelperGPU.js +214 -0
  97. package/Resources/WebLibraries/three/addons/helpers/VertexNormalsHelper.js +155 -0
  98. package/Resources/WebLibraries/three/addons/helpers/VertexTangentsHelper.js +133 -0
  99. package/Resources/WebLibraries/three/addons/helpers/ViewHelper.js +529 -0
  100. package/Resources/WebLibraries/three/addons/interactive/HTMLMesh.js +617 -0
  101. package/Resources/WebLibraries/three/addons/interactive/InteractiveGroup.js +224 -0
  102. package/Resources/WebLibraries/three/addons/interactive/SelectionBox.js +324 -0
  103. package/Resources/WebLibraries/three/addons/interactive/SelectionHelper.js +150 -0
  104. package/Resources/WebLibraries/three/addons/libs/fflate.module.js +2699 -0
  105. package/Resources/WebLibraries/three/addons/libs/lil-gui.module.min.js +8 -0
  106. package/Resources/WebLibraries/three/addons/libs/meshopt_decoder.module.js +196 -0
  107. package/Resources/WebLibraries/three/addons/libs/potpack.module.js +125 -0
  108. package/Resources/WebLibraries/three/addons/libs/stats.module.js +167 -0
  109. package/Resources/WebLibraries/three/addons/libs/tween.module.js +876 -0
  110. package/Resources/WebLibraries/three/addons/lighting/ClusteredLighting.js +153 -0
  111. package/Resources/WebLibraries/three/addons/lighting/DynamicLighting.js +82 -0
  112. package/Resources/WebLibraries/three/addons/lighting/LightMapper.js +295 -0
  113. package/Resources/WebLibraries/three/addons/lighting/LightProbeGrid.js +923 -0
  114. package/Resources/WebLibraries/three/addons/lighting/LightProbeGridUtils.js +107 -0
  115. package/Resources/WebLibraries/three/addons/lighting/LightProbeGridWebGL.js +846 -0
  116. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIConeTracer.js +243 -0
  117. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIIrradiance.js +43 -0
  118. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGINode.js +617 -0
  119. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGISceneCollector.js +793 -0
  120. package/Resources/WebLibraries/three/addons/lighting/vxgi/VXGIVolume.js +1440 -0
  121. package/Resources/WebLibraries/three/addons/lights/LightProbeGenerator.js +337 -0
  122. package/Resources/WebLibraries/three/addons/lights/RectAreaLightTexturesLib.js +127 -0
  123. package/Resources/WebLibraries/three/addons/lights/RectAreaLightUniformsLib.js +40 -0
  124. package/Resources/WebLibraries/three/addons/lights/SunLight.js +100 -0
  125. package/Resources/WebLibraries/three/addons/lights/SunLightNode.js +56 -0
  126. package/Resources/WebLibraries/three/addons/lights/SunLightShadow.js +319 -0
  127. package/Resources/WebLibraries/three/addons/lights/SunShadowNode.js +312 -0
  128. package/Resources/WebLibraries/three/addons/lines/Line2.js +56 -0
  129. package/Resources/WebLibraries/three/addons/lines/LineGeometry.js +157 -0
  130. package/Resources/WebLibraries/three/addons/lines/LineMaterial.js +742 -0
  131. package/Resources/WebLibraries/three/addons/lines/LineSegments2.js +434 -0
  132. package/Resources/WebLibraries/three/addons/lines/LineSegmentsGeometry.js +298 -0
  133. package/Resources/WebLibraries/three/addons/lines/Wireframe.js +108 -0
  134. package/Resources/WebLibraries/three/addons/lines/WireframeGeometry2.js +49 -0
  135. package/Resources/WebLibraries/three/addons/lines/webgpu/Line2.js +46 -0
  136. package/Resources/WebLibraries/three/addons/lines/webgpu/LineSegments2.js +419 -0
  137. package/Resources/WebLibraries/three/addons/lines/webgpu/Wireframe.js +86 -0
  138. package/Resources/WebLibraries/three/addons/loaders/EXRLoader.js +3411 -0
  139. package/Resources/WebLibraries/three/addons/loaders/FBXLoader.js +4660 -0
  140. package/Resources/WebLibraries/three/addons/loaders/FontLoader.js +262 -0
  141. package/Resources/WebLibraries/three/addons/loaders/GLTFLoader.js +5006 -0
  142. package/Resources/WebLibraries/three/addons/loaders/HDRLoader.js +463 -0
  143. package/Resources/WebLibraries/three/addons/loaders/MTLLoader.js +601 -0
  144. package/Resources/WebLibraries/three/addons/loaders/OBJLoader.js +961 -0
  145. package/Resources/WebLibraries/three/addons/loaders/PLYLoader.js +992 -0
  146. package/Resources/WebLibraries/three/addons/loaders/RGBELoader.js +18 -0
  147. package/Resources/WebLibraries/three/addons/loaders/STLLoader.js +423 -0
  148. package/Resources/WebLibraries/three/addons/loaders/SVGLoader.js +3297 -0
  149. package/Resources/WebLibraries/three/addons/loaders/TGALoader.js +539 -0
  150. package/Resources/WebLibraries/three/addons/loaders/UltraHDRLoader.js +757 -0
  151. package/Resources/WebLibraries/three/addons/math/Capsule.js +159 -0
  152. package/Resources/WebLibraries/three/addons/math/ColorConverter.js +62 -0
  153. package/Resources/WebLibraries/three/addons/math/ColorSpaces.js +147 -0
  154. package/Resources/WebLibraries/three/addons/math/ConvexHull.js +1695 -0
  155. package/Resources/WebLibraries/three/addons/math/ImprovedNoise.js +88 -0
  156. package/Resources/WebLibraries/three/addons/math/Lut.js +317 -0
  157. package/Resources/WebLibraries/three/addons/math/MeshSurfaceSampler.js +315 -0
  158. package/Resources/WebLibraries/three/addons/math/OBB.js +535 -0
  159. package/Resources/WebLibraries/three/addons/math/Octree.js +825 -0
  160. package/Resources/WebLibraries/three/addons/math/SimplexNoise.js +470 -0
  161. package/Resources/WebLibraries/three/addons/misc/ConvexObjectBreaker.js +539 -0
  162. package/Resources/WebLibraries/three/addons/misc/GPUComputationRenderer.js +508 -0
  163. package/Resources/WebLibraries/three/addons/misc/Gyroscope.js +78 -0
  164. package/Resources/WebLibraries/three/addons/misc/MorphAnimMesh.js +119 -0
  165. package/Resources/WebLibraries/three/addons/misc/MorphBlendMesh.js +425 -0
  166. package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMap.js +370 -0
  167. package/Resources/WebLibraries/three/addons/misc/ProgressiveLightMapGPU.js +322 -0
  168. package/Resources/WebLibraries/three/addons/misc/RollerCoaster.js +661 -0
  169. package/Resources/WebLibraries/three/addons/misc/Sculptor.js +1679 -0
  170. package/Resources/WebLibraries/three/addons/misc/SculptorMesh.js +1504 -0
  171. package/Resources/WebLibraries/three/addons/misc/SculptorTools.js +1180 -0
  172. package/Resources/WebLibraries/three/addons/misc/SculptorUtils.js +345 -0
  173. package/Resources/WebLibraries/three/addons/misc/TileCreasedNormalsPlugin.js +270 -0
  174. package/Resources/WebLibraries/three/addons/misc/TubePainter.js +611 -0
  175. package/Resources/WebLibraries/three/addons/misc/Volume.js +520 -0
  176. package/Resources/WebLibraries/three/addons/misc/VolumeSlice.js +275 -0
  177. package/Resources/WebLibraries/three/addons/modifiers/CurveModifier.js +374 -0
  178. package/Resources/WebLibraries/three/addons/modifiers/CurveModifierGPU.js +256 -0
  179. package/Resources/WebLibraries/three/addons/modifiers/EdgeSplitModifier.js +299 -0
  180. package/Resources/WebLibraries/three/addons/modifiers/TessellateModifier.js +340 -0
  181. package/Resources/WebLibraries/three/addons/objects/GroundedSkybox.js +69 -0
  182. package/Resources/WebLibraries/three/addons/objects/Lensflare.js +489 -0
  183. package/Resources/WebLibraries/three/addons/objects/LensflareMesh.js +376 -0
  184. package/Resources/WebLibraries/three/addons/objects/MarchingCubes.js +1261 -0
  185. package/Resources/WebLibraries/three/addons/objects/Reflector.js +390 -0
  186. package/Resources/WebLibraries/three/addons/objects/ReflectorForSSRPass.js +393 -0
  187. package/Resources/WebLibraries/three/addons/objects/Refractor.js +389 -0
  188. package/Resources/WebLibraries/three/addons/objects/ShadowMesh.js +130 -0
  189. package/Resources/WebLibraries/three/addons/objects/Sky.js +342 -0
  190. package/Resources/WebLibraries/three/addons/objects/SkyMesh.js +403 -0
  191. package/Resources/WebLibraries/three/addons/objects/Water.js +374 -0
  192. package/Resources/WebLibraries/three/addons/objects/Water2.js +403 -0
  193. package/Resources/WebLibraries/three/addons/objects/Water2Mesh.js +199 -0
  194. package/Resources/WebLibraries/three/addons/objects/WaterMesh.js +194 -0
  195. package/Resources/WebLibraries/three/addons/postprocessing/AfterimagePass.js +187 -0
  196. package/Resources/WebLibraries/three/addons/postprocessing/BloomPass.js +274 -0
  197. package/Resources/WebLibraries/three/addons/postprocessing/BokehPass.js +218 -0
  198. package/Resources/WebLibraries/three/addons/postprocessing/ClearPass.js +97 -0
  199. package/Resources/WebLibraries/three/addons/postprocessing/CubeTexturePass.js +146 -0
  200. package/Resources/WebLibraries/three/addons/postprocessing/DotScreenPass.js +114 -0
  201. package/Resources/WebLibraries/three/addons/postprocessing/EffectComposer.js +365 -0
  202. package/Resources/WebLibraries/three/addons/postprocessing/FXAAPass.js +40 -0
  203. package/Resources/WebLibraries/three/addons/postprocessing/FilmPass.js +113 -0
  204. package/Resources/WebLibraries/three/addons/postprocessing/GTAOPass.js +735 -0
  205. package/Resources/WebLibraries/three/addons/postprocessing/GlitchPass.js +177 -0
  206. package/Resources/WebLibraries/three/addons/postprocessing/HalftonePass.js +134 -0
  207. package/Resources/WebLibraries/three/addons/postprocessing/LUTPass.js +138 -0
  208. package/Resources/WebLibraries/three/addons/postprocessing/MaskPass.js +195 -0
  209. package/Resources/WebLibraries/three/addons/postprocessing/OutlinePass.js +776 -0
  210. package/Resources/WebLibraries/three/addons/postprocessing/OutputPass.js +148 -0
  211. package/Resources/WebLibraries/three/addons/postprocessing/Pass.js +191 -0
  212. package/Resources/WebLibraries/three/addons/postprocessing/RenderPass.js +193 -0
  213. package/Resources/WebLibraries/three/addons/postprocessing/RenderPixelatedPass.js +314 -0
  214. package/Resources/WebLibraries/three/addons/postprocessing/RenderTransitionPass.js +267 -0
  215. package/Resources/WebLibraries/three/addons/postprocessing/SAOPass.js +407 -0
  216. package/Resources/WebLibraries/three/addons/postprocessing/SMAAPass.js +230 -0
  217. package/Resources/WebLibraries/three/addons/postprocessing/SSAARenderPass.js +313 -0
  218. package/Resources/WebLibraries/three/addons/postprocessing/SSAOPass.js +527 -0
  219. package/Resources/WebLibraries/three/addons/postprocessing/SSRPass.js +858 -0
  220. package/Resources/WebLibraries/three/addons/postprocessing/SavePass.js +132 -0
  221. package/Resources/WebLibraries/three/addons/postprocessing/ShaderPass.js +135 -0
  222. package/Resources/WebLibraries/three/addons/postprocessing/TAARenderPass.js +243 -0
  223. package/Resources/WebLibraries/three/addons/postprocessing/TexturePass.js +131 -0
  224. package/Resources/WebLibraries/three/addons/postprocessing/UnrealBloomPass.js +541 -0
  225. package/Resources/WebLibraries/three/addons/shaders/ACESFilmicToneMappingShader.js +96 -0
  226. package/Resources/WebLibraries/three/addons/shaders/AfterimageShader.js +63 -0
  227. package/Resources/WebLibraries/three/addons/shaders/BasicShader.js +36 -0
  228. package/Resources/WebLibraries/three/addons/shaders/BleachBypassShader.js +68 -0
  229. package/Resources/WebLibraries/three/addons/shaders/BlendShader.js +56 -0
  230. package/Resources/WebLibraries/three/addons/shaders/BokehShader.js +151 -0
  231. package/Resources/WebLibraries/three/addons/shaders/BokehShader2.js +404 -0
  232. package/Resources/WebLibraries/three/addons/shaders/BrightnessContrastShader.js +62 -0
  233. package/Resources/WebLibraries/three/addons/shaders/ColorCorrectionShader.js +59 -0
  234. package/Resources/WebLibraries/three/addons/shaders/ColorifyShader.js +57 -0
  235. package/Resources/WebLibraries/three/addons/shaders/ConvolutionShader.js +74 -0
  236. package/Resources/WebLibraries/three/addons/shaders/CopyShader.js +52 -0
  237. package/Resources/WebLibraries/three/addons/shaders/DOFMipMapShader.js +63 -0
  238. package/Resources/WebLibraries/three/addons/shaders/DepthLimitedBlurShader.js +183 -0
  239. package/Resources/WebLibraries/three/addons/shaders/DigitalGlitch.js +104 -0
  240. package/Resources/WebLibraries/three/addons/shaders/DotScreenShader.js +75 -0
  241. package/Resources/WebLibraries/three/addons/shaders/ExposureShader.js +51 -0
  242. package/Resources/WebLibraries/three/addons/shaders/FXAAShader.js +298 -0
  243. package/Resources/WebLibraries/three/addons/shaders/FilmShader.js +73 -0
  244. package/Resources/WebLibraries/three/addons/shaders/FocusShader.js +94 -0
  245. package/Resources/WebLibraries/three/addons/shaders/FreiChenShader.js +103 -0
  246. package/Resources/WebLibraries/three/addons/shaders/GTAOShader.js +437 -0
  247. package/Resources/WebLibraries/three/addons/shaders/GammaCorrectionShader.js +52 -0
  248. package/Resources/WebLibraries/three/addons/shaders/HalftoneShader.js +332 -0
  249. package/Resources/WebLibraries/three/addons/shaders/HorizontalBlurShader.js +68 -0
  250. package/Resources/WebLibraries/three/addons/shaders/HorizontalTiltShiftShader.js +70 -0
  251. package/Resources/WebLibraries/three/addons/shaders/HueSaturationShader.js +74 -0
  252. package/Resources/WebLibraries/three/addons/shaders/KaleidoShader.js +65 -0
  253. package/Resources/WebLibraries/three/addons/shaders/LuminosityHighPassShader.js +68 -0
  254. package/Resources/WebLibraries/three/addons/shaders/LuminosityShader.js +54 -0
  255. package/Resources/WebLibraries/three/addons/shaders/MirrorShader.js +62 -0
  256. package/Resources/WebLibraries/three/addons/shaders/NormalMapShader.js +60 -0
  257. package/Resources/WebLibraries/three/addons/shaders/OutputShader.js +103 -0
  258. package/Resources/WebLibraries/three/addons/shaders/PoissonDenoiseShader.js +230 -0
  259. package/Resources/WebLibraries/three/addons/shaders/RGBShiftShader.js +61 -0
  260. package/Resources/WebLibraries/three/addons/shaders/SAOShader.js +201 -0
  261. package/Resources/WebLibraries/three/addons/shaders/SMAAShader.js +489 -0
  262. package/Resources/WebLibraries/three/addons/shaders/SSAOShader.js +331 -0
  263. package/Resources/WebLibraries/three/addons/shaders/SSRShader.js +396 -0
  264. package/Resources/WebLibraries/three/addons/shaders/SepiaShader.js +57 -0
  265. package/Resources/WebLibraries/three/addons/shaders/SobelOperatorShader.js +98 -0
  266. package/Resources/WebLibraries/three/addons/shaders/SubsurfaceScatteringShader.js +95 -0
  267. package/Resources/WebLibraries/three/addons/shaders/TechnicolorShader.js +51 -0
  268. package/Resources/WebLibraries/three/addons/shaders/ToonShader.js +349 -0
  269. package/Resources/WebLibraries/three/addons/shaders/TriangleBlurShader.js +79 -0
  270. package/Resources/WebLibraries/three/addons/shaders/UnpackDepthRGBAShader.js +60 -0
  271. package/Resources/WebLibraries/three/addons/shaders/VelocityShader.js +137 -0
  272. package/Resources/WebLibraries/three/addons/shaders/VerticalBlurShader.js +66 -0
  273. package/Resources/WebLibraries/three/addons/shaders/VerticalTiltShiftShader.js +70 -0
  274. package/Resources/WebLibraries/three/addons/shaders/VignetteShader.js +56 -0
  275. package/Resources/WebLibraries/three/addons/shaders/VolumeShader.js +285 -0
  276. package/Resources/WebLibraries/three/addons/shaders/WaterRefractionShader.js +106 -0
  277. package/Resources/WebLibraries/three/addons/textures/FlakesTexture.js +54 -0
  278. package/Resources/WebLibraries/three/addons/tsl/WebGLNodesHandler.js +607 -0
  279. package/Resources/WebLibraries/three/addons/tsl/display/AfterImageNode.js +256 -0
  280. package/Resources/WebLibraries/three/addons/tsl/display/AnaglyphPassNode.js +550 -0
  281. package/Resources/WebLibraries/three/addons/tsl/display/BilateralBlurNode.js +377 -0
  282. package/Resources/WebLibraries/three/addons/tsl/display/BleachBypass.js +33 -0
  283. package/Resources/WebLibraries/three/addons/tsl/display/BloomNode.js +599 -0
  284. package/Resources/WebLibraries/three/addons/tsl/display/CRT.js +150 -0
  285. package/Resources/WebLibraries/three/addons/tsl/display/ChromaticAberrationNode.js +163 -0
  286. package/Resources/WebLibraries/three/addons/tsl/display/DenoiseNode.js +354 -0
  287. package/Resources/WebLibraries/three/addons/tsl/display/DepthOfFieldNode.js +572 -0
  288. package/Resources/WebLibraries/three/addons/tsl/display/DotScreenNode.js +104 -0
  289. package/Resources/WebLibraries/three/addons/tsl/display/FSR1Node.js +481 -0
  290. package/Resources/WebLibraries/three/addons/tsl/display/FXAANode.js +357 -0
  291. package/Resources/WebLibraries/three/addons/tsl/display/FilmNode.js +101 -0
  292. package/Resources/WebLibraries/three/addons/tsl/display/GTAONode.js +727 -0
  293. package/Resources/WebLibraries/three/addons/tsl/display/GaussianBlurNode.js +412 -0
  294. package/Resources/WebLibraries/three/addons/tsl/display/GodraysNode.js +604 -0
  295. package/Resources/WebLibraries/three/addons/tsl/display/ImportanceSampledEnvironment.js +564 -0
  296. package/Resources/WebLibraries/three/addons/tsl/display/LensflareNode.js +282 -0
  297. package/Resources/WebLibraries/three/addons/tsl/display/Lut3DNode.js +109 -0
  298. package/Resources/WebLibraries/three/addons/tsl/display/MotionBlur.js +33 -0
  299. package/Resources/WebLibraries/three/addons/tsl/display/OITPassNode.js +341 -0
  300. package/Resources/WebLibraries/three/addons/tsl/display/OutlineNode.js +916 -0
  301. package/Resources/WebLibraries/three/addons/tsl/display/ParallaxBarrierPassNode.js +90 -0
  302. package/Resources/WebLibraries/three/addons/tsl/display/PixelationPassNode.js +227 -0
  303. package/Resources/WebLibraries/three/addons/tsl/display/RGBShiftNode.js +96 -0
  304. package/Resources/WebLibraries/three/addons/tsl/display/RecurrentDenoiseNode.js +812 -0
  305. package/Resources/WebLibraries/three/addons/tsl/display/RetroPassNode.js +263 -0
  306. package/Resources/WebLibraries/three/addons/tsl/display/SMAANode.js +729 -0
  307. package/Resources/WebLibraries/three/addons/tsl/display/SSAAPassNode.js +344 -0
  308. package/Resources/WebLibraries/three/addons/tsl/display/SSAONode.js +422 -0
  309. package/Resources/WebLibraries/three/addons/tsl/display/SSGINode.js +698 -0
  310. package/Resources/WebLibraries/three/addons/tsl/display/SSRNode.js +1430 -0
  311. package/Resources/WebLibraries/three/addons/tsl/display/SSSNode.js +479 -0
  312. package/Resources/WebLibraries/three/addons/tsl/display/Sepia.js +24 -0
  313. package/Resources/WebLibraries/three/addons/tsl/display/Shape.js +29 -0
  314. package/Resources/WebLibraries/three/addons/tsl/display/SharpenNode.js +284 -0
  315. package/Resources/WebLibraries/three/addons/tsl/display/SobelOperatorNode.js +168 -0
  316. package/Resources/WebLibraries/three/addons/tsl/display/StereoCompositePassNode.js +190 -0
  317. package/Resources/WebLibraries/three/addons/tsl/display/StereoPassNode.js +117 -0
  318. package/Resources/WebLibraries/three/addons/tsl/display/TAAUNode.js +700 -0
  319. package/Resources/WebLibraries/three/addons/tsl/display/TRAANode.js +609 -0
  320. package/Resources/WebLibraries/three/addons/tsl/display/TemporalReprojectNode.js +1024 -0
  321. package/Resources/WebLibraries/three/addons/tsl/display/TransitionNode.js +141 -0
  322. package/Resources/WebLibraries/three/addons/tsl/display/boxBlur.js +65 -0
  323. package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlend.js +80 -0
  324. package/Resources/WebLibraries/three/addons/tsl/display/depthAwareBlur.js +63 -0
  325. package/Resources/WebLibraries/three/addons/tsl/display/hashBlur.js +55 -0
  326. package/Resources/WebLibraries/three/addons/tsl/display/lensDirt.js +30 -0
  327. package/Resources/WebLibraries/three/addons/tsl/display/radialBlur.js +68 -0
  328. package/Resources/WebLibraries/three/addons/tsl/lighting/ClusteredLightsNode.js +994 -0
  329. package/Resources/WebLibraries/three/addons/tsl/lighting/DynamicLightsNode.js +201 -0
  330. package/Resources/WebLibraries/three/addons/tsl/lighting/LightProbeGridNode.js +183 -0
  331. package/Resources/WebLibraries/three/addons/tsl/lighting/data/AmbientLightDataNode.js +67 -0
  332. package/Resources/WebLibraries/three/addons/tsl/lighting/data/DirectionalLightDataNode.js +117 -0
  333. package/Resources/WebLibraries/three/addons/tsl/lighting/data/HemisphereLightDataNode.js +105 -0
  334. package/Resources/WebLibraries/three/addons/tsl/lighting/data/PointLightDataNode.js +140 -0
  335. package/Resources/WebLibraries/three/addons/tsl/lighting/data/SpotLightDataNode.js +167 -0
  336. package/Resources/WebLibraries/three/addons/tsl/math/Bayer.js +84 -0
  337. package/Resources/WebLibraries/three/addons/tsl/math/curlNoise.js +107 -0
  338. package/Resources/WebLibraries/three/addons/tsl/math/voronoiNoise.js +112 -0
  339. package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNode.js +542 -0
  340. package/Resources/WebLibraries/three/addons/tsl/shadows/TileShadowNodeHelper.js +212 -0
  341. package/Resources/WebLibraries/three/addons/tsl/utils/GroundedSkybox.js +62 -0
  342. package/Resources/WebLibraries/three/addons/tsl/utils/RNoise.js +51 -0
  343. package/Resources/WebLibraries/three/addons/tsl/utils/Raymarching.js +70 -0
  344. package/Resources/WebLibraries/three/addons/tsl/utils/SoftParticles.js +53 -0
  345. package/Resources/WebLibraries/three/addons/tsl/utils/SpecularHelpers.js +302 -0
  346. package/Resources/WebLibraries/three/addons/tsl/utils/TAAUtils.js +184 -0
  347. package/Resources/WebLibraries/three/addons/utils/BufferGeometryUtils.js +1523 -0
  348. package/Resources/WebLibraries/three/addons/utils/CameraUtils.js +82 -0
  349. package/Resources/WebLibraries/three/addons/utils/ColorUtils.js +76 -0
  350. package/Resources/WebLibraries/three/addons/utils/GaussianSplatUtils.js +229 -0
  351. package/Resources/WebLibraries/three/addons/utils/GeometryCompressionUtils.js +547 -0
  352. package/Resources/WebLibraries/three/addons/utils/GeometryUtils.js +226 -0
  353. package/Resources/WebLibraries/three/addons/utils/LDrawUtils.js +211 -0
  354. package/Resources/WebLibraries/three/addons/utils/SceneOptimizer.js +459 -0
  355. package/Resources/WebLibraries/three/addons/utils/SceneUtils.js +363 -0
  356. package/Resources/WebLibraries/three/addons/utils/ShadowMapViewer.js +244 -0
  357. package/Resources/WebLibraries/three/addons/utils/ShadowMapViewerGPU.js +233 -0
  358. package/Resources/WebLibraries/three/addons/utils/SkeletonUtils.js +496 -0
  359. package/Resources/WebLibraries/three/addons/utils/SortUtils.js +175 -0
  360. package/Resources/WebLibraries/three/addons/utils/UVsDebug.js +173 -0
  361. package/Resources/WebLibraries/three/addons/utils/WebGLTextureUtils.js +115 -0
  362. package/Resources/WebLibraries/three/addons/utils/WebGPUTextureUtils.js +81 -0
  363. package/Resources/WebLibraries/three/addons/utils/WorkerPool.js +167 -0
  364. package/Resources/WebLibraries/three/addons/utils/unwrapUVs.js +865 -0
  365. package/Resources/WebLibraries/three/three.core.js +61162 -0
  366. package/Resources/WebLibraries/three/three.module.js +19537 -0
  367. package/Resources/WebLibraries/three/three.tsl.js +41903 -0
  368. package/Resources/WebLibraries/three/three.webgpu.js +53714 -0
  369. package/Resources/skills/2d-game/SKILL.md +305 -0
  370. package/Resources/skills/3d-game/SKILL.md +274 -0
  371. package/Resources/skills/accounts/SKILL.md +41 -0
  372. package/Resources/skills/android-design/SKILL.md +159 -0
  373. package/Resources/skills/app-ai/SKILL.md +154 -0
  374. package/Resources/skills/app-intents/SKILL.md +31 -0
  375. package/Resources/skills/app-kinds/SKILL.md +122 -0
  376. package/Resources/skills/apple-watch/SKILL.md +43 -0
  377. package/Resources/skills/assets/SKILL.md +183 -0
  378. package/Resources/skills/building-blocks/SKILL.md +97 -0
  379. package/Resources/skills/device-control/SKILL.md +56 -0
  380. package/Resources/skills/device-integrations/SKILL.md +278 -0
  381. package/Resources/skills/finder-files/SKILL.md +19 -0
  382. package/Resources/skills/game/SKILL.md +414 -0
  383. package/Resources/skills/game-3d/SKILL.md +12 -0
  384. package/Resources/skills/game-art/SKILL.md +11 -0
  385. package/Resources/skills/game-feel/SKILL.md +13 -0
  386. package/Resources/skills/game-levels/SKILL.md +12 -0
  387. package/Resources/skills/game-live/SKILL.md +12 -0
  388. package/Resources/skills/game-physics/SKILL.md +13 -0
  389. package/Resources/skills/game-playtest/SKILL.md +26 -0
  390. package/Resources/skills/game-ui/SKILL.md +278 -0
  391. package/Resources/skills/github-projects/SKILL.md +59 -0
  392. package/Resources/skills/icloud-sync/SKILL.md +30 -0
  393. package/Resources/skills/iphone-hardware/SKILL.md +57 -0
  394. package/Resources/skills/iphone-widgets/SKILL.md +53 -0
  395. package/Resources/skills/lg-developer-mode/SKILL.md +152 -0
  396. package/Resources/skills/mac-widgets/SKILL.md +60 -0
  397. package/Resources/skills/maps/SKILL.md +8 -0
  398. package/Resources/skills/menu-bar/SKILL.md +36 -0
  399. package/Resources/skills/more-apps/SKILL.md +53 -0
  400. package/Resources/skills/phone-controllers/SKILL.md +79 -0
  401. package/Resources/skills/phone-pages/SKILL.md +173 -0
  402. package/Resources/skills/roku-developer-mode/SKILL.md +106 -0
  403. package/Resources/skills/scene-3d/SKILL.md +27 -0
  404. package/Resources/skills/scripting/SKILL.md +17 -0
  405. package/Resources/skills/share-extension/SKILL.md +22 -0
  406. package/Resources/skills/tv-design/SKILL.md +72 -0
  407. package/Resources/skills/web-app/SKILL.md +136 -0
  408. package/Resources/skills/web-game/SKILL.md +95 -0
  409. package/Resources/skills/web-or-native/SKILL.md +103 -0
  410. package/Resources/skills/wish-links/SKILL.md +156 -0
  411. package/THIRD_PARTY_NOTICES.md +170 -0
  412. package/cli/android.mjs +941 -0
  413. package/cli/browser.mjs +268 -0
  414. package/cli/calls.mjs +390 -0
  415. package/cli/dev.mjs +773 -0
  416. package/cli/devices.mjs +984 -0
  417. package/cli/lamp.mjs +1016 -0
  418. package/cli/lampapp.mjs +332 -0
  419. package/cli/lamps/android-host/LampPageGateway.kt +345 -0
  420. package/cli/lamps/android-host/app/build.gradle.kts +40 -0
  421. package/cli/lamps/android-host/build.gradle.kts +4 -0
  422. package/cli/lamps/android-host/game/AndroidManifest.xml +33 -0
  423. package/cli/lamps/android-host/game/MainActivity.kt +173 -0
  424. package/cli/lamps/android-host/gradle/libs.versions.toml +39 -0
  425. package/cli/lamps/android-host/gradle.properties +8 -0
  426. package/cli/lamps/android-host/page/AndroidManifest.xml +35 -0
  427. package/cli/lamps/android-host/page/MainActivity.kt +193 -0
  428. package/cli/lamps/android-host/settings.gradle.kts +30 -0
  429. package/cli/lamps/android-host/tools.json +43 -0
  430. package/cli/lamps/lamp-controllers.js +2 -0
  431. package/cli/lamps/lamp-for-games.js +6863 -0
  432. package/cli/lamps/lamp.js +7023 -0
  433. package/cli/lamps/mac-starter/.lamp/meta.json +1 -0
  434. package/cli/lamps/mac-starter/APP.md +12 -0
  435. package/cli/lamps/mac-starter/Package.swift +8 -0
  436. package/cli/lamps/mac-starter/Sources/App.swift +11 -0
  437. package/cli/lamps/mac-starter/Sources/ContentView.swift +17 -0
  438. package/cli/lamps/mac-starter/Sources/LampSupport.swift +18097 -0
  439. package/cli/lamps/mac-starter/build.sh +336 -0
  440. package/cli/lamps/mac-starter/gitignore +3 -0
  441. package/cli/lamps/mac-starter/lamp-starter.json +6 -0
  442. package/cli/lamps/web-starter/APP.md +8 -0
  443. package/cli/lamps/web-starter/app.js +1 -0
  444. package/cli/lamps/web-starter/index.html +17 -0
  445. package/cli/lamps/web-starter/lamp-starter.json +5 -0
  446. package/cli/lamps/web-starter/lamp.js +7023 -0
  447. package/cli/lamps/web-starter/style.css +25 -0
  448. package/cli/link.mjs +138 -0
  449. package/cli/mac.mjs +621 -0
  450. package/cli/mdns.mjs +205 -0
  451. package/cli/msix.mjs +413 -0
  452. package/cli/network.mjs +209 -0
  453. package/cli/outside.mjs +140 -0
  454. package/cli/page.js +165 -0
  455. package/cli/place.mjs +298 -0
  456. package/cli/png.mjs +184 -0
  457. package/cli/share.mjs +202 -0
  458. package/cli/skill/SKILL.md +255 -0
  459. package/cli/skills.mjs +71 -0
  460. package/cli/state.mjs +173 -0
  461. package/cli/update.mjs +57 -0
  462. package/package.json +20 -4
  463. package/site/lib/quota.js +59 -0
  464. package/site/lib/shared-wishes.js +996 -0
@@ -0,0 +1,3543 @@
1
+ import {
2
+ Controls,
3
+ GridHelper,
4
+ EllipseCurve,
5
+ BufferGeometry,
6
+ Line,
7
+ LineBasicMaterial,
8
+ Raycaster,
9
+ Group,
10
+ Box3,
11
+ Sphere,
12
+ Quaternion,
13
+ Vector2,
14
+ Vector3,
15
+ Matrix4,
16
+ MathUtils
17
+ } from 'three';
18
+
19
+ //trackball state
20
+ const STATE = {
21
+
22
+ IDLE: Symbol(),
23
+ ROTATE: Symbol(),
24
+ PAN: Symbol(),
25
+ SCALE: Symbol(),
26
+ FOV: Symbol(),
27
+ FOCUS: Symbol(),
28
+ ZROTATE: Symbol(),
29
+ TOUCH_MULTI: Symbol(),
30
+ ANIMATION_FOCUS: Symbol(),
31
+ ANIMATION_ROTATE: Symbol()
32
+
33
+ };
34
+
35
+ const INPUT = {
36
+
37
+ NONE: Symbol(),
38
+ ONE_FINGER: Symbol(),
39
+ ONE_FINGER_SWITCHED: Symbol(),
40
+ TWO_FINGER: Symbol(),
41
+ MULT_FINGER: Symbol(),
42
+ CURSOR: Symbol()
43
+
44
+ };
45
+
46
+ //cursor center coordinates
47
+ const _center = {
48
+
49
+ x: 0,
50
+ y: 0
51
+
52
+ };
53
+
54
+ //transformation matrices for gizmos and camera
55
+ const _transformation = {
56
+
57
+ camera: new Matrix4(),
58
+ gizmos: new Matrix4()
59
+
60
+ };
61
+
62
+ /**
63
+ * Fires when the camera has been transformed by the controls.
64
+ *
65
+ * @event ArcballControls#change
66
+ * @type {Object}
67
+ */
68
+ const _changeEvent = { type: 'change' };
69
+
70
+ /**
71
+ * Fires when an interaction was initiated.
72
+ *
73
+ * @event ArcballControls#start
74
+ * @type {Object}
75
+ */
76
+ const _startEvent = { type: 'start' };
77
+
78
+ /**
79
+ * Fires when an interaction has finished.
80
+ *
81
+ * @event ArcballControls#end
82
+ * @type {Object}
83
+ */
84
+ const _endEvent = { type: 'end' };
85
+
86
+ const _raycaster = new Raycaster();
87
+ const _offset = new Vector3();
88
+
89
+ const _gizmoMatrixStateTemp = new Matrix4();
90
+ const _cameraMatrixStateTemp = new Matrix4();
91
+ const _scalePointTemp = new Vector3();
92
+
93
+ const _EPS = 0.000001;
94
+
95
+ /**
96
+ * Arcball controls allow the camera to be controlled by a virtual trackball with full touch support and advanced navigation functionality.
97
+ * Cursor/finger positions and movements are mapped over a virtual trackball surface represented by a gizmo and mapped in intuitive and
98
+ * consistent camera movements. Dragging cursor/fingers will cause camera to orbit around the center of the trackball in a conservative
99
+ * way (returning to the starting point will make the camera return to its starting orientation).
100
+ *
101
+ * In addition to supporting pan, zoom and pinch gestures, double clicking/tapping focuses on a point, intuitively moving the object's
102
+ * point of interest to the center of the virtual trackball. Focus allows a much better inspection and navigation in complex environment.
103
+ * Moreover Arcball controls allow FOV manipulation (in a vertigo-style method) and z-rotation. Saving and restoring of Camera State
104
+ * is supported also through clipboard (use ctrl+c and ctrl+v shortcuts for copy and paste the state).
105
+ *
106
+ * Unlike {@link OrbitControls} and {@link TrackballControls}, `ArcballControls` doesn't require `update()` to be called externally in an
107
+ * animation loop when animations are on.
108
+ *
109
+ * @augments Controls
110
+ * @three_import import { ArcballControls } from 'three/addons/controls/ArcballControls.js';
111
+ */
112
+ class ArcballControls extends Controls {
113
+
114
+ /**
115
+ * Constructs a new controls instance.
116
+ *
117
+ * @param {Camera} camera - The camera to be controlled. The camera must not be a child of another object, unless that object is the scene itself.
118
+ * @param {?HTMLElement} [domElement=null] - The HTML element used for event listeners.
119
+ * @param {?Scene} [scene=null] The scene rendered by the camera. If not given, gizmos cannot be shown.
120
+ */
121
+ constructor( camera, domElement = null, scene = null ) {
122
+
123
+ super( camera, domElement );
124
+
125
+ /**
126
+ * The scene rendered by the camera. If not given, gizmos cannot be shown.
127
+ *
128
+ * @type {?Scene}
129
+ * @default null
130
+ */
131
+ this.scene = scene;
132
+
133
+ /**
134
+ * The control's focus point.
135
+ *
136
+ * @type {Vector3}
137
+ */
138
+ this.target = new Vector3();
139
+ this._currentTarget = new Vector3();
140
+
141
+ /**
142
+ * The size of the gizmo relative to the screen width and height.
143
+ *
144
+ * @type {number}
145
+ * @default 0.67
146
+ */
147
+ this.radiusFactor = 0.67;
148
+
149
+ /**
150
+ * Holds the mouse actions of this controls. This property is maintained by the methods
151
+ * `setMouseAction()` and `unsetMouseAction()`.
152
+ *
153
+ * @type {Array<Object>}
154
+ */
155
+ this.mouseActions = [];
156
+ this._mouseOp = null;
157
+
158
+
159
+ //global vectors and matrices that are used in some operations to avoid creating new objects every time (e.g. every time cursor moves)
160
+ this._v2_1 = new Vector2();
161
+ this._v3_1 = new Vector3();
162
+ this._v3_2 = new Vector3();
163
+
164
+ this._m4_1 = new Matrix4();
165
+ this._m4_2 = new Matrix4();
166
+
167
+ this._quat = new Quaternion();
168
+
169
+ //transformation matrices
170
+ this._translationMatrix = new Matrix4(); //matrix for translation operation
171
+ this._rotationMatrix = new Matrix4(); //matrix for rotation operation
172
+ this._scaleMatrix = new Matrix4(); //matrix for scaling operation
173
+
174
+ this._rotationAxis = new Vector3(); //axis for rotate operation
175
+
176
+
177
+ //camera state
178
+ this._cameraMatrixState = new Matrix4();
179
+ this._cameraProjectionState = new Matrix4();
180
+
181
+ this._fovState = 1;
182
+ this._upState = new Vector3();
183
+ this._zoomState = 1;
184
+ this._nearPos = 0;
185
+ this._farPos = 0;
186
+
187
+ this._gizmoMatrixState = new Matrix4();
188
+
189
+ //initial values
190
+ this._up0 = new Vector3();
191
+ this._zoom0 = 1;
192
+ this._fov0 = 0;
193
+ this._initialNear = 0;
194
+ this._nearPos0 = 0;
195
+ this._initialFar = 0;
196
+ this._farPos0 = 0;
197
+ this._cameraMatrixState0 = new Matrix4();
198
+ this._gizmoMatrixState0 = new Matrix4();
199
+ this._target0 = new Vector3();
200
+
201
+ //pointers array
202
+ this._button = - 1;
203
+ this._touchStart = [];
204
+ this._touchCurrent = [];
205
+ this._input = INPUT.NONE;
206
+
207
+ //two fingers touch interaction
208
+ this._switchSensibility = 32; //minimum movement to be performed to fire single pan start after the second finger has been released
209
+ this._startFingerDistance = 0; //distance between two fingers
210
+ this._currentFingerDistance = 0;
211
+ this._startFingerRotation = 0; //amount of rotation performed with two fingers
212
+ this._currentFingerRotation = 0;
213
+
214
+ //double tap
215
+ this._devPxRatio = 0;
216
+ this._downValid = true;
217
+ this._nclicks = 0;
218
+ this._downEvents = [];
219
+ this._downStart = 0; //pointerDown time
220
+ this._clickStart = 0; //first click time
221
+ this._maxDownTime = 250;
222
+ this._maxInterval = 300;
223
+ this._posThreshold = 24;
224
+ this._movementThreshold = 24;
225
+
226
+ //cursor positions
227
+ this._currentCursorPosition = new Vector3();
228
+ this._startCursorPosition = new Vector3();
229
+
230
+ //grid
231
+ this._grid = null; //grid to be visualized during pan operation
232
+ this._gridPosition = new Vector3();
233
+
234
+ //gizmos
235
+ this._gizmos = new Group();
236
+ this._curvePts = 128;
237
+
238
+
239
+ //animations
240
+ this._timeStart = - 1; //initial time
241
+ this._animationId = - 1;
242
+
243
+ /**
244
+ * Duration of focus animations in ms.
245
+ *
246
+ * @type {number}
247
+ * @default 500
248
+ */
249
+ this.focusAnimationTime = 500;
250
+
251
+ //rotate animation
252
+ this._timePrev = 0; //time at which previous rotate operation has been detected
253
+ this._timeCurrent = 0; //time at which current rotate operation has been detected
254
+ this._anglePrev = 0; //angle of previous rotation
255
+ this._angleCurrent = 0; //angle of current rotation
256
+ this._cursorPosPrev = new Vector3(); //cursor position when previous rotate operation has been detected
257
+ this._cursorPosCurr = new Vector3();//cursor position when current rotate operation has been detected
258
+ this._wPrev = 0; //angular velocity of the previous rotate operation
259
+ this._wCurr = 0; //angular velocity of the current rotate operation
260
+
261
+ //parameters
262
+
263
+ /**
264
+ * If set to `true`, the camera's near and far values will be adjusted every time zoom is
265
+ * performed trying to maintain the same visible portion given by initial near and far
266
+ * values. Only works with perspective cameras.
267
+ *
268
+ * This feature only works as expected if the camera's initial state (position, near and far values)
269
+ * is correctly configured before creating the controls. Otherwise {@link ArcballControls#setCamera}
270
+ * must be called by the application.
271
+ *
272
+ * @type {boolean}
273
+ * @default false
274
+ */
275
+ this.adjustNearFar = false;
276
+
277
+ /**
278
+ * The scaling factor used when performing zoom operation.
279
+ *
280
+ * @type {number}
281
+ * @default 1.1
282
+ */
283
+ this.scaleFactor = 1.1;
284
+
285
+ /**
286
+ * The damping inertia used if 'enableAnimations` is set to `true`.
287
+ *
288
+ * @type {number}
289
+ * @default 25
290
+ */
291
+ this.dampingFactor = 25;
292
+
293
+ /**
294
+ * Maximum angular velocity allowed on rotation animation start.
295
+ *
296
+ * @type {number}
297
+ * @default 20
298
+ */
299
+ this.wMax = 20;
300
+
301
+ /**
302
+ * Set to `true` to enable animations for rotation (damping) and focus operation.
303
+ *
304
+ * @type {boolean}
305
+ * @default true
306
+ */
307
+ this.enableAnimations = true;
308
+
309
+ /**
310
+ * If set to `true`, a grid will appear when panning operation is being performed
311
+ * (desktop interaction only).
312
+ *
313
+ * @type {boolean}
314
+ * @default false
315
+ */
316
+ this.enableGrid = false;
317
+
318
+ /**
319
+ * Set to `true` to make zoom become cursor centered.
320
+ *
321
+ * @type {boolean}
322
+ * @default false
323
+ */
324
+ this.cursorZoom = false;
325
+
326
+ /**
327
+ * The minimum FOV in degrees.
328
+ *
329
+ * @type {number}
330
+ * @default 5
331
+ */
332
+ this.minFov = 5;
333
+
334
+ /**
335
+ * The maximum FOV in degrees.
336
+ *
337
+ * @type {number}
338
+ * @default 90
339
+ */
340
+ this.maxFov = 90;
341
+
342
+ /**
343
+ * Speed of rotation.
344
+ *
345
+ * @type {number}
346
+ * @default 1
347
+ */
348
+ this.rotateSpeed = 1;
349
+
350
+ /**
351
+ * Enable or disable camera panning.
352
+ *
353
+ * @type {boolean}
354
+ * @default true
355
+ */
356
+ this.enablePan = true;
357
+
358
+ /**
359
+ * Enable or disable camera rotation.
360
+ *
361
+ * @type {boolean}
362
+ * @default true
363
+ */
364
+ this.enableRotate = true;
365
+
366
+ /**
367
+ * Enable or disable camera zoom.
368
+ *
369
+ * @type {boolean}
370
+ * @default true
371
+ */
372
+ this.enableZoom = true;
373
+
374
+ /**
375
+ * Enable or disable gizmos.
376
+ *
377
+ * @type {boolean}
378
+ * @default true
379
+ */
380
+ this.enableGizmos = true;
381
+
382
+ /**
383
+ * Enable or disable camera focusing on double-tap (or click) operations.
384
+ *
385
+ * @type {boolean}
386
+ * @default true
387
+ */
388
+ this.enableFocus = true;
389
+
390
+ /**
391
+ * How far you can dolly in. For perspective cameras only.
392
+ *
393
+ * @type {number}
394
+ * @default 0
395
+ */
396
+ this.minDistance = 0;
397
+
398
+ /**
399
+ * How far you can dolly out. For perspective cameras only.
400
+ *
401
+ * @type {number}
402
+ * @default Infinity
403
+ */
404
+ this.maxDistance = Infinity;
405
+
406
+ /**
407
+ * How far you can zoom in. For orthographic cameras only.
408
+ *
409
+ * @type {number}
410
+ * @default 0
411
+ */
412
+ this.minZoom = 0;
413
+
414
+ /**
415
+ * How far you can zoom out. For orthographic cameras only.
416
+ *
417
+ * @type {number}
418
+ * @default Infinity
419
+ */
420
+ this.maxZoom = Infinity;
421
+
422
+ //trackball parameters
423
+ this._tbRadius = 1;
424
+
425
+ //FSA
426
+ this._state = STATE.IDLE;
427
+
428
+ this.setCamera( camera );
429
+
430
+ if ( this.scene != null ) {
431
+
432
+ this.scene.add( this._gizmos );
433
+
434
+ }
435
+
436
+ this.initializeMouseActions();
437
+
438
+ // event listeners
439
+
440
+ this._onContextMenu = onContextMenu.bind( this );
441
+ this._onWheel = onWheel.bind( this );
442
+ this._onPointerUp = onPointerUp.bind( this );
443
+ this._onPointerMove = onPointerMove.bind( this );
444
+ this._onPointerDown = onPointerDown.bind( this );
445
+ this._onPointerCancel = onPointerCancel.bind( this );
446
+ this._onWindowResize = onWindowResize.bind( this );
447
+
448
+ if ( domElement !== null ) {
449
+
450
+ this.connect( domElement );
451
+
452
+ }
453
+
454
+ }
455
+
456
+ connect( element ) {
457
+
458
+ super.connect( element );
459
+
460
+ this._devPxRatio = window.devicePixelRatio;
461
+
462
+ this.domElement.addEventListener( 'contextmenu', this._onContextMenu );
463
+ this.domElement.addEventListener( 'wheel', this._onWheel, { passive: false } );
464
+ this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
465
+ this.domElement.addEventListener( 'pointercancel', this._onPointerCancel );
466
+
467
+ window.addEventListener( 'resize', this._onWindowResize );
468
+
469
+ this.domElement.style.touchAction = 'none'; // Disable touch scroll
470
+
471
+ }
472
+
473
+ disconnect() {
474
+
475
+ this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
476
+ this.domElement.removeEventListener( 'pointercancel', this._onPointerCancel );
477
+ this.domElement.removeEventListener( 'wheel', this._onWheel );
478
+ this.domElement.removeEventListener( 'contextmenu', this._onContextMenu );
479
+
480
+ window.removeEventListener( 'pointermove', this._onPointerMove );
481
+ window.removeEventListener( 'pointerup', this._onPointerUp );
482
+
483
+ window.removeEventListener( 'resize', this._onWindowResize );
484
+
485
+ this.domElement.style.touchAction = ''; // Restore touch scroll
486
+
487
+ }
488
+
489
+ onSinglePanStart( event, operation ) {
490
+
491
+ if ( this.enabled ) {
492
+
493
+ this.dispatchEvent( _startEvent );
494
+
495
+ this.setCenter( event.clientX, event.clientY );
496
+
497
+ switch ( operation ) {
498
+
499
+ case 'PAN':
500
+
501
+ if ( ! this.enablePan ) {
502
+
503
+ return;
504
+
505
+ }
506
+
507
+ if ( this._animationId != - 1 ) {
508
+
509
+ cancelAnimationFrame( this._animationId );
510
+ this._animationId = - 1;
511
+ this._timeStart = - 1;
512
+
513
+ this.activateGizmos( false );
514
+ this.dispatchEvent( _changeEvent );
515
+
516
+ }
517
+
518
+ this.updateTbState( STATE.PAN, true );
519
+ this._startCursorPosition.copy( this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement ) );
520
+ if ( this.enableGrid ) {
521
+
522
+ this.drawGrid();
523
+ this.dispatchEvent( _changeEvent );
524
+
525
+ }
526
+
527
+ break;
528
+
529
+ case 'ROTATE':
530
+
531
+ if ( ! this.enableRotate ) {
532
+
533
+ return;
534
+
535
+ }
536
+
537
+ if ( this._animationId != - 1 ) {
538
+
539
+ cancelAnimationFrame( this._animationId );
540
+ this._animationId = - 1;
541
+ this._timeStart = - 1;
542
+
543
+ }
544
+
545
+ this.updateTbState( STATE.ROTATE, true );
546
+ this._startCursorPosition.copy( this.unprojectOnTbSurface( this.object, _center.x, _center.y, this.domElement, this._tbRadius ) );
547
+ this.activateGizmos( true );
548
+ if ( this.enableAnimations ) {
549
+
550
+ this._timePrev = this._timeCurrent = performance.now();
551
+ this._angleCurrent = this._anglePrev = 0;
552
+ this._cursorPosPrev.copy( this._startCursorPosition );
553
+ this._cursorPosCurr.copy( this._cursorPosPrev );
554
+ this._wCurr = 0;
555
+ this._wPrev = this._wCurr;
556
+
557
+ }
558
+
559
+ this.dispatchEvent( _changeEvent );
560
+ break;
561
+
562
+ case 'FOV':
563
+
564
+ if ( ! this.object.isPerspectiveCamera || ! this.enableZoom ) {
565
+
566
+ return;
567
+
568
+ }
569
+
570
+ if ( this._animationId != - 1 ) {
571
+
572
+ cancelAnimationFrame( this._animationId );
573
+ this._animationId = - 1;
574
+ this._timeStart = - 1;
575
+
576
+ this.activateGizmos( false );
577
+ this.dispatchEvent( _changeEvent );
578
+
579
+ }
580
+
581
+ this.updateTbState( STATE.FOV, true );
582
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
583
+ this._currentCursorPosition.copy( this._startCursorPosition );
584
+ break;
585
+
586
+ case 'ZOOM':
587
+
588
+ if ( ! this.enableZoom ) {
589
+
590
+ return;
591
+
592
+ }
593
+
594
+ if ( this._animationId != - 1 ) {
595
+
596
+ cancelAnimationFrame( this._animationId );
597
+ this._animationId = - 1;
598
+ this._timeStart = - 1;
599
+
600
+ this.activateGizmos( false );
601
+ this.dispatchEvent( _changeEvent );
602
+
603
+ }
604
+
605
+ this.updateTbState( STATE.SCALE, true );
606
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
607
+ this._currentCursorPosition.copy( this._startCursorPosition );
608
+ break;
609
+
610
+ }
611
+
612
+ }
613
+
614
+ }
615
+
616
+ onSinglePanMove( event, opState ) {
617
+
618
+ if ( this.enabled ) {
619
+
620
+ const restart = opState != this._state;
621
+ this.setCenter( event.clientX, event.clientY );
622
+
623
+ switch ( opState ) {
624
+
625
+ case STATE.PAN:
626
+
627
+ if ( this.enablePan ) {
628
+
629
+ if ( restart ) {
630
+
631
+ //switch to pan operation
632
+
633
+ this.dispatchEvent( _endEvent );
634
+ this.dispatchEvent( _startEvent );
635
+
636
+ this.updateTbState( opState, true );
637
+ this._startCursorPosition.copy( this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement ) );
638
+ if ( this.enableGrid ) {
639
+
640
+ this.drawGrid();
641
+
642
+ }
643
+
644
+ this.activateGizmos( false );
645
+
646
+ } else {
647
+
648
+ //continue with pan operation
649
+ this._currentCursorPosition.copy( this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement ) );
650
+ this.applyTransformMatrix( this.pan( this._startCursorPosition, this._currentCursorPosition ) );
651
+
652
+ }
653
+
654
+ }
655
+
656
+ break;
657
+
658
+ case STATE.ROTATE:
659
+
660
+ if ( this.enableRotate ) {
661
+
662
+ if ( restart ) {
663
+
664
+ //switch to rotate operation
665
+
666
+ this.dispatchEvent( _endEvent );
667
+ this.dispatchEvent( _startEvent );
668
+
669
+ this.updateTbState( opState, true );
670
+ this._startCursorPosition.copy( this.unprojectOnTbSurface( this.object, _center.x, _center.y, this.domElement, this._tbRadius ) );
671
+
672
+ if ( this.enableGrid ) {
673
+
674
+ this.disposeGrid();
675
+
676
+ }
677
+
678
+ this.activateGizmos( true );
679
+
680
+ } else {
681
+
682
+ //continue with rotate operation
683
+ this._currentCursorPosition.copy( this.unprojectOnTbSurface( this.object, _center.x, _center.y, this.domElement, this._tbRadius ) );
684
+
685
+ const distance = this._startCursorPosition.distanceTo( this._currentCursorPosition );
686
+ const angle = this._startCursorPosition.angleTo( this._currentCursorPosition );
687
+ const amount = Math.max( distance / this._tbRadius, angle ) * this.rotateSpeed; //effective rotation angle
688
+
689
+ this.applyTransformMatrix( this.rotate( this.calculateRotationAxis( this._startCursorPosition, this._currentCursorPosition ), amount ) );
690
+
691
+ if ( this.enableAnimations ) {
692
+
693
+ this._timePrev = this._timeCurrent;
694
+ this._timeCurrent = performance.now();
695
+ this._anglePrev = this._angleCurrent;
696
+ this._angleCurrent = amount;
697
+ this._cursorPosPrev.copy( this._cursorPosCurr );
698
+ this._cursorPosCurr.copy( this._currentCursorPosition );
699
+ this._wPrev = this._wCurr;
700
+ this._wCurr = this.calculateAngularSpeed( this._anglePrev, this._angleCurrent, this._timePrev, this._timeCurrent );
701
+
702
+ }
703
+
704
+ }
705
+
706
+ }
707
+
708
+ break;
709
+
710
+ case STATE.SCALE:
711
+
712
+ if ( this.enableZoom ) {
713
+
714
+ if ( restart ) {
715
+
716
+ //switch to zoom operation
717
+
718
+ this.dispatchEvent( _endEvent );
719
+ this.dispatchEvent( _startEvent );
720
+
721
+ this.updateTbState( opState, true );
722
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
723
+ this._currentCursorPosition.copy( this._startCursorPosition );
724
+
725
+ if ( this.enableGrid ) {
726
+
727
+ this.disposeGrid();
728
+
729
+ }
730
+
731
+ this.activateGizmos( false );
732
+
733
+ } else {
734
+
735
+ //continue with zoom operation
736
+ const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
737
+ this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
738
+
739
+ const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
740
+
741
+ let size = 1;
742
+
743
+ if ( movement < 0 ) {
744
+
745
+ size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
746
+
747
+ } else if ( movement > 0 ) {
748
+
749
+ size = Math.pow( this.scaleFactor, movement * screenNotches );
750
+
751
+ }
752
+
753
+ this._v3_1.setFromMatrixPosition( this._gizmoMatrixState );
754
+
755
+ this.applyTransformMatrix( this.scale( size, this._v3_1 ) );
756
+
757
+ }
758
+
759
+ }
760
+
761
+ break;
762
+
763
+ case STATE.FOV:
764
+
765
+ if ( this.enableZoom && this.object.isPerspectiveCamera ) {
766
+
767
+ if ( restart ) {
768
+
769
+ //switch to fov operation
770
+
771
+ this.dispatchEvent( _endEvent );
772
+ this.dispatchEvent( _startEvent );
773
+
774
+ this.updateTbState( opState, true );
775
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
776
+ this._currentCursorPosition.copy( this._startCursorPosition );
777
+
778
+ if ( this.enableGrid ) {
779
+
780
+ this.disposeGrid();
781
+
782
+ }
783
+
784
+ this.activateGizmos( false );
785
+
786
+ } else {
787
+
788
+ //continue with fov operation
789
+ const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
790
+ this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
791
+
792
+ const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
793
+
794
+ let size = 1;
795
+
796
+ if ( movement < 0 ) {
797
+
798
+ size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
799
+
800
+ } else if ( movement > 0 ) {
801
+
802
+ size = Math.pow( this.scaleFactor, movement * screenNotches );
803
+
804
+ }
805
+
806
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
807
+ const x = this._v3_1.distanceTo( this._gizmos.position );
808
+ let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
809
+
810
+ //check min and max distance
811
+ xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
812
+
813
+ const y = x * Math.tan( MathUtils.DEG2RAD * this._fovState * 0.5 );
814
+
815
+ //calculate new fov
816
+ let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
817
+
818
+ //check min and max fov
819
+ newFov = MathUtils.clamp( newFov, this.minFov, this.maxFov );
820
+
821
+ const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
822
+ size = x / newDistance;
823
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
824
+
825
+ this.setFov( newFov );
826
+ this.applyTransformMatrix( this.scale( size, this._v3_2, false ) );
827
+
828
+ //adjusting distance
829
+ _offset.copy( this._gizmos.position ).sub( this.object.position ).normalize().multiplyScalar( newDistance / x );
830
+ this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
831
+
832
+ }
833
+
834
+ }
835
+
836
+ break;
837
+
838
+ }
839
+
840
+ this.dispatchEvent( _changeEvent );
841
+
842
+ }
843
+
844
+ }
845
+
846
+ onSinglePanEnd() {
847
+
848
+ if ( this._state == STATE.ROTATE ) {
849
+
850
+
851
+ if ( ! this.enableRotate ) {
852
+
853
+ return;
854
+
855
+ }
856
+
857
+ if ( this.enableAnimations ) {
858
+
859
+ //perform rotation animation
860
+ const deltaTime = ( performance.now() - this._timeCurrent );
861
+ if ( deltaTime < 120 ) {
862
+
863
+ const w = Math.abs( ( this._wPrev + this._wCurr ) / 2 );
864
+
865
+ const self = this;
866
+ this._animationId = window.requestAnimationFrame( function ( t ) {
867
+
868
+ self.updateTbState( STATE.ANIMATION_ROTATE, true );
869
+ const rotationAxis = self.calculateRotationAxis( self._cursorPosPrev, self._cursorPosCurr );
870
+
871
+ self.onRotationAnim( t, rotationAxis, Math.min( w, self.wMax ) );
872
+
873
+ } );
874
+
875
+ } else {
876
+
877
+ //cursor has been standing still for over 120 ms since last movement
878
+ this.updateTbState( STATE.IDLE, false );
879
+ this.activateGizmos( false );
880
+ this.dispatchEvent( _changeEvent );
881
+
882
+ }
883
+
884
+ } else {
885
+
886
+ this.updateTbState( STATE.IDLE, false );
887
+ this.activateGizmos( false );
888
+ this.dispatchEvent( _changeEvent );
889
+
890
+ }
891
+
892
+ } else if ( this._state == STATE.PAN || this._state == STATE.IDLE ) {
893
+
894
+ this.updateTbState( STATE.IDLE, false );
895
+
896
+ if ( this.enableGrid ) {
897
+
898
+ this.disposeGrid();
899
+
900
+ }
901
+
902
+ this.activateGizmos( false );
903
+ this.dispatchEvent( _changeEvent );
904
+
905
+
906
+ }
907
+
908
+ this.dispatchEvent( _endEvent );
909
+
910
+ }
911
+
912
+ onDoubleTap( event ) {
913
+
914
+ if ( this.enabled && this.enablePan && this.enableFocus && this.scene != null ) {
915
+
916
+ this.dispatchEvent( _startEvent );
917
+
918
+ this.setCenter( event.clientX, event.clientY );
919
+ const hitP = this.unprojectOnObj( this.getCursorNDC( _center.x, _center.y, this.domElement ), this.object );
920
+
921
+ if ( hitP != null && this.enableAnimations ) {
922
+
923
+ const self = this;
924
+ if ( this._animationId != - 1 ) {
925
+
926
+ window.cancelAnimationFrame( this._animationId );
927
+
928
+ }
929
+
930
+ this._timeStart = - 1;
931
+ this._animationId = window.requestAnimationFrame( function ( t ) {
932
+
933
+ self.updateTbState( STATE.ANIMATION_FOCUS, true );
934
+ self.onFocusAnim( t, hitP, self._cameraMatrixState, self._gizmoMatrixState );
935
+
936
+ } );
937
+
938
+ } else if ( hitP != null && ! this.enableAnimations ) {
939
+
940
+ this.updateTbState( STATE.FOCUS, true );
941
+ this.focus( hitP, this.scaleFactor );
942
+ this.updateTbState( STATE.IDLE, false );
943
+ this.dispatchEvent( _changeEvent );
944
+
945
+ }
946
+
947
+ }
948
+
949
+ this.dispatchEvent( _endEvent );
950
+
951
+ }
952
+
953
+ onDoublePanStart() {
954
+
955
+ if ( this.enabled && this.enablePan ) {
956
+
957
+ this.dispatchEvent( _startEvent );
958
+
959
+ this.updateTbState( STATE.PAN, true );
960
+
961
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
962
+ this._startCursorPosition.copy( this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement, true ) );
963
+ this._currentCursorPosition.copy( this._startCursorPosition );
964
+
965
+ this.activateGizmos( false );
966
+
967
+ }
968
+
969
+ }
970
+
971
+ onDoublePanMove() {
972
+
973
+ if ( this.enabled && this.enablePan ) {
974
+
975
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
976
+
977
+ if ( this._state != STATE.PAN ) {
978
+
979
+ this.updateTbState( STATE.PAN, true );
980
+ this._startCursorPosition.copy( this._currentCursorPosition );
981
+
982
+ }
983
+
984
+ this._currentCursorPosition.copy( this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement, true ) );
985
+ this.applyTransformMatrix( this.pan( this._startCursorPosition, this._currentCursorPosition, true ) );
986
+ this.dispatchEvent( _changeEvent );
987
+
988
+ }
989
+
990
+ }
991
+
992
+ onDoublePanEnd() {
993
+
994
+ this.updateTbState( STATE.IDLE, false );
995
+ this.dispatchEvent( _endEvent );
996
+
997
+ }
998
+
999
+ onRotateStart() {
1000
+
1001
+ if ( this.enabled && this.enableRotate ) {
1002
+
1003
+ this.dispatchEvent( _startEvent );
1004
+
1005
+ this.updateTbState( STATE.ZROTATE, true );
1006
+
1007
+ //this._startFingerRotation = event.rotation;
1008
+
1009
+ this._startFingerRotation = this.getAngle( this._touchCurrent[ 1 ], this._touchCurrent[ 0 ] ) + this.getAngle( this._touchStart[ 1 ], this._touchStart[ 0 ] );
1010
+ this._currentFingerRotation = this._startFingerRotation;
1011
+
1012
+ this.object.getWorldDirection( this._rotationAxis ); //rotation axis
1013
+
1014
+ if ( ! this.enablePan && ! this.enableZoom ) {
1015
+
1016
+ this.activateGizmos( true );
1017
+
1018
+ }
1019
+
1020
+ }
1021
+
1022
+ }
1023
+
1024
+ onRotateMove() {
1025
+
1026
+ if ( this.enabled && this.enableRotate ) {
1027
+
1028
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
1029
+ let rotationPoint;
1030
+
1031
+ if ( this._state != STATE.ZROTATE ) {
1032
+
1033
+ this.updateTbState( STATE.ZROTATE, true );
1034
+ this._startFingerRotation = this._currentFingerRotation;
1035
+
1036
+ }
1037
+
1038
+ //this._currentFingerRotation = event.rotation;
1039
+ this._currentFingerRotation = this.getAngle( this._touchCurrent[ 1 ], this._touchCurrent[ 0 ] ) + this.getAngle( this._touchStart[ 1 ], this._touchStart[ 0 ] );
1040
+
1041
+ if ( ! this.enablePan ) {
1042
+
1043
+ rotationPoint = new Vector3().setFromMatrixPosition( this._gizmoMatrixState );
1044
+
1045
+ } else {
1046
+
1047
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
1048
+ rotationPoint = this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement ).applyQuaternion( this.object.quaternion ).multiplyScalar( 1 / this.object.zoom ).add( this._v3_2 );
1049
+
1050
+ }
1051
+
1052
+ const amount = MathUtils.DEG2RAD * ( this._startFingerRotation - this._currentFingerRotation );
1053
+
1054
+ this.applyTransformMatrix( this.zRotate( rotationPoint, amount ) );
1055
+ this.dispatchEvent( _changeEvent );
1056
+
1057
+ }
1058
+
1059
+ }
1060
+
1061
+ onRotateEnd() {
1062
+
1063
+ this.updateTbState( STATE.IDLE, false );
1064
+ this.activateGizmos( false );
1065
+ this.dispatchEvent( _endEvent );
1066
+
1067
+ }
1068
+
1069
+ onPinchStart() {
1070
+
1071
+ if ( this.enabled && this.enableZoom ) {
1072
+
1073
+ this.dispatchEvent( _startEvent );
1074
+ this.updateTbState( STATE.SCALE, true );
1075
+
1076
+ this._startFingerDistance = this.calculatePointersDistance( this._touchCurrent[ 0 ], this._touchCurrent[ 1 ] );
1077
+ this._currentFingerDistance = this._startFingerDistance;
1078
+
1079
+ this.activateGizmos( false );
1080
+
1081
+ }
1082
+
1083
+ }
1084
+
1085
+ onPinchMove() {
1086
+
1087
+ if ( this.enabled && this.enableZoom ) {
1088
+
1089
+ this.setCenter( ( this._touchCurrent[ 0 ].clientX + this._touchCurrent[ 1 ].clientX ) / 2, ( this._touchCurrent[ 0 ].clientY + this._touchCurrent[ 1 ].clientY ) / 2 );
1090
+ const minDistance = 12; //minimum distance between fingers (in css pixels)
1091
+
1092
+ if ( this._state != STATE.SCALE ) {
1093
+
1094
+ this._startFingerDistance = this._currentFingerDistance;
1095
+ this.updateTbState( STATE.SCALE, true );
1096
+
1097
+ }
1098
+
1099
+ this._currentFingerDistance = Math.max( this.calculatePointersDistance( this._touchCurrent[ 0 ], this._touchCurrent[ 1 ] ), minDistance * this._devPxRatio );
1100
+ const amount = this._currentFingerDistance / this._startFingerDistance;
1101
+
1102
+ let scalePoint;
1103
+
1104
+ if ( ! this.enablePan ) {
1105
+
1106
+ scalePoint = this._gizmos.position;
1107
+
1108
+ } else {
1109
+
1110
+ if ( this.object.isOrthographicCamera ) {
1111
+
1112
+ scalePoint = this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement )
1113
+ .applyQuaternion( this.object.quaternion )
1114
+ .multiplyScalar( 1 / this.object.zoom )
1115
+ .add( this._gizmos.position );
1116
+
1117
+ } else if ( this.object.isPerspectiveCamera ) {
1118
+
1119
+ scalePoint = this.unprojectOnTbPlane( this.object, _center.x, _center.y, this.domElement )
1120
+ .applyQuaternion( this.object.quaternion )
1121
+ .add( this._gizmos.position );
1122
+
1123
+ }
1124
+
1125
+ }
1126
+
1127
+ this.applyTransformMatrix( this.scale( amount, scalePoint ) );
1128
+ this.dispatchEvent( _changeEvent );
1129
+
1130
+ }
1131
+
1132
+ }
1133
+
1134
+ onPinchEnd() {
1135
+
1136
+ this.updateTbState( STATE.IDLE, false );
1137
+ this.dispatchEvent( _endEvent );
1138
+
1139
+ }
1140
+
1141
+ onTriplePanStart() {
1142
+
1143
+ if ( this.enabled && this.enableZoom ) {
1144
+
1145
+ this.dispatchEvent( _startEvent );
1146
+
1147
+ this.updateTbState( STATE.SCALE, true );
1148
+
1149
+ //const center = event.center;
1150
+ let clientX = 0;
1151
+ let clientY = 0;
1152
+ const nFingers = this._touchCurrent.length;
1153
+
1154
+ for ( let i = 0; i < nFingers; i ++ ) {
1155
+
1156
+ clientX += this._touchCurrent[ i ].clientX;
1157
+ clientY += this._touchCurrent[ i ].clientY;
1158
+
1159
+ }
1160
+
1161
+ this.setCenter( clientX / nFingers, clientY / nFingers );
1162
+
1163
+ this._startCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
1164
+ this._currentCursorPosition.copy( this._startCursorPosition );
1165
+
1166
+ }
1167
+
1168
+ }
1169
+
1170
+ onTriplePanMove() {
1171
+
1172
+ if ( this.enabled && this.enableZoom ) {
1173
+
1174
+ // fov / 2
1175
+ // |\
1176
+ // | \
1177
+ // | \
1178
+ // x | \
1179
+ // | \
1180
+ // | \
1181
+ // | _ _ _\
1182
+ // y
1183
+
1184
+ //const center = event.center;
1185
+ let clientX = 0;
1186
+ let clientY = 0;
1187
+ const nFingers = this._touchCurrent.length;
1188
+
1189
+ for ( let i = 0; i < nFingers; i ++ ) {
1190
+
1191
+ clientX += this._touchCurrent[ i ].clientX;
1192
+ clientY += this._touchCurrent[ i ].clientY;
1193
+
1194
+ }
1195
+
1196
+ this.setCenter( clientX / nFingers, clientY / nFingers );
1197
+
1198
+ const screenNotches = 8; //how many wheel notches corresponds to a full screen pan
1199
+ this._currentCursorPosition.setY( this.getCursorNDC( _center.x, _center.y, this.domElement ).y * 0.5 );
1200
+
1201
+ const movement = this._currentCursorPosition.y - this._startCursorPosition.y;
1202
+
1203
+ let size = 1;
1204
+
1205
+ if ( movement < 0 ) {
1206
+
1207
+ size = 1 / ( Math.pow( this.scaleFactor, - movement * screenNotches ) );
1208
+
1209
+ } else if ( movement > 0 ) {
1210
+
1211
+ size = Math.pow( this.scaleFactor, movement * screenNotches );
1212
+
1213
+ }
1214
+
1215
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
1216
+ const x = this._v3_1.distanceTo( this._gizmos.position );
1217
+ let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
1218
+
1219
+ //check min and max distance
1220
+ xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
1221
+
1222
+ const y = x * Math.tan( MathUtils.DEG2RAD * this._fovState * 0.5 );
1223
+
1224
+ //calculate new fov
1225
+ let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
1226
+
1227
+ //check min and max fov
1228
+ newFov = MathUtils.clamp( newFov, this.minFov, this.maxFov );
1229
+
1230
+ const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
1231
+ size = x / newDistance;
1232
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
1233
+
1234
+ this.setFov( newFov );
1235
+ this.applyTransformMatrix( this.scale( size, this._v3_2, false ) );
1236
+
1237
+ //adjusting distance
1238
+ _offset.copy( this._gizmos.position ).sub( this.object.position ).normalize().multiplyScalar( newDistance / x );
1239
+ this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
1240
+
1241
+ this.dispatchEvent( _changeEvent );
1242
+
1243
+ }
1244
+
1245
+ }
1246
+
1247
+ onTriplePanEnd() {
1248
+
1249
+ this.updateTbState( STATE.IDLE, false );
1250
+ this.dispatchEvent( _endEvent );
1251
+ //this.dispatchEvent( _changeEvent );
1252
+
1253
+ }
1254
+
1255
+ /**
1256
+ * Set _center's x/y coordinates.
1257
+ *
1258
+ * @private
1259
+ * @param {number} clientX - The x coordinate.
1260
+ * @param {number} clientY - The y coordinate.
1261
+ */
1262
+ setCenter( clientX, clientY ) {
1263
+
1264
+ _center.x = clientX;
1265
+ _center.y = clientY;
1266
+
1267
+ }
1268
+
1269
+ /**
1270
+ * Set default mouse actions.
1271
+ *
1272
+ * @private
1273
+ */
1274
+ initializeMouseActions() {
1275
+
1276
+ this.setMouseAction( 'PAN', 0, 'CTRL' );
1277
+ this.setMouseAction( 'PAN', 2 );
1278
+
1279
+ this.setMouseAction( 'ROTATE', 0 );
1280
+
1281
+ this.setMouseAction( 'ZOOM', 'WHEEL' );
1282
+ this.setMouseAction( 'ZOOM', 1 );
1283
+
1284
+ this.setMouseAction( 'FOV', 'WHEEL', 'SHIFT' );
1285
+ this.setMouseAction( 'FOV', 1, 'SHIFT' );
1286
+
1287
+
1288
+ }
1289
+
1290
+ /**
1291
+ * Compare two mouse actions.
1292
+ *
1293
+ * @private
1294
+ * @param {Object} action1 - The first mouse action.
1295
+ * @param {Object} action2 - The second mouse action.
1296
+ * @returns {boolean} `true` if action1 and action 2 are the same mouse action, `false` otherwise.
1297
+ */
1298
+ compareMouseAction( action1, action2 ) {
1299
+
1300
+ if ( action1.operation == action2.operation ) {
1301
+
1302
+ if ( action1.mouse == action2.mouse && action1.key == action2.key ) {
1303
+
1304
+ return true;
1305
+
1306
+ } else {
1307
+
1308
+ return false;
1309
+
1310
+ }
1311
+
1312
+ } else {
1313
+
1314
+ return false;
1315
+
1316
+ }
1317
+
1318
+ }
1319
+
1320
+ /**
1321
+ * Set a new mouse action by specifying the operation to be performed and a mouse/key combination. In case of conflict, replaces the existing one.
1322
+ *
1323
+ * @param {'PAN'|'ROTATE'|'ZOOM'|'FOV'} operation - The operation to be performed ('PAN', 'ROTATE', 'ZOOM', 'FOV').
1324
+ * @param {0|1|2|'WHEEL'} mouse - A mouse button (0, 1, 2) or 'WHEEL' for wheel notches.
1325
+ * @param {?('CTRL'|'SHIFT')} [key=null] - The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed.
1326
+ * @returns {boolean} `true` if the mouse action has been successfully added, `false` otherwise.
1327
+ */
1328
+ setMouseAction( operation, mouse, key = null ) {
1329
+
1330
+ const operationInput = [ 'PAN', 'ROTATE', 'ZOOM', 'FOV' ];
1331
+ const mouseInput = [ 0, 1, 2, 'WHEEL' ];
1332
+ const keyInput = [ 'CTRL', 'SHIFT', null ];
1333
+ let state;
1334
+
1335
+ if ( ! operationInput.includes( operation ) || ! mouseInput.includes( mouse ) || ! keyInput.includes( key ) ) {
1336
+
1337
+ //invalid parameters
1338
+ return false;
1339
+
1340
+ }
1341
+
1342
+ if ( mouse == 'WHEEL' ) {
1343
+
1344
+ if ( operation != 'ZOOM' && operation != 'FOV' ) {
1345
+
1346
+ //cannot associate 2D operation to 1D input
1347
+ return false;
1348
+
1349
+ }
1350
+
1351
+ }
1352
+
1353
+ switch ( operation ) {
1354
+
1355
+ case 'PAN':
1356
+
1357
+ state = STATE.PAN;
1358
+ break;
1359
+
1360
+ case 'ROTATE':
1361
+
1362
+ state = STATE.ROTATE;
1363
+ break;
1364
+
1365
+ case 'ZOOM':
1366
+
1367
+ state = STATE.SCALE;
1368
+ break;
1369
+
1370
+ case 'FOV':
1371
+
1372
+ state = STATE.FOV;
1373
+ break;
1374
+
1375
+ }
1376
+
1377
+ const action = {
1378
+
1379
+ operation: operation,
1380
+ mouse: mouse,
1381
+ key: key,
1382
+ state: state
1383
+
1384
+ };
1385
+
1386
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1387
+
1388
+ if ( this.mouseActions[ i ].mouse == action.mouse && this.mouseActions[ i ].key == action.key ) {
1389
+
1390
+ this.mouseActions.splice( i, 1, action );
1391
+ return true;
1392
+
1393
+ }
1394
+
1395
+ }
1396
+
1397
+ this.mouseActions.push( action );
1398
+ return true;
1399
+
1400
+ }
1401
+
1402
+ /**
1403
+ * Remove a mouse action by specifying its mouse/key combination.
1404
+ *
1405
+ * @param {0|1|2|'WHEEL'} mouse - A mouse button (0, 1, 2) or 'WHEEL' for wheel notches.
1406
+ * @param {?('CTRL'|'SHIFT')} key - The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed.
1407
+ * @returns {boolean} `true` if the operation has been successfully removed, `false` otherwise.
1408
+ */
1409
+ unsetMouseAction( mouse, key = null ) {
1410
+
1411
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1412
+
1413
+ if ( this.mouseActions[ i ].mouse == mouse && this.mouseActions[ i ].key == key ) {
1414
+
1415
+ this.mouseActions.splice( i, 1 );
1416
+ return true;
1417
+
1418
+ }
1419
+
1420
+ }
1421
+
1422
+ return false;
1423
+
1424
+ }
1425
+
1426
+ /**
1427
+ * Return the operation associated to a mouse/keyboard combination.
1428
+ *
1429
+ * @private
1430
+ * @param {0|1|2|'WHEEL'} mouse - Mouse button index (0, 1, 2) or 'WHEEL' for wheel notches.
1431
+ * @param {?('CTRL'|'SHIFT')} key - Keyboard modifier.
1432
+ * @returns {?('PAN'|'ROTATE'|'ZOOM'|'FOV')} The operation if it has been found, `null` otherwise.
1433
+ */
1434
+ getOpFromAction( mouse, key ) {
1435
+
1436
+ let action;
1437
+
1438
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1439
+
1440
+ action = this.mouseActions[ i ];
1441
+ if ( action.mouse == mouse && action.key == key ) {
1442
+
1443
+ return action.operation;
1444
+
1445
+ }
1446
+
1447
+ }
1448
+
1449
+ if ( key != null ) {
1450
+
1451
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1452
+
1453
+ action = this.mouseActions[ i ];
1454
+ if ( action.mouse == mouse && action.key == null ) {
1455
+
1456
+ return action.operation;
1457
+
1458
+ }
1459
+
1460
+ }
1461
+
1462
+ }
1463
+
1464
+ return null;
1465
+
1466
+ }
1467
+
1468
+ /**
1469
+ * Get the operation associated to mouse and key combination and returns the corresponding FSA state.
1470
+ *
1471
+ * @private
1472
+ * @param {0|1|2} mouse - Mouse button index (0, 1, 2)
1473
+ * @param {?('CTRL'|'SHIFT')} key - Keyboard modifier
1474
+ * @returns {?STATE} The FSA state obtained from the operation associated to mouse/keyboard combination.
1475
+ */
1476
+ getOpStateFromAction( mouse, key ) {
1477
+
1478
+ let action;
1479
+
1480
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1481
+
1482
+ action = this.mouseActions[ i ];
1483
+ if ( action.mouse == mouse && action.key == key ) {
1484
+
1485
+ return action.state;
1486
+
1487
+ }
1488
+
1489
+ }
1490
+
1491
+ if ( key != null ) {
1492
+
1493
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
1494
+
1495
+ action = this.mouseActions[ i ];
1496
+ if ( action.mouse == mouse && action.key == null ) {
1497
+
1498
+ return action.state;
1499
+
1500
+ }
1501
+
1502
+ }
1503
+
1504
+ }
1505
+
1506
+ return null;
1507
+
1508
+ }
1509
+
1510
+ /**
1511
+ * Calculate the angle between two pointers.
1512
+ *
1513
+ * @private
1514
+ * @param {PointerEvent} p1 - The first pointer event.
1515
+ * @param {PointerEvent} p2 - The second pointer event.
1516
+ * @returns {number} The angle between two pointers in degrees.
1517
+ */
1518
+ getAngle( p1, p2 ) {
1519
+
1520
+ return Math.atan2( p2.clientY - p1.clientY, p2.clientX - p1.clientX ) * 180 / Math.PI;
1521
+
1522
+ }
1523
+
1524
+ /**
1525
+ * Updates a PointerEvent inside current pointerevents array.
1526
+ *
1527
+ * @private
1528
+ * @param {PointerEvent} event - The pointer event.
1529
+ */
1530
+ updateTouchEvent( event ) {
1531
+
1532
+ for ( let i = 0; i < this._touchCurrent.length; i ++ ) {
1533
+
1534
+ if ( this._touchCurrent[ i ].pointerId == event.pointerId ) {
1535
+
1536
+ this._touchCurrent.splice( i, 1, event );
1537
+ break;
1538
+
1539
+ }
1540
+
1541
+ }
1542
+
1543
+ }
1544
+
1545
+ /**
1546
+ * Applies a transformation matrix, to the camera and gizmos.
1547
+ *
1548
+ * @private
1549
+ * @param {Object} transformation - Object containing matrices to apply to camera and gizmos.
1550
+ */
1551
+ applyTransformMatrix( transformation ) {
1552
+
1553
+ if ( transformation.camera != null ) {
1554
+
1555
+ this._m4_1.copy( this._cameraMatrixState ).premultiply( transformation.camera );
1556
+ this._m4_1.decompose( this.object.position, this.object.quaternion, this.object.scale );
1557
+ this.object.updateMatrix();
1558
+
1559
+ //update camera up vector
1560
+ if ( this._state == STATE.ROTATE || this._state == STATE.ZROTATE || this._state == STATE.ANIMATION_ROTATE ) {
1561
+
1562
+ this.object.up.copy( this._upState ).applyQuaternion( this.object.quaternion );
1563
+
1564
+ }
1565
+
1566
+ }
1567
+
1568
+ if ( transformation.gizmos != null ) {
1569
+
1570
+ this._m4_1.copy( this._gizmoMatrixState ).premultiply( transformation.gizmos );
1571
+ this._m4_1.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1572
+ this._gizmos.updateMatrix();
1573
+
1574
+ }
1575
+
1576
+ if ( this._state == STATE.SCALE || this._state == STATE.FOCUS || this._state == STATE.ANIMATION_FOCUS ) {
1577
+
1578
+ this._tbRadius = this.calculateTbRadius( this.object );
1579
+
1580
+ if ( this.adjustNearFar ) {
1581
+
1582
+ const cameraDistance = this.object.position.distanceTo( this._gizmos.position );
1583
+
1584
+ const bb = new Box3();
1585
+ bb.setFromObject( this._gizmos );
1586
+ const sphere = new Sphere();
1587
+ bb.getBoundingSphere( sphere );
1588
+
1589
+ const adjustedNearPosition = Math.max( this._nearPos0, sphere.radius + sphere.center.length() );
1590
+ const regularNearPosition = cameraDistance - this._initialNear;
1591
+
1592
+ const minNearPos = Math.min( adjustedNearPosition, regularNearPosition );
1593
+ this.object.near = cameraDistance - minNearPos;
1594
+
1595
+
1596
+ const adjustedFarPosition = Math.min( this._farPos0, - sphere.radius + sphere.center.length() );
1597
+ const regularFarPosition = cameraDistance - this._initialFar;
1598
+
1599
+ const minFarPos = Math.min( adjustedFarPosition, regularFarPosition );
1600
+ this.object.far = cameraDistance - minFarPos;
1601
+
1602
+ this.object.updateProjectionMatrix();
1603
+
1604
+ } else {
1605
+
1606
+ let update = false;
1607
+
1608
+ if ( this.object.near != this._initialNear ) {
1609
+
1610
+ this.object.near = this._initialNear;
1611
+ update = true;
1612
+
1613
+ }
1614
+
1615
+ if ( this.object.far != this._initialFar ) {
1616
+
1617
+ this.object.far = this._initialFar;
1618
+ update = true;
1619
+
1620
+ }
1621
+
1622
+ if ( update ) {
1623
+
1624
+ this.object.updateProjectionMatrix();
1625
+
1626
+ }
1627
+
1628
+ }
1629
+
1630
+ }
1631
+
1632
+ }
1633
+
1634
+ /**
1635
+ * Calculates the angular speed.
1636
+ *
1637
+ * @private
1638
+ * @param {number} p0 - Position at t0.
1639
+ * @param {number} p1 - Position at t1.
1640
+ * @param {number} t0 - Initial time in milliseconds.
1641
+ * @param {number} t1 - Ending time in milliseconds.
1642
+ * @returns {number} The angular speed.
1643
+ */
1644
+ calculateAngularSpeed( p0, p1, t0, t1 ) {
1645
+
1646
+ const s = p1 - p0;
1647
+ const t = ( t1 - t0 ) / 1000;
1648
+ if ( t == 0 ) {
1649
+
1650
+ return 0;
1651
+
1652
+ }
1653
+
1654
+ return s / t;
1655
+
1656
+ }
1657
+
1658
+ /**
1659
+ * Calculates the distance between two pointers.
1660
+ *
1661
+ * @private
1662
+ * @param {PointerEvent} p0 - The first pointer.
1663
+ * @param {PointerEvent} p1 - The second pointer.
1664
+ * @returns {number} The distance between the two pointers.
1665
+ */
1666
+ calculatePointersDistance( p0, p1 ) {
1667
+
1668
+ return Math.sqrt( Math.pow( p1.clientX - p0.clientX, 2 ) + Math.pow( p1.clientY - p0.clientY, 2 ) );
1669
+
1670
+ }
1671
+
1672
+ /**
1673
+ * Calculates the rotation axis as the vector perpendicular between two vectors.
1674
+ *
1675
+ * @private
1676
+ * @param {Vector3} vec1 - The first vector.
1677
+ * @param {Vector3} vec2 - The second vector.
1678
+ * @returns {Vector3} The normalized rotation axis.
1679
+ */
1680
+ calculateRotationAxis( vec1, vec2 ) {
1681
+
1682
+ this._rotationMatrix.extractRotation( this._cameraMatrixState );
1683
+ this._quat.setFromRotationMatrix( this._rotationMatrix );
1684
+
1685
+ this._rotationAxis.crossVectors( vec1, vec2 ).applyQuaternion( this._quat );
1686
+ return this._rotationAxis.normalize().clone();
1687
+
1688
+ }
1689
+
1690
+ /**
1691
+ * Calculates the trackball radius so that gizmo's diameter will be 2/3 of the minimum side of the camera frustum.
1692
+ *
1693
+ * @private
1694
+ * @param {Camera} camera - The camera.
1695
+ * @returns {number} The trackball radius.
1696
+ */
1697
+ calculateTbRadius( camera ) {
1698
+
1699
+ const distance = camera.position.distanceTo( this._gizmos.position );
1700
+
1701
+ if ( camera.type == 'PerspectiveCamera' ) {
1702
+
1703
+ const halfFovV = MathUtils.DEG2RAD * camera.fov * 0.5; //vertical fov/2 in radians
1704
+ const halfFovH = Math.atan( ( camera.aspect ) * Math.tan( halfFovV ) ); //horizontal fov/2 in radians
1705
+ return Math.tan( Math.min( halfFovV, halfFovH ) ) * distance * this.radiusFactor;
1706
+
1707
+ } else if ( camera.type == 'OrthographicCamera' ) {
1708
+
1709
+ return Math.min( camera.top, camera.right ) * this.radiusFactor;
1710
+
1711
+ }
1712
+
1713
+ }
1714
+
1715
+ /**
1716
+ * Focus operation consist of positioning the point of interest in front of the camera and a slightly zoom in.
1717
+ *
1718
+ * @private
1719
+ * @param {Vector3} point - The point of interest.
1720
+ * @param {number} size - Scale factor.
1721
+ * @param {number} [amount=1] - Amount of operation to be completed (used for focus animations, default is complete full operation).
1722
+ */
1723
+ focus( point, size, amount = 1 ) {
1724
+
1725
+ //move center of camera (along with gizmos) towards point of interest
1726
+ _offset.copy( point ).sub( this._gizmos.position ).multiplyScalar( amount );
1727
+ this._translationMatrix.makeTranslation( _offset.x, _offset.y, _offset.z );
1728
+
1729
+ _gizmoMatrixStateTemp.copy( this._gizmoMatrixState );
1730
+ this._gizmoMatrixState.premultiply( this._translationMatrix );
1731
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
1732
+
1733
+ _cameraMatrixStateTemp.copy( this._cameraMatrixState );
1734
+ this._cameraMatrixState.premultiply( this._translationMatrix );
1735
+ this._cameraMatrixState.decompose( this.object.position, this.object.quaternion, this.object.scale );
1736
+
1737
+ //apply zoom
1738
+ if ( this.enableZoom ) {
1739
+
1740
+ this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
1741
+
1742
+ }
1743
+
1744
+ this._gizmoMatrixState.copy( _gizmoMatrixStateTemp );
1745
+ this._cameraMatrixState.copy( _cameraMatrixStateTemp );
1746
+
1747
+ }
1748
+
1749
+ /**
1750
+ * Creates a grid if necessary and adds it to the scene.
1751
+ *
1752
+ * @private
1753
+ */
1754
+ drawGrid() {
1755
+
1756
+ if ( this.scene != null ) {
1757
+
1758
+ const color = 0x888888;
1759
+ const multiplier = 3;
1760
+ let size, divisions, maxLength, tick;
1761
+
1762
+ if ( this.object.isOrthographicCamera ) {
1763
+
1764
+ const width = this.object.right - this.object.left;
1765
+ const height = this.object.bottom - this.object.top;
1766
+
1767
+ maxLength = Math.max( width, height );
1768
+ tick = maxLength / 20;
1769
+
1770
+ size = maxLength / this.object.zoom * multiplier;
1771
+ divisions = size / tick * this.object.zoom;
1772
+
1773
+ } else if ( this.object.isPerspectiveCamera ) {
1774
+
1775
+ const distance = this.object.position.distanceTo( this._gizmos.position );
1776
+ const halfFovV = MathUtils.DEG2RAD * this.object.fov * 0.5;
1777
+ const halfFovH = Math.atan( ( this.object.aspect ) * Math.tan( halfFovV ) );
1778
+
1779
+ maxLength = Math.tan( Math.max( halfFovV, halfFovH ) ) * distance * 2;
1780
+ tick = maxLength / 20;
1781
+
1782
+ size = maxLength * multiplier;
1783
+ divisions = size / tick;
1784
+
1785
+ }
1786
+
1787
+ if ( this._grid == null ) {
1788
+
1789
+ this._grid = new GridHelper( size, divisions, color, color );
1790
+ this._grid.position.copy( this._gizmos.position );
1791
+ this._gridPosition.copy( this._grid.position );
1792
+ this._grid.quaternion.copy( this.object.quaternion );
1793
+ this._grid.rotateX( Math.PI * 0.5 );
1794
+
1795
+ this.scene.add( this._grid );
1796
+
1797
+ }
1798
+
1799
+ }
1800
+
1801
+ }
1802
+
1803
+ dispose() {
1804
+
1805
+ if ( this._animationId != - 1 ) {
1806
+
1807
+ window.cancelAnimationFrame( this._animationId );
1808
+
1809
+ }
1810
+
1811
+ this.disconnect();
1812
+
1813
+ if ( this.scene !== null ) this.scene.remove( this._gizmos );
1814
+ this.disposeGrid();
1815
+
1816
+ }
1817
+
1818
+ /**
1819
+ * Removes the grid from the scene.
1820
+ */
1821
+ disposeGrid() {
1822
+
1823
+ if ( this._grid != null && this.scene != null ) {
1824
+
1825
+ this.scene.remove( this._grid );
1826
+ this._grid = null;
1827
+
1828
+ }
1829
+
1830
+ }
1831
+
1832
+ /**
1833
+ * Computes the easing out cubic function for ease out effect in animation.
1834
+ *
1835
+ * @private
1836
+ * @param {number} t - The absolute progress of the animation in the bound of `0` (beginning of the) and `1` (ending of animation).
1837
+ * @returns {number} Result of easing out cubic at time `t`.
1838
+ */
1839
+ easeOutCubic( t ) {
1840
+
1841
+ return 1 - Math.pow( 1 - t, 3 );
1842
+
1843
+ }
1844
+
1845
+ /**
1846
+ * Makes rotation gizmos more or less visible.
1847
+ *
1848
+ * @param {boolean} isActive - If set to `true`, gizmos are more visible.
1849
+ */
1850
+ activateGizmos( isActive ) {
1851
+
1852
+ const gizmoX = this._gizmos.children[ 0 ];
1853
+ const gizmoY = this._gizmos.children[ 1 ];
1854
+ const gizmoZ = this._gizmos.children[ 2 ];
1855
+
1856
+ if ( isActive ) {
1857
+
1858
+ gizmoX.material.setValues( { opacity: 1 } );
1859
+ gizmoY.material.setValues( { opacity: 1 } );
1860
+ gizmoZ.material.setValues( { opacity: 1 } );
1861
+
1862
+ } else {
1863
+
1864
+ gizmoX.material.setValues( { opacity: 0.6 } );
1865
+ gizmoY.material.setValues( { opacity: 0.6 } );
1866
+ gizmoZ.material.setValues( { opacity: 0.6 } );
1867
+
1868
+ }
1869
+
1870
+ }
1871
+
1872
+ /**
1873
+ * Calculates the cursor position in NDC.
1874
+ *
1875
+ * @private
1876
+ * @param {number} cursorX - Cursor horizontal coordinate within the canvas.
1877
+ * @param {number} cursorY - Cursor vertical coordinate within the canvas.
1878
+ * @param {HTMLElement} canvas - The canvas where the renderer draws its output.
1879
+ * @returns {Vector2} Cursor normalized position inside the canvas.
1880
+ */
1881
+ getCursorNDC( cursorX, cursorY, canvas ) {
1882
+
1883
+ const canvasRect = canvas.getBoundingClientRect();
1884
+ this._v2_1.setX( ( ( cursorX - canvasRect.left ) / canvasRect.width ) * 2 - 1 );
1885
+ this._v2_1.setY( ( ( canvasRect.bottom - cursorY ) / canvasRect.height ) * 2 - 1 );
1886
+ return this._v2_1.clone();
1887
+
1888
+ }
1889
+
1890
+ /**
1891
+ * Calculates the cursor position inside the canvas x/y coordinates with the origin being in the center of the canvas.
1892
+ *
1893
+ * @private
1894
+ * @param {number} cursorX - Cursor horizontal coordinate within the canvas.
1895
+ * @param {number} cursorY - Cursor vertical coordinate within the canvas.
1896
+ * @param {HTMLElement} canvas - The canvas where the renderer draws its output.
1897
+ * @returns {Vector2} Cursor position inside the canvas.
1898
+ */
1899
+ getCursorPosition( cursorX, cursorY, canvas ) {
1900
+
1901
+ this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
1902
+ this._v2_1.x *= ( this.object.right - this.object.left ) * 0.5;
1903
+ this._v2_1.y *= ( this.object.top - this.object.bottom ) * 0.5;
1904
+ return this._v2_1.clone();
1905
+
1906
+ }
1907
+
1908
+ /**
1909
+ * Sets the camera to be controlled. Must be called in order to set a new camera to be controlled.
1910
+ *
1911
+ * @param {Camera} camera - The camera to be controlled.
1912
+ */
1913
+ setCamera( camera ) {
1914
+
1915
+ camera.lookAt( this.target );
1916
+ camera.updateMatrix();
1917
+
1918
+ //setting state
1919
+ if ( camera.type == 'PerspectiveCamera' ) {
1920
+
1921
+ this._fov0 = camera.fov;
1922
+ this._fovState = camera.fov;
1923
+
1924
+ }
1925
+
1926
+ this._cameraMatrixState0.copy( camera.matrix );
1927
+ this._cameraMatrixState.copy( this._cameraMatrixState0 );
1928
+ this._cameraProjectionState.copy( camera.projectionMatrix );
1929
+ this._zoom0 = camera.zoom;
1930
+ this._zoomState = this._zoom0;
1931
+
1932
+ this._initialNear = camera.near;
1933
+ this._nearPos0 = camera.position.distanceTo( this.target ) - camera.near;
1934
+ this._nearPos = this._initialNear;
1935
+
1936
+ this._initialFar = camera.far;
1937
+ this._farPos0 = camera.position.distanceTo( this.target ) - camera.far;
1938
+ this._farPos = this._initialFar;
1939
+
1940
+ this._up0.copy( camera.up );
1941
+ this._upState.copy( camera.up );
1942
+
1943
+ this.object = camera;
1944
+ this.object.updateProjectionMatrix();
1945
+
1946
+ //making gizmos
1947
+ this._tbRadius = this.calculateTbRadius( camera );
1948
+ this.makeGizmos( this.target, this._tbRadius );
1949
+
1950
+ }
1951
+
1952
+ /**
1953
+ * Sets gizmos visibility.
1954
+ *
1955
+ * @param {boolean} value - Value of gizmos visibility.
1956
+ */
1957
+ setGizmosVisible( value ) {
1958
+
1959
+ this._gizmos.visible = value;
1960
+ this.dispatchEvent( _changeEvent );
1961
+
1962
+ }
1963
+
1964
+ /**
1965
+ * Sets gizmos radius factor and redraws gizmos.
1966
+ *
1967
+ * @param {number} value - Value of radius factor.
1968
+ */
1969
+ setTbRadius( value ) {
1970
+
1971
+ this.radiusFactor = value;
1972
+ this._tbRadius = this.calculateTbRadius( this.object );
1973
+
1974
+ const curve = new EllipseCurve( 0, 0, this._tbRadius, this._tbRadius );
1975
+ const points = curve.getPoints( this._curvePts );
1976
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
1977
+
1978
+
1979
+ for ( const gizmo in this._gizmos.children ) {
1980
+
1981
+ this._gizmos.children[ gizmo ].geometry = curveGeometry;
1982
+
1983
+ }
1984
+
1985
+ this.dispatchEvent( _changeEvent );
1986
+
1987
+ }
1988
+
1989
+ /**
1990
+ * Creates the rotation gizmos matching trackball center and radius.
1991
+ *
1992
+ * @private
1993
+ * @param {Vector3} tbCenter - The trackball center.
1994
+ * @param {number} tbRadius - The trackball radius.
1995
+ */
1996
+ makeGizmos( tbCenter, tbRadius ) {
1997
+
1998
+ const curve = new EllipseCurve( 0, 0, tbRadius, tbRadius );
1999
+ const points = curve.getPoints( this._curvePts );
2000
+
2001
+ //geometry
2002
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
2003
+
2004
+ //material
2005
+ const curveMaterialX = new LineBasicMaterial( { color: 0xff8080, fog: false, transparent: true, opacity: 0.6 } );
2006
+ const curveMaterialY = new LineBasicMaterial( { color: 0x80ff80, fog: false, transparent: true, opacity: 0.6 } );
2007
+ const curveMaterialZ = new LineBasicMaterial( { color: 0x8080ff, fog: false, transparent: true, opacity: 0.6 } );
2008
+
2009
+ //line
2010
+ const gizmoX = new Line( curveGeometry, curveMaterialX );
2011
+ const gizmoY = new Line( curveGeometry, curveMaterialY );
2012
+ const gizmoZ = new Line( curveGeometry, curveMaterialZ );
2013
+
2014
+ const rotation = Math.PI * 0.5;
2015
+ gizmoX.rotation.y = rotation;
2016
+ gizmoY.rotation.x = rotation;
2017
+
2018
+
2019
+ //setting state
2020
+ this._gizmoMatrixState0.identity().setPosition( tbCenter );
2021
+ this._gizmoMatrixState.copy( this._gizmoMatrixState0 );
2022
+
2023
+ if ( this.object.zoom !== 1 ) {
2024
+
2025
+ //adapt gizmos size to camera zoom
2026
+ const size = 1 / this.object.zoom;
2027
+ this._scaleMatrix.makeScale( size, size, size );
2028
+ this._translationMatrix.makeTranslation( - tbCenter.x, - tbCenter.y, - tbCenter.z );
2029
+
2030
+ this._gizmoMatrixState.premultiply( this._translationMatrix ).premultiply( this._scaleMatrix );
2031
+ this._translationMatrix.makeTranslation( tbCenter.x, tbCenter.y, tbCenter.z );
2032
+ this._gizmoMatrixState.premultiply( this._translationMatrix );
2033
+
2034
+ }
2035
+
2036
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
2037
+
2038
+ //
2039
+
2040
+ this._gizmos.traverse( function ( object ) {
2041
+
2042
+ if ( object.isLine ) {
2043
+
2044
+ object.geometry.dispose();
2045
+ object.material.dispose();
2046
+
2047
+ }
2048
+
2049
+ } );
2050
+
2051
+ this._gizmos.clear();
2052
+
2053
+ //
2054
+
2055
+ this._gizmos.add( gizmoX );
2056
+ this._gizmos.add( gizmoY );
2057
+ this._gizmos.add( gizmoZ );
2058
+
2059
+ }
2060
+
2061
+ /**
2062
+ * Performs animation for focus operation.
2063
+ *
2064
+ * @private
2065
+ * @param {number} time - Instant in which this function is called as performance.now().
2066
+ * @param {Vector3} point - Point of interest for focus operation.
2067
+ * @param {Matrix4} cameraMatrix - Camera matrix.
2068
+ * @param {Matrix4} gizmoMatrix - Gizmos matrix.
2069
+ */
2070
+ onFocusAnim( time, point, cameraMatrix, gizmoMatrix ) {
2071
+
2072
+ if ( this._timeStart == - 1 ) {
2073
+
2074
+ //animation start
2075
+ this._timeStart = time;
2076
+
2077
+ }
2078
+
2079
+ if ( this._state == STATE.ANIMATION_FOCUS ) {
2080
+
2081
+ const deltaTime = time - this._timeStart;
2082
+ const animTime = deltaTime / this.focusAnimationTime;
2083
+
2084
+ this._gizmoMatrixState.copy( gizmoMatrix );
2085
+
2086
+ if ( animTime >= 1 ) {
2087
+
2088
+ //animation end
2089
+
2090
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
2091
+
2092
+ this.focus( point, this.scaleFactor );
2093
+
2094
+ this._timeStart = - 1;
2095
+ this.updateTbState( STATE.IDLE, false );
2096
+ this.activateGizmos( false );
2097
+
2098
+ this.dispatchEvent( _changeEvent );
2099
+
2100
+ } else {
2101
+
2102
+ const amount = this.easeOutCubic( animTime );
2103
+ const size = ( ( 1 - amount ) + ( this.scaleFactor * amount ) );
2104
+
2105
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
2106
+ this.focus( point, size, amount );
2107
+
2108
+ this.dispatchEvent( _changeEvent );
2109
+ const self = this;
2110
+ this._animationId = window.requestAnimationFrame( function ( t ) {
2111
+
2112
+ self.onFocusAnim( t, point, cameraMatrix, gizmoMatrix.clone() );
2113
+
2114
+ } );
2115
+
2116
+ }
2117
+
2118
+ } else {
2119
+
2120
+ //interrupt animation
2121
+
2122
+ this._animationId = - 1;
2123
+ this._timeStart = - 1;
2124
+
2125
+ }
2126
+
2127
+ }
2128
+
2129
+ /**
2130
+ * Performs animation for rotation operation.
2131
+ *
2132
+ * @private
2133
+ * @param {number} time - Instant in which this function is called as performance.now().
2134
+ * @param {Vector3} rotationAxis - Rotation axis.
2135
+ * @param {number} w0 - Initial angular velocity.
2136
+ */
2137
+ onRotationAnim( time, rotationAxis, w0 ) {
2138
+
2139
+ if ( this._timeStart == - 1 ) {
2140
+
2141
+ //animation start
2142
+ this._anglePrev = 0;
2143
+ this._angleCurrent = 0;
2144
+ this._timeStart = time;
2145
+
2146
+ }
2147
+
2148
+ if ( this._state == STATE.ANIMATION_ROTATE ) {
2149
+
2150
+ //w = w0 + alpha * t
2151
+ const deltaTime = ( time - this._timeStart ) / 1000;
2152
+ const w = w0 + ( ( - this.dampingFactor ) * deltaTime );
2153
+
2154
+ if ( w > 0 ) {
2155
+
2156
+ //tetha = 0.5 * alpha * t^2 + w0 * t + tetha0
2157
+ this._angleCurrent = 0.5 * ( - this.dampingFactor ) * Math.pow( deltaTime, 2 ) + w0 * deltaTime + 0;
2158
+ this.applyTransformMatrix( this.rotate( rotationAxis, this._angleCurrent ) );
2159
+ this.dispatchEvent( _changeEvent );
2160
+ const self = this;
2161
+ this._animationId = window.requestAnimationFrame( function ( t ) {
2162
+
2163
+ self.onRotationAnim( t, rotationAxis, w0 );
2164
+
2165
+ } );
2166
+
2167
+ } else {
2168
+
2169
+ this._animationId = - 1;
2170
+ this._timeStart = - 1;
2171
+
2172
+ this.updateTbState( STATE.IDLE, false );
2173
+ this.activateGizmos( false );
2174
+
2175
+ this.dispatchEvent( _changeEvent );
2176
+
2177
+ }
2178
+
2179
+ } else {
2180
+
2181
+ //interrupt animation
2182
+
2183
+ this._animationId = - 1;
2184
+ this._timeStart = - 1;
2185
+
2186
+ if ( this._state != STATE.ROTATE ) {
2187
+
2188
+ this.activateGizmos( false );
2189
+ this.dispatchEvent( _changeEvent );
2190
+
2191
+ }
2192
+
2193
+ }
2194
+
2195
+ }
2196
+
2197
+
2198
+ /**
2199
+ * Performs pan operation moving camera between two points.
2200
+ *
2201
+ * @private
2202
+ * @param {Vector3} p0 - Initial point.
2203
+ * @param {Vector3} p1 - Ending point.
2204
+ * @param {boolean} [adjust=false] - If movement should be adjusted considering camera distance (Perspective only).
2205
+ * @returns {Object}
2206
+ */
2207
+ pan( p0, p1, adjust = false ) {
2208
+
2209
+ const movement = p0.clone().sub( p1 );
2210
+
2211
+ if ( this.object.isOrthographicCamera ) {
2212
+
2213
+ //adjust movement amount
2214
+ movement.multiplyScalar( 1 / this.object.zoom );
2215
+
2216
+ } else if ( this.object.isPerspectiveCamera && adjust ) {
2217
+
2218
+ //adjust movement amount
2219
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState0 ); //camera's initial position
2220
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState0 ); //gizmo's initial position
2221
+ const distanceFactor = this._v3_1.distanceTo( this._v3_2 ) / this.object.position.distanceTo( this._gizmos.position );
2222
+ movement.multiplyScalar( 1 / distanceFactor );
2223
+
2224
+ }
2225
+
2226
+ this._v3_1.set( movement.x, movement.y, 0 ).applyQuaternion( this.object.quaternion );
2227
+
2228
+ this._m4_1.makeTranslation( this._v3_1.x, this._v3_1.y, this._v3_1.z );
2229
+
2230
+ this.setTransformationMatrices( this._m4_1, this._m4_1 );
2231
+ return _transformation;
2232
+
2233
+ }
2234
+
2235
+ /**
2236
+ * Resets the controls.
2237
+ */
2238
+ reset() {
2239
+
2240
+ this.target.copy( this._target0 );
2241
+ this.object.zoom = this._zoom0;
2242
+
2243
+ if ( this.object.isPerspectiveCamera ) {
2244
+
2245
+ this.object.fov = this._fov0;
2246
+
2247
+ }
2248
+
2249
+ this.object.near = this._nearPos;
2250
+ this.object.far = this._farPos;
2251
+ this._cameraMatrixState.copy( this._cameraMatrixState0 );
2252
+ this._cameraMatrixState.decompose( this.object.position, this.object.quaternion, this.object.scale );
2253
+ this.object.up.copy( this._up0 );
2254
+
2255
+ this.object.updateMatrix();
2256
+ this.object.updateProjectionMatrix();
2257
+
2258
+ this._gizmoMatrixState.copy( this._gizmoMatrixState0 );
2259
+ this._gizmoMatrixState0.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
2260
+ this._gizmos.updateMatrix();
2261
+
2262
+ this._tbRadius = this.calculateTbRadius( this.object );
2263
+ this.makeGizmos( this._gizmos.position, this._tbRadius );
2264
+
2265
+ this.object.lookAt( this._gizmos.position );
2266
+
2267
+ this.updateTbState( STATE.IDLE, false );
2268
+
2269
+ this.dispatchEvent( _changeEvent );
2270
+
2271
+ }
2272
+
2273
+ /**
2274
+ * Rotates the camera around an axis passing by trackball's center.
2275
+ *
2276
+ * @private
2277
+ * @param {Vector3} axis - Rotation axis.
2278
+ * @param {number} angle - Angle in radians.
2279
+ * @returns {Object} Object with 'camera' field containing transformation matrix resulting from the operation to be applied to the camera.
2280
+ */
2281
+ rotate( axis, angle ) {
2282
+
2283
+ const point = this._gizmos.position; //rotation center
2284
+ this._translationMatrix.makeTranslation( - point.x, - point.y, - point.z );
2285
+ this._rotationMatrix.makeRotationAxis( axis, - angle );
2286
+
2287
+ //rotate camera
2288
+ this._m4_1.makeTranslation( point.x, point.y, point.z );
2289
+ this._m4_1.multiply( this._rotationMatrix );
2290
+ this._m4_1.multiply( this._translationMatrix );
2291
+
2292
+ this.setTransformationMatrices( this._m4_1 );
2293
+
2294
+ return _transformation;
2295
+
2296
+ }
2297
+
2298
+ /**
2299
+ * Copy the current state to clipboard (as a readable JSON text).
2300
+ */
2301
+ copyState() {
2302
+
2303
+ let state;
2304
+ if ( this.object.isOrthographicCamera ) {
2305
+
2306
+ state = JSON.stringify( {
2307
+ arcballState: {
2308
+ cameraFar: this.object.far,
2309
+ cameraMatrix: this.object.matrix,
2310
+ cameraNear: this.object.near,
2311
+ cameraUp: this.object.up,
2312
+ cameraZoom: this.object.zoom,
2313
+ gizmoMatrix: this._gizmos.matrix,
2314
+ target: this.target
2315
+
2316
+ }
2317
+ } );
2318
+
2319
+ } else if ( this.object.isPerspectiveCamera ) {
2320
+
2321
+ state = JSON.stringify( {
2322
+ arcballState: {
2323
+ cameraFar: this.object.far,
2324
+ cameraFov: this.object.fov,
2325
+ cameraMatrix: this.object.matrix,
2326
+ cameraNear: this.object.near,
2327
+ cameraUp: this.object.up,
2328
+ cameraZoom: this.object.zoom,
2329
+ gizmoMatrix: this._gizmos.matrix,
2330
+ target: this.target
2331
+
2332
+ }
2333
+ } );
2334
+
2335
+ }
2336
+
2337
+ navigator.clipboard.writeText( state );
2338
+
2339
+ }
2340
+
2341
+ /**
2342
+ * Set the controls state from the clipboard, assumes that the clipboard stores a JSON
2343
+ * text as saved from `copyState()`.
2344
+ */
2345
+ pasteState() {
2346
+
2347
+ const self = this;
2348
+ navigator.clipboard.readText().then( function resolved( value ) {
2349
+
2350
+ self.setStateFromJSON( value );
2351
+
2352
+ } );
2353
+
2354
+ }
2355
+
2356
+ /**
2357
+ * Saves the current state of the control. This can later be recover with `reset()`.
2358
+ */
2359
+ saveState() {
2360
+
2361
+ this.object.updateMatrix();
2362
+ this._gizmos.updateMatrix();
2363
+
2364
+ this._target0.copy( this.target );
2365
+ this._cameraMatrixState0.copy( this.object.matrix );
2366
+ this._gizmoMatrixState0.copy( this._gizmos.matrix );
2367
+ this._nearPos = this.object.near;
2368
+ this._farPos = this.object.far;
2369
+ this._zoom0 = this.object.zoom;
2370
+ this._up0.copy( this.object.up );
2371
+
2372
+ if ( this.object.isPerspectiveCamera ) {
2373
+
2374
+ this._fov0 = this.object.fov;
2375
+
2376
+ }
2377
+
2378
+ }
2379
+
2380
+ /**
2381
+ * Performs uniform scale operation around a given point.
2382
+ *
2383
+ * @private
2384
+ * @param {number} size - Scale factor.
2385
+ * @param {Vector3} point - Point around which scale.
2386
+ * @param {boolean} scaleGizmos - If gizmos should be scaled (Perspective only).
2387
+ * @returns {Object} Object with 'camera' and 'gizmo' fields containing transformation matrices resulting from the operation to be applied to the camera and gizmos.
2388
+ */
2389
+ scale( size, point, scaleGizmos = true ) {
2390
+
2391
+ _scalePointTemp.copy( point );
2392
+ let sizeInverse = 1 / size;
2393
+
2394
+ if ( this.object.isOrthographicCamera ) {
2395
+
2396
+ //camera zoom
2397
+ this.object.zoom = this._zoomState;
2398
+ this.object.zoom *= size;
2399
+
2400
+ //check min and max zoom
2401
+ if ( this.object.zoom > this.maxZoom ) {
2402
+
2403
+ this.object.zoom = this.maxZoom;
2404
+ sizeInverse = this._zoomState / this.maxZoom;
2405
+
2406
+ } else if ( this.object.zoom < this.minZoom ) {
2407
+
2408
+ this.object.zoom = this.minZoom;
2409
+ sizeInverse = this._zoomState / this.minZoom;
2410
+
2411
+ }
2412
+
2413
+ this.object.updateProjectionMatrix();
2414
+
2415
+ this._v3_1.setFromMatrixPosition( this._gizmoMatrixState ); //gizmos position
2416
+
2417
+ //scale gizmos so they appear in the same spot having the same dimension
2418
+ this._scaleMatrix.makeScale( sizeInverse, sizeInverse, sizeInverse );
2419
+ this._translationMatrix.makeTranslation( - this._v3_1.x, - this._v3_1.y, - this._v3_1.z );
2420
+
2421
+ this._m4_2.makeTranslation( this._v3_1.x, this._v3_1.y, this._v3_1.z ).multiply( this._scaleMatrix );
2422
+ this._m4_2.multiply( this._translationMatrix );
2423
+
2424
+
2425
+ //move camera and gizmos to obtain pinch effect
2426
+ _scalePointTemp.sub( this._v3_1 );
2427
+
2428
+ const amount = _scalePointTemp.clone().multiplyScalar( sizeInverse );
2429
+ _scalePointTemp.sub( amount );
2430
+
2431
+ this._m4_1.makeTranslation( _scalePointTemp.x, _scalePointTemp.y, _scalePointTemp.z );
2432
+ this._m4_2.premultiply( this._m4_1 );
2433
+
2434
+ this.setTransformationMatrices( this._m4_1, this._m4_2 );
2435
+ return _transformation;
2436
+
2437
+ } else if ( this.object.isPerspectiveCamera ) {
2438
+
2439
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
2440
+ this._v3_2.setFromMatrixPosition( this._gizmoMatrixState );
2441
+
2442
+ //move camera
2443
+ let distance = this._v3_1.distanceTo( _scalePointTemp );
2444
+ let amount = distance - ( distance * sizeInverse );
2445
+
2446
+ //check min and max distance
2447
+ const newDistance = distance - amount;
2448
+ if ( newDistance < this.minDistance ) {
2449
+
2450
+ sizeInverse = this.minDistance / distance;
2451
+ amount = distance - ( distance * sizeInverse );
2452
+
2453
+ } else if ( newDistance > this.maxDistance ) {
2454
+
2455
+ sizeInverse = this.maxDistance / distance;
2456
+ amount = distance - ( distance * sizeInverse );
2457
+
2458
+ }
2459
+
2460
+ _offset.copy( _scalePointTemp ).sub( this._v3_1 ).normalize().multiplyScalar( amount );
2461
+
2462
+ this._m4_1.makeTranslation( _offset.x, _offset.y, _offset.z );
2463
+
2464
+
2465
+ if ( scaleGizmos ) {
2466
+
2467
+ //scale gizmos so they appear in the same spot having the same dimension
2468
+ const pos = this._v3_2;
2469
+
2470
+ distance = pos.distanceTo( _scalePointTemp );
2471
+ amount = distance - ( distance * sizeInverse );
2472
+ _offset.copy( _scalePointTemp ).sub( this._v3_2 ).normalize().multiplyScalar( amount );
2473
+
2474
+ this._translationMatrix.makeTranslation( pos.x, pos.y, pos.z );
2475
+ this._scaleMatrix.makeScale( sizeInverse, sizeInverse, sizeInverse );
2476
+
2477
+ this._m4_2.makeTranslation( _offset.x, _offset.y, _offset.z ).multiply( this._translationMatrix );
2478
+ this._m4_2.multiply( this._scaleMatrix );
2479
+
2480
+ this._translationMatrix.makeTranslation( - pos.x, - pos.y, - pos.z );
2481
+
2482
+ this._m4_2.multiply( this._translationMatrix );
2483
+ this.setTransformationMatrices( this._m4_1, this._m4_2 );
2484
+
2485
+
2486
+ } else {
2487
+
2488
+ this.setTransformationMatrices( this._m4_1 );
2489
+
2490
+ }
2491
+
2492
+ return _transformation;
2493
+
2494
+ }
2495
+
2496
+ }
2497
+
2498
+ /**
2499
+ * Sets camera fov.
2500
+ *
2501
+ * @private
2502
+ * @param {number} value - The FOV to be set.
2503
+ */
2504
+ setFov( value ) {
2505
+
2506
+ if ( this.object.isPerspectiveCamera ) {
2507
+
2508
+ this.object.fov = MathUtils.clamp( value, this.minFov, this.maxFov );
2509
+ this.object.updateProjectionMatrix();
2510
+
2511
+ }
2512
+
2513
+ }
2514
+
2515
+ /**
2516
+ * Sets values in transformation object.
2517
+ *
2518
+ * @private
2519
+ * @param {?Matrix4} [camera=null] - Transformation to be applied to the camera.
2520
+ * @param {?Matrix4} [gizmos=null] - Transformation to be applied to gizmos.
2521
+ */
2522
+ setTransformationMatrices( camera = null, gizmos = null ) {
2523
+
2524
+ if ( camera != null ) {
2525
+
2526
+ if ( _transformation.camera != null ) {
2527
+
2528
+ _transformation.camera.copy( camera );
2529
+
2530
+ } else {
2531
+
2532
+ _transformation.camera = camera.clone();
2533
+
2534
+ }
2535
+
2536
+ } else {
2537
+
2538
+ _transformation.camera = null;
2539
+
2540
+ }
2541
+
2542
+ if ( gizmos != null ) {
2543
+
2544
+ if ( _transformation.gizmos != null ) {
2545
+
2546
+ _transformation.gizmos.copy( gizmos );
2547
+
2548
+ } else {
2549
+
2550
+ _transformation.gizmos = gizmos.clone();
2551
+
2552
+ }
2553
+
2554
+ } else {
2555
+
2556
+ _transformation.gizmos = null;
2557
+
2558
+ }
2559
+
2560
+ }
2561
+
2562
+ /**
2563
+ * Rotates camera around its direction axis passing by a given point by a given angle.
2564
+ *
2565
+ * @private
2566
+ * @param {Vector3} point - The point where the rotation axis is passing through.
2567
+ * @param {number} angle - Angle in radians.
2568
+ * @returns {Object} The computed transformation matrix.
2569
+ */
2570
+ zRotate( point, angle ) {
2571
+
2572
+ this._rotationMatrix.makeRotationAxis( this._rotationAxis, angle );
2573
+ this._translationMatrix.makeTranslation( - point.x, - point.y, - point.z );
2574
+
2575
+ this._m4_1.makeTranslation( point.x, point.y, point.z );
2576
+ this._m4_1.multiply( this._rotationMatrix );
2577
+ this._m4_1.multiply( this._translationMatrix );
2578
+
2579
+ this._v3_1.setFromMatrixPosition( this._gizmoMatrixState ).sub( point ); //vector from rotation center to gizmos position
2580
+ this._v3_2.copy( this._v3_1 ).applyAxisAngle( this._rotationAxis, angle ); //apply rotation
2581
+ this._v3_2.sub( this._v3_1 );
2582
+
2583
+ this._m4_2.makeTranslation( this._v3_2.x, this._v3_2.y, this._v3_2.z );
2584
+
2585
+ this.setTransformationMatrices( this._m4_1, this._m4_2 );
2586
+ return _transformation;
2587
+
2588
+ }
2589
+
2590
+ /**
2591
+ * Returns the raycaster that is used for user interaction. This object is shared between all
2592
+ * instances of `ArcballControls`.
2593
+ *
2594
+ * @returns {Raycaster} The internal raycaster.
2595
+ */
2596
+ getRaycaster() {
2597
+
2598
+ return _raycaster;
2599
+
2600
+ }
2601
+
2602
+
2603
+ /**
2604
+ * Unprojects the cursor on the 3D object surface.
2605
+ *
2606
+ * @private
2607
+ * @param {Vector2} cursor - Cursor coordinates in NDC.
2608
+ * @param {Camera} camera - Virtual camera.
2609
+ * @returns {?Vector3} The point of intersection with the model, if exist, null otherwise.
2610
+ */
2611
+ unprojectOnObj( cursor, camera ) {
2612
+
2613
+ const raycaster = this.getRaycaster();
2614
+ raycaster.near = camera.near;
2615
+ raycaster.far = camera.far;
2616
+ raycaster.setFromCamera( cursor, camera );
2617
+
2618
+ const intersect = raycaster.intersectObjects( this.scene.children, true );
2619
+
2620
+ for ( let i = 0; i < intersect.length; i ++ ) {
2621
+
2622
+ if ( intersect[ i ].object.uuid != this._gizmos.uuid && intersect[ i ].face != null ) {
2623
+
2624
+ return intersect[ i ].point.clone();
2625
+
2626
+ }
2627
+
2628
+ }
2629
+
2630
+ return null;
2631
+
2632
+ }
2633
+
2634
+ /**
2635
+ * Unproject the cursor on the trackball surface.
2636
+ *
2637
+ * @private
2638
+ * @param {Camera} camera - The virtual camera.
2639
+ * @param {number} cursorX - Cursor horizontal coordinate on screen.
2640
+ * @param {number} cursorY - Cursor vertical coordinate on screen.
2641
+ * @param {HTMLElement} canvas - The canvas where the renderer draws its output.
2642
+ * @param {number} tbRadius - The trackball radius.
2643
+ * @returns {Vector3} The unprojected point on the trackball surface.
2644
+ */
2645
+ unprojectOnTbSurface( camera, cursorX, cursorY, canvas, tbRadius ) {
2646
+
2647
+ if ( camera.type == 'OrthographicCamera' ) {
2648
+
2649
+ this._v2_1.copy( this.getCursorPosition( cursorX, cursorY, canvas ) );
2650
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
2651
+
2652
+ const x2 = Math.pow( this._v2_1.x, 2 );
2653
+ const y2 = Math.pow( this._v2_1.y, 2 );
2654
+ const r2 = Math.pow( this._tbRadius, 2 );
2655
+
2656
+ if ( x2 + y2 <= r2 * 0.5 ) {
2657
+
2658
+ //intersection with sphere
2659
+ this._v3_1.setZ( Math.sqrt( r2 - ( x2 + y2 ) ) );
2660
+
2661
+ } else {
2662
+
2663
+ //intersection with hyperboloid
2664
+ this._v3_1.setZ( ( r2 * 0.5 ) / ( Math.sqrt( x2 + y2 ) ) );
2665
+
2666
+ }
2667
+
2668
+ return this._v3_1;
2669
+
2670
+ } else if ( camera.type == 'PerspectiveCamera' ) {
2671
+
2672
+ //unproject cursor on the near plane
2673
+ this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
2674
+
2675
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, - 1 );
2676
+ this._v3_1.applyMatrix4( camera.projectionMatrixInverse );
2677
+
2678
+ const rayDir = this._v3_1.clone().normalize(); //unprojected ray direction
2679
+ const cameraGizmoDistance = camera.position.distanceTo( this._gizmos.position );
2680
+ const radius2 = Math.pow( tbRadius, 2 );
2681
+
2682
+ // camera
2683
+ // |\
2684
+ // | \
2685
+ // | \
2686
+ // h | \
2687
+ // | \
2688
+ // | \
2689
+ // _ _ | _ _ _\ _ _ near plane
2690
+ // l
2691
+
2692
+ const h = this._v3_1.z;
2693
+ const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
2694
+
2695
+ if ( l == 0 ) {
2696
+
2697
+ //ray aligned with camera
2698
+ rayDir.set( this._v3_1.x, this._v3_1.y, tbRadius );
2699
+ return rayDir;
2700
+
2701
+ }
2702
+
2703
+ const m = h / l;
2704
+ const q = cameraGizmoDistance;
2705
+
2706
+ /*
2707
+ * calculate intersection point between unprojected ray and trackball surface
2708
+ *|y = m * x + q
2709
+ *|x^2 + y^2 = r^2
2710
+ *
2711
+ * (m^2 + 1) * x^2 + (2 * m * q) * x + q^2 - r^2 = 0
2712
+ */
2713
+ let a = Math.pow( m, 2 ) + 1;
2714
+ let b = 2 * m * q;
2715
+ let c = Math.pow( q, 2 ) - radius2;
2716
+ let delta = Math.pow( b, 2 ) - ( 4 * a * c );
2717
+
2718
+ if ( delta >= 0 ) {
2719
+
2720
+ //intersection with sphere
2721
+ this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
2722
+ this._v2_1.setY( m * this._v2_1.x + q );
2723
+
2724
+ const angle = MathUtils.RAD2DEG * this._v2_1.angle();
2725
+
2726
+ if ( angle >= 45 ) {
2727
+
2728
+ //if angle between intersection point and X' axis is >= 45°, return that point
2729
+ //otherwise, calculate intersection point with hyperboloid
2730
+
2731
+ const rayLength = Math.sqrt( Math.pow( this._v2_1.x, 2 ) + Math.pow( ( cameraGizmoDistance - this._v2_1.y ), 2 ) );
2732
+ rayDir.multiplyScalar( rayLength );
2733
+ rayDir.z += cameraGizmoDistance;
2734
+ return rayDir;
2735
+
2736
+ }
2737
+
2738
+ }
2739
+
2740
+ //intersection with hyperboloid
2741
+ /*
2742
+ *|y = m * x + q
2743
+ *|y = (1 / x) * (r^2 / 2)
2744
+ *
2745
+ * m * x^2 + q * x - r^2 / 2 = 0
2746
+ */
2747
+
2748
+ a = m;
2749
+ b = q;
2750
+ c = - radius2 * 0.5;
2751
+ delta = Math.pow( b, 2 ) - ( 4 * a * c );
2752
+ this._v2_1.setX( ( - b - Math.sqrt( delta ) ) / ( 2 * a ) );
2753
+ this._v2_1.setY( m * this._v2_1.x + q );
2754
+
2755
+ const rayLength = Math.sqrt( Math.pow( this._v2_1.x, 2 ) + Math.pow( ( cameraGizmoDistance - this._v2_1.y ), 2 ) );
2756
+
2757
+ rayDir.multiplyScalar( rayLength );
2758
+ rayDir.z += cameraGizmoDistance;
2759
+ return rayDir;
2760
+
2761
+ }
2762
+
2763
+ }
2764
+
2765
+
2766
+ /**
2767
+ * Unprojects the cursor on the plane passing through the center of the trackball orthogonal to the camera.
2768
+ *
2769
+ * @private
2770
+ * @param {Camera} camera - The virtual camera.
2771
+ * @param {number} cursorX - Cursor horizontal coordinate on screen.
2772
+ * @param {number} cursorY - Cursor vertical coordinate on screen.
2773
+ * @param {HTMLElement} canvas - The canvas where the renderer draws its output.
2774
+ * @param {boolean} [initialDistance=false] - If initial distance between camera and gizmos should be used for calculations instead of current (Perspective only).
2775
+ * @returns {Vector3} The unprojected point on the trackball plane.
2776
+ */
2777
+ unprojectOnTbPlane( camera, cursorX, cursorY, canvas, initialDistance = false ) {
2778
+
2779
+ if ( camera.type == 'OrthographicCamera' ) {
2780
+
2781
+ this._v2_1.copy( this.getCursorPosition( cursorX, cursorY, canvas ) );
2782
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, 0 );
2783
+
2784
+ return this._v3_1.clone();
2785
+
2786
+ } else if ( camera.type == 'PerspectiveCamera' ) {
2787
+
2788
+ this._v2_1.copy( this.getCursorNDC( cursorX, cursorY, canvas ) );
2789
+
2790
+ //unproject cursor on the near plane
2791
+ this._v3_1.set( this._v2_1.x, this._v2_1.y, - 1 );
2792
+ this._v3_1.applyMatrix4( camera.projectionMatrixInverse );
2793
+
2794
+ const rayDir = this._v3_1.clone().normalize(); //unprojected ray direction
2795
+
2796
+ // camera
2797
+ // |\
2798
+ // | \
2799
+ // | \
2800
+ // h | \
2801
+ // | \
2802
+ // | \
2803
+ // _ _ | _ _ _\ _ _ near plane
2804
+ // l
2805
+
2806
+ const h = this._v3_1.z;
2807
+ const l = Math.sqrt( Math.pow( this._v3_1.x, 2 ) + Math.pow( this._v3_1.y, 2 ) );
2808
+ let cameraGizmoDistance;
2809
+
2810
+ if ( initialDistance ) {
2811
+
2812
+ cameraGizmoDistance = this._v3_1.setFromMatrixPosition( this._cameraMatrixState0 ).distanceTo( this._v3_2.setFromMatrixPosition( this._gizmoMatrixState0 ) );
2813
+
2814
+ } else {
2815
+
2816
+ cameraGizmoDistance = camera.position.distanceTo( this._gizmos.position );
2817
+
2818
+ }
2819
+
2820
+ /*
2821
+ * calculate intersection point between unprojected ray and the plane
2822
+ *|y = mx + q
2823
+ *|y = 0
2824
+ *
2825
+ * x = -q/m
2826
+ */
2827
+ if ( l == 0 ) {
2828
+
2829
+ //ray aligned with camera
2830
+ rayDir.set( 0, 0, 0 );
2831
+ return rayDir;
2832
+
2833
+ }
2834
+
2835
+ const m = h / l;
2836
+ const q = cameraGizmoDistance;
2837
+ const x = - q / m;
2838
+
2839
+ const rayLength = Math.sqrt( Math.pow( q, 2 ) + Math.pow( x, 2 ) );
2840
+ rayDir.multiplyScalar( rayLength );
2841
+ rayDir.z = 0;
2842
+ return rayDir;
2843
+
2844
+ }
2845
+
2846
+ }
2847
+
2848
+ /**
2849
+ * Updates camera and gizmos state.
2850
+ *
2851
+ * @private
2852
+ */
2853
+ updateMatrixState() {
2854
+
2855
+ //update camera and gizmos state
2856
+ this._cameraMatrixState.copy( this.object.matrix );
2857
+ this._gizmoMatrixState.copy( this._gizmos.matrix );
2858
+
2859
+ if ( this.object.isOrthographicCamera ) {
2860
+
2861
+ this._cameraProjectionState.copy( this.object.projectionMatrix );
2862
+ this.object.updateProjectionMatrix();
2863
+ this._zoomState = this.object.zoom;
2864
+
2865
+ } else if ( this.object.isPerspectiveCamera ) {
2866
+
2867
+ this._fovState = this.object.fov;
2868
+
2869
+ }
2870
+
2871
+ }
2872
+
2873
+ /**
2874
+ * Updates the trackball FSA.
2875
+ *
2876
+ * @private
2877
+ * @param {STATE} newState - New state of the FSA.
2878
+ * @param {boolean} updateMatrices - If matrices state should be updated.
2879
+ */
2880
+ updateTbState( newState, updateMatrices ) {
2881
+
2882
+ this._state = newState;
2883
+ if ( updateMatrices ) {
2884
+
2885
+ this.updateMatrixState();
2886
+
2887
+ }
2888
+
2889
+ }
2890
+
2891
+ update() {
2892
+
2893
+ if ( this.target.equals( this._currentTarget ) === false ) {
2894
+
2895
+ this._gizmos.position.copy( this.target ); //for correct radius calculation
2896
+ this._tbRadius = this.calculateTbRadius( this.object );
2897
+ this.makeGizmos( this.target, this._tbRadius );
2898
+ this._currentTarget.copy( this.target );
2899
+
2900
+ }
2901
+
2902
+ //check min/max parameters
2903
+ if ( this.object.isOrthographicCamera ) {
2904
+
2905
+ //check zoom
2906
+ if ( this.object.zoom > this.maxZoom || this.object.zoom < this.minZoom ) {
2907
+
2908
+ const newZoom = MathUtils.clamp( this.object.zoom, this.minZoom, this.maxZoom );
2909
+ this.applyTransformMatrix( this.scale( newZoom / this.object.zoom, this._gizmos.position, true ) );
2910
+
2911
+ }
2912
+
2913
+ } else if ( this.object.isPerspectiveCamera ) {
2914
+
2915
+ //check distance
2916
+ const distance = this.object.position.distanceTo( this._gizmos.position );
2917
+
2918
+ if ( distance > this.maxDistance + _EPS || distance < this.minDistance - _EPS ) {
2919
+
2920
+ const newDistance = MathUtils.clamp( distance, this.minDistance, this.maxDistance );
2921
+ this.applyTransformMatrix( this.scale( newDistance / distance, this._gizmos.position ) );
2922
+ this.updateMatrixState();
2923
+
2924
+ }
2925
+
2926
+ //check fov
2927
+ if ( this.object.fov < this.minFov || this.object.fov > this.maxFov ) {
2928
+
2929
+ this.object.fov = MathUtils.clamp( this.object.fov, this.minFov, this.maxFov );
2930
+ this.object.updateProjectionMatrix();
2931
+
2932
+ }
2933
+
2934
+ const oldRadius = this._tbRadius;
2935
+ this._tbRadius = this.calculateTbRadius( this.object );
2936
+
2937
+ if ( oldRadius < this._tbRadius - _EPS || oldRadius > this._tbRadius + _EPS ) {
2938
+
2939
+ const scale = ( this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z ) / 3;
2940
+ const newRadius = this._tbRadius / scale;
2941
+ const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
2942
+ const points = curve.getPoints( this._curvePts );
2943
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
2944
+
2945
+ for ( const gizmo in this._gizmos.children ) {
2946
+
2947
+ this._gizmos.children[ gizmo ].geometry = curveGeometry;
2948
+
2949
+ }
2950
+
2951
+ }
2952
+
2953
+ }
2954
+
2955
+ this.object.lookAt( this._gizmos.position );
2956
+
2957
+ }
2958
+
2959
+ setStateFromJSON( json ) {
2960
+
2961
+ const state = JSON.parse( json );
2962
+
2963
+ if ( state.arcballState != undefined ) {
2964
+
2965
+ this.target.fromArray( state.arcballState.target );
2966
+
2967
+ this._cameraMatrixState.fromArray( state.arcballState.cameraMatrix.elements );
2968
+ this._cameraMatrixState.decompose( this.object.position, this.object.quaternion, this.object.scale );
2969
+
2970
+ this.object.up.copy( state.arcballState.cameraUp );
2971
+ this.object.near = state.arcballState.cameraNear;
2972
+ this.object.far = state.arcballState.cameraFar;
2973
+
2974
+ this.object.zoom = state.arcballState.cameraZoom;
2975
+
2976
+ if ( this.object.isPerspectiveCamera ) {
2977
+
2978
+ this.object.fov = state.arcballState.cameraFov;
2979
+
2980
+ }
2981
+
2982
+ this._gizmoMatrixState.fromArray( state.arcballState.gizmoMatrix.elements );
2983
+ this._gizmoMatrixState.decompose( this._gizmos.position, this._gizmos.quaternion, this._gizmos.scale );
2984
+
2985
+ this.object.updateMatrix();
2986
+ this.object.updateProjectionMatrix();
2987
+
2988
+ this._gizmos.updateMatrix();
2989
+
2990
+ this._tbRadius = this.calculateTbRadius( this.object );
2991
+ const gizmoTmp = new Matrix4().copy( this._gizmoMatrixState0 );
2992
+ this.makeGizmos( this._gizmos.position, this._tbRadius );
2993
+ this._gizmoMatrixState0.copy( gizmoTmp );
2994
+
2995
+ this.object.lookAt( this._gizmos.position );
2996
+ this.updateTbState( STATE.IDLE, false );
2997
+
2998
+ this.dispatchEvent( _changeEvent );
2999
+
3000
+ }
3001
+
3002
+ }
3003
+
3004
+ }
3005
+
3006
+ //listeners
3007
+
3008
+ function onWindowResize() {
3009
+
3010
+ const scale = ( this._gizmos.scale.x + this._gizmos.scale.y + this._gizmos.scale.z ) / 3;
3011
+ this._tbRadius = this.calculateTbRadius( this.object );
3012
+
3013
+ const newRadius = this._tbRadius / scale;
3014
+ const curve = new EllipseCurve( 0, 0, newRadius, newRadius );
3015
+ const points = curve.getPoints( this._curvePts );
3016
+ const curveGeometry = new BufferGeometry().setFromPoints( points );
3017
+
3018
+
3019
+ for ( const gizmo in this._gizmos.children ) {
3020
+
3021
+ this._gizmos.children[ gizmo ].geometry = curveGeometry;
3022
+
3023
+ }
3024
+
3025
+ this.dispatchEvent( _changeEvent );
3026
+
3027
+ }
3028
+
3029
+ function onContextMenu( event ) {
3030
+
3031
+ if ( ! this.enabled ) {
3032
+
3033
+ return;
3034
+
3035
+ }
3036
+
3037
+ for ( let i = 0; i < this.mouseActions.length; i ++ ) {
3038
+
3039
+ if ( this.mouseActions[ i ].mouse == 2 ) {
3040
+
3041
+ //prevent only if button 2 is actually used
3042
+ event.preventDefault();
3043
+ break;
3044
+
3045
+ }
3046
+
3047
+ }
3048
+
3049
+ }
3050
+
3051
+ function onPointerCancel() {
3052
+
3053
+ this._touchStart.splice( 0, this._touchStart.length );
3054
+ this._touchCurrent.splice( 0, this._touchCurrent.length );
3055
+ this._input = INPUT.NONE;
3056
+
3057
+ }
3058
+
3059
+ function onPointerDown( event ) {
3060
+
3061
+ if ( event.button == 0 && event.isPrimary ) {
3062
+
3063
+ this._downValid = true;
3064
+ this._downEvents.push( event );
3065
+ this._downStart = performance.now();
3066
+
3067
+ } else {
3068
+
3069
+ this._downValid = false;
3070
+
3071
+ }
3072
+
3073
+ if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
3074
+
3075
+ this._touchStart.push( event );
3076
+ this._touchCurrent.push( event );
3077
+
3078
+ switch ( this._input ) {
3079
+
3080
+ case INPUT.NONE:
3081
+
3082
+ //singleStart
3083
+ this._input = INPUT.ONE_FINGER;
3084
+ this.onSinglePanStart( event, 'ROTATE' );
3085
+
3086
+ window.addEventListener( 'pointermove', this._onPointerMove );
3087
+ window.addEventListener( 'pointerup', this._onPointerUp );
3088
+
3089
+ break;
3090
+
3091
+ case INPUT.ONE_FINGER:
3092
+ case INPUT.ONE_FINGER_SWITCHED:
3093
+
3094
+ //doubleStart
3095
+ this._input = INPUT.TWO_FINGER;
3096
+
3097
+ this.onRotateStart();
3098
+ this.onPinchStart();
3099
+ this.onDoublePanStart();
3100
+
3101
+ break;
3102
+
3103
+ case INPUT.TWO_FINGER:
3104
+
3105
+ //multipleStart
3106
+ this._input = INPUT.MULT_FINGER;
3107
+ this.onTriplePanStart( event );
3108
+ break;
3109
+
3110
+ }
3111
+
3112
+ } else if ( event.pointerType != 'touch' && this._input == INPUT.NONE ) {
3113
+
3114
+ let modifier = null;
3115
+
3116
+ if ( event.ctrlKey || event.metaKey ) {
3117
+
3118
+ modifier = 'CTRL';
3119
+
3120
+ } else if ( event.shiftKey ) {
3121
+
3122
+ modifier = 'SHIFT';
3123
+
3124
+ }
3125
+
3126
+ this._mouseOp = this.getOpFromAction( event.button, modifier );
3127
+ if ( this._mouseOp != null ) {
3128
+
3129
+ window.addEventListener( 'pointermove', this._onPointerMove );
3130
+ window.addEventListener( 'pointerup', this._onPointerUp );
3131
+
3132
+ //singleStart
3133
+ this._input = INPUT.CURSOR;
3134
+ this._button = event.button;
3135
+ this.onSinglePanStart( event, this._mouseOp );
3136
+
3137
+ }
3138
+
3139
+ }
3140
+
3141
+ }
3142
+
3143
+ function onPointerMove( event ) {
3144
+
3145
+ if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
3146
+
3147
+ switch ( this._input ) {
3148
+
3149
+ case INPUT.ONE_FINGER:
3150
+
3151
+ //singleMove
3152
+ this.updateTouchEvent( event );
3153
+
3154
+ this.onSinglePanMove( event, STATE.ROTATE );
3155
+ break;
3156
+
3157
+ case INPUT.ONE_FINGER_SWITCHED:
3158
+
3159
+ const movement = this.calculatePointersDistance( this._touchCurrent[ 0 ], event ) * this._devPxRatio;
3160
+
3161
+ if ( movement >= this._switchSensibility ) {
3162
+
3163
+ //singleMove
3164
+ this._input = INPUT.ONE_FINGER;
3165
+ this.updateTouchEvent( event );
3166
+
3167
+ this.onSinglePanStart( event, 'ROTATE' );
3168
+ break;
3169
+
3170
+ }
3171
+
3172
+ break;
3173
+
3174
+ case INPUT.TWO_FINGER:
3175
+
3176
+ //rotate/pan/pinchMove
3177
+ this.updateTouchEvent( event );
3178
+
3179
+ this.onRotateMove();
3180
+ this.onPinchMove();
3181
+ this.onDoublePanMove();
3182
+
3183
+ break;
3184
+
3185
+ case INPUT.MULT_FINGER:
3186
+
3187
+ //multMove
3188
+ this.updateTouchEvent( event );
3189
+
3190
+ this.onTriplePanMove( event );
3191
+ break;
3192
+
3193
+ }
3194
+
3195
+ } else if ( event.pointerType != 'touch' && this._input == INPUT.CURSOR ) {
3196
+
3197
+ let modifier = null;
3198
+
3199
+ if ( event.ctrlKey || event.metaKey ) {
3200
+
3201
+ modifier = 'CTRL';
3202
+
3203
+ } else if ( event.shiftKey ) {
3204
+
3205
+ modifier = 'SHIFT';
3206
+
3207
+ }
3208
+
3209
+ const mouseOpState = this.getOpStateFromAction( this._button, modifier );
3210
+
3211
+ if ( mouseOpState != null ) {
3212
+
3213
+ this.onSinglePanMove( event, mouseOpState );
3214
+
3215
+ }
3216
+
3217
+ }
3218
+
3219
+ //checkDistance
3220
+ if ( this._downValid ) {
3221
+
3222
+ const movement = this.calculatePointersDistance( this._downEvents[ this._downEvents.length - 1 ], event ) * this._devPxRatio;
3223
+ if ( movement > this._movementThreshold ) {
3224
+
3225
+ this._downValid = false;
3226
+
3227
+ }
3228
+
3229
+ }
3230
+
3231
+ }
3232
+
3233
+ function onPointerUp( event ) {
3234
+
3235
+ if ( event.pointerType == 'touch' && this._input != INPUT.CURSOR ) {
3236
+
3237
+ const nTouch = this._touchCurrent.length;
3238
+
3239
+ for ( let i = 0; i < nTouch; i ++ ) {
3240
+
3241
+ if ( this._touchCurrent[ i ].pointerId == event.pointerId ) {
3242
+
3243
+ this._touchCurrent.splice( i, 1 );
3244
+ this._touchStart.splice( i, 1 );
3245
+ break;
3246
+
3247
+ }
3248
+
3249
+ }
3250
+
3251
+ switch ( this._input ) {
3252
+
3253
+ case INPUT.ONE_FINGER:
3254
+ case INPUT.ONE_FINGER_SWITCHED:
3255
+
3256
+ //singleEnd
3257
+ window.removeEventListener( 'pointermove', this._onPointerMove );
3258
+ window.removeEventListener( 'pointerup', this._onPointerUp );
3259
+
3260
+ this._input = INPUT.NONE;
3261
+ this.onSinglePanEnd();
3262
+
3263
+ break;
3264
+
3265
+ case INPUT.TWO_FINGER:
3266
+
3267
+ //doubleEnd
3268
+ this.onDoublePanEnd( event );
3269
+ this.onPinchEnd( event );
3270
+ this.onRotateEnd( event );
3271
+
3272
+ //switching to singleStart
3273
+ this._input = INPUT.ONE_FINGER_SWITCHED;
3274
+
3275
+ break;
3276
+
3277
+ case INPUT.MULT_FINGER:
3278
+
3279
+ if ( this._touchCurrent.length == 0 ) {
3280
+
3281
+ window.removeEventListener( 'pointermove', this._onPointerMove );
3282
+ window.removeEventListener( 'pointerup', this._onPointerUp );
3283
+
3284
+ //multCancel
3285
+ this._input = INPUT.NONE;
3286
+ this.onTriplePanEnd();
3287
+
3288
+ }
3289
+
3290
+ break;
3291
+
3292
+ }
3293
+
3294
+ } else if ( event.pointerType != 'touch' && this._input == INPUT.CURSOR ) {
3295
+
3296
+ window.removeEventListener( 'pointermove', this._onPointerMove );
3297
+ window.removeEventListener( 'pointerup', this._onPointerUp );
3298
+
3299
+ this._input = INPUT.NONE;
3300
+ this.onSinglePanEnd();
3301
+ this._button = - 1;
3302
+
3303
+ }
3304
+
3305
+ if ( event.isPrimary ) {
3306
+
3307
+ if ( this._downValid ) {
3308
+
3309
+ const downTime = event.timeStamp - this._downEvents[ this._downEvents.length - 1 ].timeStamp;
3310
+
3311
+ if ( downTime <= this._maxDownTime ) {
3312
+
3313
+ if ( this._nclicks == 0 ) {
3314
+
3315
+ //first valid click detected
3316
+ this._nclicks = 1;
3317
+ this._clickStart = performance.now();
3318
+
3319
+ } else {
3320
+
3321
+ const clickInterval = event.timeStamp - this._clickStart;
3322
+ const movement = this.calculatePointersDistance( this._downEvents[ 1 ], this._downEvents[ 0 ] ) * this._devPxRatio;
3323
+
3324
+ if ( clickInterval <= this._maxInterval && movement <= this._posThreshold ) {
3325
+
3326
+ //second valid click detected
3327
+ //fire double tap and reset values
3328
+ this._nclicks = 0;
3329
+ this._downEvents.splice( 0, this._downEvents.length );
3330
+ this.onDoubleTap( event );
3331
+
3332
+ } else {
3333
+
3334
+ //new 'first click'
3335
+ this._nclicks = 1;
3336
+ this._downEvents.shift();
3337
+ this._clickStart = performance.now();
3338
+
3339
+ }
3340
+
3341
+ }
3342
+
3343
+ } else {
3344
+
3345
+ this._downValid = false;
3346
+ this._nclicks = 0;
3347
+ this._downEvents.splice( 0, this._downEvents.length );
3348
+
3349
+ }
3350
+
3351
+ } else {
3352
+
3353
+ this._nclicks = 0;
3354
+ this._downEvents.splice( 0, this._downEvents.length );
3355
+
3356
+ }
3357
+
3358
+ }
3359
+
3360
+ }
3361
+
3362
+ function onWheel( event ) {
3363
+
3364
+ if ( this.enabled && this.enableZoom ) {
3365
+
3366
+ let modifier = null;
3367
+
3368
+ if ( event.ctrlKey || event.metaKey ) {
3369
+
3370
+ modifier = 'CTRL';
3371
+
3372
+ } else if ( event.shiftKey ) {
3373
+
3374
+ modifier = 'SHIFT';
3375
+
3376
+ }
3377
+
3378
+ const mouseOp = this.getOpFromAction( 'WHEEL', modifier );
3379
+
3380
+ if ( mouseOp != null ) {
3381
+
3382
+ event.preventDefault();
3383
+ this.dispatchEvent( _startEvent );
3384
+
3385
+ const notchDeltaY = 125; //distance of one notch of mouse wheel
3386
+ let sgn = event.deltaY / notchDeltaY;
3387
+
3388
+ let size = 1;
3389
+
3390
+ if ( sgn > 0 ) {
3391
+
3392
+ size = 1 / this.scaleFactor;
3393
+
3394
+ } else if ( sgn < 0 ) {
3395
+
3396
+ size = this.scaleFactor;
3397
+
3398
+ }
3399
+
3400
+ switch ( mouseOp ) {
3401
+
3402
+ case 'ZOOM':
3403
+
3404
+ this.updateTbState( STATE.SCALE, true );
3405
+
3406
+ if ( sgn > 0 ) {
3407
+
3408
+ size = 1 / ( Math.pow( this.scaleFactor, sgn ) );
3409
+
3410
+ } else if ( sgn < 0 ) {
3411
+
3412
+ size = Math.pow( this.scaleFactor, - sgn );
3413
+
3414
+ }
3415
+
3416
+ if ( this.cursorZoom && this.enablePan ) {
3417
+
3418
+ let scalePoint;
3419
+
3420
+ if ( this.object.isOrthographicCamera ) {
3421
+
3422
+ scalePoint = this.unprojectOnTbPlane( this.object, event.clientX, event.clientY, this.domElement ).applyQuaternion( this.object.quaternion ).multiplyScalar( 1 / this.object.zoom ).add( this._gizmos.position );
3423
+
3424
+ } else if ( this.object.isPerspectiveCamera ) {
3425
+
3426
+ scalePoint = this.unprojectOnTbPlane( this.object, event.clientX, event.clientY, this.domElement ).applyQuaternion( this.object.quaternion ).add( this._gizmos.position );
3427
+
3428
+ }
3429
+
3430
+ this.applyTransformMatrix( this.scale( size, scalePoint ) );
3431
+
3432
+ } else {
3433
+
3434
+ this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
3435
+
3436
+ }
3437
+
3438
+ if ( this._grid != null ) {
3439
+
3440
+ this.disposeGrid();
3441
+ this.drawGrid();
3442
+
3443
+ }
3444
+
3445
+ this.updateTbState( STATE.IDLE, false );
3446
+
3447
+ this.dispatchEvent( _changeEvent );
3448
+ this.dispatchEvent( _endEvent );
3449
+
3450
+ break;
3451
+
3452
+ case 'FOV':
3453
+
3454
+ if ( this.object.isPerspectiveCamera ) {
3455
+
3456
+ this.updateTbState( STATE.FOV, true );
3457
+
3458
+
3459
+ //Vertigo effect
3460
+
3461
+ // fov / 2
3462
+ // |\
3463
+ // | \
3464
+ // | \
3465
+ // x | \
3466
+ // | \
3467
+ // | \
3468
+ // | _ _ _\
3469
+ // y
3470
+
3471
+ //check for iOs shift shortcut
3472
+ if ( event.deltaX != 0 ) {
3473
+
3474
+ sgn = event.deltaX / notchDeltaY;
3475
+
3476
+ size = 1;
3477
+
3478
+ if ( sgn > 0 ) {
3479
+
3480
+ size = 1 / ( Math.pow( this.scaleFactor, sgn ) );
3481
+
3482
+ } else if ( sgn < 0 ) {
3483
+
3484
+ size = Math.pow( this.scaleFactor, - sgn );
3485
+
3486
+ }
3487
+
3488
+ }
3489
+
3490
+ this._v3_1.setFromMatrixPosition( this._cameraMatrixState );
3491
+ const x = this._v3_1.distanceTo( this._gizmos.position );
3492
+ let xNew = x / size; //distance between camera and gizmos if scale(size, scalepoint) would be performed
3493
+
3494
+ //check min and max distance
3495
+ xNew = MathUtils.clamp( xNew, this.minDistance, this.maxDistance );
3496
+
3497
+ const y = x * Math.tan( MathUtils.DEG2RAD * this.object.fov * 0.5 );
3498
+
3499
+ //calculate new fov
3500
+ let newFov = MathUtils.RAD2DEG * ( Math.atan( y / xNew ) * 2 );
3501
+
3502
+ //check min and max fov
3503
+ if ( newFov > this.maxFov ) {
3504
+
3505
+ newFov = this.maxFov;
3506
+
3507
+ } else if ( newFov < this.minFov ) {
3508
+
3509
+ newFov = this.minFov;
3510
+
3511
+ }
3512
+
3513
+ const newDistance = y / Math.tan( MathUtils.DEG2RAD * ( newFov / 2 ) );
3514
+ size = x / newDistance;
3515
+
3516
+ this.setFov( newFov );
3517
+ this.applyTransformMatrix( this.scale( size, this._gizmos.position, false ) );
3518
+
3519
+ }
3520
+
3521
+ if ( this._grid != null ) {
3522
+
3523
+ this.disposeGrid();
3524
+ this.drawGrid();
3525
+
3526
+ }
3527
+
3528
+ this.updateTbState( STATE.IDLE, false );
3529
+
3530
+ this.dispatchEvent( _changeEvent );
3531
+ this.dispatchEvent( _endEvent );
3532
+
3533
+ break;
3534
+
3535
+ }
3536
+
3537
+ }
3538
+
3539
+ }
3540
+
3541
+ }
3542
+
3543
+ export { ArcballControls };