@needle-tools/engine 2.57.0-pre → 2.58.0-pre
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 +4 -0
- package/dist/needle-engine.d.ts +33 -2
- package/dist/needle-engine.js +200 -200
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +18 -18
- package/dist/needle-engine.min.js.map +4 -4
- package/dist/needle-engine.tsbuildinfo +1 -1
- package/lib/engine/codegen/register_types.js +2 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine.d.ts +1 -0
- package/lib/engine/engine.js +1 -0
- package/lib/engine/engine.js.map +1 -1
- package/lib/engine/engine_hot_reload.d.ts +3 -0
- package/lib/engine/engine_hot_reload.js +168 -0
- package/lib/engine/engine_hot_reload.js.map +1 -0
- package/lib/engine/engine_input.js +1 -1
- package/lib/engine/engine_setup.js +41 -36
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine-components/Fog.d.ts +20 -0
- package/lib/engine-components/Fog.js +61 -0
- package/lib/engine-components/Fog.js.map +1 -0
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.d.ts +1 -1
- package/lib/engine-components/ui/EventSystem.js +25 -10
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/PointerEvents.d.ts +3 -1
- package/lib/engine-components/ui/PointerEvents.js +1 -0
- package/lib/engine-components/ui/PointerEvents.js.map +1 -1
- package/lib/engine-components/ui/Raycaster.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.js +2 -0
- package/src/engine/engine.ts +2 -0
- package/src/engine/engine_hot_reload.ts +186 -0
- package/src/engine/engine_input.ts +1 -1
- package/src/engine/engine_setup.ts +39 -36
- package/src/engine-components/Fog.ts +60 -0
- package/src/engine-components/codegen/components.ts +1 -0
- package/src/engine-components/ui/EventSystem.ts +30 -15
- package/src/engine-components/ui/PointerEvents.ts +7 -4
- package/src/engine-components/ui/Raycaster.ts +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.58.0-pre",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally.",
|
|
5
5
|
"main": "dist/needle-engine.js",
|
|
6
6
|
"module": "src/needle-engine.ts",
|
|
@@ -55,6 +55,7 @@ import { EventTrigger } from "../../engine-components/EventTrigger.ts";
|
|
|
55
55
|
import { FieldWithDefault } from "../../engine-components/Renderer.ts";
|
|
56
56
|
import { FixedJoint } from "../../engine-components/Joints.ts";
|
|
57
57
|
import { FlyControls } from "../../engine-components/FlyControls.ts";
|
|
58
|
+
import { Fog } from "../../engine-components/Fog.ts";
|
|
58
59
|
import { GltfExport } from "../../engine-components/export/gltf/GltfExport.ts";
|
|
59
60
|
import { GltfExportBox } from "../../engine-components/export/gltf/GltfExport.ts";
|
|
60
61
|
import { Gradient } from "../../engine-components/ParticleSystemModules.ts";
|
|
@@ -225,6 +226,7 @@ TypeStore.add("EventTrigger", EventTrigger);
|
|
|
225
226
|
TypeStore.add("FieldWithDefault", FieldWithDefault);
|
|
226
227
|
TypeStore.add("FixedJoint", FixedJoint);
|
|
227
228
|
TypeStore.add("FlyControls", FlyControls);
|
|
229
|
+
TypeStore.add("Fog", Fog);
|
|
228
230
|
TypeStore.add("GltfExport", GltfExport);
|
|
229
231
|
TypeStore.add("GltfExportBox", GltfExportBox);
|
|
230
232
|
TypeStore.add("Gradient", Gradient);
|
package/src/engine/engine.ts
CHANGED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { IComponent } from "./engine_types";
|
|
2
|
+
import { TypeStore } from "./engine_typestore";
|
|
3
|
+
import { addScriptToArrays, removeScriptFromContext } from "./engine_mainloop_utils"
|
|
4
|
+
import { showBalloonWarning } from "./debug/debug";
|
|
5
|
+
import { getParam } from "./engine_utils";
|
|
6
|
+
|
|
7
|
+
const debug = getParam("debughotreload");
|
|
8
|
+
|
|
9
|
+
declare type BeforeUpdateArgs = {
|
|
10
|
+
type: string,
|
|
11
|
+
updates: Array<{ path: string, timestamp: number, acceptedPath: string, explicitImportRequired: boolean, type: string }>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//@ts-ignore
|
|
15
|
+
if (import.meta.hot) {
|
|
16
|
+
//@ts-ignore
|
|
17
|
+
import.meta.hot.on('vite:beforeUpdate', (cb: BeforeUpdateArgs) => {
|
|
18
|
+
if (debug) console.log(cb);
|
|
19
|
+
for (const update of cb.updates) {
|
|
20
|
+
console.log("[Needle Engine] Hot reloading " + update.path);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
let isApplyingChanges = false;
|
|
27
|
+
|
|
28
|
+
const instances: Map<string, object[]> = new Map();
|
|
29
|
+
|
|
30
|
+
export function register(instance: object) {
|
|
31
|
+
if (isApplyingChanges) return;
|
|
32
|
+
const type = instance.constructor;
|
|
33
|
+
const name = type.name;
|
|
34
|
+
if (!instances.has(name)) {
|
|
35
|
+
instances.set(name, [instance]);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
instances.get(name)?.push(instance);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function unregister(instance: object) {
|
|
43
|
+
if (isApplyingChanges) return;
|
|
44
|
+
const type = instance.constructor;
|
|
45
|
+
const name = type.name;
|
|
46
|
+
const instancesOfType = instances.get(name);
|
|
47
|
+
if (!instancesOfType) return;
|
|
48
|
+
const idx = instancesOfType.indexOf(instance);
|
|
49
|
+
if (idx === -1) return;
|
|
50
|
+
instancesOfType.splice(idx, 1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
let didRegisterUnhandledExceptionListener = false;
|
|
55
|
+
function reloadPageOnHotReloadError() {
|
|
56
|
+
if (debug) return;
|
|
57
|
+
if (didRegisterUnhandledExceptionListener) return;
|
|
58
|
+
didRegisterUnhandledExceptionListener = true;
|
|
59
|
+
|
|
60
|
+
const error = console.error;
|
|
61
|
+
console.error = (...args: any[]) => {
|
|
62
|
+
if (args.length) {
|
|
63
|
+
const arg: string = args[0];
|
|
64
|
+
// When making changes in e.g. the engine package and then making changes in project scripts again that import the engine package: hot reload fails and reports redefinitions of types, we just reload the page in those cases for now
|
|
65
|
+
// editing a script in one package seems to work for now so it should be good enough for a start
|
|
66
|
+
if (typeof arg === "string" && arg.includes("[hmr] Failed to reload ")) {
|
|
67
|
+
console.log("[Needle Engine] Hot reloading failed")
|
|
68
|
+
window.location.reload();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
error.apply(console, args);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
export function applyChanges(newModule): boolean {
|
|
79
|
+
|
|
80
|
+
reloadPageOnHotReloadError();
|
|
81
|
+
|
|
82
|
+
// showBalloonMessage("Hot reloading");
|
|
83
|
+
|
|
84
|
+
// console.dir(newModule);
|
|
85
|
+
|
|
86
|
+
for (const key of Object.keys(newModule)) {
|
|
87
|
+
try {
|
|
88
|
+
isApplyingChanges = true;
|
|
89
|
+
|
|
90
|
+
const typeToUpdate = TypeStore.get(key);
|
|
91
|
+
if (!typeToUpdate)
|
|
92
|
+
{
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const newType = newModule[key];
|
|
96
|
+
|
|
97
|
+
console.log("[Needle Engine] Updating type: " + key);
|
|
98
|
+
|
|
99
|
+
// Update prototype (methods and properties)
|
|
100
|
+
const previousMethods = Object.getOwnPropertyNames(typeToUpdate.prototype);
|
|
101
|
+
const methodsAndProperties = Object.getOwnPropertyDescriptors(newType.prototype);
|
|
102
|
+
for (const typeKey in methodsAndProperties) {
|
|
103
|
+
const desc = methodsAndProperties[typeKey];
|
|
104
|
+
if (!desc.writable) continue;
|
|
105
|
+
typeToUpdate.prototype[typeKey] = newModule[key].prototype[typeKey];
|
|
106
|
+
}
|
|
107
|
+
// Remove methods that are no longer present
|
|
108
|
+
for (const typeKey of previousMethods) {
|
|
109
|
+
if (!methodsAndProperties[typeKey]) {
|
|
110
|
+
delete typeToUpdate.prototype[typeKey];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Update fields (we only add new fields if they are undefined)
|
|
115
|
+
// we create a instance to get access to the fields
|
|
116
|
+
const instancesOfType = instances.get(newType.name);
|
|
117
|
+
if (instancesOfType) {
|
|
118
|
+
const newTypeInstance = new newType();
|
|
119
|
+
const keys = Object.getOwnPropertyDescriptors(newTypeInstance);
|
|
120
|
+
for (const inst of instancesOfType) {
|
|
121
|
+
const componentInstance = inst as unknown as IComponent;
|
|
122
|
+
const isComponent = componentInstance.isComponent === true;
|
|
123
|
+
const active = isComponent ? componentInstance.activeAndEnabled : true;
|
|
124
|
+
const context = isComponent ? componentInstance.context : undefined;
|
|
125
|
+
try {
|
|
126
|
+
if (isComponent) {
|
|
127
|
+
removeScriptFromContext(componentInstance, context);
|
|
128
|
+
}
|
|
129
|
+
if (isComponent && active) {
|
|
130
|
+
componentInstance.enabled = false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (inst["onBeforeHotReloadFields"]) {
|
|
134
|
+
const res = inst["onBeforeHotReloadFields"]();
|
|
135
|
+
if (res === false) continue;
|
|
136
|
+
}
|
|
137
|
+
for (const key in keys) {
|
|
138
|
+
const desc = keys[key];
|
|
139
|
+
if (!desc.writable) continue;
|
|
140
|
+
if (inst[key] === undefined) {
|
|
141
|
+
inst[key] = newTypeInstance[key];
|
|
142
|
+
}
|
|
143
|
+
// if its a function but not on the prototype
|
|
144
|
+
// then its a bound method that needs to be rebound
|
|
145
|
+
else if (typeof inst[key] === "function" && !inst[key].prototype) {
|
|
146
|
+
const boundMethod = inst[key];
|
|
147
|
+
// try to get the target method name
|
|
148
|
+
const targetMethodName = boundMethod.name;
|
|
149
|
+
const prefix = "bound "; // < magic prefix
|
|
150
|
+
if (targetMethodName === prefix) continue;
|
|
151
|
+
const name = boundMethod.name.substring(prefix.length);
|
|
152
|
+
// if the target method name still exists on the new prototype
|
|
153
|
+
// we want to rebind it and assign it to the field
|
|
154
|
+
// Beware that this will not work if the method is added to some event listener etc
|
|
155
|
+
const newTarget = newType.prototype[name];
|
|
156
|
+
if (newTarget)
|
|
157
|
+
inst[key] = newTarget.bind(inst);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (inst["onAfterHotReloadFields"]) inst["onAfterHotReloadFields"]();
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
if (isComponent) {
|
|
164
|
+
addScriptToArrays(componentInstance, context);
|
|
165
|
+
}
|
|
166
|
+
if (isComponent && active) {
|
|
167
|
+
componentInstance.enabled = true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
if (debug) console.error(err);
|
|
175
|
+
// we only want to invalidate changes if we debug hot reload
|
|
176
|
+
else return false;
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
isApplyingChanges = false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
@@ -170,7 +170,7 @@ export class Input extends EventTarget {
|
|
|
170
170
|
*foreachPointerId(pointerType?: string | PointerType | string[] | PointerType[]): Generator<number> {
|
|
171
171
|
for (let i = 0; i < this._pointerTypes.length; i++) {
|
|
172
172
|
// check if the pointer is active
|
|
173
|
-
if (this._pointerIsActive
|
|
173
|
+
if (this._pointerIsActive(i)) {
|
|
174
174
|
// if specific pointer types are requested
|
|
175
175
|
if (pointerType !== undefined) {
|
|
176
176
|
const type = this._pointerTypes[i];
|
|
@@ -809,47 +809,50 @@ export class Context {
|
|
|
809
809
|
if (this.coroutines[evt]) {
|
|
810
810
|
const evts = this.coroutines[evt];
|
|
811
811
|
for (let i = 0; i < evts.length; i++) {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
const iter = evt.chained;
|
|
821
|
-
if (iter && iter.length > 0) {
|
|
822
|
-
const last: Generator = iter[iter.length - 1];
|
|
823
|
-
const res = last.next();
|
|
824
|
-
if (res.done) {
|
|
825
|
-
iter.pop();
|
|
812
|
+
try {
|
|
813
|
+
const evt = evts[i];
|
|
814
|
+
// TODO we might want to keep coroutines playing even if the component is disabled or inactive
|
|
815
|
+
const remove = !evt.comp || evt.comp.destroyed || !evt.main || evt.comp["enabled"] === false;
|
|
816
|
+
if (remove) {
|
|
817
|
+
evts.splice(i, 1);
|
|
818
|
+
--i;
|
|
819
|
+
continue;
|
|
826
820
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
821
|
+
const iter = evt.chained;
|
|
822
|
+
if (iter && iter.length > 0) {
|
|
823
|
+
const last: Generator = iter[iter.length - 1];
|
|
824
|
+
const res = last.next();
|
|
825
|
+
if (res.done) {
|
|
826
|
+
iter.pop();
|
|
827
|
+
}
|
|
828
|
+
if (isGenerator(res)) {
|
|
829
|
+
if (!evt.chained) evt.chained = [];
|
|
830
|
+
evt.chained.push(res.value);
|
|
831
|
+
}
|
|
832
|
+
if (!res.done) continue;
|
|
830
833
|
}
|
|
831
|
-
if (!res.done) continue;
|
|
832
|
-
}
|
|
833
834
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
835
|
+
const res = evt.main.next();
|
|
836
|
+
if (res.done === true) {
|
|
837
|
+
evts.splice(i, 1);
|
|
838
|
+
--i;
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
const val = res.value;
|
|
842
|
+
if (isGenerator(val)) {
|
|
843
|
+
// invoke once if its a generator
|
|
844
|
+
// this means e.g. WaitForFrame(1) works and will capture
|
|
845
|
+
// the frame it was created
|
|
846
|
+
const gen = val as Generator;
|
|
847
|
+
const res = gen.next();
|
|
848
|
+
if (res.done) continue;
|
|
849
|
+
if (!evt.chained) evt.chained = [];
|
|
850
|
+
evt.chained.push(val as Generator);
|
|
851
|
+
}
|
|
839
852
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
// invoke once if its a generator
|
|
843
|
-
// this means e.g. WaitForFrame(1) works and will capture
|
|
844
|
-
// the frame it was created
|
|
845
|
-
const gen = val as Generator;
|
|
846
|
-
const res = gen.next();
|
|
847
|
-
if (res.done) continue;
|
|
848
|
-
if (!evt.chained) evt.chained = [];
|
|
849
|
-
evt.chained.push(val as Generator);
|
|
853
|
+
catch (e) {
|
|
854
|
+
console.error(e);
|
|
850
855
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
856
|
}
|
|
854
857
|
}
|
|
855
858
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Behaviour } from "./Component";
|
|
2
|
+
import { Color, Fog as Fog3 } from "three";
|
|
3
|
+
import { serializable } from "../engine/engine_serialization";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export enum FogMode {
|
|
7
|
+
|
|
8
|
+
Linear = 1,
|
|
9
|
+
Exponential = 2,
|
|
10
|
+
ExponentialSquared = 3,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Fog extends Behaviour {
|
|
14
|
+
|
|
15
|
+
get fog() {
|
|
16
|
+
if (!this._fog) this._fog = new Fog3(0x000000, 0, 50);
|
|
17
|
+
return this._fog;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get mode() {
|
|
21
|
+
return FogMode.Linear;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@serializable()
|
|
25
|
+
set near(value: number) {
|
|
26
|
+
this.fog.near = value;
|
|
27
|
+
}
|
|
28
|
+
get near() {
|
|
29
|
+
return this.fog.near;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@serializable()
|
|
33
|
+
set far(value: number) {
|
|
34
|
+
this.fog.far = value;
|
|
35
|
+
}
|
|
36
|
+
get far() {
|
|
37
|
+
return this.fog.far;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@serializable(Color)
|
|
41
|
+
set color(value: Color) {
|
|
42
|
+
this.fog.color.copy(value);
|
|
43
|
+
}
|
|
44
|
+
get color() {
|
|
45
|
+
return this.fog.color;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private _fog?: Fog3;
|
|
49
|
+
|
|
50
|
+
onEnable() {
|
|
51
|
+
this.scene.fog = this.fog;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
onDisable() {
|
|
55
|
+
if (this.scene.fog === this._fog)
|
|
56
|
+
this.scene.fog = null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
}
|
|
@@ -53,6 +53,7 @@ export { EventTrigger } from "../EventTrigger";
|
|
|
53
53
|
export { FieldWithDefault } from "../Renderer";
|
|
54
54
|
export { FixedJoint } from "../Joints";
|
|
55
55
|
export { FlyControls } from "../FlyControls";
|
|
56
|
+
export { Fog } from "../Fog";
|
|
56
57
|
export { GltfExport } from "../export/gltf/GltfExport";
|
|
57
58
|
export { GltfExportBox } from "../export/gltf/GltfExport";
|
|
58
59
|
export { Gradient } from "../ParticleSystemModules";
|
|
@@ -36,13 +36,12 @@ export class EventSystem extends Behaviour {
|
|
|
36
36
|
GameObject.addNewComponent(go, EventSystem);
|
|
37
37
|
context.scene.add(go);
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
static get systems(): EventSystem[]
|
|
41
|
-
{
|
|
39
|
+
|
|
40
|
+
static get systems(): EventSystem[] {
|
|
42
41
|
const context = Context.Current;
|
|
43
42
|
if (!this._eventSystemMap.has(context)) {
|
|
44
43
|
this._eventSystemMap.set(context, []);
|
|
45
|
-
}
|
|
44
|
+
}
|
|
46
45
|
return this._eventSystemMap.get(context)!;
|
|
47
46
|
}
|
|
48
47
|
|
|
@@ -91,6 +90,7 @@ export class EventSystem extends Behaviour {
|
|
|
91
90
|
private _selectStartFn?: any;
|
|
92
91
|
private _selectEndFn?: any;
|
|
93
92
|
private _selectUpdateFn?: any;
|
|
93
|
+
private _onBeforeUpdateFn?: any;
|
|
94
94
|
|
|
95
95
|
onEnable(): void {
|
|
96
96
|
|
|
@@ -118,7 +118,7 @@ export class EventSystem extends Behaviour {
|
|
|
118
118
|
opts.isPressed = ctrl.selectionPressed;
|
|
119
119
|
opts.isClicked = ctrl.selectionClick;
|
|
120
120
|
this.handleEvents(args.grab, opts);
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
const prevGrabbed = grabbed.get(ctrl);
|
|
123
123
|
grabbed.set(ctrl, null);
|
|
124
124
|
if (prevGrabbed) {
|
|
@@ -149,20 +149,22 @@ export class EventSystem extends Behaviour {
|
|
|
149
149
|
WebXRController.addEventListener(ControllerEvents.SelectEnd, this._selectEndFn);
|
|
150
150
|
WebXRController.addEventListener(ControllerEvents.Update, this._selectUpdateFn);
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
this.
|
|
152
|
+
// TODO: unregister
|
|
153
|
+
this._onBeforeUpdateFn ??= this.onBeforeUpdate.bind(this);
|
|
154
|
+
this.context.pre_update_callbacks.push(this._onBeforeUpdateFn);
|
|
155
|
+
this.context.input.addEventListener(InputEvents.PointerDown, this._onBeforeUpdateFn);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
onDisable(): void {
|
|
157
159
|
WebXRController.removeEventListener(ControllerEvents.SelectStart, this._selectStartFn);
|
|
158
160
|
WebXRController.removeEventListener(ControllerEvents.SelectEnd, this._selectEndFn);
|
|
159
161
|
WebXRController.removeEventListener(ControllerEvents.Update, this._selectUpdateFn);
|
|
160
|
-
}
|
|
161
162
|
|
|
162
|
-
|
|
163
|
-
this.
|
|
163
|
+
this.context.pre_update_callbacks.splice(this.context.pre_update_callbacks.indexOf(this._onBeforeUpdateFn), 1);
|
|
164
|
+
this.context.input.removeEventListener(InputEvents.PointerDown, this._onBeforeUpdateFn);
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
|
|
166
168
|
// doesnt work in dist
|
|
167
169
|
// onBeforeRender() {
|
|
168
170
|
// MeshUIHelper.update(this.context);
|
|
@@ -195,12 +197,25 @@ export class EventSystem extends Behaviour {
|
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
const hits = this.performRaycast(null);
|
|
198
|
-
|
|
200
|
+
let pointerId = 0;
|
|
201
|
+
for (const i of this.context.input.foreachPointerId()) {
|
|
202
|
+
const isDown = this.context.input.getPointerDown(i);
|
|
203
|
+
const isUp = this.context.input.getPointerUp(i);
|
|
204
|
+
if (isDown || isUp) {
|
|
205
|
+
pointerId = i;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const ptr = this.context.input.getPointerEvent(pointerId);
|
|
210
|
+
// console.log(ptr);
|
|
211
|
+
const args: PointerEventData = new PointerEventData(ptr);
|
|
199
212
|
args.inputSource = this.context.input;
|
|
200
|
-
args.
|
|
201
|
-
args.
|
|
202
|
-
args.
|
|
203
|
-
args.
|
|
213
|
+
args.pointerId = pointerId;
|
|
214
|
+
args.isClicked = this.context.input.getPointerClicked(pointerId)
|
|
215
|
+
args.isDown = this.context.input.getPointerDown(pointerId);
|
|
216
|
+
args.isUp = this.context.input.getPointerUp(pointerId);
|
|
217
|
+
args.isPressed = this.context.input.getPointerPressed(pointerId);
|
|
218
|
+
// if(args.isClicked || args.isUp) console.log("clicked", args);
|
|
204
219
|
this.lastPointerEvent = args;
|
|
205
220
|
if (!hits) return;
|
|
206
221
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Input } from "../../engine/engine_input";
|
|
2
|
+
|
|
1
3
|
export interface IInputEventArgs {
|
|
2
4
|
get used(): boolean;
|
|
3
5
|
Use(): void;
|
|
@@ -5,7 +7,7 @@ export interface IInputEventArgs {
|
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
export class PointerEventData implements IInputEventArgs {
|
|
8
|
-
used: boolean = false;
|
|
10
|
+
used: boolean = false;
|
|
9
11
|
|
|
10
12
|
Use() {
|
|
11
13
|
this.used = true;
|
|
@@ -15,17 +17,18 @@ export class PointerEventData implements IInputEventArgs {
|
|
|
15
17
|
this.event?.stopImmediatePropagation();
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
inputSource: any;
|
|
20
|
+
inputSource: Input | any;
|
|
19
21
|
object!: THREE.Object3D;
|
|
20
22
|
|
|
23
|
+
pointerId: number | undefined;
|
|
21
24
|
isDown: boolean | undefined;
|
|
22
25
|
isUp: boolean | undefined;
|
|
23
26
|
isPressed: boolean | undefined;
|
|
24
27
|
isClicked: boolean | undefined;
|
|
25
28
|
|
|
26
|
-
private event?:Event;
|
|
29
|
+
private event?: Event;
|
|
27
30
|
|
|
28
|
-
constructor(events?:Event){
|
|
31
|
+
constructor(events?: Event) {
|
|
29
32
|
this.event = events;
|
|
30
33
|
}
|
|
31
34
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Camera } from "three";
|
|
2
1
|
import { RaycastOptions } from "../../engine/engine_physics";
|
|
3
|
-
import { Behaviour } from "../Component";
|
|
2
|
+
import { Behaviour, Component } from "../Component";
|
|
4
3
|
import { EventSystem } from "./EventSystem";
|
|
5
4
|
|
|
5
|
+
|
|
6
6
|
export class Raycaster extends Behaviour {
|
|
7
7
|
awake(): void {
|
|
8
8
|
EventSystem.createIfNoneExists(this.context);
|
|
@@ -21,6 +21,7 @@ export class Raycaster extends Behaviour {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
|
|
24
25
|
export class ObjectRaycaster extends Raycaster {
|
|
25
26
|
private targets: THREE.Object3D[] | null = null;
|
|
26
27
|
private raycastHits: THREE.Intersection[] = [];
|
|
@@ -44,4 +45,6 @@ export class GraphicRaycaster extends ObjectRaycaster {
|
|
|
44
45
|
// eventCamera: Camera | null = null;
|
|
45
46
|
// ignoreReversedGraphics: boolean = false;
|
|
46
47
|
// rootRaycaster: GraphicRaycaster | null = null;
|
|
47
|
-
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|