@needle-tools/engine 3.3.0-alpha → 3.5.0-alpha

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 (149) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/needle-engine.js +62620 -61118
  3. package/dist/needle-engine.min.js +434 -410
  4. package/dist/needle-engine.umd.cjs +435 -411
  5. package/lib/engine/api.d.ts +1 -0
  6. package/lib/engine/api.js +1 -0
  7. package/lib/engine/api.js.map +1 -1
  8. package/lib/engine/codegen/register_types.js +50 -2
  9. package/lib/engine/codegen/register_types.js.map +1 -1
  10. package/lib/engine/engine_context.d.ts +1 -1
  11. package/lib/engine/engine_context.js +21 -15
  12. package/lib/engine/engine_context.js.map +1 -1
  13. package/lib/engine/engine_context_registry.d.ts +5 -3
  14. package/lib/engine/engine_context_registry.js +10 -2
  15. package/lib/engine/engine_context_registry.js.map +1 -1
  16. package/lib/engine/engine_element.js.map +1 -1
  17. package/lib/engine/engine_element_loading.js +2 -3
  18. package/lib/engine/engine_element_loading.js.map +1 -1
  19. package/lib/engine/engine_gameobject.d.ts +1 -1
  20. package/lib/engine/engine_gameobject.js +4 -2
  21. package/lib/engine/engine_gameobject.js.map +1 -1
  22. package/lib/engine/engine_input.d.ts +2 -2
  23. package/lib/engine/engine_physics.d.ts +20 -93
  24. package/lib/engine/engine_physics.js +20 -892
  25. package/lib/engine/engine_physics.js.map +1 -1
  26. package/lib/engine/engine_physics.types.js.map +1 -1
  27. package/lib/engine/engine_physics_rapier.d.ts +103 -0
  28. package/lib/engine/engine_physics_rapier.js +1003 -0
  29. package/lib/engine/engine_physics_rapier.js.map +1 -0
  30. package/lib/engine/engine_three_utils.js +2 -2
  31. package/lib/engine/engine_three_utils.js.map +1 -1
  32. package/lib/engine/engine_types.d.ts +50 -1
  33. package/lib/engine/engine_types.js +8 -0
  34. package/lib/engine/engine_types.js.map +1 -1
  35. package/lib/engine-components/Animation.js +4 -0
  36. package/lib/engine-components/Animation.js.map +1 -1
  37. package/lib/engine-components/Collider.js +6 -6
  38. package/lib/engine-components/Collider.js.map +1 -1
  39. package/lib/engine-components/Joints.js +2 -2
  40. package/lib/engine-components/Joints.js.map +1 -1
  41. package/lib/engine-components/RigidBody.d.ts +0 -1
  42. package/lib/engine-components/RigidBody.js +24 -30
  43. package/lib/engine-components/RigidBody.js.map +1 -1
  44. package/lib/engine-components/codegen/components.d.ts +25 -1
  45. package/lib/engine-components/codegen/components.js +25 -1
  46. package/lib/engine-components/codegen/components.js.map +1 -1
  47. package/lib/engine-components/export/usdz/Extension.d.ts +4 -4
  48. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +86 -0
  49. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +858 -0
  50. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -0
  51. package/lib/engine-components/export/usdz/USDZExporter.d.ts +6 -3
  52. package/lib/engine-components/export/usdz/USDZExporter.js +34 -11
  53. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  54. package/lib/engine-components/export/usdz/extensions/Animation.d.ts +15 -15
  55. package/lib/engine-components/export/usdz/extensions/Animation.js +24 -29
  56. package/lib/engine-components/export/usdz/extensions/Animation.js.map +1 -1
  57. package/lib/engine-components/export/usdz/extensions/DocumentExtension.d.ts +5 -0
  58. package/lib/engine-components/export/usdz/extensions/DocumentExtension.js +7 -0
  59. package/lib/engine-components/export/usdz/extensions/DocumentExtension.js.map +1 -0
  60. package/lib/engine-components/export/usdz/extensions/USDZText.d.ts +47 -0
  61. package/lib/engine-components/export/usdz/extensions/USDZText.js +114 -0
  62. package/lib/engine-components/export/usdz/extensions/USDZText.js.map +1 -0
  63. package/lib/engine-components/export/usdz/extensions/behavior/Actions.d.ts +30 -0
  64. package/lib/engine-components/export/usdz/extensions/behavior/Actions.js +89 -0
  65. package/lib/engine-components/export/usdz/extensions/behavior/Actions.js.map +1 -0
  66. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.d.ts +23 -0
  67. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js +114 -0
  68. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js.map +1 -0
  69. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +102 -0
  70. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +458 -0
  71. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -0
  72. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.d.ts +111 -0
  73. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js +409 -0
  74. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js.map +1 -0
  75. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  76. package/lib/engine-components/ui/BaseUIComponent.d.ts +2 -0
  77. package/lib/engine-components/ui/BaseUIComponent.js +6 -0
  78. package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
  79. package/lib/engine-components/ui/Canvas.d.ts +11 -1
  80. package/lib/engine-components/ui/Canvas.js +72 -3
  81. package/lib/engine-components/ui/Canvas.js.map +1 -1
  82. package/lib/engine-components/ui/Graphic.js.map +1 -1
  83. package/lib/engine-components/ui/Image.js +4 -4
  84. package/lib/engine-components/ui/Image.js.map +1 -1
  85. package/lib/engine-components/ui/Interfaces.d.ts +11 -0
  86. package/lib/engine-components/ui/Interfaces.js +11 -0
  87. package/lib/engine-components/ui/Interfaces.js.map +1 -1
  88. package/lib/engine-components/ui/Layout.d.ts +65 -3
  89. package/lib/engine-components/ui/Layout.js +304 -3
  90. package/lib/engine-components/ui/Layout.js.map +1 -1
  91. package/lib/engine-components/ui/RectTransform.d.ts +8 -7
  92. package/lib/engine-components/ui/RectTransform.js +66 -36
  93. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  94. package/lib/engine-components/utils/LookAt.d.ts +7 -1
  95. package/lib/engine-components/utils/LookAt.js +43 -6
  96. package/lib/engine-components/utils/LookAt.js.map +1 -1
  97. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +4 -3
  98. package/lib/engine-components/webxr/WebXRImageTracking.js +81 -25
  99. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  100. package/lib/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +1 -1
  102. package/plugins/vite/config.js +2 -1
  103. package/plugins/vite/defines.js +30 -0
  104. package/plugins/vite/dependency-watcher.js +173 -0
  105. package/plugins/vite/editor-connection.js +37 -39
  106. package/plugins/vite/index.js +5 -1
  107. package/plugins/vite/reload.js +16 -3
  108. package/src/engine/api.ts +1 -0
  109. package/src/engine/codegen/register_types.js +50 -2
  110. package/src/engine/engine_context.ts +32 -23
  111. package/src/engine/engine_context_registry.ts +13 -6
  112. package/src/engine/engine_element.ts +2 -1
  113. package/src/engine/engine_element_loading.ts +2 -3
  114. package/src/engine/engine_gameobject.ts +3 -2
  115. package/src/engine/engine_input.ts +2 -2
  116. package/src/engine/engine_physics.ts +25 -1020
  117. package/src/engine/engine_physics.types.ts +1 -3
  118. package/src/engine/engine_physics_rapier.ts +1127 -0
  119. package/src/engine/engine_three_utils.ts +2 -2
  120. package/src/engine/engine_types.ts +66 -4
  121. package/src/engine-components/Animation.ts +4 -0
  122. package/src/engine-components/Collider.ts +6 -6
  123. package/src/engine-components/Joints.ts +2 -2
  124. package/src/engine-components/RigidBody.ts +24 -31
  125. package/src/engine-components/codegen/components.ts +25 -1
  126. package/src/engine-components/export/usdz/Extension.ts +4 -5
  127. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +1312 -0
  128. package/src/engine-components/export/usdz/USDZExporter.ts +39 -17
  129. package/src/engine-components/export/usdz/extensions/Animation.ts +37 -45
  130. package/src/engine-components/export/usdz/extensions/DocumentExtension.ts +10 -0
  131. package/src/engine-components/export/usdz/extensions/USDZText.ts +142 -0
  132. package/src/engine-components/export/usdz/extensions/behavior/Actions.ts +99 -0
  133. package/src/engine-components/export/usdz/extensions/behavior/Behaviour.ts +181 -0
  134. package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +545 -0
  135. package/src/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.ts +459 -0
  136. package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
  137. package/src/engine-components/ui/BaseUIComponent.ts +7 -1
  138. package/src/engine-components/ui/Canvas.ts +80 -5
  139. package/src/engine-components/ui/Graphic.ts +2 -0
  140. package/src/engine-components/ui/Image.ts +3 -3
  141. package/src/engine-components/ui/Interfaces.ts +30 -6
  142. package/src/engine-components/ui/Layout.ts +303 -4
  143. package/src/engine-components/ui/RectTransform.ts +67 -41
  144. package/src/engine-components/utils/LookAt.ts +60 -7
  145. package/src/engine-components/webxr/WebXRImageTracking.ts +100 -27
  146. package/lib/engine-components/export/usdz/types.d.ts +0 -34
  147. package/lib/engine-components/export/usdz/types.js +0 -2
  148. package/lib/engine-components/export/usdz/types.js.map +0 -1
  149. package/src/engine-components/export/usdz/types.ts +0 -39
@@ -0,0 +1,459 @@
1
+ import { Object3D } from "three";
2
+ import { USDDocument, USDObject, USDWriter, makeNameSafeForUSD } from "../../ThreeUSDZExporter";
3
+
4
+ import { BehaviorExtension } from "./Behaviour";
5
+
6
+ // TODO: rename to usdz element
7
+ export interface IBehaviorElement {
8
+ id: string;
9
+ writeTo(document: USDDocument, writer: USDWriter);
10
+ }
11
+
12
+ export class BehaviorModel {
13
+
14
+ static global_id: number = 0;
15
+ id: string;
16
+ trigger: IBehaviorElement | IBehaviorElement[];
17
+ action: IBehaviorElement;
18
+ exclusive: boolean = false;
19
+
20
+ makeExclusive(exclusive: boolean): BehaviorModel {
21
+ this.exclusive = exclusive;
22
+ return this;
23
+ }
24
+
25
+ constructor(id: string, trigger: IBehaviorElement | IBehaviorElement[], action: IBehaviorElement) {
26
+ this.id = "Behavior_" + makeNameSafeForUSD(id) + "_" + BehaviorModel.global_id++;
27
+ this.trigger = trigger;
28
+ this.action = action;
29
+ }
30
+
31
+ writeTo(_ext: BehaviorExtension, document: USDDocument, writer: USDWriter) {
32
+ if (!this.trigger || !this.action) return;
33
+ writer.beginBlock(`def Preliminary_Behavior "${this.id}"`);
34
+ writer.appendLine(`rel actions = <${this.action.id}>`);
35
+ writer.appendLine(`uniform bool exclusive = ${this.exclusive}`);
36
+ let triggerString = "";
37
+ if (Array.isArray(this.trigger)) {
38
+ triggerString = "[";
39
+ for (let i = 0; i < this.trigger.length; i++) {
40
+ const tr = this.trigger[i];
41
+ triggerString += "<" + tr.id + ">";
42
+ if (i + 1 < this.trigger.length) triggerString += ", ";
43
+ }
44
+ triggerString += "]";
45
+ }
46
+ else
47
+ triggerString = `<${this.trigger.id}>`;
48
+
49
+ writer.appendLine(`rel triggers = ${triggerString} `);
50
+ writer.appendLine();
51
+ if (Array.isArray(this.trigger)) {
52
+ for (const trigger of this.trigger) {
53
+ trigger.writeTo(document, writer);
54
+ writer.appendLine();
55
+ }
56
+ }
57
+ else
58
+ this.trigger.writeTo(document, writer);
59
+ writer.appendLine();
60
+ this.action.writeTo(document, writer);
61
+ writer.closeBlock();
62
+ }
63
+ }
64
+
65
+
66
+ type Target = USDObject | USDObject[] | Object3D | Object3D[];
67
+
68
+ /** called to resolve target objects to usdz paths */
69
+ function resolve(targetObject: Target, document: USDDocument): string {
70
+ let result: string = "";
71
+ if (Array.isArray(targetObject)) {
72
+ let str = "[ ";
73
+ for (let i = 0; i < targetObject.length; i++) {
74
+ let obj = targetObject[i];
75
+ if (typeof obj === "string")
76
+ str += obj;
77
+ else if ( typeof obj === "object") {
78
+ //@ts-ignore
79
+ if (obj.isObject3D) {
80
+ //@ts-ignore
81
+ obj = document.findById(obj.uuid);
82
+ }
83
+ const res = (obj as any).getPath?.call(obj) as string;
84
+ str += res;
85
+ }
86
+ if (i + 1 < targetObject.length) str += ", ";
87
+ }
88
+ str += " ]";
89
+ result = str;
90
+ }
91
+ else if (typeof targetObject === "object") {
92
+ //@ts-ignore
93
+ if (targetObject.isObject3D) {
94
+ //@ts-ignore
95
+ targetObject = document.findById(targetObject.uuid);
96
+ }
97
+ result = (targetObject as any).getPath?.call(targetObject) as string;
98
+ }
99
+
100
+ // in three there's now a new "Scenes" parent and "Scene" xform that's injected;
101
+ // we need to add this to our path here so that we have full paths
102
+ result = result.replace(document.name, document.name + "/Scenes/Scene");
103
+ return result;
104
+ }
105
+
106
+ export class TriggerModel implements IBehaviorElement {
107
+ static global_id: number = 0;
108
+
109
+ id: string;
110
+ targetId?: string | Target;
111
+ tokenId?: string;
112
+ type?: string;
113
+
114
+ constructor(targetId?: string | Target, id?: string) {
115
+ if (targetId) this.targetId = targetId;
116
+ if (id) this.id = id;
117
+ else this.id = "Trigger_" + TriggerModel.global_id++;
118
+ }
119
+
120
+ writeTo(document: USDDocument, writer: USDWriter) {
121
+ writer.beginBlock(`def Preliminary_Trigger "${this.id}"`);
122
+ if (this.targetId) {
123
+ if (typeof this.targetId !== "string") this.targetId = resolve(this.targetId, document);
124
+ writer.appendLine(`rel affectedObjects = ` + this.targetId);
125
+ }
126
+ if (this.tokenId)
127
+ writer.appendLine(`token info:id = "${this.tokenId}"`);
128
+ if (this.type)
129
+ writer.appendLine(`token type = "${this.type}"`);
130
+ writer.closeBlock();
131
+ }
132
+ }
133
+
134
+ export class TriggerBuilder {
135
+
136
+ static sceneStartTrigger(): TriggerModel {
137
+ const trigger = new TriggerModel();
138
+ trigger.targetId = undefined;
139
+ trigger.tokenId = "SceneTransition";
140
+ trigger.type = "enter";
141
+ return trigger;
142
+ }
143
+
144
+ static tapTrigger(targetObject: Target): TriggerModel {
145
+ const trigger = new TriggerModel(targetObject);
146
+ trigger.tokenId = "TapGesture";
147
+ return trigger;
148
+ }
149
+
150
+ static isTapTrigger(trigger?: TriggerModel) {
151
+ return trigger?.tokenId === "TapGesture";
152
+ }
153
+ }
154
+
155
+ export class GroupActionModel implements IBehaviorElement {
156
+
157
+ static global_id: number = 0;
158
+ static getId(): number {
159
+ return this.global_id++;
160
+ }
161
+
162
+ id: string;
163
+ actions: IBehaviorElement[];
164
+ loops: number = 0;
165
+ performCount: number = 1;
166
+ type: string = "serial";
167
+
168
+ constructor(id: string, actions: IBehaviorElement[]) {
169
+ this.id = id;
170
+ this.actions = actions;
171
+ }
172
+
173
+ addAction(el: IBehaviorElement): GroupActionModel {
174
+ this.actions.push(el);
175
+ return this;
176
+ }
177
+
178
+ makeParallel(): GroupActionModel {
179
+ this.type = "parallel";
180
+ return this;
181
+ }
182
+
183
+ makeSequence(): GroupActionModel {
184
+ this.type = "serial";
185
+ return this;
186
+ }
187
+
188
+ makeLooping() {
189
+ this.loops = 1;
190
+ return this;
191
+ }
192
+
193
+ makeRepeat(count: number) {
194
+ this.performCount = count;
195
+ return this;
196
+ }
197
+
198
+ writeTo(document: USDDocument, writer: USDWriter) {
199
+ writer.beginBlock(`def Preliminary_Action "${this.id}"`);
200
+ writer.beginArray("rel actions");
201
+ for (const act of this.actions) {
202
+ if (!act) continue;
203
+ writer.appendLine("<" + act.id + ">,");
204
+ }
205
+ writer.closeArray();
206
+ writer.appendLine();
207
+
208
+ writer.appendLine(`token info:id = "Group"`);
209
+ writer.appendLine(`bool loops = ${this.loops} `);
210
+ writer.appendLine(`int performCount = ${this.performCount} `);
211
+ writer.appendLine(`token type = "${this.type}"`);
212
+ writer.appendLine();
213
+
214
+ for (const act of this.actions) {
215
+ if (!act) continue;
216
+ act.writeTo(document, writer);
217
+ writer.appendLine();
218
+ }
219
+
220
+ writer.closeBlock();
221
+ }
222
+ }
223
+
224
+ export enum MotionType {
225
+ pop = 0,
226
+ blink = 1,
227
+ bounce = 2,
228
+ flip = 3,
229
+ float = 4,
230
+ jiggle = 5,
231
+ pulse = 6,
232
+ spin = 7,
233
+ };
234
+
235
+ export enum Space {
236
+ Relative = "relative",
237
+ Absolute = "absolute"
238
+ };
239
+
240
+ export class ActionModel implements IBehaviorElement {
241
+
242
+ private static global_id: number = 0;
243
+
244
+ id: string;
245
+ tokenId?: string;
246
+ affectedObjects?: string | Target;
247
+ easeType?: string;;
248
+ motionType?: string;
249
+ duration?: number;
250
+ moveDistance?: number;
251
+ style?: string;
252
+ type?: string;
253
+ front?: Vec3;
254
+ up?: Vec3;
255
+ start?: number;
256
+ animationSpeed?: number;
257
+ reversed?: boolean;
258
+ pingPong?: boolean;
259
+ xFormTarget?: Target | string;
260
+
261
+ clone(): ActionModel {
262
+ const copy = new ActionModel();
263
+ const id = copy.id;
264
+ Object.assign(copy, this);
265
+ copy.id = id;
266
+ return copy;
267
+ }
268
+
269
+ constructor(affectedObjects?: string | Target, id?: string) {
270
+ if (affectedObjects) this.affectedObjects = affectedObjects;
271
+ if (id) this.id = id;
272
+ /*else if (affectedObjects) {
273
+ this.id = "Action_" + sanitizeId(affectedObjects);
274
+ }
275
+ else */
276
+ else
277
+ this.id = "Action";
278
+ this.id += "_" + ActionModel.global_id++;
279
+ }
280
+
281
+ writeTo(document: USDDocument, writer: USDWriter) {
282
+ writer.beginBlock(`def Preliminary_Action "${this.id}"`);
283
+ if (this.affectedObjects) {
284
+ if (typeof this.affectedObjects !== "string") this.affectedObjects = resolve(this.affectedObjects, document);
285
+ writer.appendLine('rel affectedObjects = ' + this.affectedObjects);
286
+ }
287
+ if (typeof this.duration === "number")
288
+ writer.appendLine(`double duration = ${this.duration} `);
289
+ if (this.easeType)
290
+ writer.appendLine(`token easeType = "${this.easeType}"`);
291
+ if (this.tokenId)
292
+ writer.appendLine(`token info:id = "${this.tokenId}"`);
293
+ if (this.motionType)
294
+ writer.appendLine(`token motionType = "${this.motionType}"`);
295
+ if (typeof this.moveDistance === "number")
296
+ writer.appendLine(`double moveDistance = ${this.moveDistance} `);
297
+ if (this.style)
298
+ writer.appendLine(`token style = "${this.style}"`);
299
+ if (this.type)
300
+ writer.appendLine(`token type = "${this.type}"`);
301
+ if (this.front)
302
+ writer.appendLine(`vector3d front = (${this.front.x}, ${this.front.y}, ${this.front.z})`);
303
+ if (this.up)
304
+ writer.appendLine(`vector3d upVector = (${this.up.x}, ${this.up.y}, ${this.up.z})`);
305
+ if (typeof this.start === "number") {
306
+ writer.appendLine(`double start = ${this.start} `);
307
+ }
308
+ if (typeof this.animationSpeed === "number") {
309
+ writer.appendLine(`double animationSpeed = ${this.animationSpeed} `);
310
+ }
311
+ if (typeof this.reversed === "boolean") {
312
+ writer.appendLine(`bool reversed = ${this.reversed}`)
313
+ }
314
+ if (typeof this.pingPong === "boolean") {
315
+ writer.appendLine(`bool reverses = ${this.pingPong}`)
316
+ }
317
+ if (this.xFormTarget) {
318
+ if (typeof this.xFormTarget !== "string")
319
+ this.xFormTarget = resolve(this.xFormTarget, document);
320
+ writer.appendLine(`rel xformTarget = ${this.xFormTarget}`)
321
+ }
322
+ writer.closeBlock();
323
+ }
324
+ }
325
+
326
+ class Vec3 {
327
+ x: number = 0;
328
+ y: number = 0;
329
+ z: number = 0;
330
+
331
+ constructor(x: number, y: number, z: number) {
332
+ this.x = x;
333
+ this.y = y;
334
+ this.z = z;
335
+ }
336
+
337
+ static get up(): Vec3 {
338
+ return new Vec3(0, 1, 0);
339
+ }
340
+
341
+ static get right(): Vec3 {
342
+ return new Vec3(1, 0, 0);
343
+ }
344
+
345
+ static get forward(): Vec3 {
346
+ return new Vec3(0, 0, 1);
347
+ }
348
+
349
+ static get back(): Vec3 {
350
+ return new Vec3(0, 0, -1);
351
+ }
352
+
353
+ static get zero(): Vec3 {
354
+ return new Vec3(0, 0, 0);
355
+ }
356
+ }
357
+
358
+ export class ActionBuilder {
359
+
360
+ static sequence(...params: IBehaviorElement[]) {
361
+ const group = new GroupActionModel("group_" + GroupActionModel.getId(), params);
362
+ return group.makeSequence();
363
+ }
364
+
365
+ static parallel(...params: IBehaviorElement[]) {
366
+ const group = new GroupActionModel("group_" + GroupActionModel.getId(), params);
367
+ return group.makeParallel();
368
+ }
369
+
370
+ static fadeAction(targetObject: Target, duration: number, show: boolean): ActionModel {
371
+ const act = new ActionModel(targetObject);
372
+ act.tokenId = "Visibility";
373
+ act.type = show ? "show" : "hide";
374
+ act.duration = duration;
375
+
376
+ act.style = "basic";
377
+ act.motionType = "none";
378
+ act.moveDistance = 0;
379
+ act.easeType = "none";
380
+ return act;
381
+ }
382
+
383
+ /**
384
+ * creates an action that plays an animation
385
+ * @param start offset in seconds!
386
+ * @param duration in seconds! 0 means play to end
387
+ */
388
+ static startAnimationAction(targetObject: Target, start: number, duration: number = 0, animationSpeed: number = 1, reversed: boolean = false, pingPong: boolean = false): IBehaviorElement {
389
+ const act = new ActionModel(targetObject);
390
+ act.tokenId = "StartAnimation";
391
+ act.start = start;
392
+ // start is time in seconds, the documentation is not right here
393
+ act.duration = duration;
394
+ // duration of 0 is play to end
395
+ act.animationSpeed = animationSpeed;
396
+ act.reversed = reversed;
397
+ act.pingPong = pingPong;
398
+ if (reversed) {
399
+ act.start -= duration;
400
+ //console.warn("Reversed animation does currently not work. The resulting file will most likely not playback.", act.id, targetObject);
401
+ }
402
+ if (pingPong) {
403
+ act.pingPong = false;
404
+ const back = act.clone();
405
+ back.reversed = !reversed;
406
+ back.start = act.start;
407
+ if (back.reversed) {
408
+ back.start -= duration;
409
+ }
410
+ const group = ActionBuilder.sequence(act, back);
411
+ return group;
412
+ }
413
+ return act;
414
+ }
415
+
416
+ static waitAction(duration: number): ActionModel {
417
+ const act = new ActionModel();
418
+ act.tokenId = "Wait";
419
+ act.duration = duration;
420
+ return act;
421
+ }
422
+
423
+ static lookAtCameraAction(targets: Target, duration: number = 9999999999999, front?: Vec3, up?: Vec3): ActionModel {
424
+ const act = new ActionModel(targets);
425
+ act.tokenId = "LookAtCamera";
426
+ act.duration = duration;
427
+ act.front = front ?? Vec3.forward;
428
+ // 0,0,0 is a special case for "free look"
429
+ // 0,1,0 is for "y-locked look-at"
430
+ act.up = up ?? Vec3.up;
431
+ return act;
432
+ }
433
+
434
+ static emphasize(targets: Target, duration: number, motionType: MotionType = MotionType.bounce, moveDistance: number = 1, style: string = "basic") {
435
+ const act = new ActionModel(targets);
436
+ act.tokenId = "Emphasize";
437
+ act.duration = duration;
438
+ act.style = style ?? "basic";
439
+ act.motionType = MotionType[motionType];
440
+ act.moveDistance = moveDistance;
441
+ return act;
442
+ }
443
+
444
+ static transformAction(targets: Target, transformTarget: Target, duration: number, transformType: Space, easeType: string = "inout") {
445
+ const act = new ActionModel(targets);
446
+ act.tokenId = "Transform";
447
+ act.duration = duration;
448
+ act.type = transformType;
449
+ act.easeType = easeType;
450
+ if (Array.isArray(transformTarget)) {
451
+ console.error("Transform target must not be an array", transformTarget);
452
+ }
453
+ act.xFormTarget = transformTarget;
454
+ return act;
455
+ }
456
+
457
+ }
458
+
459
+ export { Vec3 as USDVec3 }
@@ -1,4 +1,4 @@
1
- import { HalfFloatType, sRGBEncoding, WebGLRenderTarget } from "three";
1
+ import { HalfFloatType } from "three";
2
2
  import { Context } from "../../engine/engine_setup";
3
3
  import { getParam, isMobileDevice } from "../../engine/engine_utils";
4
4
  import { BloomEffect, BrightnessContrastEffect, ChromaticAberrationEffect, DepthDownsamplingPass, DepthOfFieldEffect, Effect, EffectComposer, EffectPass, HueSaturationEffect, NormalPass, Pass, PixelationEffect, RenderPass, SelectiveBloomEffect, SSAOEffect, VignetteEffect } from "postprocessing";
@@ -4,7 +4,7 @@ import { Behaviour, GameObject } from "../Component";
4
4
  import { EventSystem } from "./EventSystem";
5
5
  import { showGizmos } from '../../engine/engine_default_parameters';
6
6
  import { AxesHelper, Object3D } from 'three';
7
- import { IGraphic } from './Interfaces';
7
+ import { ICanvas, IGraphic } from './Interfaces';
8
8
  import { ShadowCastingMode } from '../Renderer';
9
9
  export const includesDir = "./include";
10
10
 
@@ -50,6 +50,12 @@ export class BaseUIComponent extends Behaviour {
50
50
  return this._root;
51
51
  }
52
52
 
53
+ protected get Canvas() {
54
+ const cv = this.Root as any as ICanvas;
55
+ if (cv?.isCanvas) return cv;
56
+ return null;
57
+ }
58
+
53
59
  // private _intermediate?: Object3D;
54
60
  protected _parentComponent?: BaseUIComponent | null = undefined;
55
61
 
@@ -3,12 +3,14 @@ import { serializable } from "../../engine/engine_serialization_decorator";
3
3
  import { FrameEvent } from "../../engine/engine_setup";
4
4
  import { BaseUIComponent, UIRootComponent } from "./BaseUIComponent";
5
5
  import { GameObject } from "../Component";
6
- import { Object3D } from "three";
6
+ import { Matrix4, Object3D } from "three";
7
7
  import { RectTransform } from "./RectTransform";
8
- import { ICanvas } from "./Interfaces";
8
+ import { ICanvas, ILayoutGroup, IRectTransform } from "./Interfaces";
9
9
  import { Camera } from "../Camera";
10
10
  import { EventSystem } from "./EventSystem";
11
11
  import * as ThreeMeshUI from 'three-mesh-ui'
12
+ import { getParam } from "../../engine/engine_utils";
13
+ import { LayoutGroup } from "./Layout";
12
14
 
13
15
  export enum RenderMode {
14
16
  ScreenSpaceOverlay = 0,
@@ -17,8 +19,14 @@ export enum RenderMode {
17
19
  Undefined = -1,
18
20
  }
19
21
 
22
+ const debugLayout = getParam("debuguilayout");
23
+
20
24
  export class Canvas extends UIRootComponent implements ICanvas {
21
25
 
26
+ get isCanvas() {
27
+ return true;
28
+ }
29
+
22
30
  get screenspace(): any {
23
31
  return this.renderMode !== RenderMode.WorldSpace;
24
32
  }
@@ -122,6 +130,10 @@ export class Canvas extends UIRootComponent implements ICanvas {
122
130
  super.awake();
123
131
  }
124
132
 
133
+ start() {
134
+ this.onUpdateRenderMode();
135
+ }
136
+
125
137
  onEnable() {
126
138
  super.onEnable();
127
139
  this._updateRenderSettingsRoutine = undefined;
@@ -149,6 +161,28 @@ export class Canvas extends UIRootComponent implements ICanvas {
149
161
  private _boundRenderSettingsChanged = this.onRenderSettingsChanged.bind(this);
150
162
 
151
163
  private previousParent: Object3D | null = null;
164
+ private _lastMatrixWorld: Matrix4 | null = null;
165
+ private _rectTransforms: IRectTransform[] = [];
166
+
167
+ registerTransform(rt: IRectTransform) {
168
+ this._rectTransforms.push(rt);
169
+ }
170
+ unregisterTransform(rt: IRectTransform) {
171
+ const index = this._rectTransforms.indexOf(rt);
172
+ if (index !== -1) {
173
+ this._rectTransforms.splice(index, 1);
174
+ }
175
+ }
176
+
177
+ private _layoutGroups: Map<Object3D, ILayoutGroup> = new Map();
178
+ registerLayoutGroup(group: ILayoutGroup) {
179
+ const obj = group.gameObject;
180
+ this._layoutGroups.set(obj, group)
181
+ }
182
+ unregisterLayoutGroup(group: ILayoutGroup) {
183
+ const obj = group.gameObject;
184
+ this._layoutGroups.delete(obj);
185
+ }
152
186
 
153
187
  onBeforeRenderRoutine = () => {
154
188
  if (this.renderOnTop) {
@@ -158,6 +192,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
158
192
  }
159
193
  else {
160
194
  this.onUpdateRenderMode();
195
+ this.handleLayoutUpdates();
161
196
  // TODO: we might need to optimize this. This is here to make sure the TMUI text clipping matrices are correct. Ideally the text does use onBeforeRender and apply the clipping matrix there so we dont have to force update all the matrices here
162
197
  this.shadowComponent?.updateMatrixWorld(true);
163
198
  this.shadowComponent?.updateWorldMatrix(true, true);
@@ -171,11 +206,40 @@ export class Canvas extends UIRootComponent implements ICanvas {
171
206
  this.context.renderer.autoClear = false;
172
207
  this.context.renderer.clearDepth();
173
208
  this.onUpdateRenderMode(true);
209
+ this.handleLayoutUpdates();
174
210
  this.shadowComponent?.updateMatrixWorld(true);
211
+ // this.handleLayoutUpdates();
175
212
  EventSystem.ensureUpdateMeshUI(ThreeMeshUI, this.context);
176
213
  this.context.renderer.render(this.gameObject, this.context.mainCamera);
177
214
  this.context.renderer.autoClear = true;
178
215
  }
216
+ this._lastMatrixWorld?.copy(this.gameObject.matrixWorld);
217
+ }
218
+
219
+ private handleLayoutUpdates() {
220
+ if (this._lastMatrixWorld === null) {
221
+ this._lastMatrixWorld = new Matrix4();
222
+ }
223
+ const matrixWorldChanged = !this._lastMatrixWorld.equals(this.gameObject.matrixWorld);
224
+ if (debugLayout && matrixWorldChanged) console.log("Canvas Layout changed", this.context.time.frameCount, this.name);
225
+
226
+ // TODO: optimize this, we should only need to update a subhierarchy of the parts where layout has changed
227
+ let didLog = false;
228
+ for (const ch of this._rectTransforms) {
229
+ if (matrixWorldChanged) ch.markDirty();
230
+ let layout = this._layoutGroups.get(ch.gameObject);
231
+ if(ch.isDirty && !layout){
232
+ layout = ch.gameObject.getComponentInParent(LayoutGroup) as LayoutGroup;
233
+ }
234
+ if (ch.isDirty || layout?.isDirty) {
235
+ if (debugLayout && !didLog) {
236
+ console.log("CANVAS UPDATE ### " + ch.name + " ##################################### " + this.context.time.frame);
237
+ // didLog = true;
238
+ }
239
+ layout?.updateLayout();
240
+ ch.updateTransform();
241
+ }
242
+ }
179
243
  }
180
244
 
181
245
  applyRenderSettings() {
@@ -205,6 +269,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
205
269
  private _lastWidth: number = -1;
206
270
  private _lastHeight: number = -1;
207
271
 
272
+
208
273
  private onUpdateRenderMode(force: boolean = false) {
209
274
  if (!force) {
210
275
  if (this._renderMode === this._activeRenderMode && this._lastWidth === this.context.domWidth && this._lastHeight === this.context.domHeight) {
@@ -241,6 +306,13 @@ export class Canvas extends UIRootComponent implements ICanvas {
241
306
  canvas.quaternion.identity();
242
307
 
243
308
  const rect = this.gameObject.getComponent(RectTransform)!;
309
+ let hasChanged = false;
310
+ if (rect.sizeDelta.x !== this.context.domWidth) {
311
+ hasChanged = true;
312
+ }
313
+ if (rect.sizeDelta.y !== this.context.domHeight) {
314
+ hasChanged = true;
315
+ }
244
316
 
245
317
  const vFOV = camera.fieldOfView! * Math.PI / 180;
246
318
  const h = 2 * Math.tan(vFOV / 2) * Math.abs(plane);
@@ -248,9 +320,12 @@ export class Canvas extends UIRootComponent implements ICanvas {
248
320
  canvas.scale.y = h / this.context.domHeight;
249
321
  // Set scale.z, otherwise small offsets in screenspace mode have different visual results based on export scale and other settings
250
322
  canvas.scale.z = .01;
251
- rect.sizeDelta.x = this.context.domWidth;
252
- rect.sizeDelta.y = this.context.domHeight;
253
- rect?.markDirty();
323
+
324
+ if (hasChanged) {
325
+ rect.sizeDelta.x = this.context.domWidth;
326
+ rect.sizeDelta.y = this.context.domHeight;
327
+ rect?.markDirty();
328
+ }
254
329
 
255
330
 
256
331
  // this.context.scene.add(this.gameObject)
@@ -9,6 +9,8 @@ import { onChange, scheduleAction } from "./Utils"
9
9
  import { GameObject } from '../Component';
10
10
  import SimpleStateBehavior from "three-mesh-ui/examples/behaviors/states/SimpleStateBehavior"
11
11
  import { Outline } from './Outline';
12
+ import { BehaviorExtension, UsdzBehaviour } from '../../engine-components/export/usdz/extensions/behavior/Behaviour';
13
+ import { USDObject } from '../../engine-components/export/usdz/ThreeUSDZExporter';
12
14
 
13
15
  const _colorStateObject: { backgroundColor: Color, backgroundOpacity: number } = {
14
16
  backgroundColor: new Color(1, 1, 1),
@@ -49,9 +49,9 @@ export class Image extends MaskableGraphic {
49
49
  if(this.sprite?.texture?.name === "Knob") {
50
50
  opts.borderRadius = 999;
51
51
  }
52
- opts.borderColor = new Color(.4, .4, .4);
53
- opts.borderOpacity = this.color.alpha;
54
- opts.borderWidth = .3;
52
+ // opts.borderColor = new Color(.4, .4, .4);
53
+ // opts.borderOpacity = this.color.alpha;
54
+ // opts.borderWidth = .3;
55
55
  }
56
56
 
57
57
  }