@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "3.2.6-alpha",
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
- this._ambientLightObj = new AmbientLight(this.ambientLight, this.ambientIntensity);
131
- if (debug) console.log("Created ambient light", this.sourceId, this._ambientLightObj)
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
- this._hemisphereLightObj = new HemisphereLight(sky, ground, this.ambientIntensity);
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