@needle-tools/engine 3.2.6-alpha → 3.2.8-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 +8 -0
- package/dist/needle-engine.js +2490 -2445
- package/dist/needle-engine.min.js +93 -93
- package/dist/needle-engine.umd.cjs +65 -65
- package/lib/engine/engine_input.d.ts +3 -0
- package/lib/engine/engine_input.js +19 -0
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_physics.js +27 -2
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lighting_settings.d.ts +1 -0
- package/lib/engine/extensions/NEEDLE_lighting_settings.js +15 -3
- package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
- package/lib/engine-components/Component.js +13 -0
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +4 -4
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/PointerEvents.d.ts +2 -1
- package/lib/engine-components/ui/PointerEvents.js +6 -1
- package/lib/engine-components/ui/PointerEvents.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.js +2 -2
- package/src/engine/engine_input.ts +18 -0
- package/src/engine/engine_physics.ts +23 -2
- package/src/engine/extensions/NEEDLE_lighting_settings.ts +15 -3
- package/src/engine-components/Component.ts +13 -0
- package/src/engine-components/ui/EventSystem.ts +4 -4
- package/src/engine-components/ui/PointerEvents.ts +8 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.8-alpha",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in",
|
|
5
5
|
"main": "dist/needle-engine.umd.cjs",
|
|
6
6
|
"type": "module",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypeStore } from "./../engine_typestore"
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
// Import types
|
|
4
4
|
import { __Ignore } from "../../engine-components/codegen/components";
|
|
5
5
|
import { AlignmentConstraint } from "../../engine-components/AlignmentConstraint";
|
|
@@ -187,7 +187,7 @@ import { XRGrabModel } from "../../engine-components/webxr/WebXRGrabRendering";
|
|
|
187
187
|
import { XRGrabRendering } from "../../engine-components/webxr/WebXRGrabRendering";
|
|
188
188
|
import { XRRig } from "../../engine-components/webxr/WebXRRig";
|
|
189
189
|
import { XRState } from "../../engine-components/XRFlag";
|
|
190
|
-
|
|
190
|
+
|
|
191
191
|
// Register types
|
|
192
192
|
TypeStore.add("__Ignore", __Ignore);
|
|
193
193
|
TypeStore.add("AlignmentConstraint", AlignmentConstraint);
|
|
@@ -79,6 +79,20 @@ export class Input extends EventTarget {
|
|
|
79
79
|
this.context.domElement.style.cursor = "default";
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
setPointerUsed(i: number, used: boolean = true) {
|
|
83
|
+
if (i >= this._pointerUsed.length) {
|
|
84
|
+
if (i >= this._pointerIds.length)
|
|
85
|
+
return;
|
|
86
|
+
while (this._pointerUsed.length <= i) {
|
|
87
|
+
this._pointerUsed.push(false);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this._pointerUsed[i] = used;
|
|
91
|
+
}
|
|
92
|
+
getPointerUsed(i: number) {
|
|
93
|
+
if (i >= this._pointerUsed.length) return false;
|
|
94
|
+
return this._pointerUsed[i];
|
|
95
|
+
}
|
|
82
96
|
/** how many pointers are currently pressed */
|
|
83
97
|
getPointerPressedCount(): number {
|
|
84
98
|
let count = 0;
|
|
@@ -225,6 +239,7 @@ export class Input extends EventTarget {
|
|
|
225
239
|
private _mouseWheelChanged: boolean[] = [false];
|
|
226
240
|
private _mouseWheelDeltaY: number[] = [0];
|
|
227
241
|
private _pointerEvent: Event[] = [];
|
|
242
|
+
private _pointerUsed: boolean[] = [];
|
|
228
243
|
|
|
229
244
|
getKeyDown(): string | null {
|
|
230
245
|
for (const key in this.keysPressed) {
|
|
@@ -545,6 +560,9 @@ export class Input extends EventTarget {
|
|
|
545
560
|
// }
|
|
546
561
|
this.setPointerState(evt.button, this._pointerUp, true);
|
|
547
562
|
|
|
563
|
+
while (evt.button >= this._pointerUsed.length) this._pointerUsed.push(false);
|
|
564
|
+
this.setPointerState(evt.button, this._pointerUsed, false);
|
|
565
|
+
|
|
548
566
|
this.updatePointerPosition(evt);
|
|
549
567
|
|
|
550
568
|
if (!this._pointerPositionDown[evt.button]) {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { InstancingUtil } from './engine_instancing';
|
|
16
16
|
import { foreachComponent } from './engine_gameobject';
|
|
17
17
|
|
|
18
|
-
import RAPIER, { ActiveEvents, CoefficientCombineRule, Collider, ColliderDesc, EventQueue, JointData, QueryFilterFlags, RigidBody, RigidBodyType, ShapeColliderTOI, World } from '@dimforge/rapier3d-compat';
|
|
18
|
+
import RAPIER, { ActiveCollisionTypes, ActiveEvents, CoefficientCombineRule, Collider, ColliderDesc, EventQueue, JointData, QueryFilterFlags, RigidBody, RigidBodyType, ShapeColliderTOI, World } from '@dimforge/rapier3d-compat';
|
|
19
19
|
import { CollisionDetectionMode, PhysicsMaterialCombine } from '../engine/engine_physics.types';
|
|
20
20
|
import { Gizmos } from './engine_gizmos';
|
|
21
21
|
import { Mathf } from './engine_math';
|
|
@@ -645,6 +645,8 @@ export class Physics {
|
|
|
645
645
|
col[$componentKey] = collider;
|
|
646
646
|
collider[$bodyKey] = col;
|
|
647
647
|
col.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
|
648
|
+
// We want to receive collisitons between two triggers too
|
|
649
|
+
col.setActiveCollisionTypes(ActiveCollisionTypes.ALL);
|
|
648
650
|
|
|
649
651
|
// const objectLayerMask = collider.gameObject.layers.mask;
|
|
650
652
|
// const mask = objectLayerMask & ~2;
|
|
@@ -1082,7 +1084,7 @@ class PhysicsCollisionHandler {
|
|
|
1082
1084
|
// if one is a trigger we dont get collisions but want to raise the trigger events
|
|
1083
1085
|
if (self.isTrigger || other.isTrigger) {
|
|
1084
1086
|
foreachComponent(self.gameObject, (c: IComponent) => {
|
|
1085
|
-
if (c.onTriggerEnter) {
|
|
1087
|
+
if (c.onTriggerEnter && !c.destroyed) {
|
|
1086
1088
|
c.onTriggerEnter(other);
|
|
1087
1089
|
}
|
|
1088
1090
|
this.activeTriggers.push({ collider: self, component: c, otherCollider: other });
|
|
@@ -1093,6 +1095,7 @@ class PhysicsCollisionHandler {
|
|
|
1093
1095
|
// TODO: we dont respect the flip value here!
|
|
1094
1096
|
this.world.contactPair(selfBody, otherBody, (manifold, _flipped) => {
|
|
1095
1097
|
foreachComponent(object, (c: IComponent) => {
|
|
1098
|
+
if(c.destroyed) return;
|
|
1096
1099
|
const hasDeclaredEventMethod = c.onCollisionEnter || c.onCollisionStay || c.onCollisionExit;
|
|
1097
1100
|
if (hasDeclaredEventMethod || debugCollisions) {
|
|
1098
1101
|
if (!collision) {
|
|
@@ -1137,6 +1140,7 @@ class PhysicsCollisionHandler {
|
|
|
1137
1140
|
private onHandleCollisionStay() {
|
|
1138
1141
|
for (const active of this.activeCollisionsStay) {
|
|
1139
1142
|
const c = active.component;
|
|
1143
|
+
if(c.destroyed) continue;
|
|
1140
1144
|
if (c.activeAndEnabled && c.onCollisionStay) {
|
|
1141
1145
|
const arg = active.collision;
|
|
1142
1146
|
c.onCollisionStay(arg);
|
|
@@ -1144,6 +1148,7 @@ class PhysicsCollisionHandler {
|
|
|
1144
1148
|
}
|
|
1145
1149
|
for (const active of this.activeTriggers) {
|
|
1146
1150
|
const c = active.component;
|
|
1151
|
+
if(c.destroyed) continue;
|
|
1147
1152
|
if (c.activeAndEnabled && c.onTriggerStay) {
|
|
1148
1153
|
const arg = active.otherCollider;
|
|
1149
1154
|
c.onTriggerStay(arg);
|
|
@@ -1152,9 +1157,15 @@ class PhysicsCollisionHandler {
|
|
|
1152
1157
|
}
|
|
1153
1158
|
|
|
1154
1159
|
private onCollisionEnded(self: ICollider, other: ICollider) {
|
|
1160
|
+
if(self.destroyed || other.destroyed) return;
|
|
1155
1161
|
for (let i = 0; i < this.activeCollisions.length; i++) {
|
|
1156
1162
|
const active = this.activeCollisions[i];
|
|
1157
1163
|
const collider = active.collider;
|
|
1164
|
+
if(collider.destroyed) {
|
|
1165
|
+
this.activeCollisions.splice(i, 1);
|
|
1166
|
+
i--;
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1158
1169
|
if (collider === self && active.collision.collider === other) {
|
|
1159
1170
|
const c = active.component;
|
|
1160
1171
|
this.activeCollisions.splice(i, 1);
|
|
@@ -1168,6 +1179,11 @@ class PhysicsCollisionHandler {
|
|
|
1168
1179
|
for (let i = 0; i < this.activeCollisionsStay.length; i++) {
|
|
1169
1180
|
const active = this.activeCollisionsStay[i];
|
|
1170
1181
|
const collider = active.collider;
|
|
1182
|
+
if(collider.destroyed) {
|
|
1183
|
+
this.activeCollisionsStay.splice(i, 1);
|
|
1184
|
+
i--;
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1171
1187
|
if (collider === self && active.collision.collider === other) {
|
|
1172
1188
|
const c = active.component;
|
|
1173
1189
|
this.activeCollisionsStay.splice(i, 1);
|
|
@@ -1181,6 +1197,11 @@ class PhysicsCollisionHandler {
|
|
|
1181
1197
|
for (let i = 0; i < this.activeTriggers.length; i++) {
|
|
1182
1198
|
const active = this.activeTriggers[i];
|
|
1183
1199
|
const collider = active.collider;
|
|
1200
|
+
if(collider.destroyed) {
|
|
1201
|
+
this.activeTriggers.splice(i, 1);
|
|
1202
|
+
i--;
|
|
1203
|
+
continue;
|
|
1204
|
+
}
|
|
1184
1205
|
if (collider === self && active.otherCollider === other) {
|
|
1185
1206
|
const c = active.component;
|
|
1186
1207
|
this.activeTriggers.splice(i, 1);
|
|
@@ -8,6 +8,7 @@ import { getParam } from "../engine_utils";
|
|
|
8
8
|
import { Context } from "../engine_setup";
|
|
9
9
|
import { LightProbe } from "three";
|
|
10
10
|
import { ContextEvent, ContextRegistry } from "../engine_context_registry";
|
|
11
|
+
import { Mathf } from "../engine_math";
|
|
11
12
|
|
|
12
13
|
export const EXTENSION_NAME = "NEEDLE_lighting_settings";
|
|
13
14
|
const debug = getParam("debugenvlight");
|
|
@@ -122,13 +123,22 @@ export class SceneLightSettings extends Behaviour {
|
|
|
122
123
|
this.context.sceneLighting.internalUnregisterSceneLightSettings(this);
|
|
123
124
|
}
|
|
124
125
|
|
|
126
|
+
private calculateIntensityFactor(col:Color){
|
|
127
|
+
const intensity = Math.max(col.r, col.g, col.b);// * 0.2126 + col.g * 0.7152 + col.b * 0.0722;
|
|
128
|
+
const factor = 2.2 * Mathf.lerp(0, 1.33, intensity); // scale based on intensity
|
|
129
|
+
return factor;
|
|
130
|
+
}
|
|
131
|
+
|
|
125
132
|
onEnable(): void {
|
|
126
133
|
if (debug) console.warn("💡🟡 >>> Enable lighting", this.sourceId, this);
|
|
127
134
|
|
|
128
135
|
if (this.ambientMode == AmbientMode.Flat) {
|
|
129
136
|
if (this.ambientLight && !this._ambientLightObj) {
|
|
130
|
-
|
|
131
|
-
|
|
137
|
+
// TODO: currently ambient intensity is always exported as 1? The exported values are not correct in threejs
|
|
138
|
+
// the following calculation is a workaround to get the correct intensity
|
|
139
|
+
const factor = this.calculateIntensityFactor(this.ambientLight);
|
|
140
|
+
this._ambientLightObj = new AmbientLight(this.ambientLight, this.ambientIntensity * factor);
|
|
141
|
+
if (debug) console.log("Created ambient light", this.sourceId, this._ambientLightObj, this.ambientIntensity, factor)
|
|
132
142
|
}
|
|
133
143
|
if (this._ambientLightObj) {
|
|
134
144
|
this.gameObject.add(this._ambientLightObj)
|
|
@@ -139,8 +149,10 @@ export class SceneLightSettings extends Behaviour {
|
|
|
139
149
|
if (this.ambientTrilight) {
|
|
140
150
|
const ground = this.ambientTrilight[0];
|
|
141
151
|
const sky = this.ambientTrilight[this.ambientTrilight.length - 1];
|
|
142
|
-
|
|
152
|
+
const factor = this.calculateIntensityFactor(sky);
|
|
153
|
+
this._hemisphereLightObj = new HemisphereLight(sky, ground, this.ambientIntensity * factor);
|
|
143
154
|
this.gameObject.add(this._hemisphereLightObj)
|
|
155
|
+
if (debug) console.log("Created hemisphere ambient light", this.sourceId, this._hemisphereLightObj, this.ambientIntensity, factor)
|
|
144
156
|
}
|
|
145
157
|
}
|
|
146
158
|
else {
|
|
@@ -9,6 +9,7 @@ import { addNewComponent, destroyComponentInstance, findObjectOfType, findObject
|
|
|
9
9
|
import { findByGuid, destroy, InstantiateOptions, instantiate, HideFlags, foreachComponent, markAsInstancedRendered, isActiveInHierarchy, isActiveSelf, isUsingInstancing, setActive, isDestroyed } from "../engine/engine_gameobject";
|
|
10
10
|
|
|
11
11
|
import { Euler, Object3D, Quaternion, Scene, Vector3 } from "three";
|
|
12
|
+
import { showBalloonWarning, isDevEnvironment } from "../engine/debug";
|
|
12
13
|
|
|
13
14
|
// export interface ISerializationCallbackReceiver {
|
|
14
15
|
// onBeforeSerialize?(): object | void;
|
|
@@ -470,6 +471,12 @@ export class Component implements IComponent, EventTarget {
|
|
|
470
471
|
|
|
471
472
|
/** @internal */
|
|
472
473
|
__internalEnable(): boolean {
|
|
474
|
+
if (this.__destroyed) {
|
|
475
|
+
if (isDevEnvironment()) {
|
|
476
|
+
console.warn("[Needle Engine Dev] Trying to enable destroyed component");
|
|
477
|
+
}
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
473
480
|
// Don't change enable before awake
|
|
474
481
|
// But a user can change enable during awake
|
|
475
482
|
if (!this.__didAwake) return false;
|
|
@@ -511,6 +518,12 @@ export class Component implements IComponent, EventTarget {
|
|
|
511
518
|
return typeof this.__isEnabled === "boolean" ? this.__isEnabled : true; // if it has no enabled field it is always enabled
|
|
512
519
|
}
|
|
513
520
|
set enabled(val: boolean) {
|
|
521
|
+
if (this.__destroyed) {
|
|
522
|
+
if (isDevEnvironment()) {
|
|
523
|
+
console.warn(`[Needle Engine Dev] Trying to ${val ? "enable" : "disable"} destroyed component`);
|
|
524
|
+
}
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
514
527
|
// when called from animationclip we receive numbers
|
|
515
528
|
// due to interpolation they can be anything between 0 and 1
|
|
516
529
|
if (typeof val === "number") {
|
|
@@ -113,7 +113,7 @@ export class EventSystem extends Behaviour {
|
|
|
113
113
|
this._selectStartFn ??= (ctrl, args: { grab: THREE.Object3D | null }) => {
|
|
114
114
|
if (!args.grab) return;
|
|
115
115
|
MeshUIHelper.resetLastSelected();
|
|
116
|
-
const opts = new PointerEventData();
|
|
116
|
+
const opts = new PointerEventData(this.context.input);
|
|
117
117
|
opts.inputSource = ctrl;
|
|
118
118
|
opts.isDown = ctrl.selectionDown;
|
|
119
119
|
opts.isUp = ctrl.selectionUp;
|
|
@@ -126,7 +126,7 @@ export class EventSystem extends Behaviour {
|
|
|
126
126
|
}
|
|
127
127
|
this._selectEndFn ??= (ctrl, args: { grab: THREE.Object3D }) => {
|
|
128
128
|
if (!args.grab) return;
|
|
129
|
-
const opts = new PointerEventData();
|
|
129
|
+
const opts = new PointerEventData(this.context.input);
|
|
130
130
|
opts.inputSource = ctrl;
|
|
131
131
|
opts.isDown = ctrl.selectionDown;
|
|
132
132
|
opts.isUp = ctrl.selectionUp;
|
|
@@ -155,7 +155,7 @@ export class EventSystem extends Behaviour {
|
|
|
155
155
|
controllerRcOpts.ray = _ctrl.getRay();
|
|
156
156
|
const rc = this.performRaycast(controllerRcOpts);
|
|
157
157
|
if (!rc) return;
|
|
158
|
-
const opts = new PointerEventData();
|
|
158
|
+
const opts = new PointerEventData(this.context.input);
|
|
159
159
|
opts.inputSource = _ctrl;
|
|
160
160
|
this.handleIntersections(rc, opts);
|
|
161
161
|
};
|
|
@@ -230,7 +230,7 @@ export class EventSystem extends Behaviour {
|
|
|
230
230
|
|
|
231
231
|
const ptr = this.context.input.getPointerEvent(pointerId);
|
|
232
232
|
// console.log(ptr);
|
|
233
|
-
const args: PointerEventData = new PointerEventData(ptr);
|
|
233
|
+
const args: PointerEventData = new PointerEventData(this.context.input, ptr);
|
|
234
234
|
args.inputSource = this.context.input;
|
|
235
235
|
args.pointerId = pointerId;
|
|
236
236
|
args.isClicked = this.context.input.getPointerClicked(pointerId)
|
|
@@ -7,10 +7,14 @@ export interface IInputEventArgs {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export class PointerEventData implements IInputEventArgs {
|
|
10
|
+
|
|
11
|
+
// TODO: should we make this a getter and return the input used state instead? -> this.context.getPointerUsed(this.pointerId);
|
|
10
12
|
used: boolean = false;
|
|
11
13
|
|
|
12
14
|
Use() {
|
|
13
15
|
this.used = true;
|
|
16
|
+
if (this.pointerId !== undefined)
|
|
17
|
+
this.input.setPointerUsed(this.pointerId);
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
StopPropagation() {
|
|
@@ -26,10 +30,13 @@ export class PointerEventData implements IInputEventArgs {
|
|
|
26
30
|
isPressed: boolean | undefined;
|
|
27
31
|
isClicked: boolean | undefined;
|
|
28
32
|
|
|
33
|
+
private input: Input;
|
|
34
|
+
|
|
29
35
|
private event?: Event;
|
|
30
36
|
|
|
31
|
-
constructor(events?: Event) {
|
|
37
|
+
constructor(input: Input, events?: Event) {
|
|
32
38
|
this.event = events;
|
|
39
|
+
this.input = input;
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
42
|
|