@needle-tools/engine 3.2.15-alpha → 3.4.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 (151) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/needle-engine.js +44005 -36382
  3. package/dist/needle-engine.min.js +706 -513
  4. package/dist/needle-engine.umd.cjs +685 -492
  5. package/lib/engine/codegen/register_types.js +54 -4
  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 +19 -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_math.d.ts +4 -0
  18. package/lib/engine/engine_math.js +6 -0
  19. package/lib/engine/engine_math.js.map +1 -1
  20. package/lib/engine/engine_three_utils.js +2 -2
  21. package/lib/engine/engine_three_utils.js.map +1 -1
  22. package/lib/engine-components/Animation.js +4 -0
  23. package/lib/engine-components/Animation.js.map +1 -1
  24. package/lib/engine-components/AnimatorController.js +7 -2
  25. package/lib/engine-components/AnimatorController.js.map +1 -1
  26. package/lib/engine-components/OrbitControls.js +13 -4
  27. package/lib/engine-components/OrbitControls.js.map +1 -1
  28. package/lib/engine-components/TransformGizmo.d.ts +8 -4
  29. package/lib/engine-components/TransformGizmo.js +62 -63
  30. package/lib/engine-components/TransformGizmo.js.map +1 -1
  31. package/lib/engine-components/codegen/components.d.ts +27 -2
  32. package/lib/engine-components/codegen/components.js +27 -2
  33. package/lib/engine-components/codegen/components.js.map +1 -1
  34. package/lib/engine-components/export/usdz/Extension.d.ts +4 -4
  35. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +86 -0
  36. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +830 -0
  37. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -0
  38. package/lib/engine-components/export/usdz/USDZExporter.d.ts +6 -3
  39. package/lib/engine-components/export/usdz/USDZExporter.js +34 -11
  40. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  41. package/lib/engine-components/export/usdz/extensions/Animation.d.ts +15 -15
  42. package/lib/engine-components/export/usdz/extensions/Animation.js +24 -29
  43. package/lib/engine-components/export/usdz/extensions/Animation.js.map +1 -1
  44. package/lib/engine-components/export/usdz/extensions/DocumentExtension.d.ts +5 -0
  45. package/lib/engine-components/export/usdz/extensions/DocumentExtension.js +7 -0
  46. package/lib/engine-components/export/usdz/extensions/DocumentExtension.js.map +1 -0
  47. package/lib/engine-components/export/usdz/extensions/USDZText.d.ts +47 -0
  48. package/lib/engine-components/export/usdz/extensions/USDZText.js +114 -0
  49. package/lib/engine-components/export/usdz/extensions/USDZText.js.map +1 -0
  50. package/lib/engine-components/export/usdz/extensions/behavior/Actions.d.ts +30 -0
  51. package/lib/engine-components/export/usdz/extensions/behavior/Actions.js +89 -0
  52. package/lib/engine-components/export/usdz/extensions/behavior/Actions.js.map +1 -0
  53. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.d.ts +23 -0
  54. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js +114 -0
  55. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js.map +1 -0
  56. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +96 -0
  57. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +421 -0
  58. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -0
  59. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.d.ts +111 -0
  60. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js +409 -0
  61. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js.map +1 -0
  62. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  63. package/lib/engine-components/ui/BaseUIComponent.d.ts +2 -0
  64. package/lib/engine-components/ui/BaseUIComponent.js +6 -0
  65. package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
  66. package/lib/engine-components/ui/Button.js +9 -5
  67. package/lib/engine-components/ui/Button.js.map +1 -1
  68. package/lib/engine-components/ui/Canvas.d.ts +23 -6
  69. package/lib/engine-components/ui/Canvas.js +167 -34
  70. package/lib/engine-components/ui/Canvas.js.map +1 -1
  71. package/lib/engine-components/ui/EventSystem.d.ts +6 -0
  72. package/lib/engine-components/ui/EventSystem.js +4 -4
  73. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  74. package/lib/engine-components/ui/Graphic.d.ts +5 -2
  75. package/lib/engine-components/ui/Graphic.js +38 -7
  76. package/lib/engine-components/ui/Graphic.js.map +1 -1
  77. package/lib/engine-components/ui/Image.d.ts +1 -0
  78. package/lib/engine-components/ui/Image.js +14 -5
  79. package/lib/engine-components/ui/Image.js.map +1 -1
  80. package/lib/engine-components/ui/InputField.d.ts +1 -0
  81. package/lib/engine-components/ui/InputField.js +8 -0
  82. package/lib/engine-components/ui/InputField.js.map +1 -1
  83. package/lib/engine-components/ui/Interfaces.d.ts +19 -0
  84. package/lib/engine-components/ui/Interfaces.js +11 -0
  85. package/lib/engine-components/ui/Interfaces.js.map +1 -1
  86. package/lib/engine-components/ui/Layout.d.ts +65 -3
  87. package/lib/engine-components/ui/Layout.js +304 -3
  88. package/lib/engine-components/ui/Layout.js.map +1 -1
  89. package/lib/engine-components/ui/Outline.d.ts +7 -0
  90. package/lib/engine-components/ui/Outline.js +21 -0
  91. package/lib/engine-components/ui/Outline.js.map +1 -0
  92. package/lib/engine-components/ui/RectTransform.d.ts +32 -13
  93. package/lib/engine-components/ui/RectTransform.js +216 -56
  94. package/lib/engine-components/ui/RectTransform.js.map +1 -1
  95. package/lib/engine-components/ui/Text.d.ts +13 -10
  96. package/lib/engine-components/ui/Text.js +177 -246
  97. package/lib/engine-components/ui/Text.js.map +1 -1
  98. package/lib/engine-components/utils/LookAt.d.ts +13 -0
  99. package/lib/engine-components/utils/LookAt.js +66 -0
  100. package/lib/engine-components/utils/LookAt.js.map +1 -0
  101. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +12 -3
  102. package/lib/engine-components/webxr/WebXRImageTracking.js +156 -24
  103. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  104. package/lib/tsconfig.tsbuildinfo +1 -1
  105. package/package.json +2 -2
  106. package/plugins/vite/reload.js +13 -2
  107. package/src/engine/codegen/register_types.js +56 -6
  108. package/src/engine/engine_addressables.ts +28 -10
  109. package/src/engine/engine_element.ts +1 -1
  110. package/src/engine/engine_gameobject.ts +19 -1
  111. package/src/engine/engine_input.ts +11 -0
  112. package/src/engine/engine_math.ts +10 -0
  113. package/src/engine/engine_three_utils.ts +2 -2
  114. package/src/engine-components/Animation.ts +4 -0
  115. package/src/engine-components/AnimatorController.ts +7 -1
  116. package/src/engine-components/OrbitControls.ts +14 -6
  117. package/src/engine-components/TransformGizmo.ts +64 -70
  118. package/src/engine-components/codegen/components.ts +27 -2
  119. package/src/engine-components/export/usdz/Extension.ts +4 -5
  120. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +1280 -0
  121. package/src/engine-components/export/usdz/USDZExporter.ts +39 -17
  122. package/src/engine-components/export/usdz/extensions/Animation.ts +37 -45
  123. package/src/engine-components/export/usdz/extensions/DocumentExtension.ts +10 -0
  124. package/src/engine-components/export/usdz/extensions/USDZText.ts +142 -0
  125. package/src/engine-components/export/usdz/extensions/behavior/Actions.ts +99 -0
  126. package/src/engine-components/export/usdz/extensions/behavior/Behaviour.ts +181 -0
  127. package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +503 -0
  128. package/src/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.ts +459 -0
  129. package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
  130. package/src/engine-components/ui/BaseUIComponent.ts +7 -1
  131. package/src/engine-components/ui/Button.ts +14 -9
  132. package/src/engine-components/ui/Canvas.ts +178 -39
  133. package/src/engine-components/ui/EventSystem.ts +16 -9
  134. package/src/engine-components/ui/Graphic.ts +46 -8
  135. package/src/engine-components/ui/Image.ts +13 -4
  136. package/src/engine-components/ui/InputField.ts +9 -1
  137. package/src/engine-components/ui/Interfaces.ts +39 -3
  138. package/src/engine-components/ui/Layout.ts +303 -4
  139. package/src/engine-components/ui/Outline.ts +13 -0
  140. package/src/engine-components/ui/RectTransform.ts +236 -68
  141. package/src/engine-components/ui/Text.ts +284 -265
  142. package/src/engine-components/utils/LookAt.ts +74 -0
  143. package/src/engine-components/webxr/WebXRImageTracking.ts +179 -31
  144. package/lib/engine-components/export/usdz/types.d.ts +0 -34
  145. package/lib/engine-components/export/usdz/types.js +0 -2
  146. package/lib/engine-components/export/usdz/types.js.map +0 -1
  147. package/lib/engine-components/ui/Keyboard.d.ts +0 -31
  148. package/lib/engine-components/ui/Keyboard.js +0 -178
  149. package/lib/engine-components/ui/Keyboard.js.map +0 -1
  150. package/src/engine-components/export/usdz/types.ts +0 -39
  151. package/src/engine-components/ui/Keyboard.ts +0 -204
@@ -2,13 +2,15 @@ import { onChange, updateRenderSettings as updateRenderSettingsRecursive } from
2
2
  import { serializable } from "../../engine/engine_serialization_decorator";
3
3
  import { FrameEvent } from "../../engine/engine_setup";
4
4
  import { BaseUIComponent, UIRootComponent } from "./BaseUIComponent";
5
- import { Mathf } from "../../engine/engine_math";
6
- import * as THREE from "three";
7
- import { getComponentsInChildren } from "../../engine/engine_components";
8
- import { IComponent } from "../../engine/engine_types";
9
5
  import { GameObject } from "../Component";
10
- import { showBalloonMessage, showBalloonWarning } from "../../engine/debug";
11
- import { Object3D } from "three";
6
+ import { Matrix4, Object3D } from "three";
7
+ import { RectTransform } from "./RectTransform";
8
+ import { ICanvas, ILayoutGroup, IRectTransform } from "./Interfaces";
9
+ import { Camera } from "../Camera";
10
+ import { EventSystem } from "./EventSystem";
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,7 +19,17 @@ export enum RenderMode {
17
19
  Undefined = -1,
18
20
  }
19
21
 
20
- export class Canvas extends UIRootComponent {
22
+ const debugLayout = getParam("debuguilayout");
23
+
24
+ export class Canvas extends UIRootComponent implements ICanvas {
25
+
26
+ get isCanvas() {
27
+ return true;
28
+ }
29
+
30
+ get screenspace(): any {
31
+ return this.renderMode !== RenderMode.WorldSpace;
32
+ }
21
33
 
22
34
  @serializable()
23
35
  set renderOnTop(val: boolean) {
@@ -27,8 +39,15 @@ export class Canvas extends UIRootComponent {
27
39
  this._renderOnTop = val;
28
40
  this.onRenderSettingsChanged();
29
41
  }
30
- get renderOnTop() { return this._renderOnTop; }
31
- private _renderOnTop: boolean = false;
42
+ get renderOnTop() {
43
+ if (this._renderOnTop !== undefined) return this._renderOnTop;
44
+ if (this.screenspace) {
45
+ // Render ScreenSpaceOverlay always on top
46
+ if (this._renderMode === RenderMode.ScreenSpaceOverlay) return true;
47
+ }
48
+ return false;
49
+ }
50
+ private _renderOnTop: boolean | undefined;
32
51
 
33
52
  @serializable()
34
53
  set depthWrite(val: boolean) {
@@ -99,43 +118,131 @@ export class Canvas extends UIRootComponent {
99
118
  this._scaleFactor = val;
100
119
  }
101
120
 
121
+ @serializable(Camera)
122
+ worldCamera?: Camera;
123
+
124
+ @serializable()
125
+ planeDistance: number = -1;
126
+
102
127
  awake() {
128
+ //@ts-ignore
103
129
  this.shadowComponent = this.gameObject;
104
130
  super.awake();
105
131
  }
106
132
 
133
+ start() {
134
+ this.onUpdateRenderMode();
135
+ }
136
+
107
137
  onEnable() {
108
138
  super.onEnable();
109
139
  this._updateRenderSettingsRoutine = undefined;
110
140
  this.onRenderSettingsChanged();
141
+ document.addEventListener("resize", this._boundRenderSettingsChanged);
142
+ // We want to run AFTER all regular onBeforeRender callbacks
143
+ this.context.pre_render_callbacks.push(this.onBeforeRenderRoutine);
144
+ this.context.post_render_callbacks.push(this.onAfterRenderRoutine);
145
+ }
146
+
147
+ onDisable(): void {
148
+ super.onDisable();
149
+ document.removeEventListener("resize", this._boundRenderSettingsChanged);
150
+ // Remove callbacks
151
+ const preRenderIndex = this.context.pre_render_callbacks.indexOf(this.onBeforeRenderRoutine);
152
+ if (preRenderIndex !== -1) {
153
+ this.context.pre_render_callbacks.splice(preRenderIndex, 1);
154
+ }
155
+ const postRenderIndex = this.context.post_render_callbacks.indexOf(this.onAfterRenderRoutine);
156
+ if (postRenderIndex !== -1) {
157
+ this.context.post_render_callbacks.splice(postRenderIndex, 1);
158
+ }
111
159
  }
112
160
 
113
- private previousAspect: number = -1;
161
+ private _boundRenderSettingsChanged = this.onRenderSettingsChanged.bind(this);
162
+
114
163
  private previousParent: Object3D | null = null;
164
+ private _lastMatrixWorld: Matrix4 | null = null;
165
+ private _rectTransforms: IRectTransform[] = [];
115
166
 
116
- onBeforeRender() {
117
- if (this.isScreenSpace && this.context.mainCameraComponent && this.context.mainCameraComponent.aspect !== this.previousAspect) {
118
- this.previousAspect = this.context.mainCameraComponent.aspect;
119
- this.updateRenderMode();
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);
120
174
  }
121
- else if(this.renderOnTop){
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
+ }
186
+
187
+ onBeforeRenderRoutine = () => {
188
+ if (this.renderOnTop) {
122
189
  // This is just a test but in reality it should be combined with all world canvases with render on top in one render pass
123
190
  this.previousParent = this.gameObject.parent;
124
191
  this.gameObject.removeFromParent();
125
192
  }
193
+ else {
194
+ this.onUpdateRenderMode();
195
+ this.handleLayoutUpdates();
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
197
+ this.shadowComponent?.updateMatrixWorld(true);
198
+ this.shadowComponent?.updateWorldMatrix(true, true);
199
+ EventSystem.ensureUpdateMeshUI(ThreeMeshUI, this.context);
200
+ }
126
201
  }
127
202
 
128
- onAfterRender(): void {
203
+ onAfterRenderRoutine = () => {
129
204
  if (this.renderOnTop && this.previousParent && this.context.mainCamera) {
130
205
  this.previousParent.add(this.gameObject);
131
206
  this.context.renderer.autoClear = false;
132
207
  this.context.renderer.clearDepth();
208
+ this.onUpdateRenderMode(true);
209
+ this.handleLayoutUpdates();
210
+ this.shadowComponent?.updateMatrixWorld(true);
211
+ // this.handleLayoutUpdates();
212
+ EventSystem.ensureUpdateMeshUI(ThreeMeshUI, this.context);
133
213
  this.context.renderer.render(this.gameObject, this.context.mainCamera);
134
214
  this.context.renderer.autoClear = true;
135
215
  }
216
+ this._lastMatrixWorld?.copy(this.gameObject.matrixWorld);
136
217
  }
137
218
 
138
- applyRenderSettings(){
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
+ }
243
+ }
244
+
245
+ applyRenderSettings() {
139
246
  this.onRenderSettingsChanged();
140
247
  }
141
248
 
@@ -149,7 +256,7 @@ export class Canvas extends UIRootComponent {
149
256
  yield;
150
257
  this._updateRenderSettingsRoutine = undefined;
151
258
  if (this.shadowComponent) {
152
- this.updateRenderMode();
259
+ this.onUpdateRenderMode();
153
260
  // this.onWillUpdateRenderSettings();
154
261
  updateRenderSettingsRecursive(this.shadowComponent, this);
155
262
  for (const ch of GameObject.getComponentsInChildren(this.gameObject, BaseUIComponent)) {
@@ -159,44 +266,76 @@ export class Canvas extends UIRootComponent {
159
266
  }
160
267
 
161
268
  private _activeRenderMode: RenderMode = -1;
269
+ private _lastWidth: number = -1;
270
+ private _lastHeight: number = -1;
162
271
 
163
- private get isScreenSpace(): boolean {
164
- return this._activeRenderMode === RenderMode.ScreenSpaceCamera || this._activeRenderMode === RenderMode.ScreenSpaceOverlay;
165
- }
166
272
 
167
- private updateRenderMode() {
168
- if (this.renderMode === this._activeRenderMode) return;
169
- switch (this.renderMode) {
273
+ private onUpdateRenderMode(force: boolean = false) {
274
+ if (!force) {
275
+ if (this._renderMode === this._activeRenderMode && this._lastWidth === this.context.domWidth && this._lastHeight === this.context.domHeight) {
276
+ return;
277
+ }
278
+ }
279
+ this._activeRenderMode = this._renderMode;
280
+ let camera = this.context.mainCameraComponent;
281
+ let planeDistance: number = camera?.farClipPlane ?? 100;
282
+ if (this._renderMode === RenderMode.ScreenSpaceCamera) {
283
+ if (this.worldCamera)
284
+ camera = this.worldCamera as Camera;
285
+ if (this.planeDistance > 0)
286
+ planeDistance = this.planeDistance;
287
+ }
288
+
289
+ switch (this._renderMode) {
170
290
  case RenderMode.ScreenSpaceOverlay:
171
291
  case RenderMode.ScreenSpaceCamera:
172
- showBalloonWarning("Screenspace Canvas is not supported yet. Please use worldspace");
173
- const camera = this.context.mainCameraComponent;
292
+ this._lastWidth = this.context.domWidth;
293
+ this._lastHeight = this.context.domHeight;
294
+
295
+ // showBalloonWarning("Screenspace Canvas is not supported yet. Please use worldspace");
174
296
  if (!camera) return;
297
+
175
298
  const canvas = this.gameObject;
176
299
  const camObj = camera.gameObject;
177
300
  camObj?.add(canvas);
178
- const pos = camera.farClipPlane;
301
+ // we move the plane SLIGHTLY closer to be sure not to cull the canvas
302
+ const plane = planeDistance - .1;
179
303
  canvas.position.x = 0;
180
304
  canvas.position.y = 0;
181
- canvas.position.z = -pos;
305
+ canvas.position.z = -plane;
306
+ canvas.quaternion.identity();
182
307
 
183
- // console.log(this.shadowComponent)
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
+ }
184
316
 
185
- if (camera.fieldOfView) {
186
- const w = Math.tan(Mathf.toRadians(camera.fieldOfView) * pos) * (camera.aspect * 1.333333);
187
- const h = w * (this.context.domHeight / this.context.domWidth);
188
- canvas.scale.x = -w;
189
- canvas.scale.y = h;
317
+ const vFOV = camera.fieldOfView! * Math.PI / 180;
318
+ const h = 2 * Math.tan(vFOV / 2) * Math.abs(plane);
319
+ canvas.scale.x = h / this.context.domHeight;
320
+ canvas.scale.y = h / this.context.domHeight;
321
+ // Set scale.z, otherwise small offsets in screenspace mode have different visual results based on export scale and other settings
322
+ canvas.scale.z = .01;
190
323
 
324
+ if (hasChanged) {
325
+ rect.sizeDelta.x = this.context.domWidth;
326
+ rect.sizeDelta.y = this.context.domHeight;
327
+ rect?.markDirty();
191
328
  }
192
- // const rects = this.gameObject.getComponentsInChildren(BaseUIComponent);
193
- // for (const rect of rects) {
194
- // rect.set({ width: this.context.domWidth * .5, height: 100 })
195
- // }
329
+
330
+
331
+ // this.context.scene.add(this.gameObject)
332
+ // this.gameObject.scale.multiplyScalar(.01);
333
+ // this.gameObject.position.set(0,0,0);
196
334
 
197
335
  break;
198
336
  case RenderMode.WorldSpace:
199
-
337
+ this._lastWidth = -1;
338
+ this._lastHeight = -1;
200
339
  break;
201
340
  }
202
341
  }
@@ -7,7 +7,7 @@ import { Context } from "../../engine/engine_setup";
7
7
  import { OrbitControls } from "../OrbitControls";
8
8
  import { IPointerEventHandler, PointerEventData } from "./PointerEvents";
9
9
  import { ObjectRaycaster, Raycaster } from "./Raycaster";
10
- import { InputEvents } from "../../engine/engine_input";
10
+ import { InputEvents, PointerEventArgs } from "../../engine/engine_input";
11
11
  import { Object3D } from "three";
12
12
  import { ICanvasGroup, IGraphic } from "./Interfaces";
13
13
  import { getParam } from "../../engine/engine_utils";
@@ -22,6 +22,12 @@ export enum EventSystemEvents {
22
22
  AfterHandleInput = "AfterHandleInput",
23
23
  }
24
24
 
25
+ export declare type AfterHandleInputEvent = {
26
+ sender: EventSystem,
27
+ args: PointerEventData,
28
+ hasActiveUI: boolean
29
+ }
30
+
25
31
  export class EventSystem extends Behaviour {
26
32
 
27
33
 
@@ -249,16 +255,16 @@ export class EventSystem extends Behaviour {
249
255
  if (!hits) return;
250
256
  this.lastPointerEvent = args;
251
257
 
252
- const evt = {
258
+ const evt : AfterHandleInputEvent = {
253
259
  sender: this,
254
260
  args: args,
255
261
  hasActiveUI: this.currentActiveMeshUIComponents.length > 0,
256
262
  }
257
- if(debug && args.isClicked)
258
- showBalloonMessage("EventSystem: " + args.pointerId + " - " + this.context.time.frame + " - Up:" + args.isUp + ", Down:" + args.isDown)
263
+ if (debug && args.isClicked)
264
+ showBalloonMessage("EventSystem: " + args.pointerId + " - " + this.context.time.frame + " - Up:" + args.isUp + ", Down:" + args.isDown)
259
265
  this.dispatchEvent(new CustomEvent(EventSystemEvents.BeforeHandleInput, { detail: evt }))
260
266
  this.handleIntersections(hits, args);
261
- this.dispatchEvent(new CustomEvent(EventSystemEvents.AfterHandleInput, { detail: evt }))
267
+ this.dispatchEvent(new CustomEvent<AfterHandleInputEvent>(EventSystemEvents.AfterHandleInput, { detail: evt }))
262
268
  }
263
269
 
264
270
  private _tempComponentsArray: Behaviour[] = [];
@@ -518,8 +524,8 @@ class MeshUIHelper {
518
524
  if (currentFrame === lu.frame) return;
519
525
  lu.frame = currentFrame;
520
526
  let shouldUpdate = this.needsUpdate || currentFrame < 1;
521
- if(lu.nextUpdate === context.time.frameCount) shouldUpdate = true;
522
- if(this.needsUpdate) lu.nextUpdate = currentFrame + 3;
527
+ if (lu.nextUpdate === context.time.frameCount) shouldUpdate = true;
528
+ // if(this.needsUpdate) lu.nextUpdate = currentFrame + 3;
523
529
  if (shouldUpdate) {
524
530
  if (debug)
525
531
  console.log("Update threemeshui");
@@ -564,8 +570,9 @@ class MeshUIHelper {
564
570
  static findBlockInParent(elem: any): ThreeMeshUI.Block | null {
565
571
  if (!elem) return null;
566
572
  if (elem.isBlock) {
567
- if (Object.keys(elem.states).length > 0)
568
- return elem;
573
+ // @TODO : Replace states managements
574
+ // if (Object.keys(elem.states).length > 0)
575
+ return elem;
569
576
  }
570
577
  return this.findBlockInParent(elem.parent);
571
578
  }
@@ -1,4 +1,4 @@
1
- import { IGraphic } from './Interfaces';
1
+ import { IGraphic, IRectTransformChangedReceiver } from './Interfaces';
2
2
  import * as ThreeMeshUI from 'three-mesh-ui'
3
3
  import { RGBAColor } from "../js-extensions/RGBAColor"
4
4
  import { BaseUIComponent } from "./BaseUIComponent";
@@ -7,9 +7,17 @@ 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';
10
+ import SimpleStateBehavior from "three-mesh-ui/examples/behaviors/states/SimpleStateBehavior"
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';
10
14
 
15
+ const _colorStateObject: { backgroundColor: Color, backgroundOpacity: number } = {
16
+ backgroundColor: new Color(1, 1, 1),
17
+ backgroundOpacity: 1,
18
+ };
11
19
 
12
- export class Graphic extends BaseUIComponent implements IGraphic {
20
+ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransformChangedReceiver {
13
21
 
14
22
  get isGraphic() { return true; }
15
23
 
@@ -26,9 +34,11 @@ export class Graphic extends BaseUIComponent implements IGraphic {
26
34
  }
27
35
  this._color.copy(col);
28
36
  }
37
+
29
38
  protected onColorChanged() {
30
- const newcolor = this.color;
31
- this.setOptions({ backgroundColor: newcolor, backgroundOpacity: newcolor.alpha, borderOpacity: newcolor.alpha });
39
+ _colorStateObject.backgroundColor = this._color;
40
+ _colorStateObject.backgroundOpacity = this._color.alpha;
41
+ this.uiObject?.set(_colorStateObject);
32
42
  }
33
43
 
34
44
  // used via animations
@@ -44,6 +54,9 @@ export class Graphic extends BaseUIComponent implements IGraphic {
44
54
 
45
55
 
46
56
  private _rect: RectTransform | null = null;
57
+
58
+ private _stateManager : SimpleStateBehavior | null = null;
59
+
47
60
  protected get rectTransform(): RectTransform {
48
61
  if (!this._rect) {
49
62
  this._rect = GameObject.getComponent(this.gameObject, RectTransform);
@@ -51,6 +64,11 @@ export class Graphic extends BaseUIComponent implements IGraphic {
51
64
  return this._rect!;
52
65
  }
53
66
 
67
+ onParentRectTransformChanged() {
68
+ this.uiObject?.set({ width: this.rectTransform.width, height:this.rectTransform.height })
69
+ this.markDirty();
70
+ }
71
+
54
72
  __internalNewInstanceCreated(): void {
55
73
  super.__internalNewInstanceCreated();
56
74
  this._rect = null;
@@ -63,14 +81,21 @@ export class Graphic extends BaseUIComponent implements IGraphic {
63
81
  if (this.uiObject) {
64
82
  //@ts-ignore
65
83
  this.uiObject.setState(state);
84
+ this?.markDirty();
66
85
  }
67
86
  }
68
87
 
69
88
  setupState(state: object) {
70
89
  this.makePanel();
71
90
  if (this.uiObject) {
91
+
92
+ // @marwie : v7.x now have a concurrent state management in core mimicking html/css
93
+ // ie : (::firstChild::hover::disabled) where firstchild, hover and disabled are all on different channels
94
+ // In order to keep needle Raycaster and EventSystem intact, I added in v7 a SimpleStateBehavior, which acts as previously
95
+
96
+ if( !this._stateManager ) this._stateManager = new SimpleStateBehavior(this.uiObject);
72
97
  //@ts-ignore
73
- this.uiObject.setupState(state);
98
+ this.uiObject.setupState(state.state, state.attributes);
74
99
  }
75
100
  }
76
101
 
@@ -79,8 +104,8 @@ export class Graphic extends BaseUIComponent implements IGraphic {
79
104
  if (this.uiObject) {
80
105
  //@ts-ignore
81
106
  this.uiObject.set(opts);
82
- if (opts["backgroundColor"] !== undefined || opts["backgroundOpacity"] !== undefined)
83
- this.uiObject["updateBackgroundMaterial"]?.call(this.uiObject);
107
+ // if (opts["backgroundColor"] !== undefined || opts["backgroundOpacity"] !== undefined)
108
+ // this.uiObject["updateBackgroundMaterial"]?.call(this.uiObject);
84
109
  }
85
110
  }
86
111
 
@@ -119,6 +144,7 @@ export class Graphic extends BaseUIComponent implements IGraphic {
119
144
  offset: 1, // without a tiny offset we get z fighting
120
145
  };
121
146
  this.onBeforeCreate(opts);
147
+ this.applyEffects(opts);
122
148
  this.onCreate(opts);
123
149
  this.controlsChildLayout = false;
124
150
  this._currentlyCreatingPanel = false;
@@ -133,6 +159,17 @@ export class Graphic extends BaseUIComponent implements IGraphic {
133
159
  }
134
160
  protected onAfterCreated() { }
135
161
 
162
+ private applyEffects(opts){
163
+ const outline = this.gameObject?.getComponent(Outline);
164
+ if (outline) {
165
+ if (outline.effectDistance) opts.borderWidth = Math.max(Math.abs(outline.effectDistance.x), Math.abs(outline.effectDistance.y));
166
+ if (outline.effectColor) {
167
+ opts.borderColor = outline.effectColor;
168
+ opts.borderOpacity = outline.effectColor.alpha;
169
+ }
170
+ }
171
+ }
172
+
136
173
  /** used internally to ensure textures assigned to UI use linear encoding */
137
174
  static textureCache: Map<Texture, Texture> = new Map();
138
175
 
@@ -151,13 +188,14 @@ export class Graphic extends BaseUIComponent implements IGraphic {
151
188
  tex = clone;
152
189
  }
153
190
  }
154
- this.setOptions({ backgroundTexture: tex, borderRadius: 0, backgroundOpacity: this.color.alpha, backgroundSize: "stretch" });
191
+ this.setOptions({ backgroundImage: tex, borderRadius: 0, backgroundOpacity: this.color.alpha, backgroundSize: "stretch" });
155
192
  }
156
193
  }
157
194
 
158
195
  protected onAfterAddedToScene(): void {
159
196
  super.onAfterAddedToScene();
160
197
  if (this.shadowComponent) {
198
+ // @TODO: I think we dont even need this anymore and this leads to the offset being applied twice
161
199
  //@ts-ignore
162
200
  this.shadowComponent.offset = this.shadowComponent.position.z;
163
201
 
@@ -24,11 +24,15 @@ export class Image extends MaskableGraphic {
24
24
 
25
25
  private _sprite?: Sprite;
26
26
 
27
+ @serializable()
28
+ private pixelsPerUnitMultiplier: number = 1;
29
+
27
30
  private isBuiltinSprite() {
28
31
  switch (this.sprite?.texture?.name) {
29
32
  case "InputFieldBackground":
30
33
  case "UISprite":
31
34
  case "Background":
35
+ case "Knob":
32
36
  return true;
33
37
  }
34
38
  // this is a hack/workaround for production builds where the name of the sprite is missing
@@ -39,12 +43,17 @@ export class Image extends MaskableGraphic {
39
43
  }
40
44
 
41
45
  protected onBeforeCreate(opts: any): void {
46
+ super.onBeforeCreate(opts);
42
47
  if (this.isBuiltinSprite()) {
43
- opts.borderRadius = 5;
44
- opts.borderColor = new Color(.4, .4, .4);
45
- opts.borderOpacity = this.color.alpha;
46
- opts.borderWidth = .3;
48
+ opts.borderRadius = 5 / this.pixelsPerUnitMultiplier;
49
+ if(this.sprite?.texture?.name === "Knob") {
50
+ opts.borderRadius = 999;
51
+ }
52
+ // opts.borderColor = new Color(.4, .4, .4);
53
+ // opts.borderOpacity = this.color.alpha;
54
+ // opts.borderWidth = .3;
47
55
  }
56
+
48
57
  }
49
58
 
50
59
  protected onAfterCreated(): void {
@@ -13,7 +13,7 @@ const debug = getParam("debuginputfield");
13
13
 
14
14
  export class InputField extends Behaviour implements IPointerEventHandler {
15
15
 
16
- get text() : string {
16
+ get text(): string {
17
17
  return this.textComponent?.text ?? "";
18
18
  }
19
19
 
@@ -148,6 +148,14 @@ export class InputField extends Behaviour implements IPointerEventHandler {
148
148
  this.onEndEdit?.invoke(InputField.htmlField.value);
149
149
  }
150
150
 
151
+ // @Marwie, I can provide this fix. But the issue seems to comes from Raycaster+EventSystem
152
+ // As we rollout InputField, and no others elements is behind raycast,
153
+ // ThreeMeshUI.update is not called.
154
+ update() {
155
+ if (InputField.active === this) {
156
+ this.textComponent?.markDirty();
157
+ }
158
+ }
151
159
 
152
160
  private onInput(evt: KeyboardEvent) {
153
161
  if (InputField.active !== this) return;
@@ -1,12 +1,48 @@
1
+ import { Behaviour } from "../Component";
1
2
  import { IComponent } from "../../engine/engine_types";
2
3
 
4
+ export interface ICanvas {
5
+ get isCanvas(): boolean;
6
+ get screenspace(): boolean;
7
+ registerTransform(rt: IRectTransform);
8
+ unregisterTransform(rt: IRectTransform);
9
+ }
10
+
3
11
  export interface ICanvasGroup {
4
- get isCanvasGroup() : boolean;
12
+ get isCanvasGroup(): boolean;
5
13
  blocksRaycasts: boolean;
6
14
  interactable: boolean;
7
15
  }
8
16
 
9
17
  export interface IGraphic extends IComponent {
10
- get isGraphic() : boolean;
18
+ get isGraphic(): boolean;
11
19
  raycastTarget: boolean;
12
- }
20
+ }
21
+
22
+ export interface IRectTransform extends IComponent {
23
+ get isDirty(): boolean;
24
+ markDirty();
25
+ updateTransform();
26
+ }
27
+
28
+ export interface IRectTransformChangedReceiver {
29
+ onParentRectTransformChanged(comp: IRectTransform): void;
30
+ }
31
+
32
+ export interface ILayoutGroup extends IComponent {
33
+ get isLayoutGroup(): boolean;
34
+ get isDirty(): boolean;
35
+ updateLayout();
36
+ }
37
+
38
+ // export abstract class LayoutGroup extends Behaviour implements IRectTransformChangedReceiver, ILayoutGroup {
39
+ // get isLayoutGroup(): boolean {
40
+ // return true;
41
+ // }
42
+ // updateLayout() {
43
+ // throw new Error("Method not implemented.");
44
+ // }
45
+ // onParentRectTransformChanged(comp: IRectTransform): void {
46
+ // throw new Error("Method not implemented.");
47
+ // }
48
+ // }