@needle-tools/engine 3.3.0-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.
- package/CHANGELOG.md +10 -0
- package/dist/needle-engine.js +26116 -24881
- package/dist/needle-engine.min.js +384 -383
- package/dist/needle-engine.umd.cjs +372 -371
- package/lib/engine/codegen/register_types.js +50 -2
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_gameobject.d.ts +1 -1
- package/lib/engine/engine_gameobject.js +4 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_three_utils.js +2 -2
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine-components/Animation.js +4 -0
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +25 -1
- package/lib/engine-components/codegen/components.js +25 -1
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/export/usdz/Extension.d.ts +4 -4
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +86 -0
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +830 -0
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -0
- package/lib/engine-components/export/usdz/USDZExporter.d.ts +6 -3
- package/lib/engine-components/export/usdz/USDZExporter.js +34 -11
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/Animation.d.ts +15 -15
- package/lib/engine-components/export/usdz/extensions/Animation.js +24 -29
- package/lib/engine-components/export/usdz/extensions/Animation.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/DocumentExtension.d.ts +5 -0
- package/lib/engine-components/export/usdz/extensions/DocumentExtension.js +7 -0
- package/lib/engine-components/export/usdz/extensions/DocumentExtension.js.map +1 -0
- package/lib/engine-components/export/usdz/extensions/USDZText.d.ts +47 -0
- package/lib/engine-components/export/usdz/extensions/USDZText.js +114 -0
- package/lib/engine-components/export/usdz/extensions/USDZText.js.map +1 -0
- package/lib/engine-components/export/usdz/extensions/behavior/Actions.d.ts +30 -0
- package/lib/engine-components/export/usdz/extensions/behavior/Actions.js +89 -0
- package/lib/engine-components/export/usdz/extensions/behavior/Actions.js.map +1 -0
- package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.d.ts +23 -0
- package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js +114 -0
- package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js.map +1 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +96 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +421 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.d.ts +111 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js +409 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js.map +1 -0
- package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
- package/lib/engine-components/ui/BaseUIComponent.d.ts +2 -0
- package/lib/engine-components/ui/BaseUIComponent.js +6 -0
- package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
- package/lib/engine-components/ui/Canvas.d.ts +11 -1
- package/lib/engine-components/ui/Canvas.js +72 -3
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Image.js +4 -4
- package/lib/engine-components/ui/Image.js.map +1 -1
- package/lib/engine-components/ui/Interfaces.d.ts +11 -0
- package/lib/engine-components/ui/Interfaces.js +11 -0
- package/lib/engine-components/ui/Interfaces.js.map +1 -1
- package/lib/engine-components/ui/Layout.d.ts +65 -3
- package/lib/engine-components/ui/Layout.js +304 -3
- package/lib/engine-components/ui/Layout.js.map +1 -1
- package/lib/engine-components/ui/RectTransform.d.ts +8 -7
- package/lib/engine-components/ui/RectTransform.js +63 -35
- package/lib/engine-components/ui/RectTransform.js.map +1 -1
- package/lib/engine-components/utils/LookAt.d.ts +7 -1
- package/lib/engine-components/utils/LookAt.js +43 -6
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.d.ts +4 -3
- package/lib/engine-components/webxr/WebXRImageTracking.js +81 -25
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugins/vite/reload.js +13 -2
- package/src/engine/codegen/register_types.js +52 -4
- package/src/engine/engine_gameobject.ts +3 -2
- package/src/engine/engine_three_utils.ts +2 -2
- package/src/engine-components/Animation.ts +4 -0
- package/src/engine-components/codegen/components.ts +25 -1
- package/src/engine-components/export/usdz/Extension.ts +4 -5
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +1280 -0
- package/src/engine-components/export/usdz/USDZExporter.ts +39 -17
- package/src/engine-components/export/usdz/extensions/Animation.ts +37 -45
- package/src/engine-components/export/usdz/extensions/DocumentExtension.ts +10 -0
- package/src/engine-components/export/usdz/extensions/USDZText.ts +142 -0
- package/src/engine-components/export/usdz/extensions/behavior/Actions.ts +99 -0
- package/src/engine-components/export/usdz/extensions/behavior/Behaviour.ts +181 -0
- package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +503 -0
- package/src/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.ts +459 -0
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
- package/src/engine-components/ui/BaseUIComponent.ts +7 -1
- package/src/engine-components/ui/Canvas.ts +80 -5
- package/src/engine-components/ui/Graphic.ts +2 -0
- package/src/engine-components/ui/Image.ts +3 -3
- package/src/engine-components/ui/Interfaces.ts +30 -6
- package/src/engine-components/ui/Layout.ts +303 -4
- package/src/engine-components/ui/RectTransform.ts +65 -40
- package/src/engine-components/utils/LookAt.ts +60 -7
- package/src/engine-components/webxr/WebXRImageTracking.ts +100 -27
- package/lib/engine-components/export/usdz/types.d.ts +0 -34
- package/lib/engine-components/export/usdz/types.js +0 -2
- package/lib/engine-components/export/usdz/types.js.map +0 -1
- package/src/engine-components/export/usdz/types.ts +0 -39
|
@@ -1,24 +1,48 @@
|
|
|
1
|
+
import { Behaviour } from "../Component";
|
|
1
2
|
import { IComponent } from "../../engine/engine_types";
|
|
2
3
|
|
|
3
4
|
export interface ICanvas {
|
|
4
|
-
get
|
|
5
|
+
get isCanvas(): boolean;
|
|
6
|
+
get screenspace(): boolean;
|
|
7
|
+
registerTransform(rt: IRectTransform);
|
|
8
|
+
unregisterTransform(rt: IRectTransform);
|
|
5
9
|
}
|
|
6
10
|
|
|
7
11
|
export interface ICanvasGroup {
|
|
8
|
-
get isCanvasGroup()
|
|
12
|
+
get isCanvasGroup(): boolean;
|
|
9
13
|
blocksRaycasts: boolean;
|
|
10
14
|
interactable: boolean;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export interface IGraphic extends IComponent {
|
|
14
|
-
get isGraphic()
|
|
18
|
+
get isGraphic(): boolean;
|
|
15
19
|
raycastTarget: boolean;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
export interface IRectTransform extends IComponent {
|
|
19
|
-
|
|
23
|
+
get isDirty(): boolean;
|
|
24
|
+
markDirty();
|
|
25
|
+
updateTransform();
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
export interface IRectTransformChangedReceiver {
|
|
23
|
-
onParentRectTransformChanged(comp
|
|
24
|
-
}
|
|
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
|
+
// }
|
|
@@ -1,17 +1,316 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ILayoutGroup, IRectTransform, IRectTransformChangedReceiver } from "./Interfaces";
|
|
2
|
+
import { Behaviour, GameObject } from "../Component";
|
|
3
|
+
import { serializable } from "../../engine/engine_serialization";
|
|
4
|
+
import { Canvas } from "./Canvas";
|
|
5
|
+
import { RectTransform } from "./RectTransform";
|
|
6
|
+
import { getParam } from "../../engine/engine_utils";
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
const debug = getParam("debuguilayout");
|
|
9
|
+
|
|
10
|
+
export class Padding {
|
|
11
|
+
@serializable()
|
|
12
|
+
left: number = 0;
|
|
13
|
+
@serializable()
|
|
14
|
+
right: number = 0;
|
|
15
|
+
@serializable()
|
|
16
|
+
top: number = 0;
|
|
17
|
+
@serializable()
|
|
18
|
+
bottom: number = 0;
|
|
19
|
+
|
|
20
|
+
get vertical() {
|
|
21
|
+
return this.top + this.bottom;
|
|
22
|
+
}
|
|
23
|
+
get horizontal() {
|
|
24
|
+
return this.left + this.right;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export enum TextAnchor {
|
|
29
|
+
UpperLeft = 0,
|
|
30
|
+
UpperCenter = 1,
|
|
31
|
+
UpperRight = 2,
|
|
32
|
+
MiddleLeft = 3,
|
|
33
|
+
MiddleCenter = 4,
|
|
34
|
+
MiddleRight = 5,
|
|
35
|
+
LowerLeft = 6,
|
|
36
|
+
LowerCenter = 7,
|
|
37
|
+
LowerRight = 8,
|
|
38
|
+
Custom = 9
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
enum Axis {
|
|
42
|
+
Horizontal = "x",
|
|
43
|
+
Vertical = "y"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export abstract class LayoutGroup extends Behaviour implements ILayoutGroup {
|
|
47
|
+
|
|
48
|
+
private _rectTransform: RectTransform | null = null;
|
|
49
|
+
private get rectTransform() {
|
|
50
|
+
return this._rectTransform;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
onParentRectTransformChanged(_comp: IRectTransform): void {
|
|
54
|
+
this._needsUpdate = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private _needsUpdate: boolean = false;
|
|
58
|
+
get isDirty(): boolean {
|
|
59
|
+
return this._needsUpdate;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get isLayoutGroup(): boolean {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
updateLayout() {
|
|
67
|
+
if (!this._rectTransform) return;
|
|
68
|
+
if (debug)
|
|
69
|
+
console.warn("Layout Update", this.context.time.frame, this.name);
|
|
70
|
+
this._needsUpdate = false;
|
|
71
|
+
this.onCalculateLayout(this._rectTransform);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// onBeforeRender(): void {
|
|
75
|
+
// this.updateLayout();
|
|
76
|
+
// }
|
|
77
|
+
|
|
78
|
+
@serializable()
|
|
79
|
+
childAlignment: TextAnchor = TextAnchor.UpperLeft;
|
|
80
|
+
|
|
81
|
+
@serializable()
|
|
4
82
|
reverseArrangement: boolean = false;
|
|
83
|
+
|
|
84
|
+
@serializable()
|
|
85
|
+
spacing: number = 0;
|
|
86
|
+
@serializable(Padding)
|
|
87
|
+
padding!: Padding;
|
|
88
|
+
|
|
89
|
+
@serializable()
|
|
90
|
+
minWidth: number = 0;
|
|
91
|
+
@serializable()
|
|
92
|
+
minHeight: number = 0;
|
|
93
|
+
|
|
94
|
+
@serializable()
|
|
95
|
+
flexibleHeight: number = 0;
|
|
96
|
+
@serializable()
|
|
97
|
+
flexibleWidth: number = 0;
|
|
98
|
+
|
|
99
|
+
@serializable()
|
|
100
|
+
preferredHeight: number = 0;
|
|
101
|
+
@serializable()
|
|
102
|
+
preferredWidth: number = 0;
|
|
103
|
+
|
|
104
|
+
start() {
|
|
105
|
+
this._needsUpdate = true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
onEnable(): void {
|
|
109
|
+
if(debug) console.log(this.name, this);
|
|
110
|
+
this._rectTransform = this.gameObject.getComponent(RectTransform);
|
|
111
|
+
const canvas = this.gameObject.getComponentInParent(Canvas);
|
|
112
|
+
if (canvas) {
|
|
113
|
+
canvas.registerLayoutGroup(this);
|
|
114
|
+
}
|
|
115
|
+
this._needsUpdate = true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
onDisable(): void {
|
|
119
|
+
const canvas = this.gameObject.getComponentInParent(Canvas);
|
|
120
|
+
if (canvas) {
|
|
121
|
+
canvas.unregisterLayoutGroup(this);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
protected abstract onCalculateLayout(rt: RectTransform);
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
// for animation:
|
|
130
|
+
private set m_Spacing(val) {
|
|
131
|
+
if (val === this.spacing) return;
|
|
132
|
+
this._needsUpdate = true;
|
|
133
|
+
this.spacing = val;
|
|
134
|
+
}
|
|
135
|
+
get m_Spacing() {
|
|
136
|
+
return this.spacing;
|
|
137
|
+
}
|
|
5
138
|
}
|
|
6
139
|
|
|
7
|
-
export class
|
|
140
|
+
export abstract class HorizontalOrVerticalLayoutGroup extends LayoutGroup {
|
|
141
|
+
|
|
142
|
+
@serializable()
|
|
143
|
+
childControlHeight: boolean = true;
|
|
144
|
+
@serializable()
|
|
145
|
+
childControlWidth: boolean = true;
|
|
146
|
+
@serializable()
|
|
147
|
+
childForceExpandHeight: boolean = false;
|
|
148
|
+
@serializable()
|
|
149
|
+
childForceExpandWidth: boolean = false;
|
|
150
|
+
@serializable()
|
|
151
|
+
childScaleHeight: boolean = false;
|
|
152
|
+
@serializable()
|
|
153
|
+
childScaleWidth: boolean = false;
|
|
154
|
+
|
|
155
|
+
protected abstract get primaryAxis(): Axis;
|
|
156
|
+
|
|
157
|
+
protected onCalculateLayout(rect: RectTransform) {
|
|
158
|
+
const axis = this.primaryAxis;
|
|
159
|
+
|
|
160
|
+
const totalWidth = rect.width;
|
|
161
|
+
let actualWidth = totalWidth;
|
|
162
|
+
const totalHeight = rect.height;
|
|
163
|
+
let actualHeight = totalHeight;
|
|
164
|
+
actualWidth -= this.padding.horizontal;
|
|
165
|
+
actualHeight -= this.padding.vertical;
|
|
166
|
+
|
|
167
|
+
// console.log(rt.name, "width=" + totalWidth + ", height=" + totalHeight)
|
|
168
|
+
|
|
169
|
+
const paddingAxis = axis === Axis.Horizontal ? this.padding.horizontal : this.padding.vertical;
|
|
170
|
+
const isHorizontal = axis === Axis.Horizontal;
|
|
171
|
+
const isVertical = !isHorizontal;
|
|
172
|
+
const otherAxis = isHorizontal ? "y" : "x";
|
|
173
|
+
const controlSize = isHorizontal ? this.childControlWidth : this.childControlHeight;
|
|
174
|
+
const controlSizeOtherAxis = isHorizontal ? this.childControlHeight : this.childControlWidth;
|
|
175
|
+
const forceExpandSize = isHorizontal ? this.childForceExpandWidth : this.childForceExpandHeight;
|
|
176
|
+
const forceExpandSizeOtherAxis = isHorizontal ? this.childForceExpandHeight : this.childForceExpandWidth;
|
|
177
|
+
const actualExpandSize = isHorizontal ? actualHeight : actualWidth;
|
|
178
|
+
const totalSpace = isHorizontal ? totalWidth : totalHeight;
|
|
179
|
+
// 0 is left/top, 0.5 is middle, 1 is right/bottom
|
|
180
|
+
const alignmentOnAxis = 0.5 * (isHorizontal ? this.childAlignment % 3 : Math.floor(this.childAlignment / 3));
|
|
181
|
+
|
|
182
|
+
let start = 0;
|
|
183
|
+
if (isHorizontal) {
|
|
184
|
+
start += this.padding.left;
|
|
185
|
+
}
|
|
186
|
+
else
|
|
187
|
+
start += this.padding.top;
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
// Calculate total size of the elements
|
|
191
|
+
let totalChildSize = 0;
|
|
192
|
+
let actualRectTransformChildCount = 0;
|
|
193
|
+
for (let i = 0; i < this.gameObject.children.length; i++) {
|
|
194
|
+
const ch = this.gameObject.children[i];
|
|
195
|
+
const rt = GameObject.getComponent(ch, RectTransform);
|
|
196
|
+
if (rt?.activeAndEnabled) {
|
|
197
|
+
actualRectTransformChildCount += 1;
|
|
198
|
+
if (isHorizontal) {
|
|
199
|
+
totalChildSize += rt.width;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
totalChildSize += rt.height;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let sizePerChild = 0;
|
|
208
|
+
const totalSpacing = this.spacing * (actualRectTransformChildCount - 1)
|
|
209
|
+
if (forceExpandSize || controlSize) {
|
|
210
|
+
let size = 0;
|
|
211
|
+
if (isHorizontal) {
|
|
212
|
+
size = actualWidth -= totalSpacing;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
size = actualHeight -= totalSpacing;
|
|
216
|
+
}
|
|
217
|
+
if (actualRectTransformChildCount > 0)
|
|
218
|
+
sizePerChild = size / actualRectTransformChildCount;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
let leftOffset = 0;
|
|
222
|
+
leftOffset += this.padding.left;
|
|
223
|
+
leftOffset -= this.padding.right;
|
|
224
|
+
|
|
225
|
+
if (alignmentOnAxis !== 0) {
|
|
226
|
+
start = totalSpace - totalChildSize;
|
|
227
|
+
start *= alignmentOnAxis;
|
|
228
|
+
start -= totalSpacing * alignmentOnAxis;
|
|
229
|
+
if (isHorizontal) {
|
|
230
|
+
start -= this.padding.right * alignmentOnAxis;
|
|
231
|
+
start += this.padding.left * (1 - alignmentOnAxis);
|
|
232
|
+
if (start < this.padding.left) {
|
|
233
|
+
start = this.padding.left;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
start -= this.padding.bottom * alignmentOnAxis;
|
|
238
|
+
start += this.padding.top * (1 - alignmentOnAxis);
|
|
239
|
+
if (start < this.padding.top) {
|
|
240
|
+
start = this.padding.top;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Apply layout
|
|
246
|
+
let k = 0;
|
|
247
|
+
for (let i = 0; i < this.gameObject.children.length; i++) {
|
|
248
|
+
const ch = this.gameObject.children[i];
|
|
249
|
+
const rt = GameObject.getComponent(ch, RectTransform);
|
|
250
|
+
if (rt?.activeAndEnabled) {
|
|
251
|
+
rt.pivot?.set(.5, .5);
|
|
252
|
+
// Horizontal padding
|
|
253
|
+
const x = totalWidth * .5 + leftOffset * .5;
|
|
254
|
+
if (rt.anchoredPosition.x !== x)
|
|
255
|
+
rt.anchoredPosition.x = x;
|
|
256
|
+
const y = totalHeight * -.5
|
|
257
|
+
if (rt.anchoredPosition.y !== y)
|
|
258
|
+
rt.anchoredPosition.y = y;
|
|
259
|
+
// Set the size for the secondary axis (e.g. height for a horizontal layout group)
|
|
260
|
+
if (forceExpandSizeOtherAxis && controlSizeOtherAxis && rt.sizeDelta[otherAxis] !== actualExpandSize) {
|
|
261
|
+
rt.sizeDelta[otherAxis] = actualExpandSize;
|
|
262
|
+
}
|
|
263
|
+
// Set the size for the primary axis (e.g. width for a horizontal layout group)
|
|
264
|
+
if (forceExpandSize && controlSize && rt.sizeDelta[axis] !== sizePerChild) {
|
|
265
|
+
rt.sizeDelta[axis] = sizePerChild
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const size = isHorizontal ? rt.width : rt.height;
|
|
269
|
+
let halfSize = size * .5;
|
|
270
|
+
start += halfSize;
|
|
271
|
+
|
|
272
|
+
if (forceExpandSize) {
|
|
273
|
+
let preferredStart = sizePerChild * (k + 1) - sizePerChild * .5;
|
|
274
|
+
if (preferredStart > start)
|
|
275
|
+
start = preferredStart;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
let value = start;
|
|
279
|
+
if (axis === Axis.Vertical)
|
|
280
|
+
value = -value;
|
|
281
|
+
// Only set the position if it's not already the correct one to avoid triggering the rectTransform dirty event
|
|
282
|
+
if (rt.anchoredPosition[axis] !== value) {
|
|
283
|
+
rt.anchoredPosition[axis] = value
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
start += halfSize;
|
|
287
|
+
start += this.spacing;
|
|
288
|
+
k += 1;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export class VerticalLayoutGroup extends HorizontalOrVerticalLayoutGroup {
|
|
297
|
+
|
|
298
|
+
protected get primaryAxis() {
|
|
299
|
+
return Axis.Vertical;
|
|
300
|
+
}
|
|
8
301
|
|
|
9
302
|
}
|
|
10
303
|
|
|
11
|
-
export class HorizontalLayoutGroup extends
|
|
304
|
+
export class HorizontalLayoutGroup extends HorizontalOrVerticalLayoutGroup {
|
|
305
|
+
|
|
306
|
+
protected get primaryAxis() {
|
|
307
|
+
return Axis.Horizontal;
|
|
308
|
+
}
|
|
12
309
|
|
|
13
310
|
}
|
|
14
311
|
|
|
15
312
|
export class GridLayoutGroup extends LayoutGroup {
|
|
313
|
+
protected onCalculateLayout() {
|
|
314
|
+
}
|
|
16
315
|
|
|
17
316
|
}
|
|
@@ -7,10 +7,11 @@ import { EventSystem } from "./EventSystem";
|
|
|
7
7
|
import { getParam } from "../../engine/engine_utils";
|
|
8
8
|
import { onChange } from "./Utils";
|
|
9
9
|
import { foreachComponentEnumerator } from "../../engine/engine_gameobject";
|
|
10
|
-
import { ICanvas, IRectTransform, IRectTransformChangedReceiver } from "./Interfaces";
|
|
10
|
+
import { ICanvas, IRectTransform, IRectTransformChangedReceiver, ILayoutGroup } from "./Interfaces";
|
|
11
11
|
import { GameObject } from '../Component';
|
|
12
12
|
|
|
13
13
|
const debug = getParam("debugui");
|
|
14
|
+
const debugLayout = getParam("debuguilayout");
|
|
14
15
|
|
|
15
16
|
export class Size {
|
|
16
17
|
width!: number;
|
|
@@ -30,7 +31,7 @@ const tempQuaternion = new Quaternion();
|
|
|
30
31
|
|
|
31
32
|
export class RectTransform extends BaseUIComponent implements IRectTransform, IRectTransformChangedReceiver {
|
|
32
33
|
|
|
33
|
-
offset: number = 0.
|
|
34
|
+
offset: number = 0.1;
|
|
34
35
|
|
|
35
36
|
// @serializable(Object3D)
|
|
36
37
|
// root? : Object3D;
|
|
@@ -94,14 +95,13 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
|
|
|
94
95
|
return this.sizeDelta.y;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
private lastMatrixWorld!: Matrix4;
|
|
98
|
+
// private lastMatrixWorld!: Matrix4;
|
|
98
99
|
private lastMatrix!: Matrix4;
|
|
99
100
|
private rectBlock!: Object3D;
|
|
100
101
|
private _transformNeedsUpdate: boolean = false;
|
|
101
102
|
|
|
102
103
|
awake() {
|
|
103
104
|
super.awake();
|
|
104
|
-
this.lastMatrixWorld = new Matrix4();
|
|
105
105
|
this.lastMatrix = new Matrix4();
|
|
106
106
|
this.rectBlock = new Object3D();;
|
|
107
107
|
this.rectBlock.position.z = .1;
|
|
@@ -112,9 +112,10 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
|
|
|
112
112
|
|
|
113
113
|
// TODO: we need to replace this with the watch that e.g. Rigibody is using (or the one in utils?)
|
|
114
114
|
// perhaps we can also just manually check the few properties in the update loops?
|
|
115
|
-
|
|
116
|
-
onChange(this, "
|
|
117
|
-
onChange(this, "
|
|
115
|
+
// TODO: check if value actually changed, this is called on assignment
|
|
116
|
+
onChange(this, "_anchoredPosition", () => { this.markDirty(); });
|
|
117
|
+
onChange(this, "sizeDelta", () => { this.markDirty(); });
|
|
118
|
+
onChange(this, "pivot", () => { this.markDirty(); });
|
|
118
119
|
|
|
119
120
|
// When exported with an anchored position offset we remove it here
|
|
120
121
|
// because it would otherwise be applied twice when the anchoring is animated
|
|
@@ -135,28 +136,67 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
|
|
|
135
136
|
super.onEnable();
|
|
136
137
|
this.addShadowComponent(this.rectBlock);
|
|
137
138
|
this._transformNeedsUpdate = true;
|
|
139
|
+
this.Canvas?.registerTransform(this);
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
onDisable() {
|
|
141
143
|
super.onDisable();
|
|
142
144
|
this.removeShadowComponent();
|
|
145
|
+
this.Canvas?.unregisterTransform(this);
|
|
143
146
|
}
|
|
144
147
|
|
|
145
|
-
onParentRectTransformChanged(
|
|
148
|
+
onParentRectTransformChanged(comp: IRectTransform) {
|
|
149
|
+
if (this._transformNeedsUpdate) return;
|
|
146
150
|
// When the parent rect transform changes we have to to recalculate our transform
|
|
151
|
+
this.onApplyTransform(debugLayout ? `${comp.name} changed` : undefined);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
get isDirty() {
|
|
155
|
+
if(!this._transformNeedsUpdate) this._transformNeedsUpdate = !this.lastMatrix.equals(this.gameObject.matrix);
|
|
156
|
+
return this._transformNeedsUpdate;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// private _copyMatrixAfterRender: boolean = false;
|
|
160
|
+
|
|
161
|
+
markDirty() {
|
|
162
|
+
if (this._transformNeedsUpdate) return;
|
|
163
|
+
if (debugLayout) console.warn("RectTransform markDirty()", this.name)
|
|
147
164
|
this._transformNeedsUpdate = true;
|
|
148
|
-
|
|
165
|
+
// If mark dirty is called explictly we want to allow updating the transform again when updateTransform is called
|
|
166
|
+
// if we dont reset it here we get delayed layout updates
|
|
167
|
+
this._lastUpdateFrame = -1;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
/** Will update the transforms if it changed or is dirty */
|
|
172
|
+
updateTransform() {
|
|
173
|
+
// TODO: instead of checking matrix again it would perhaps be better to test if position, rotation or scale have changed individually?
|
|
174
|
+
const transformChanged = this._transformNeedsUpdate || !this.lastMatrix.equals(this.gameObject.matrix);// || !this.lastMatrixWorld.equals(this.gameObject.matrixWorld);
|
|
175
|
+
if (transformChanged && this.canUpdate()) {
|
|
176
|
+
this.onApplyTransform(this._transformNeedsUpdate ? "Marked dirty" : "Matrix changed");
|
|
177
|
+
}
|
|
149
178
|
}
|
|
150
179
|
|
|
151
180
|
private _parentRectTransform?: RectTransform;
|
|
181
|
+
private _lastUpdateFrame: number = -1;
|
|
182
|
+
|
|
183
|
+
private canUpdate() {
|
|
184
|
+
return this._transformNeedsUpdate && this.activeAndEnabled && this._lastUpdateFrame !== this.context.time.frame;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private onApplyTransform(reason?: string) {
|
|
188
|
+
// TODO: need to improve the update logic, with this UI updates have some frame delay but dont happen exponentially per hierarchy
|
|
189
|
+
if (this.context.time.frameCount === this._lastUpdateFrame) return;
|
|
190
|
+
this._lastUpdateFrame = this.context.time.frameCount;
|
|
152
191
|
|
|
153
|
-
private applyTransform() {
|
|
154
192
|
const uiobject = this.shadowComponent;
|
|
155
193
|
if (!uiobject) return;
|
|
156
|
-
this._transformNeedsUpdate = false;
|
|
157
194
|
this._parentRectTransform = GameObject.getComponentInParent(this.gameObject.parent!, RectTransform) as RectTransform;
|
|
158
195
|
|
|
159
|
-
|
|
196
|
+
this._transformNeedsUpdate = false;
|
|
197
|
+
this.lastMatrix.copy(this.gameObject.matrix);
|
|
198
|
+
|
|
199
|
+
if (debugLayout) console.warn("RectTransform → ApplyTransform", this.name + " because " + reason);
|
|
160
200
|
|
|
161
201
|
if (!this.isRoot()) {
|
|
162
202
|
// Reset temp matrix
|
|
@@ -183,8 +223,7 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
|
|
|
183
223
|
tempMatrix.setPosition(tempVec.x, tempVec.y, tempVec.z);
|
|
184
224
|
uiobject.matrix.premultiply(tempMatrix);
|
|
185
225
|
// apply scale if necessary
|
|
186
|
-
|
|
187
|
-
uiobject.matrix.scale(this.gameObject.scale);
|
|
226
|
+
uiobject.matrix.scale(this.gameObject.scale);
|
|
188
227
|
}
|
|
189
228
|
else {
|
|
190
229
|
// We have to rotate the canvas when it's in worldspace
|
|
@@ -192,42 +231,28 @@ export class RectTransform extends BaseUIComponent implements IRectTransform, IR
|
|
|
192
231
|
if (!canvas.screenspace) uiobject.rotation.y = Math.PI;
|
|
193
232
|
}
|
|
194
233
|
|
|
195
|
-
this._copyMatrixAfterRender = true;
|
|
196
|
-
this.lastMatrix.copy(this.gameObject.matrix);
|
|
197
|
-
|
|
198
234
|
// iterate other components on this object that might need to know about the transform change
|
|
199
235
|
// e.g. Graphic components should update their width and height
|
|
200
236
|
const includeChildren = true;
|
|
201
|
-
for (const comp of foreachComponentEnumerator(this.gameObject, BaseUIComponent, includeChildren)) {
|
|
237
|
+
for (const comp of foreachComponentEnumerator(this.gameObject, BaseUIComponent, includeChildren, 1)) {
|
|
202
238
|
if (comp === this) continue;
|
|
239
|
+
if (!comp.activeAndEnabled) continue;
|
|
203
240
|
const callback = comp as any as IRectTransformChangedReceiver;
|
|
204
|
-
if (callback.onParentRectTransformChanged)
|
|
241
|
+
if (callback.onParentRectTransformChanged) {
|
|
242
|
+
// if (debugLayout) console.log(`RectTransform ${this.name} → call`, comp.name + "/" + comp.constructor.name)
|
|
205
243
|
callback.onParentRectTransformChanged(this);
|
|
244
|
+
}
|
|
206
245
|
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
private _copyMatrixAfterRender: boolean = false;
|
|
210
|
-
|
|
211
|
-
markDirty() {
|
|
212
|
-
this._transformNeedsUpdate = true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
246
|
|
|
216
|
-
|
|
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
|
-
{
|
|
221
|
-
this.applyTransform();
|
|
222
|
-
}
|
|
247
|
+
// const layout = GameObject.getComponentInParent(this.gameObject, ILayoutGroup);
|
|
223
248
|
}
|
|
224
249
|
|
|
225
|
-
onAfterRender() {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
250
|
+
// onAfterRender() {
|
|
251
|
+
// if (this._copyMatrixAfterRender) {
|
|
252
|
+
// // can we only have this event when the transform changed in this frame? Otherwise all RectTransforms will be iterated. Not sure what is better
|
|
253
|
+
// this.lastMatrixWorld.copy(this.gameObject.matrixWorld);
|
|
254
|
+
// }
|
|
255
|
+
// }
|
|
231
256
|
|
|
232
257
|
/** applies the position offset to the passed in vector */
|
|
233
258
|
private applyAnchoring(pos: Vector3) {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { serializable } from "../../engine/engine_serialization";
|
|
2
2
|
import { Behaviour } from "../Component";
|
|
3
|
-
import { Object3D } from "three";
|
|
4
|
-
import { getWorldPosition,
|
|
3
|
+
import { Matrix4, Object3D, Quaternion, Vector3 } from "three";
|
|
4
|
+
import { getWorldPosition, getWorldQuaternion, setWorldQuaternion } from "../../engine/engine_three_utils";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import { USDObject } from "../../engine-components/export/usdz/ThreeUSDZExporter";
|
|
7
|
+
import { UsdzBehaviour } from "../../engine-components/export/usdz/extensions/behavior/Behaviour";
|
|
8
|
+
import { ActionBuilder, BehaviorModel, TriggerBuilder, USDVec3 } from "../../engine-components/export/usdz/extensions/behavior/BehavioursBuilder";
|
|
9
|
+
|
|
10
|
+
export class LookAt extends Behaviour implements UsdzBehaviour {
|
|
7
11
|
|
|
8
12
|
@serializable(Object3D)
|
|
9
13
|
target?: Object3D;
|
|
@@ -11,11 +15,60 @@ export class LookAt extends Behaviour {
|
|
|
11
15
|
@serializable()
|
|
12
16
|
invertForward: boolean = false;
|
|
13
17
|
|
|
18
|
+
@serializable()
|
|
19
|
+
keepUpDirection: boolean = true;
|
|
20
|
+
|
|
21
|
+
@serializable()
|
|
22
|
+
copyTargetRotation: boolean = false;
|
|
23
|
+
|
|
24
|
+
private static flipYQuat: Quaternion = new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI);
|
|
25
|
+
|
|
14
26
|
onBeforeRender(): void {
|
|
15
|
-
|
|
16
|
-
if (!this.
|
|
17
|
-
|
|
27
|
+
let target: Object3D | null | undefined = this.target;
|
|
28
|
+
if (!target) target = this.context.mainCamera;
|
|
29
|
+
if (!target) return;
|
|
30
|
+
|
|
31
|
+
const lookTarget = getWorldPosition(target);
|
|
32
|
+
const lookFrom = getWorldPosition(this.gameObject);
|
|
33
|
+
|
|
34
|
+
if (this.keepUpDirection)
|
|
35
|
+
lookTarget.y = lookFrom.y;
|
|
36
|
+
|
|
37
|
+
if (this.copyTargetRotation)
|
|
38
|
+
setWorldQuaternion(this.gameObject, getWorldQuaternion(target));
|
|
18
39
|
else
|
|
19
|
-
|
|
40
|
+
this.gameObject.lookAt(lookTarget);
|
|
41
|
+
|
|
42
|
+
if (this.invertForward)
|
|
43
|
+
this.gameObject.quaternion.multiply(LookAt.flipYQuat);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
createBehaviours(ext, model: USDObject, _context) {
|
|
47
|
+
if (model.uuid === this.gameObject.uuid) {
|
|
48
|
+
let alignmentTarget = model;
|
|
49
|
+
|
|
50
|
+
// not entirely sure why we need to do this - looks like LookAt with up vector doesn't work properly in
|
|
51
|
+
// QuickLook, so we need to introduce an empty parent and rotate the model by 90° around Y
|
|
52
|
+
if (this.keepUpDirection) {
|
|
53
|
+
const parent = USDObject.createEmptyParent(model);
|
|
54
|
+
alignmentTarget = parent;
|
|
55
|
+
|
|
56
|
+
// rotate by 90° - counter-rotation on the parent makes sure
|
|
57
|
+
// that without Preliminary Behaviours it still looks right
|
|
58
|
+
parent.matrix.multiply(new Matrix4().makeRotationZ(Math.PI / 2));
|
|
59
|
+
model.matrix.multiply(new Matrix4().makeRotationZ(-Math.PI / 2));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const lookAt = new BehaviorModel("lookat " + this.name,
|
|
63
|
+
TriggerBuilder.sceneStartTrigger(),
|
|
64
|
+
ActionBuilder.lookAtCameraAction(
|
|
65
|
+
alignmentTarget,
|
|
66
|
+
undefined,
|
|
67
|
+
this.invertForward ? USDVec3.back : USDVec3.forward,
|
|
68
|
+
this.keepUpDirection ? USDVec3.up : USDVec3.zero
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
ext.addBehavior(lookAt);
|
|
72
|
+
}
|
|
20
73
|
}
|
|
21
74
|
}
|