@needle-tools/engine 2.52.0-pre → 2.54.2-pre

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 (220) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/needle-engine.d.ts +3018 -2680
  3. package/dist/needle-engine.js +439 -439
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +41 -41
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/dist/needle-engine.tsbuildinfo +1 -0
  8. package/lib/engine/codegen/register_types.d.ts +1 -0
  9. package/lib/engine/codegen/register_types.js +346 -0
  10. package/lib/engine/codegen/register_types.js.map +1 -0
  11. package/lib/engine/debug/debug.d.ts +1 -0
  12. package/lib/engine/debug/debug.js +4 -0
  13. package/lib/engine/debug/debug.js.map +1 -1
  14. package/lib/engine/debug/debug_console.js +2 -1
  15. package/lib/engine/debug/debug_console.js.map +1 -1
  16. package/lib/engine/debug/debug_overlay.js +3 -1
  17. package/lib/engine/debug/debug_overlay.js.map +1 -1
  18. package/lib/engine/engine_components.js +2 -2
  19. package/lib/engine/engine_components.js.map +1 -1
  20. package/lib/engine/engine_default_parameters.d.ts +2 -2
  21. package/lib/engine/engine_element.js +4 -2
  22. package/lib/engine/engine_element.js.map +1 -1
  23. package/lib/engine/engine_element_loading.d.ts +1 -0
  24. package/lib/engine/engine_element_loading.js +17 -6
  25. package/lib/engine/engine_element_loading.js.map +1 -1
  26. package/lib/engine/engine_element_overlay.js +4 -2
  27. package/lib/engine/engine_element_overlay.js.map +1 -1
  28. package/lib/engine/engine_fileloader.d.ts +3 -0
  29. package/lib/engine/engine_fileloader.js +8 -0
  30. package/lib/engine/engine_fileloader.js.map +1 -0
  31. package/lib/engine/engine_generic_utils.d.ts +1 -0
  32. package/lib/engine/engine_generic_utils.js +14 -0
  33. package/lib/engine/engine_generic_utils.js.map +1 -0
  34. package/lib/engine/engine_input.js +4 -0
  35. package/lib/engine/engine_input.js.map +1 -1
  36. package/lib/engine/engine_networking_instantiate.d.ts +1 -1
  37. package/lib/engine/engine_networking_instantiate.js +3 -0
  38. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  39. package/lib/engine/engine_networking_websocket.d.ts +1 -0
  40. package/lib/engine/engine_networking_websocket.js +1 -1
  41. package/lib/engine/engine_networking_websocket.js.map +1 -1
  42. package/lib/engine/engine_serialization_builtin_serializer.d.ts +6 -0
  43. package/lib/engine/engine_serialization_builtin_serializer.js +35 -7
  44. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  45. package/lib/engine/engine_serialization_core.d.ts +1 -0
  46. package/lib/engine/engine_serialization_core.js +6 -0
  47. package/lib/engine/engine_serialization_core.js.map +1 -1
  48. package/lib/engine/engine_setup.js +2 -2
  49. package/lib/engine/engine_setup.js.map +1 -1
  50. package/lib/engine/engine_texture.d.ts +3 -0
  51. package/lib/engine/engine_texture.js +4 -0
  52. package/lib/engine/engine_texture.js.map +1 -0
  53. package/lib/engine/engine_utils.d.ts +1 -1
  54. package/lib/engine/engine_utils.js +3 -0
  55. package/lib/engine/engine_utils.js.map +1 -1
  56. package/lib/engine/extensions/NEEDLE_components.d.ts +1 -1
  57. package/lib/engine/extensions/NEEDLE_progressive.d.ts +40 -0
  58. package/lib/engine/extensions/NEEDLE_progressive.js +322 -0
  59. package/lib/engine/extensions/NEEDLE_progressive.js.map +1 -0
  60. package/lib/engine/extensions/extensions.js +2 -2
  61. package/lib/engine/extensions/extensions.js.map +1 -1
  62. package/lib/engine-components/Camera.js +17 -2
  63. package/lib/engine-components/Camera.js.map +1 -1
  64. package/lib/engine-components/GroundProjection.d.ts +2 -1
  65. package/lib/engine-components/GroundProjection.js +19 -12
  66. package/lib/engine-components/GroundProjection.js.map +1 -1
  67. package/lib/engine-components/Light.js +1 -0
  68. package/lib/engine-components/Light.js.map +1 -1
  69. package/lib/engine-components/OrbitControls.js +6 -2
  70. package/lib/engine-components/OrbitControls.js.map +1 -1
  71. package/lib/engine-components/ParticleSystemModules.d.ts +1 -1
  72. package/lib/engine-components/ParticleSystemModules.js +48 -44
  73. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  74. package/lib/engine-components/ReflectionProbe.d.ts +1 -1
  75. package/lib/engine-components/Renderer.d.ts +1 -1
  76. package/lib/engine-components/Renderer.js +4 -9
  77. package/lib/engine-components/Renderer.js.map +1 -1
  78. package/lib/engine-components/Voip.js +13 -4
  79. package/lib/engine-components/Voip.js.map +1 -1
  80. package/lib/engine-components/Volume.js +8 -1
  81. package/lib/engine-components/Volume.js.map +1 -1
  82. package/lib/engine-components/WebXR.d.ts +2 -2
  83. package/lib/engine-components/WebXRAvatar.d.ts +1 -1
  84. package/lib/engine-components/codegen/components.d.ts +99 -95
  85. package/lib/engine-components/codegen/components.js +99 -95
  86. package/lib/engine-components/codegen/components.js.map +1 -1
  87. package/lib/engine-components/export/{GltfExport.d.ts → gltf/GltfExport.d.ts} +2 -2
  88. package/lib/engine-components/export/{GltfExport.js → gltf/GltfExport.js} +7 -7
  89. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -0
  90. package/lib/engine-components/export/usdz/Extension.d.ts +9 -0
  91. package/lib/engine-components/export/usdz/Extension.js +2 -0
  92. package/lib/engine-components/export/usdz/Extension.js.map +1 -0
  93. package/lib/engine-components/export/usdz/USDZExporter.d.ts +26 -0
  94. package/lib/engine-components/export/usdz/USDZExporter.js +209 -0
  95. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -0
  96. package/lib/engine-components/export/usdz/extensions/Animation.d.ts +44 -0
  97. package/lib/engine-components/export/usdz/extensions/Animation.js +264 -0
  98. package/lib/engine-components/export/usdz/extensions/Animation.js.map +1 -0
  99. package/lib/engine-components/export/usdz/types.d.ts +34 -0
  100. package/lib/engine-components/export/usdz/types.js +2 -0
  101. package/lib/engine-components/export/usdz/types.js.map +1 -0
  102. package/lib/engine-components/export/usdz/utils/animationutils.d.ts +3 -0
  103. package/lib/engine-components/export/usdz/utils/animationutils.js +46 -0
  104. package/lib/engine-components/export/usdz/utils/animationutils.js.map +1 -0
  105. package/lib/engine-components/export/usdz/utils/quicklook.d.ts +2 -0
  106. package/lib/engine-components/export/usdz/utils/quicklook.js +36 -0
  107. package/lib/engine-components/export/usdz/utils/quicklook.js.map +1 -0
  108. package/lib/engine-components/export/usdz/utils/timeutils.d.ts +1 -0
  109. package/lib/engine-components/export/usdz/utils/timeutils.js +15 -0
  110. package/lib/engine-components/export/usdz/utils/timeutils.js.map +1 -0
  111. package/lib/engine-components/ui/Button.js +30 -0
  112. package/lib/engine-components/ui/Button.js.map +1 -1
  113. package/lib/engine-components/ui/Graphic.d.ts +2 -0
  114. package/lib/engine-components/ui/Graphic.js +15 -0
  115. package/lib/engine-components/ui/Graphic.js.map +1 -1
  116. package/lib/engine-components/ui/InputField.d.ts +2 -0
  117. package/lib/engine-components/ui/InputField.js +23 -1
  118. package/lib/engine-components/ui/InputField.js.map +1 -1
  119. package/lib/engine-components/ui/Utils.d.ts +4 -1
  120. package/lib/engine-components/ui/Utils.js +15 -12
  121. package/lib/engine-components/ui/Utils.js.map +1 -1
  122. package/lib/engine-components-experimental/Presentation.d.ts +6 -0
  123. package/lib/engine-components-experimental/Presentation.js +11 -0
  124. package/lib/engine-components-experimental/Presentation.js.map +1 -0
  125. package/lib/engine-components-experimental/annotation/LineDrawer.d.ts +18 -0
  126. package/lib/engine-components-experimental/annotation/LineDrawer.js +175 -0
  127. package/lib/engine-components-experimental/annotation/LineDrawer.js.map +1 -0
  128. package/lib/engine-components-experimental/annotation/LinesManager.d.ts +54 -0
  129. package/lib/engine-components-experimental/annotation/LinesManager.js +155 -0
  130. package/lib/engine-components-experimental/annotation/LinesManager.js.map +1 -0
  131. package/lib/engine-components-experimental/networking/PlayerSync.d.ts +26 -0
  132. package/lib/engine-components-experimental/networking/PlayerSync.js +121 -0
  133. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -0
  134. package/lib/engine-schemes/vec2.d.ts +10 -0
  135. package/lib/engine-schemes/vec2.js +26 -0
  136. package/lib/engine-schemes/vec2.js.map +1 -0
  137. package/lib/include/three/ARButton.d.ts +3 -0
  138. package/lib/include/three/ARButton.js +158 -0
  139. package/lib/include/three/ARButton.js.map +1 -0
  140. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.d.ts +6 -0
  141. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js +46 -0
  142. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js.map +1 -0
  143. package/lib/include/three/VRButton.d.ts +5 -0
  144. package/lib/include/three/VRButton.js +122 -0
  145. package/lib/include/three/VRButton.js.map +1 -0
  146. package/lib/tsconfig.tsbuildinfo +1 -0
  147. package/package.json +2 -2
  148. package/src/engine/codegen/register_types.js +212 -204
  149. package/src/engine/debug/debug.ts +5 -0
  150. package/src/engine/debug/debug_console.ts +3 -2
  151. package/src/engine/debug/debug_overlay.ts +3 -1
  152. package/src/engine/engine_components.ts +2 -2
  153. package/src/engine/engine_element.ts +4 -2
  154. package/src/engine/engine_element_loading.ts +13 -6
  155. package/src/engine/engine_element_overlay.ts +4 -2
  156. package/src/engine/engine_input.ts +4 -0
  157. package/src/engine/engine_networking_instantiate.ts +4 -1
  158. package/src/engine/engine_networking_websocket.ts +3 -1
  159. package/src/engine/engine_serialization_builtin_serializer.ts +39 -8
  160. package/src/engine/engine_serialization_core.ts +7 -1
  161. package/src/engine/engine_setup.ts +2 -2
  162. package/src/engine/engine_texture.ts +6 -0
  163. package/src/engine/engine_utils.ts +3 -1
  164. package/src/engine/extensions/NEEDLE_progressive.ts +357 -0
  165. package/src/engine/extensions/extensions.ts +2 -2
  166. package/src/engine-components/Camera.ts +17 -3
  167. package/src/engine-components/GroundProjection.ts +18 -12
  168. package/src/engine-components/Light.ts +3 -1
  169. package/src/engine-components/OrbitControls.ts +7 -3
  170. package/src/engine-components/ParticleSystemModules.ts +50 -47
  171. package/src/engine-components/Renderer.ts +6 -10
  172. package/src/engine-components/Voip.ts +14 -4
  173. package/src/engine-components/Volume.ts +8 -1
  174. package/src/engine-components/WebXR.ts +2 -2
  175. package/src/engine-components/codegen/components.ts +99 -95
  176. package/src/engine-components/export/{GltfExport.ts → gltf/GltfExport.ts} +7 -7
  177. package/src/engine-components/export/usdz/Extension.ts +12 -0
  178. package/src/engine-components/export/usdz/USDZExporter.ts +233 -0
  179. package/src/engine-components/export/usdz/extensions/Animation.ts +306 -0
  180. package/src/engine-components/export/usdz/types.ts +39 -0
  181. package/src/engine-components/export/usdz/utils/animationutils.ts +60 -0
  182. package/src/engine-components/export/usdz/utils/quicklook.ts +43 -0
  183. package/src/engine-components/export/usdz/utils/timeutils.ts +20 -0
  184. package/src/engine-components/ui/Button.ts +8 -8
  185. package/src/engine-components/ui/Graphic.ts +15 -1
  186. package/src/engine-components/ui/InputField.ts +25 -2
  187. package/src/engine-components/ui/Utils.ts +17 -14
  188. package/src/engine-components-experimental/annotation/LineDrawer.ts +10 -7
  189. package/src/engine-components-experimental/annotation/LinesManager.ts +6 -6
  190. package/src/engine-components-experimental/networking/PlayerSync.ts +1 -1
  191. package/lib/engine/engine_caching.d.ts +0 -0
  192. package/lib/engine/engine_caching.js +0 -2
  193. package/lib/engine/engine_caching.js.map +0 -1
  194. package/lib/engine/extensions/NEEDLE_deferred_texture.d.ts +0 -18
  195. package/lib/engine/extensions/NEEDLE_deferred_texture.js +0 -194
  196. package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +0 -1
  197. package/lib/engine/tests/simulate_avatars.d.ts +0 -0
  198. package/lib/engine/tests/simulate_avatars.js +0 -3
  199. package/lib/engine/tests/simulate_avatars.js.map +0 -1
  200. package/lib/engine-components/NavMesh.d.ts +0 -0
  201. package/lib/engine-components/NavMesh.js +0 -101
  202. package/lib/engine-components/NavMesh.js.map +0 -1
  203. package/lib/engine-components/ParticleSystemBehaviours.d.ts +0 -0
  204. package/lib/engine-components/ParticleSystemBehaviours.js +0 -2
  205. package/lib/engine-components/ParticleSystemBehaviours.js.map +0 -1
  206. package/lib/engine-components/SpringJoint.d.ts +0 -0
  207. package/lib/engine-components/SpringJoint.js +0 -43
  208. package/lib/engine-components/SpringJoint.js.map +0 -1
  209. package/lib/engine-components/export/GltfExport.js.map +0 -1
  210. package/lib/engine-components/ui/CanvasScaler.d.ts +0 -0
  211. package/lib/engine-components/ui/CanvasScaler.js +0 -17
  212. package/lib/engine-components/ui/CanvasScaler.js.map +0 -1
  213. package/src/engine/dist/engine_three_utils.js +0 -279
  214. package/src/engine/engine_caching.ts +0 -0
  215. package/src/engine/extensions/NEEDLE_deferred_texture.ts +0 -217
  216. package/src/engine/tests/simulate_avatars.ts +0 -2
  217. package/src/engine-components/NavMesh.ts +0 -117
  218. package/src/engine-components/ParticleSystemBehaviours.ts +0 -0
  219. package/src/engine-components/SpringJoint.ts +0 -45
  220. package/src/engine-components/ui/CanvasScaler.ts +0 -21
@@ -0,0 +1,306 @@
1
+ import { GameObject } from "../../../Component";
2
+ import { getParam } from "../../../../engine/engine_utils";
3
+ import { Object3D, Color, Matrix4, MeshStandardMaterial, Vector3, Quaternion, Interpolant } from "three";
4
+ //@ts-ignore
5
+ import { USDZObject, buildMatrix } from "three/examples/jsm/exporters/USDZExporter"
6
+ import { IUSDZExporterExtension } from "../Extension";
7
+
8
+ const debug = getParam("debugusdzanimation");
9
+
10
+ export interface UsdzAnimation {
11
+ createAnimation(ext: AnimationExtension, model: USDZObject, context);
12
+ }
13
+
14
+ export type AnimationClipCollection = Array<{ root: Object3D, clips: Array<THREE.AnimationClip> }>;
15
+
16
+ export class RegisteredAnimationInfo {
17
+
18
+ get start(): number { return this.ext.getStartTime01(this.root, this.clip); }
19
+ get duration(): number { return this.clip.duration; }
20
+
21
+ private ext: AnimationExtension;
22
+ private root: Object3D;
23
+ private clip: THREE.AnimationClip;
24
+
25
+ constructor(ext: AnimationExtension, root: THREE.Object3D, clip: THREE.AnimationClip) {
26
+ this.ext = ext;
27
+ this.root = root;
28
+ this.clip = clip;
29
+ }
30
+ }
31
+
32
+ export class TransformData {
33
+ clip: THREE.AnimationClip;
34
+ pos?: THREE.KeyframeTrack;
35
+ rot?: THREE.KeyframeTrack;
36
+ scale?: THREE.KeyframeTrack;
37
+ get frameRate(): number { return 60; }
38
+
39
+ private ext: AnimationExtension;
40
+ private root: Object3D;
41
+ private target: Object3D;
42
+
43
+ constructor(ext: AnimationExtension, root: Object3D, target: Object3D, clip: THREE.AnimationClip) {
44
+ this.ext = ext;
45
+ this.root = root;
46
+ this.target = target;
47
+ this.clip = clip;
48
+ }
49
+
50
+ addTrack(track) {
51
+ if (track.name.endsWith("position")) this.pos = track;
52
+ if (track.name.endsWith("quaternion")) this.rot = track;
53
+ if (track.name.endsWith("scale")) this.scale = track;
54
+ }
55
+
56
+ getFrames(): number {
57
+ return Math.max(this.pos?.times?.length ?? 0, this.rot?.times?.length ?? 0, this.scale?.times?.length ?? 0);
58
+ }
59
+
60
+ getDuration(): number {
61
+ const times = this.pos?.times ?? this.rot?.times ?? this.scale?.times;
62
+ if (!times) return 0;
63
+ return times[times.length - 1];
64
+ }
65
+
66
+ getStartTime(arr: TransformData[]): number {
67
+ let sum = 0;
68
+ for (let i = 0; i < arr.length; i++) {
69
+ const entry = arr[i];
70
+ if (entry === this) {
71
+ return sum;
72
+ }
73
+ else sum += entry.getDuration();
74
+ }
75
+ return sum;
76
+ }
77
+ }
78
+
79
+ declare type AnimationDict = Map<Object3D, Array<TransformData>>;
80
+
81
+ export class AnimationExtension implements IUSDZExporterExtension {
82
+
83
+ get extensionName(): string { return "animation" }
84
+ private dict: AnimationDict = new Map();
85
+ // private rootTargetMap: Map<Object3D, Object3D[]> = new Map();
86
+ private rootTargetMap: Map<Object3D, Object3D[]> = new Map();
87
+
88
+ getStartTime01(root: Object3D, clip: THREE.AnimationClip) {
89
+ const targets = this.rootTargetMap.get(root);
90
+ if (!targets) return Infinity;
91
+ let longestStartTime: number = -1;
92
+ for (const target of targets) {
93
+ const data = this.dict.get(target);
94
+ let startTimeInSeconds = 0;
95
+ if (data?.length) {
96
+ for (const entry of data) {
97
+ if (entry.clip === clip) {
98
+ break;
99
+ }
100
+ startTimeInSeconds += entry.getDuration();
101
+ }
102
+ longestStartTime = Math.max(longestStartTime, startTimeInSeconds);
103
+ }
104
+ else {
105
+ console.warn("No animation found on root", root, clip, data);
106
+ }
107
+ }
108
+ return longestStartTime;
109
+ }
110
+
111
+ registerAnimation(root: Object3D, clip: THREE.AnimationClip): RegisteredAnimationInfo | null {
112
+ if (!clip || !root) return null;
113
+ if (!this.rootTargetMap.has(root)) this.rootTargetMap.set(root, []);
114
+ // this.rootTargetMap.get(root)?.push(clip);
115
+
116
+ for (const track of clip.tracks) {
117
+ const trackName = track.name.split(".")[2];
118
+ const animationTarget = root.getObjectByName(trackName); // object name
119
+ if (!animationTarget) {
120
+ console.warn("no object found for track", track.name, "using " + root.name + " instead");
121
+ continue;
122
+ // // if no object was found it might be that we have a component that references an animation clip but wants to target another object
123
+ // // in that case UnityGLTF writes the name of the component as track targets because it doesnt know of the intented target
124
+ // animationTarget = root;
125
+ }
126
+ if (!this.dict.has(animationTarget)) {
127
+ this.dict.set(animationTarget, []);
128
+ }
129
+ const arr = this.dict.get(animationTarget);
130
+ if (!arr) continue;
131
+
132
+ let model = arr.find(x => x.clip === clip);
133
+ if (!model) {
134
+ model = new TransformData(this, root, animationTarget, clip);
135
+ arr.push(model);
136
+ }
137
+ model.addTrack(track);
138
+
139
+ const targets = this.rootTargetMap.get(root);
140
+ if (!targets?.includes(animationTarget)) targets?.push(animationTarget);
141
+ }
142
+
143
+ // get the entry for this object.
144
+ // This doesnt work if we have clips animating multiple objects
145
+ const info = new RegisteredAnimationInfo(this, root, clip);
146
+ return info;
147
+ }
148
+
149
+ onAfterHierarchy(_context) {
150
+ if (debug)
151
+ console.log(this.dict);
152
+ }
153
+
154
+ private serializers: SerializeAnimation[] = [];
155
+
156
+ onAfterBuildDocument(_context: any) {
157
+ for (const ser of this.serializers) {
158
+ const parent = ser.model?.parent;
159
+ const isEmptyParent = parent?.isDynamic === true;
160
+ if (debug)
161
+ console.log(isEmptyParent, ser.model?.parent);
162
+ if (isEmptyParent) {
163
+ ser.registerCallback(parent);
164
+ }
165
+ }
166
+ }
167
+
168
+ onExportObject(object, model: USDZObject, _context) {
169
+
170
+ GameObject.foreachComponent(object, (comp) => {
171
+ const c = comp as unknown as UsdzAnimation;
172
+ if (typeof c.createAnimation === "function") {
173
+ c.createAnimation(this, model, _context);
174
+ }
175
+ }, false);
176
+
177
+ // we need to be able to retarget serialization to empty parents before actually serializing (we do that in another callback)
178
+ const ser = new SerializeAnimation(object, this.dict);
179
+ this.serializers.push(ser);
180
+ ser.registerCallback(model);
181
+ }
182
+
183
+ }
184
+
185
+
186
+ class SerializeAnimation {
187
+
188
+ object: Object3D;
189
+ dict: AnimationDict;
190
+ model: USDZObject;
191
+
192
+ private callback?: Function;
193
+
194
+ constructor(object: Object3D, dict: AnimationDict) {
195
+ this.object = object;
196
+ this.dict = dict;
197
+ }
198
+
199
+ registerCallback(model: USDZObject) {
200
+ if (this.model && this.callback) {
201
+ this.model.removeEventListener("serialize", this.callback);
202
+ }
203
+ if (!this.callback)
204
+ this.callback = this.onSerialize.bind(this);
205
+ if (debug)
206
+ console.log("REPARENT", model);
207
+ this.model = model;
208
+ this.model.addEventListener("serialize", this.callback);
209
+ }
210
+
211
+ onSerialize(writer, _context) {
212
+ if (debug)
213
+ console.log("SERIALIZE", this.model.name, this.object.type);
214
+ // do we have a track for this?
215
+ const object = this.object;
216
+ const arr = this.dict.get(object);
217
+ if (!arr) return;
218
+
219
+ // console.log("found data for", object, "exporting animation now");
220
+
221
+
222
+
223
+ // assumption: all tracks have the same time values
224
+ // TODO collect all time values and then use the interpolator to access
225
+
226
+ const composedTransform = new Matrix4();
227
+ const translation = new Vector3();
228
+ const rotation = new Quaternion();
229
+ const scale = new Vector3(1, 1, 1);
230
+
231
+ // TODO doesn't support individual time arrays right now
232
+ // could use these in case we don't have time values that are identical
233
+ /*
234
+ const translationInterpolant = o.pos?.createInterpolant() as THREE.Interpolant;
235
+ const rotationInterpolant = o.rot?.createInterpolant() as THREE.Interpolant;
236
+ const scaleInterpolant = o.scale?.createInterpolant() as THREE.Interpolant;
237
+ */
238
+
239
+ writer.appendLine("matrix4d xformOp:transform.timeSamples = {");
240
+ writer.indent++;
241
+
242
+ for (const transformData of arr) {
243
+ let timesArray = transformData.pos?.times;
244
+ if (!timesArray || transformData.rot && transformData.rot.times?.length > timesArray?.length) timesArray = transformData.rot?.times;
245
+ if (!timesArray || transformData.scale && transformData.scale.times?.length > timesArray?.length) timesArray = transformData.scale?.times;
246
+ if (!timesArray) {
247
+ console.error("got an animated object but no time values??", object, transformData);
248
+ continue;
249
+ }
250
+ const startTime = transformData.getStartTime(arr);
251
+
252
+ if (debug)
253
+ writer.appendLine(transformData.clip.name + ": start=" + startTime.toFixed(3) + ", length=" + transformData.getDuration().toFixed(3) + ", frames=" + transformData.getFrames());
254
+
255
+ // ignore until https://github.com/three-types/three-ts-types/pull/293 gets merged
256
+ //@ts-ignore
257
+ const positionInterpolant: Interpolant | undefined = transformData.pos?.createInterpolant();
258
+ //@ts-ignore
259
+ const rotationInterpolant: Interpolant | undefined = transformData.rot?.createInterpolant();
260
+ //@ts-ignore
261
+ const scaleInterpolant: Interpolant | undefined = transformData.scale?.createInterpolant();
262
+
263
+ if (!positionInterpolant) translation.set(object.position.x, object.position.y, object.position.z);
264
+ if (!rotationInterpolant) rotation.set(object.quaternion.x, object.quaternion.y, object.quaternion.z, object.quaternion.w);
265
+ if (!scaleInterpolant) scale.set(object.scale.x, object.scale.y, object.scale.z);
266
+
267
+ for (let index = 0; index < timesArray.length; index++) {
268
+ const time = timesArray[index];
269
+
270
+ if (positionInterpolant) {
271
+ const pos = positionInterpolant.evaluate(time);
272
+ translation.set(pos[0], pos[1], pos[2]);
273
+ }
274
+ if (rotationInterpolant) {
275
+ const quat = rotationInterpolant.evaluate(time);
276
+ rotation.set(quat[0], quat[1], quat[2], quat[3]);
277
+ }
278
+ if (scaleInterpolant) {
279
+ const scale = scaleInterpolant.evaluate(time);
280
+ scale.set(scale[0], scale[1], scale[2]);
281
+ }
282
+
283
+ composedTransform.compose(translation, rotation, scale);
284
+
285
+ let line = `${(startTime + time) * transformData.frameRate}: ${buildMatrix(composedTransform)},`;
286
+ if (debug) line = "#" + index + "\t" + line;
287
+ writer.appendLine(line);
288
+ }
289
+
290
+ }
291
+ writer.indent--;
292
+ writer.appendLine("}");
293
+
294
+ /*
295
+ let transform3 = new Matrix4();
296
+ transform3.compose(0.2,0,0);
297
+ const transform = buildMatrix(model.matrix);
298
+ const transform2 = buildMatrix(transform3.multiply(model.matrix));
299
+
300
+ writer.appendLine(`matrix4d xformOp:transform.timeSamples = {
301
+ 0: ${transform},
302
+ 30: ${transform2}
303
+ }`);
304
+ */
305
+ }
306
+ }
@@ -0,0 +1,39 @@
1
+ import { Object3D, Matrix4, Material, BufferGeometry } from "three";
2
+
3
+ // keep in sync with USDZExporter.js
4
+
5
+ /** implementation is in three */
6
+ export declare class USDZDocument {
7
+ name: string;
8
+ get isDocumentRoot(): boolean;
9
+ add(obj: USDZObject);
10
+ remove(obj: USDZObject);
11
+ traverse(callback: (obj: USDZObject) => void);
12
+ findById(uuid: string): USDZObject | undefined;
13
+ get isDynamic(): boolean;
14
+ }
15
+
16
+
17
+
18
+ /** implementation is in three */
19
+ export declare class USDZObject {
20
+ static createEmptyParent(parent: USDZObject);
21
+ uuid: string;
22
+ name: string;
23
+ matrix: Matrix4;
24
+ material: Material;
25
+ geometry: BufferGeometry;
26
+ parent: USDZObject | USDZDocument | null;
27
+ children: USDZObject[];
28
+ _eventListeners: { [event: string]: Function[] };
29
+ isDynamic: boolean;
30
+
31
+ is(obj: Object3D): boolean;
32
+ isEmpty(): boolean;
33
+ clone();
34
+ getPath();
35
+ add(child: USDZObject);
36
+ remove(child: USDZObject);
37
+ addEventListener(evt: string, listener: Function);
38
+ removeEventListener(evt: string, listener: Function);
39
+ }
@@ -0,0 +1,60 @@
1
+ import { Animator } from "../../../Animator";
2
+ import { Object3D, Color, AnimationClip, KeyframeTrack } from "three";
3
+ import { AnimationExtension } from "../extensions/Animation";
4
+ import { GameObject } from "../../../Component";
5
+ import { getParam } from "../../../../engine/engine_utils";
6
+
7
+ const debug = getParam("debugusdz");
8
+
9
+ export function registerAnimatorsImplictly(root: Object3D, ext: AnimationExtension) {
10
+
11
+ // collect animators and their clips
12
+ const animationClips: { root: Object3D, clips: THREE.AnimationClip[] }[] = [];
13
+ const animators = GameObject.getComponentsInChildren(root, Animator);
14
+
15
+ // insert rest pose clip
16
+ let injectedRestPose = false;
17
+
18
+ if (debug)
19
+ console.log(animators);
20
+
21
+ for (const animator of animators) {
22
+ if (!animator || !animator.runtimeAnimatorController) continue;
23
+
24
+ if (debug)
25
+ console.log(animator);
26
+
27
+ const clips: THREE.AnimationClip[] = [];
28
+
29
+
30
+ for (const action of animator.runtimeAnimatorController.enumerateActions()) {
31
+ if (debug)
32
+ console.log(action);
33
+ const clip = action.getClip();
34
+
35
+ // we need to inject a rest pose clip so that the animation position is correct
36
+ // e.g. when the animation starts in the air and animates down we dont want the object to move under the ground
37
+ if (!injectedRestPose && clip.tracks.length > 0) {
38
+ injectedRestPose = true;
39
+ const track = clip.tracks[0];
40
+ const trackBaseName = track.name.substring(0, track.name.lastIndexOf("."));
41
+ const currentPositionTrack = new KeyframeTrack(trackBaseName + ".position", [0, .01], [0, 0, 0, 0, 0, 0]);
42
+ const currentRotationTrack = new KeyframeTrack(trackBaseName + ".quaternion", [0, .01], [0, 0, 0, 1, 0, 0, 0, 1]);
43
+ clips.push(new AnimationClip("rest", .01, [currentPositionTrack, currentRotationTrack]));
44
+ }
45
+
46
+ if (!clips.includes(clip))
47
+ clips.push(clip);
48
+ }
49
+
50
+ animationClips.push({ root: animator.gameObject, clips: clips });
51
+ }
52
+
53
+ if (debug)
54
+ console.log(animationClips);
55
+
56
+ for (const pair of animationClips) {
57
+ for (const clip of pair.clips)
58
+ ext.registerAnimation(pair.root, clip);
59
+ }
60
+ }
@@ -0,0 +1,43 @@
1
+ import { Context } from "../../../../engine/engine_setup";
2
+
3
+
4
+ export function ensureQuicklookLinkIsCreated(context: Context) : HTMLAnchorElement {
5
+ const existingLink = context.domElement.querySelector("link[rel='ar']");
6
+ if(existingLink) return existingLink as HTMLAnchorElement;
7
+
8
+ /*
9
+ generating this:
10
+ <div class="menu">
11
+ <button id="open-in-ar">Open in QuickLook</button>
12
+ <a style="display:none;" id="link" rel="ar" href="" download="asset.usdz">
13
+ <img id="button" width="100" src="files/arkit.png">
14
+ </a>
15
+ </div>
16
+ */
17
+
18
+ const div = document.createElement("div");
19
+ div.classList.add("menu");
20
+ div.classList.add("quicklook-menu");
21
+ div.style.display = "none";
22
+ div.style.visibility = "hidden";
23
+
24
+ const button = document.createElement("button");
25
+ button.id = "open-in-ar";
26
+ button.innerText = "Open in QuickLook";
27
+ div.appendChild(button);
28
+
29
+ const link = document.createElement("a");
30
+ link.id = "needle-usdz-link";
31
+ link.style.display = "none";
32
+ link.rel = "ar";
33
+ link.href = "";
34
+ div.appendChild(link);
35
+
36
+ const img = document.createElement("img");
37
+ img.id = "button";
38
+ // img.src = "files/arkit.png";
39
+ link.appendChild(img);
40
+
41
+ context.domElement.appendChild(div);
42
+ return link as HTMLAnchorElement;
43
+ }
@@ -0,0 +1,20 @@
1
+
2
+
3
+
4
+ export function getFormattedDate() {
5
+ var date = new Date();
6
+
7
+ const month = date.getMonth() + 1;
8
+ const day = date.getDate();
9
+ const hour = date.getHours();
10
+ const min = date.getMinutes();
11
+ const sec = date.getSeconds();
12
+
13
+ const s_month = (month < 10 ? "0" : "") + month;
14
+ const s_day = (day < 10 ? "0" : "") + day;
15
+ const s_hour = (hour < 10 ? "0" : "") + hour;
16
+ const s_min = (min < 10 ? "0" : "") + min;
17
+ const s_sec = (sec < 10 ? "0" : "") + sec;
18
+
19
+ return date.getFullYear() + s_month + s_day + "-" + s_hour + s_min + s_sec;
20
+ }
@@ -31,21 +31,21 @@ export enum Transition {
31
31
  Animation
32
32
  }
33
33
 
34
- declare class ButtonColors {
34
+ class ButtonColors {
35
35
  @serializable()
36
- colorMultiplier: 1;
36
+ colorMultiplier!: 1;
37
37
  @serializable(RGBAColor)
38
- disabledColor: RGBAColor;
38
+ disabledColor!: RGBAColor;
39
39
  @serializable()
40
- fadeDuration: number;
40
+ fadeDuration!: number;
41
41
  @serializable(RGBAColor)
42
- highlightedColor: RGBAColor;
42
+ highlightedColor!: RGBAColor;
43
43
  @serializable(RGBAColor)
44
- normalColor: RGBAColor;
44
+ normalColor!: RGBAColor;
45
45
  @serializable(RGBAColor)
46
- pressedColor: RGBAColor;
46
+ pressedColor!: RGBAColor;
47
47
  @serializable(RGBAColor)
48
- selectedColor: RGBAColor;
48
+ selectedColor!: RGBAColor;
49
49
  }
50
50
 
51
51
  declare type AnimationTriggers = {
@@ -3,7 +3,7 @@ import * as ThreeMeshUI from 'three-mesh-ui'
3
3
  import { RGBAColor } from "../js-extensions/RGBAColor"
4
4
  import { BaseUIComponent } from "./BaseUIComponent";
5
5
  import { serializable } from '../../engine/engine_serialization_decorator';
6
- import { Color, Texture } from 'three';
6
+ import { Color, LinearEncoding, sRGBEncoding, Texture } from 'three';
7
7
  import { RectTransform } from './RectTransform';
8
8
  import { onChange, scheduleAction } from "./Utils"
9
9
  import { GameObject } from '../Component';
@@ -126,10 +126,24 @@ export class Graphic extends BaseUIComponent implements IGraphic {
126
126
  }
127
127
  protected onAfterCreated() { }
128
128
 
129
+ /** used internally to ensure textures assigned to UI use linear encoding */
130
+ static textureCache: Map<Texture, Texture> = new Map();
131
+
129
132
  protected async setTexture(tex: Texture | null | undefined) {
130
133
  if (!tex) return;
131
134
  this.setOptions({ backgroundOpacity: 0 });
132
135
  if (tex) {
136
+ // workaround for https://github.com/needle-tools/needle-engine-support/issues/109
137
+ if(tex.encoding === sRGBEncoding) {
138
+ if(Graphic.textureCache.has(tex)) {
139
+ tex = Graphic.textureCache.get(tex)!;
140
+ } else {
141
+ const clone = tex.clone();
142
+ clone.encoding = LinearEncoding;
143
+ Graphic.textureCache.set(tex, clone);
144
+ tex = clone;
145
+ }
146
+ }
133
147
  this.setOptions({ backgroundTexture: tex, borderRadius: 0, backgroundOpacity: this.color.alpha, backgroundSize: "stretch" });
134
148
  }
135
149
  }
@@ -1,10 +1,13 @@
1
1
  import { Behaviour, GameObject } from "../Component";
2
- import { IPointerClickHandler, IPointerEventHandler } from "./PointerEvents";
2
+ import { IPointerClickHandler, IPointerEventHandler, PointerEventData } from "./PointerEvents";
3
3
  import { FrameEvent } from "../../engine/engine_setup";
4
4
  import { serializable } from "../../engine/engine_serialization_decorator";
5
5
  import { Text } from "./Text";
6
- import { getParam } from "../../engine/engine_utils";
6
+ import { getParam, isiOS } from "../../engine/engine_utils";
7
7
  import { EventList } from "../EventList";
8
+ import { showBalloonMessage } from "../../engine/debug/debug";
9
+ import { Physics } from "../../engine/engine_physics";
10
+ import { tryGetUIComponent } from "./Utils";
8
11
 
9
12
  const debug = getParam("debuginputfield");
10
13
 
@@ -36,6 +39,7 @@ export class InputField extends Behaviour implements IPointerEventHandler {
36
39
  private static htmlField: HTMLInputElement | null = null;
37
40
 
38
41
  private inputEventFn: any;
42
+ private _iosEventFn: any;
39
43
 
40
44
  start() {
41
45
  if (debug)
@@ -45,6 +49,7 @@ export class InputField extends Behaviour implements IPointerEventHandler {
45
49
  onEnable() {
46
50
  if (!InputField.htmlField) {
47
51
  InputField.htmlField = document.createElement("input");
52
+ InputField.htmlField.style.caretColor = "transparent";
48
53
  InputField.htmlField.classList.add("ar");
49
54
  document.body.appendChild(InputField.htmlField);
50
55
  }
@@ -57,6 +62,10 @@ export class InputField extends Behaviour implements IPointerEventHandler {
57
62
  if (this.placeholder && this.textComponent?.text.length) {
58
63
  GameObject.setActive(this.placeholder.gameObject, false);
59
64
  }
65
+ if (isiOS()) {
66
+ this._iosEventFn = this.processInputOniOS.bind(this);
67
+ window.addEventListener("touchend", this._iosEventFn);
68
+ }
60
69
  }
61
70
 
62
71
  onDisable() {
@@ -64,6 +73,9 @@ export class InputField extends Behaviour implements IPointerEventHandler {
64
73
  InputField.htmlField?.removeEventListener("keyup", this.inputEventFn);
65
74
  // InputField.htmlField?.removeEventListener("change", this.inputEventFn);
66
75
  this.onDeselected();
76
+ if (this._iosEventFn) {
77
+ window.removeEventListener("touchend", this._iosEventFn);
78
+ }
67
79
  }
68
80
 
69
81
  onPointerClick(_args) {
@@ -187,6 +199,17 @@ export class InputField extends Behaviour implements IPointerEventHandler {
187
199
  }
188
200
  }
189
201
 
202
+ private processInputOniOS() {
203
+ // focus() on safari ios doesnt open the keyboard when not processed from dom event
204
+ // so we try in a touch end event if this is hit
205
+ const hits = this.context.physics.raycast();
206
+ if (!hits.length) return;
207
+ const hit = hits[0];
208
+ const obj = hit.object;
209
+ const component = tryGetUIComponent(obj);
210
+ if (component?.gameObject === this.gameObject || component?.gameObject.parent === this.gameObject)
211
+ this.selectInputField();
212
+ }
190
213
 
191
214
 
192
215
  // private static _lastDeletionTime: number = 0;
@@ -1,18 +1,19 @@
1
1
 
2
2
  import { FrontSide, DoubleSide, BackSide, TetrahedronGeometry } from "three"
3
3
  import { FrameEvent } from "../../engine/engine_setup";
4
- import { Behaviour, GameObject } from "../Component";
5
- import { $shadowDomOwner } from "./BaseUIComponent";
4
+ import { Behaviour } from "../Component";
5
+ import { $shadowDomOwner, BaseUIComponent } from "./BaseUIComponent";
6
6
 
7
- // export function makeNonRaycastable(obj: THREE.Object3D | null | undefined, recursive: boolean = false) {
8
- // if (!obj) return;
9
- // obj.layers.mask = 2;
10
- // if (recursive && obj.children) {
11
- // for (const ch of obj.children) {
12
- // if (recursive) makeNonRaycastable(ch, true);
13
- // }
14
- // }
15
- // }
7
+ export function tryGetUIComponent(obj: THREE.Object3D): BaseUIComponent | null {
8
+ const owner = obj[$shadowDomOwner];
9
+ if (owner) {
10
+ return owner;
11
+ }
12
+ if(obj.parent) {
13
+ return tryGetUIComponent(obj.parent);
14
+ }
15
+ return null;
16
+ }
16
17
 
17
18
  export function isUIObject(obj: THREE.Object3D) {
18
19
  return obj["isUI"] === true || typeof obj[$shadowDomOwner] === "object";
@@ -54,6 +55,7 @@ export declare type RevocableProxy = {
54
55
 
55
56
  // TODO: change to use utils Watch since a revocable proxy makes a object completely useless once it is revoked
56
57
  /** internal method to proxy a field to detect changes */
58
+ /**@deprecated use watcher instead */
57
59
  export function onChange<T extends object>(caller: T, field: string, callback: (newValue: any, oldValue: any) => void): RevocableProxy {
58
60
 
59
61
  if (caller[field] === undefined) {
@@ -84,12 +86,13 @@ export function onChange<T extends object>(caller: T, field: string, callback: (
84
86
 
85
87
 
86
88
  declare type ScheduleCache = { [key: number]: { [key: string]: Generator | null } };
89
+ const $scheduledActionKey = Symbol("Scheduled action");
87
90
 
88
91
  // use to schedule a callback at a specific moment in the frame
89
- /** internal method to schedula a function at a specific moment in the update loop */
92
+ /** internal method to schedule a function at a specific moment in the update loop */
90
93
  export function scheduleAction(caller: Behaviour, action: Function, timing: FrameEvent = FrameEvent.OnBeforeRender) {
91
- let cache: ScheduleCache = caller["__scheduledActions"];
92
- if (!cache) cache = caller["__scheduledActions"] = {};
94
+ let cache: ScheduleCache = caller[$scheduledActionKey];
95
+ if (!cache) cache = caller[$scheduledActionKey] = {};
93
96
 
94
97
  const key = action.name;
95
98
  if (!cache[timing]) cache[timing] = {};