@needle-tools/engine 3.2.14-alpha → 3.3.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 (101) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/needle-engine.js +42139 -35749
  3. package/dist/needle-engine.min.js +694 -516
  4. package/dist/needle-engine.umd.cjs +696 -518
  5. package/lib/engine/codegen/register_types.js +4 -2
  6. package/lib/engine/codegen/register_types.js.map +1 -1
  7. package/lib/engine/engine_addressables.d.ts +3 -3
  8. package/lib/engine/engine_addressables.js +30 -9
  9. package/lib/engine/engine_addressables.js.map +1 -1
  10. package/lib/engine/engine_element.js +1 -1
  11. package/lib/engine/engine_element.js.map +1 -1
  12. package/lib/engine/engine_gameobject.d.ts +2 -1
  13. package/lib/engine/engine_gameobject.js +17 -0
  14. package/lib/engine/engine_gameobject.js.map +1 -1
  15. package/lib/engine/engine_input.js +10 -0
  16. package/lib/engine/engine_input.js.map +1 -1
  17. package/lib/engine/engine_license.js +11 -24
  18. package/lib/engine/engine_license.js.map +1 -1
  19. package/lib/engine/engine_math.d.ts +4 -0
  20. package/lib/engine/engine_math.js +6 -0
  21. package/lib/engine/engine_math.js.map +1 -1
  22. package/lib/engine-components/AnimatorController.js +7 -2
  23. package/lib/engine-components/AnimatorController.js.map +1 -1
  24. package/lib/engine-components/OrbitControls.js +13 -4
  25. package/lib/engine-components/OrbitControls.js.map +1 -1
  26. package/lib/engine-components/SceneSwitcher.d.ts +1 -1
  27. package/lib/engine-components/SceneSwitcher.js +25 -1
  28. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  29. package/lib/engine-components/TransformGizmo.d.ts +8 -4
  30. package/lib/engine-components/TransformGizmo.js +62 -63
  31. package/lib/engine-components/TransformGizmo.js.map +1 -1
  32. package/lib/engine-components/codegen/components.d.ts +2 -1
  33. package/lib/engine-components/codegen/components.js +2 -1
  34. package/lib/engine-components/codegen/components.js.map +1 -1
  35. package/lib/engine-components/export/usdz/USDZExporter.d.ts +1 -0
  36. package/lib/engine-components/export/usdz/USDZExporter.js +10 -2
  37. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  38. package/lib/engine-components/ui/Button.js +9 -5
  39. package/lib/engine-components/ui/Button.js.map +1 -1
  40. package/lib/engine-components/ui/Canvas.d.ts +13 -6
  41. package/lib/engine-components/ui/Canvas.js +101 -37
  42. package/lib/engine-components/ui/Canvas.js.map +1 -1
  43. package/lib/engine-components/ui/EventSystem.d.ts +6 -0
  44. package/lib/engine-components/ui/EventSystem.js +4 -4
  45. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  46. package/lib/engine-components/ui/Graphic.d.ts +5 -2
  47. package/lib/engine-components/ui/Graphic.js +38 -7
  48. package/lib/engine-components/ui/Graphic.js.map +1 -1
  49. package/lib/engine-components/ui/Image.d.ts +1 -0
  50. package/lib/engine-components/ui/Image.js +10 -1
  51. package/lib/engine-components/ui/Image.js.map +1 -1
  52. package/lib/engine-components/ui/InputField.d.ts +1 -0
  53. package/lib/engine-components/ui/InputField.js +8 -0
  54. package/lib/engine-components/ui/InputField.js.map +1 -1
  55. package/lib/engine-components/ui/Interfaces.d.ts +8 -0
  56. package/lib/engine-components/ui/Outline.d.ts +7 -0
  57. package/lib/engine-components/ui/Outline.js +21 -0
  58. package/lib/engine-components/ui/Outline.js.map +1 -0
  59. package/lib/engine-components/ui/RectTransform.d.ts +29 -11
  60. package/lib/engine-components/ui/RectTransform.js +178 -46
  61. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  62. package/lib/engine-components/ui/Text.d.ts +13 -10
  63. package/lib/engine-components/ui/Text.js +177 -246
  64. package/lib/engine-components/ui/Text.js.map +1 -1
  65. package/lib/engine-components/utils/LookAt.d.ts +7 -0
  66. package/lib/engine-components/utils/LookAt.js +29 -0
  67. package/lib/engine-components/utils/LookAt.js.map +1 -0
  68. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +8 -0
  69. package/lib/engine-components/webxr/WebXRImageTracking.js +79 -3
  70. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  71. package/lib/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +2 -2
  73. package/src/engine/codegen/register_types.js +4 -2
  74. package/src/engine/engine_addressables.ts +28 -10
  75. package/src/engine/engine_element.ts +1 -1
  76. package/src/engine/engine_gameobject.ts +18 -1
  77. package/src/engine/engine_input.ts +11 -0
  78. package/src/engine/engine_license.ts +12 -25
  79. package/src/engine/engine_math.ts +10 -0
  80. package/src/engine-components/AnimatorController.ts +7 -1
  81. package/src/engine-components/OrbitControls.ts +14 -6
  82. package/src/engine-components/SceneSwitcher.ts +28 -3
  83. package/src/engine-components/TransformGizmo.ts +64 -70
  84. package/src/engine-components/codegen/components.ts +2 -1
  85. package/src/engine-components/export/usdz/USDZExporter.ts +7 -2
  86. package/src/engine-components/ui/Button.ts +14 -9
  87. package/src/engine-components/ui/Canvas.ts +104 -40
  88. package/src/engine-components/ui/EventSystem.ts +16 -9
  89. package/src/engine-components/ui/Graphic.ts +44 -8
  90. package/src/engine-components/ui/Image.ts +10 -1
  91. package/src/engine-components/ui/InputField.ts +9 -1
  92. package/src/engine-components/ui/Interfaces.ts +12 -0
  93. package/src/engine-components/ui/Outline.ts +13 -0
  94. package/src/engine-components/ui/RectTransform.ts +203 -60
  95. package/src/engine-components/ui/Text.ts +284 -265
  96. package/src/engine-components/utils/LookAt.ts +21 -0
  97. package/src/engine-components/webxr/WebXRImageTracking.ts +85 -10
  98. package/lib/engine-components/ui/Keyboard.d.ts +0 -31
  99. package/lib/engine-components/ui/Keyboard.js +0 -178
  100. package/lib/engine-components/ui/Keyboard.js.map +0 -1
  101. package/src/engine-components/ui/Keyboard.ts +0 -204
@@ -1,11 +1,14 @@
1
- import { Behaviour } from "../Component";
2
1
  import * as ThreeMeshUI from 'three-mesh-ui'
3
2
  import { BaseUIComponent } from "./BaseUIComponent";
3
+ import { DocumentedOptions as ThreeMeshUIEveryOptions } from "three-mesh-ui/build/types/core/elements/MeshUIBaseElement";
4
4
  import { serializable } from "../../engine/engine_serialization_decorator";
5
- import { Color, Matrix4, Object3D, Vector2, Vector3 } from "three";
5
+ import { Color, Matrix4, Object3D, Quaternion, Vector2, Vector3 } from "three";
6
6
  import { EventSystem } from "./EventSystem";
7
7
  import { getParam } from "../../engine/engine_utils";
8
8
  import { onChange } from "./Utils";
9
+ import { foreachComponentEnumerator } from "../../engine/engine_gameobject";
10
+ import { ICanvas, IRectTransform, IRectTransformChangedReceiver } from "./Interfaces";
11
+ import { GameObject } from '../Component';
9
12
 
10
13
  const debug = getParam("debugui");
11
14
 
@@ -21,38 +24,84 @@ export class Rect {
21
24
  height!: number;
22
25
  }
23
26
 
24
- export class RectTransform extends BaseUIComponent {
27
+ const tempVec = new Vector3();
28
+ const tempMatrix = new Matrix4();
29
+ const tempQuaternion = new Quaternion();
25
30
 
26
- offset: number = 0.01;
31
+ export class RectTransform extends BaseUIComponent implements IRectTransform, IRectTransformChangedReceiver {
32
+
33
+ offset: number = 0.05;
27
34
 
28
35
  // @serializable(Object3D)
29
36
  // root? : Object3D;
30
37
 
31
38
  get translation() { return this.gameObject.position; }
32
39
  get rotation() { return this.gameObject.quaternion; }
33
- get scale(): THREE.Vector3 { return this.gameObject.scale; }
40
+ get scale(): Vector3 { return this.gameObject.scale; }
34
41
 
35
42
  private _anchoredPosition!: Vector3;
36
- private get anchoredPosition() {
43
+
44
+ @serializable(Vector3)
45
+ get anchoredPosition() {
37
46
  if (!this._anchoredPosition) this._anchoredPosition = new Vector3();
38
47
  return this._anchoredPosition;
39
48
  }
49
+ private set anchoredPosition(value: Vector3) {
50
+ this._anchoredPosition = value;
51
+ }
40
52
 
41
53
  @serializable(Rect)
42
- rect?: Rect;
54
+ private rect?: Rect; // TODO: should we use the rect or sizeDelta?
55
+
43
56
  @serializable(Vector2)
44
- sizeDelta!: THREE.Vector2;
45
- @serializable(Vector3)
46
- anchoredPosition3D?: THREE.Vector3;
57
+ sizeDelta!: Vector2;
58
+
59
+ @serializable(Vector2)
60
+ pivot?: Vector2;
61
+
62
+ @serializable(Vector2)
63
+ anchorMin!: Vector2;
64
+ @serializable(Vector2)
65
+ anchorMax!: Vector2;
66
+
67
+ @serializable(Vector2)
68
+ offsetMin!: Vector2;
47
69
  @serializable(Vector2)
48
- pivot?: THREE.Vector2;
70
+ offsetMax!: Vector2;
49
71
 
72
+ get width() {
73
+ if (this.anchorMin.x !== this.anchorMax.x) {
74
+ if (this._parentRectTransform) {
75
+ const parentWidth = this._parentRectTransform.width;
76
+ const anchorWidth = this.anchorMax.x - this.anchorMin.x;
77
+ let width = parentWidth * anchorWidth;
78
+ width += this.sizeDelta.x;
79
+ return width;
80
+ }
81
+ }
82
+ return this.sizeDelta.x;
83
+ }
84
+ get height() {
85
+ if (this.anchorMin.y !== this.anchorMax.y) {
86
+ if (this._parentRectTransform) {
87
+ const parentHeight = this._parentRectTransform.height;
88
+ const anchorHeight = this.anchorMax.y - this.anchorMin.y;
89
+ let height = parentHeight * anchorHeight;
90
+ height += this.sizeDelta.y;
91
+ return height
92
+ }
93
+ }
94
+ return this.sizeDelta.y;
95
+ }
96
+
97
+ private lastMatrixWorld!: Matrix4;
50
98
  private lastMatrix!: Matrix4;
51
99
  private rectBlock!: Object3D;
52
100
  private _transformNeedsUpdate: boolean = false;
53
101
 
54
102
  awake() {
55
103
  super.awake();
104
+ this.lastMatrixWorld = new Matrix4();
56
105
  this.lastMatrix = new Matrix4();
57
106
  this.rectBlock = new Object3D();;
58
107
  this.rectBlock.position.z = .1;
@@ -60,7 +109,26 @@ export class RectTransform extends BaseUIComponent {
60
109
 
61
110
  // this is required if an animator animated the transform anchoring
62
111
  if (!this._anchoredPosition) this._anchoredPosition = new Vector3();
112
+
113
+ // TODO: we need to replace this with the watch that e.g. Rigibody is using (or the one in utils?)
114
+ // perhaps we can also just manually check the few properties in the update loops?
63
115
  onChange(this, "_anchoredPosition", () => { this._transformNeedsUpdate = true; });
116
+ onChange(this, "sizeDelta", () => { this._transformNeedsUpdate = true; });
117
+ onChange(this, "pivot", () => { this._transformNeedsUpdate = true; });
118
+
119
+ // When exported with an anchored position offset we remove it here
120
+ // because it would otherwise be applied twice when the anchoring is animated
121
+ // Maybe we can get rid of this workaround if we just set the mesh ui position from the
122
+ // anchored position value but then we would have to make sure if a user/the engine updates
123
+ // "position" the change would also land in anchoredPosition
124
+ // Another solution would perhaps be to get rid of the extra "anchoredPosition" vector3
125
+ // and instead use the same vector3 instance on both "position" and "anchoredPosition"
126
+ // But I'm also not sure if this will not cause issues elsewhere later / be confusing?
127
+ // (that being said we can make anchoredPosition hidden)
128
+ if (!this.isRoot()) {
129
+ this.gameObject.position.x += this.anchoredPosition.x;
130
+ this.gameObject.position.y -= this.anchoredPosition.y;
131
+ }
64
132
  }
65
133
 
66
134
  onEnable() {
@@ -74,75 +142,134 @@ export class RectTransform extends BaseUIComponent {
74
142
  this.removeShadowComponent();
75
143
  }
76
144
 
145
+ onParentRectTransformChanged(_comp: IRectTransform) {
146
+ // When the parent rect transform changes we have to to recalculate our transform
147
+ this._transformNeedsUpdate = true;
148
+ this.applyTransform();
149
+ }
150
+
151
+ private _parentRectTransform?: RectTransform;
152
+
77
153
  private applyTransform() {
78
154
  const uiobject = this.shadowComponent;
79
155
  if (!uiobject) return;
80
156
  this._transformNeedsUpdate = false;
157
+ this._parentRectTransform = GameObject.getComponentInParent(this.gameObject.parent!, RectTransform) as RectTransform;
158
+
159
+ if (debug) console.log("RectTransform ApplyTransform", this.name, this.isRoot());
81
160
 
82
161
  if (!this.isRoot()) {
83
- // this.gameObject transform has authority over three mesh ui shadow components
84
- // so we keep copy the transform to the threemesh ui components
85
- uiobject.position.copy(this.gameObject.position);
86
- uiobject.position.x *= -1;
87
- uiobject.position.z *= -1;
88
- // move slightly forward to avoid z fighting
89
- uiobject.position.z -= this.offset;
90
-
91
- uiobject.quaternion.copy(this.gameObject.quaternion);
92
- uiobject.rotation.x *= -1;
93
- // flip images
94
- uiobject.rotation.z *= -1;
95
-
96
- uiobject.scale.copy(this.gameObject.scale);
162
+ // Reset temp matrix
163
+ uiobject.matrix.identity();
164
+ uiobject.matrixAutoUpdate = false;
165
+ // calc pivot and apply
166
+ tempVec.set(0, 0, 0);
167
+ this.applyPivot(tempVec);
168
+ uiobject.matrix.setPosition(tempVec.x, tempVec.y, 0);
169
+ // calc rotation matrix and apply (we can skip this if it's not rotated)
170
+ if (this.gameObject.quaternion.x || this.gameObject.quaternion.y || this.gameObject.quaternion.z) {
171
+ tempQuaternion.copy(this.gameObject.quaternion);
172
+ tempQuaternion.x *= -1;
173
+ tempQuaternion.z *= -1;
174
+ tempMatrix.makeRotationFromQuaternion(tempQuaternion);
175
+ uiobject.matrix.premultiply(tempMatrix);
176
+ }
177
+ // calc anchors and offset and apply
178
+ tempVec.set(0, 0, 0);
179
+ this.applyAnchoring(tempVec);
180
+ tempVec.z += this.offset;
181
+ tempVec.z -= this.gameObject.position.z;
182
+ tempMatrix.identity();
183
+ tempMatrix.setPosition(tempVec.x, tempVec.y, tempVec.z);
184
+ uiobject.matrix.premultiply(tempMatrix);
185
+ // apply scale if necessary
186
+ if (this.gameObject.scale.x || this.gameObject.scale.y || this.gameObject.scale.z)
187
+ uiobject.matrix.scale(this.gameObject.scale);
97
188
  }
98
189
  else {
99
- uiobject.rotation.y = Math.PI;
190
+ // We have to rotate the canvas when it's in worldspace
191
+ const canvas = this.Root as any as ICanvas;
192
+ if (!canvas.screenspace) uiobject.rotation.y = Math.PI;
100
193
  }
101
194
 
102
- this.applyAnchoring(uiobject.position);
195
+ this._copyMatrixAfterRender = true;
103
196
  this.lastMatrix.copy(this.gameObject.matrix);
197
+
198
+ // iterate other components on this object that might need to know about the transform change
199
+ // e.g. Graphic components should update their width and height
200
+ const includeChildren = true;
201
+ for (const comp of foreachComponentEnumerator(this.gameObject, BaseUIComponent, includeChildren)) {
202
+ if (comp === this) continue;
203
+ const callback = comp as any as IRectTransformChangedReceiver;
204
+ if (callback.onParentRectTransformChanged)
205
+ callback.onParentRectTransformChanged(this);
206
+ }
104
207
  }
105
208
 
209
+ private _copyMatrixAfterRender: boolean = false;
210
+
106
211
  markDirty() {
107
212
  this._transformNeedsUpdate = true;
108
213
  }
109
214
 
215
+
110
216
  onBeforeRender() {
111
- // only handle update here if this is not the canvas
112
- // the canvas component does inherit from this class but it only serves as a root
113
- // it does not emit any UI elements and therefor we dont want to change its transform
114
- // if (this._parentComponent)
115
- // {
116
- const transformChanged = this._transformNeedsUpdate || this.lastMatrix.equals(this.gameObject.matrix) === false;
117
- if (transformChanged) {
118
- if (debug)
119
- console.log("updating", this.name);
217
+ // TODO: instead of checking matrix again it would perhaps be better to test if position, rotation or scale have changed individually?
218
+ const transformChanged = this.gameObject.matrixWorldNeedsUpdate || this._transformNeedsUpdate || !this.lastMatrixWorld.equals(this.gameObject.matrixWorld) || !this.lastMatrix.equals(this.gameObject.matrix);
219
+ if (transformChanged)
220
+ {
120
221
  this.applyTransform();
121
222
  }
122
- // }
123
- EventSystem.ensureUpdateMeshUI(ThreeMeshUI, this.context);
124
- }
125
-
126
- private applyAnchoring(pos: THREE.Vector3) {
127
- if (this.pivot && this.sizeDelta) {
128
- let tx = (this.pivot.x * 2 - 1);
129
- let ty = (this.pivot.y * 2 - 1);
130
- tx -= this.anchoredPosition.x;// * .05;
131
- ty -= this.anchoredPosition.y;// * .05;
132
- const offx = tx;
133
- const offy = ty;
134
- // console.log(this.name, this.pivot, tx, ty, "offset", offx, offy);
135
- pos.x -= offx;
136
- pos.y -= offy;
137
-
138
- // TODO update size from anchoring, width, height, sizeDelta
139
- if (this.shadowComponent)
140
- // console.log(this.shadowComponent)
141
- this.set({ width: this.sizeDelta.x, height: this.sizeDelta.y });
223
+ }
224
+
225
+ onAfterRender() {
226
+ if (this._copyMatrixAfterRender) {
227
+ // can we only have this event when the transform changed in this frame? Otherwise all RectTransforms will be iterated. Not sure what is better
228
+ this.lastMatrixWorld.copy(this.gameObject.matrixWorld);
229
+ }
230
+ }
231
+
232
+ /** applies the position offset to the passed in vector */
233
+ private applyAnchoring(pos: Vector3) {
234
+ pos.x += this.anchoredPosition.x;
235
+ pos.y += this.anchoredPosition.y;
236
+
237
+ const parent = this._parentRectTransform;
238
+ if (parent) {
239
+ // Calculate vertical offset
240
+ let oy = 0;
241
+ const vert = 1 - this.anchorMax.y - this.anchorMin.y;
242
+ oy -= (parent.height * .5) * vert;
243
+ pos.y += oy;
244
+
245
+ // calculate horizontal offset
246
+ let ox = 0;
247
+ const horz = 1 - this.anchorMax.x - this.anchorMin.x;
248
+ ox -= (parent.width * .5) * horz;
249
+ pos.x += ox;
250
+ }
251
+ }
252
+
253
+ /** applies the pivot offset to the passed in vector */
254
+ private applyPivot(vec: Vector3) {
255
+ if (this.pivot && !this.isRoot()) {
256
+ const pv = this.pivot.x - .5;
257
+ vec.x -= pv * this.sizeDelta.x * this.gameObject.scale.x;
258
+ const ph = this.pivot.y - .5;
259
+ vec.y -= ph * this.sizeDelta.y * this.gameObject.scale.y;
142
260
  }
143
261
  }
144
262
 
145
- getBasicOptions(): ThreeMeshUI.BlockOptions {
263
+ getBasicOptions(): ThreeMeshUIEveryOptions {
264
+
265
+ // @TODO : instead of getBasicOptions for each component we could use once needleEngine initialized
266
+ // ThreeMeshUI.DefaultValues.set({
267
+ // backgroundOpacity: 1,
268
+ // borderWidth: 0, // if we dont specify width here a border will automatically propagated to child blocks
269
+ // borderRadius: 0,
270
+ // borderOpacity: 0,
271
+ // })
272
+
146
273
  const opts = {
147
274
  width: this.rect!.width,
148
275
  height: this.rect!.height,// * this.context.mainCameraComponent!.aspect,
@@ -151,6 +278,7 @@ export class RectTransform extends BaseUIComponent {
151
278
  borderWidth: 0, // if we dont specify width here a border will automatically propagated to child blocks
152
279
  borderRadius: 0,
153
280
  borderOpacity: 0,
281
+ letterSpacing: -0.03,
154
282
  // justifyContent: 'center',
155
283
  // alignItems: 'center',
156
284
  // alignContent: 'center',
@@ -169,17 +297,32 @@ export class RectTransform extends BaseUIComponent {
169
297
  return opts;
170
298
  }
171
299
 
172
- private _createdBlocks : ThreeMeshUI.Block[] = [];
300
+ private _createdBlocks: ThreeMeshUI.Block[] = [];
301
+ private _createdTextBlocks: ThreeMeshUI.Text[] = [];
173
302
 
174
- createNewBlock(opts?: ThreeMeshUI.BlockOptions | object): ThreeMeshUI.Block {
303
+ createNewBlock(opts?: ThreeMeshUIEveryOptions | object): ThreeMeshUI.Block {
175
304
  opts = {
176
305
  ...this.getBasicOptions(),
177
306
  ...opts
178
307
  };
179
308
  if (debug)
180
309
  console.log(this.name, opts);
181
- const block = new ThreeMeshUI.Block(opts as ThreeMeshUI.BlockOptions);
310
+ const block = new ThreeMeshUI.Block(opts as ThreeMeshUIEveryOptions);
182
311
  this._createdBlocks.push(block);
183
312
  return block;
184
313
  }
314
+
315
+ createNewText(opts?: ThreeMeshUIEveryOptions | object): ThreeMeshUI.Block {
316
+ if (debug)
317
+ console.log(opts)
318
+ opts = {
319
+ ...this.getBasicOptions(),
320
+ ...opts,
321
+ };
322
+ if (debug)
323
+ console.log(this.name, opts);
324
+ const block = new ThreeMeshUI.Text(opts as ThreeMeshUIEveryOptions);
325
+ this._createdTextBlocks.push(block);
326
+ return block;
327
+ }
185
328
  }