@needle-tools/engine 2.56.2-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 +8 -0
- package/dist/needle-engine.d.ts +99 -160
- package/dist/needle-engine.js +279 -3420
- 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/api.d.ts +2 -1
- package/lib/engine/api.js +2 -1
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/register_types.js +2 -6
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine.d.ts +2 -28
- 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_scenetools.d.ts +1 -0
- package/lib/engine/engine_scenetools.js +8 -6
- package/lib/engine/engine_scenetools.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +4 -2
- package/lib/engine/engine_setup.js +66 -50
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine/engine_utils_screenshot.d.ts +5 -0
- package/lib/engine/engine_utils_screenshot.js +32 -0
- package/lib/engine/engine_utils_screenshot.js.map +1 -0
- 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/Skybox.js +3 -1
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/WebXR.js +2 -2
- package/lib/engine-components/WebXR.js.map +1 -1
- 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 -2
- package/src/engine/api.ts +3 -2
- package/src/engine/codegen/register_types.js +4 -8
- package/src/engine/engine.ts +3 -1
- package/src/engine/engine_hot_reload.ts +186 -0
- package/src/engine/engine_input.ts +1 -1
- package/src/engine/engine_scenetools.ts +9 -6
- package/src/engine/engine_setup.ts +66 -52
- package/src/engine/engine_three_utils.ts +4 -4
- package/src/engine/engine_utils_screenshot.ts +41 -0
- package/src/engine-components/Fog.ts +60 -0
- package/src/engine-components/Skybox.ts +3 -1
- package/src/engine-components/TestRunner.ts +1 -1
- package/src/engine-components/WebXR.ts +2 -2
- 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/lib/engine-components-experimental/annotation/LineDrawer.d.ts +0 -18
- package/lib/engine-components-experimental/annotation/LineDrawer.js +0 -175
- package/lib/engine-components-experimental/annotation/LineDrawer.js.map +0 -1
- package/lib/engine-components-experimental/annotation/LinesManager.d.ts +0 -54
- package/lib/engine-components-experimental/annotation/LinesManager.js +0 -155
- package/lib/engine-components-experimental/annotation/LinesManager.js.map +0 -1
- package/src/engine-components-experimental/annotation/LineDrawer.ts +0 -194
- package/src/engine-components-experimental/annotation/LinesManager.ts +0 -218
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",
|
|
@@ -49,7 +49,6 @@
|
|
|
49
49
|
"stats.js": "^0.17.0",
|
|
50
50
|
"three": "npm:@needle-tools/three@^0.146.2",
|
|
51
51
|
"three-mesh-ui": "^6.4.5",
|
|
52
|
-
"three.meshline": "^1.4.0",
|
|
53
52
|
"three.quarks": "^0.7.3",
|
|
54
53
|
"uuid": "^9.0.0",
|
|
55
54
|
"websocket-ts": "^1.1.1"
|
package/src/engine/api.ts
CHANGED
|
@@ -3,7 +3,8 @@ export { InstancingUtil } from "./engine_instancing";
|
|
|
3
3
|
export * from "./engine_gameobject";
|
|
4
4
|
export * from "./engine_components"
|
|
5
5
|
export { AssetReference } from "./engine_addressables";
|
|
6
|
-
export { FrameEvent } from "./engine_setup";
|
|
6
|
+
export { Context, FrameEvent } from "./engine_setup";
|
|
7
7
|
export * from "./debug/debug";
|
|
8
8
|
export { validate } from "./engine_util_decorator"
|
|
9
|
-
export { Gizmos } from "./engine_gizmos"
|
|
9
|
+
export { Gizmos } from "./engine_gizmos"
|
|
10
|
+
export * from "./engine_scenetools";
|
|
@@ -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.ts";
|
|
5
5
|
import { AlignmentConstraint } from "../../engine-components/AlignmentConstraint.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";
|
|
@@ -73,9 +74,6 @@ import { Keyboard } from "../../engine-components/ui/Keyboard.ts";
|
|
|
73
74
|
import { LayoutGroup } from "../../engine-components/ui/Layout.ts";
|
|
74
75
|
import { Light } from "../../engine-components/Light.ts";
|
|
75
76
|
import { LimitVelocityOverLifetimeModule } from "../../engine-components/ParticleSystemModules.ts";
|
|
76
|
-
import { LineInstanceHandler } from "../../engine-components-experimental/annotation/LinesManager.ts";
|
|
77
|
-
import { LinesDrawer } from "../../engine-components-experimental/annotation/LineDrawer.ts";
|
|
78
|
-
import { LinesManager } from "../../engine-components-experimental/annotation/LinesManager.ts";
|
|
79
77
|
import { LODGroup } from "../../engine-components/LODGroup.ts";
|
|
80
78
|
import { LODModel } from "../../engine-components/LODGroup.ts";
|
|
81
79
|
import { LogStats } from "../../engine-components/debug/LogStats.ts";
|
|
@@ -172,7 +170,7 @@ import { XRGrabModel } from "../../engine-components/WebXRGrabRendering.ts";
|
|
|
172
170
|
import { XRGrabRendering } from "../../engine-components/WebXRGrabRendering.ts";
|
|
173
171
|
import { XRRig } from "../../engine-components/WebXRRig.ts";
|
|
174
172
|
import { XRState } from "../../engine-components/XRFlag.ts";
|
|
175
|
-
|
|
173
|
+
|
|
176
174
|
// Register types
|
|
177
175
|
TypeStore.add("__Ignore", __Ignore);
|
|
178
176
|
TypeStore.add("AlignmentConstraint", AlignmentConstraint);
|
|
@@ -228,6 +226,7 @@ TypeStore.add("EventTrigger", EventTrigger);
|
|
|
228
226
|
TypeStore.add("FieldWithDefault", FieldWithDefault);
|
|
229
227
|
TypeStore.add("FixedJoint", FixedJoint);
|
|
230
228
|
TypeStore.add("FlyControls", FlyControls);
|
|
229
|
+
TypeStore.add("Fog", Fog);
|
|
231
230
|
TypeStore.add("GltfExport", GltfExport);
|
|
232
231
|
TypeStore.add("GltfExportBox", GltfExportBox);
|
|
233
232
|
TypeStore.add("Gradient", Gradient);
|
|
@@ -246,9 +245,6 @@ TypeStore.add("Keyboard", Keyboard);
|
|
|
246
245
|
TypeStore.add("LayoutGroup", LayoutGroup);
|
|
247
246
|
TypeStore.add("Light", Light);
|
|
248
247
|
TypeStore.add("LimitVelocityOverLifetimeModule", LimitVelocityOverLifetimeModule);
|
|
249
|
-
TypeStore.add("LineInstanceHandler", LineInstanceHandler);
|
|
250
|
-
TypeStore.add("LinesDrawer", LinesDrawer);
|
|
251
|
-
TypeStore.add("LinesManager", LinesManager);
|
|
252
248
|
TypeStore.add("LODGroup", LODGroup);
|
|
253
249
|
TypeStore.add("LODModel", LODModel);
|
|
254
250
|
TypeStore.add("LogStats", LogStats);
|
package/src/engine/engine.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import "./engine_hot_reload"
|
|
2
|
+
|
|
1
3
|
import * as layers from "./js-extensions/Layers";
|
|
2
4
|
layers.patchLayers();
|
|
3
5
|
|
|
@@ -7,7 +9,7 @@ import "./tests/test_utils";
|
|
|
7
9
|
import { RGBAColor } from "../engine-components/js-extensions/RGBAColor";
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
const engine = {
|
|
12
|
+
const engine : any = {
|
|
11
13
|
...engine_setup,
|
|
12
14
|
...engine_scenetools,
|
|
13
15
|
RGBAColor,
|
|
@@ -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];
|
|
@@ -95,13 +95,18 @@ async function handleLoadedGltf(context: Context, gltfId: string, gltf, seed: nu
|
|
|
95
95
|
// findAnimationsLate(context, gltf, context.new_scripts_pre_setup_callbacks, false);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
export function createGLTFLoader(url: string, context: Context) {
|
|
99
|
+
const loader = new GLTFLoader();
|
|
100
|
+
const sourceId: SourceIdentifier = url;
|
|
101
|
+
registerExtensions(loader, context, sourceId);
|
|
102
|
+
return loader;
|
|
103
|
+
}
|
|
104
|
+
|
|
98
105
|
export function parseSync(context: Context, data, path: string, seed: number | UIDProvider | null): Promise<GLTF | undefined> {
|
|
99
106
|
if (typeof path !== "string") {
|
|
100
107
|
console.warn("Parse gltf binary without path, this might lead to errors in resolving extensions. Please provide the source path of the gltf/glb file", path, typeof path);
|
|
101
108
|
}
|
|
102
|
-
const loader =
|
|
103
|
-
const sourceId: SourceIdentifier = path;
|
|
104
|
-
registerExtensions(loader, context, sourceId);
|
|
109
|
+
const loader = createGLTFLoader(path, context);
|
|
105
110
|
const componentsExtension = registerComponentExtension(loader);
|
|
106
111
|
return new Promise((resolve, reject) => {
|
|
107
112
|
try {
|
|
@@ -131,9 +136,7 @@ export function loadSync(context: Context, url: string, seed: number | UIDProvid
|
|
|
131
136
|
// but due to the async nature and potentially triggering multiple loads at the same time
|
|
132
137
|
// we need to make sure the extensions dont override each other
|
|
133
138
|
// creating new loaders should not be expensive as well
|
|
134
|
-
const loader =
|
|
135
|
-
const sourceId: SourceIdentifier = url;
|
|
136
|
-
registerExtensions(loader, context, sourceId);
|
|
139
|
+
const loader = createGLTFLoader(url, context);
|
|
137
140
|
const componentsExtension = registerComponentExtension(loader);
|
|
138
141
|
return new Promise((resolve, reject) => {
|
|
139
142
|
try {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DepthTexture, PerspectiveCamera, WebGLRenderer, WebGLRenderTarget } from 'three'
|
|
1
|
+
import { Camera, DepthTexture, PerspectiveCamera, WebGLRenderer, WebGLRenderTarget } from 'three'
|
|
2
2
|
import * as THREE from 'three'
|
|
3
3
|
import { Input } from './engine_input';
|
|
4
4
|
import { Physics } from './engine_physics';
|
|
@@ -300,7 +300,7 @@ export class Context {
|
|
|
300
300
|
|
|
301
301
|
// private _requestSizeUpdate : boolean = false;
|
|
302
302
|
|
|
303
|
-
|
|
303
|
+
updateSize() {
|
|
304
304
|
if (!this.isManagedExternally && !this.renderer.xr.isPresenting) {
|
|
305
305
|
this._sizeChanged = false;
|
|
306
306
|
const scaleFactor = this.resolutionScaleFactor;
|
|
@@ -322,10 +322,12 @@ export class Context {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
updateAspect(camera: THREE.PerspectiveCamera) {
|
|
325
|
+
updateAspect(camera: THREE.PerspectiveCamera, width?: number, height?: number) {
|
|
326
326
|
if (!camera) return;
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
if (width === undefined)
|
|
328
|
+
width = this.domWidth;
|
|
329
|
+
if (height === undefined)
|
|
330
|
+
height = this.domHeight;
|
|
329
331
|
const pa = camera.aspect;
|
|
330
332
|
camera.aspect = width / height;
|
|
331
333
|
if (pa !== camera.aspect)
|
|
@@ -697,21 +699,13 @@ export class Context {
|
|
|
697
699
|
}
|
|
698
700
|
}
|
|
699
701
|
|
|
700
|
-
this._currentFrameEvent = -10;
|
|
701
702
|
|
|
702
|
-
this._isRendering = true;
|
|
703
|
-
this.renderRequiredTextures();
|
|
704
703
|
if (!this.isManagedExternally) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
else if (this.mainCamera) {
|
|
709
|
-
this.renderer.render(this.scene, this.mainCamera);
|
|
710
|
-
}
|
|
704
|
+
this._currentFrameEvent = -10;
|
|
705
|
+
this.renderNow();
|
|
706
|
+
this._currentFrameEvent = FrameEvent.OnAfterRender;
|
|
711
707
|
}
|
|
712
|
-
this._isRendering = false;
|
|
713
708
|
|
|
714
|
-
this._currentFrameEvent = FrameEvent.OnAfterRender;
|
|
715
709
|
|
|
716
710
|
for (let i = 0; i < this.scripts_onAfterRender.length; i++) {
|
|
717
711
|
const script = this.scripts_onAfterRender[i];
|
|
@@ -738,6 +732,23 @@ export class Context {
|
|
|
738
732
|
this._stats?.end();
|
|
739
733
|
}
|
|
740
734
|
|
|
735
|
+
renderNow(camera?: Camera) {
|
|
736
|
+
if (!camera) {
|
|
737
|
+
camera = this.mainCamera as Camera;
|
|
738
|
+
if (!camera) return false;
|
|
739
|
+
}
|
|
740
|
+
this._isRendering = true;
|
|
741
|
+
this.renderRequiredTextures();
|
|
742
|
+
if (this.composer && !this.isInXR) {
|
|
743
|
+
this.composer.render();
|
|
744
|
+
}
|
|
745
|
+
else if (this.mainCamera) {
|
|
746
|
+
this.renderer.render(this.scene, camera);
|
|
747
|
+
}
|
|
748
|
+
this._isRendering = false;
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
|
|
741
752
|
/** returns true if we should return out of the frame loop */
|
|
742
753
|
private _wasPaused: boolean = false;
|
|
743
754
|
private onHandlePaused(): boolean {
|
|
@@ -798,47 +809,50 @@ export class Context {
|
|
|
798
809
|
if (this.coroutines[evt]) {
|
|
799
810
|
const evts = this.coroutines[evt];
|
|
800
811
|
for (let i = 0; i < evts.length; i++) {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
const iter = evt.chained;
|
|
810
|
-
if (iter && iter.length > 0) {
|
|
811
|
-
const last: Generator = iter[iter.length - 1];
|
|
812
|
-
const res = last.next();
|
|
813
|
-
if (res.done) {
|
|
814
|
-
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;
|
|
815
820
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
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;
|
|
819
833
|
}
|
|
820
|
-
if (!res.done) continue;
|
|
821
|
-
}
|
|
822
834
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
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
|
+
}
|
|
828
852
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
// invoke once if its a generator
|
|
832
|
-
// this means e.g. WaitForFrame(1) works and will capture
|
|
833
|
-
// the frame it was created
|
|
834
|
-
const gen = val as Generator;
|
|
835
|
-
const res = gen.next();
|
|
836
|
-
if (res.done) continue;
|
|
837
|
-
if (!evt.chained) evt.chained = [];
|
|
838
|
-
evt.chained.push(val as Generator);
|
|
853
|
+
catch (e) {
|
|
854
|
+
console.error(e);
|
|
839
855
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
856
|
}
|
|
843
857
|
}
|
|
844
858
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { Mathf } from "./engine_math"
|
|
3
|
-
import {
|
|
3
|
+
import { WebGLRenderer, Vector3, Quaternion, Uniform, Texture, Material, ShaderMaterial, CanvasTexture, AnimationAction, Camera, PerspectiveCamera } from "three";
|
|
4
4
|
import { CircularBuffer } from "./engine_utils";
|
|
5
5
|
|
|
6
6
|
|
|
@@ -183,8 +183,8 @@ export function logHierarchy(root: THREE.Object3D | null | undefined, collapsibl
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
|
|
186
|
-
export function isAnimationAction(obj:object){
|
|
187
|
-
if(obj){
|
|
186
|
+
export function isAnimationAction(obj: object) {
|
|
187
|
+
if (obj) {
|
|
188
188
|
// this doesnt work :(
|
|
189
189
|
// return obj instanceof AnimationAction;
|
|
190
190
|
// instead we do this:
|
|
@@ -308,4 +308,4 @@ function isImageBitmap(image) {
|
|
|
308
308
|
(typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement) ||
|
|
309
309
|
(typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas) ||
|
|
310
310
|
(typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap);
|
|
311
|
-
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Context } from "./engine_setup";
|
|
2
|
+
import { PerspectiveCamera, Camera } from "three";
|
|
3
|
+
|
|
4
|
+
declare type ImageMimeType = "image/webp" | "image/png";
|
|
5
|
+
|
|
6
|
+
export function screenshot(context: Context, width: number, height: number, mimeType: ImageMimeType = "image/webp", camera?: Camera | null) {
|
|
7
|
+
|
|
8
|
+
if (!camera) {
|
|
9
|
+
camera = context.mainCamera;
|
|
10
|
+
if (!camera) {
|
|
11
|
+
console.error("No camera found");
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const prevWidth = context.renderer.domElement.width;
|
|
16
|
+
const prevHeight = context.renderer.domElement.height;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const canvas = context.renderer.domElement;
|
|
20
|
+
|
|
21
|
+
// set the desired output size
|
|
22
|
+
context.renderer.setSize(width, height);
|
|
23
|
+
// update the camera apsect and matrix
|
|
24
|
+
if (camera instanceof PerspectiveCamera)
|
|
25
|
+
context.updateAspect(camera, width, height);
|
|
26
|
+
|
|
27
|
+
// render now
|
|
28
|
+
context.renderNow();
|
|
29
|
+
|
|
30
|
+
// const webPMimeType = "image/webp";
|
|
31
|
+
// const pngMimeType = "image/png";
|
|
32
|
+
const dataUrl = canvas.toDataURL(mimeType);
|
|
33
|
+
return dataUrl;
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
context.renderer.setSize(prevWidth, prevHeight);
|
|
37
|
+
context.updateSize();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -51,7 +51,8 @@ export class RemoteSkybox extends Behaviour {
|
|
|
51
51
|
console.warn("Potentially invalid skybox url", this.url, "on", this.name);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
if (!this._loader)
|
|
54
|
+
// if (!this._loader)
|
|
55
|
+
{
|
|
55
56
|
const isEXR = url.endsWith(".exr");
|
|
56
57
|
const isHdr = url.endsWith(".hdr");
|
|
57
58
|
if (isEXR) {
|
|
@@ -64,6 +65,7 @@ export class RemoteSkybox extends Behaviour {
|
|
|
64
65
|
this._loader = new TextureLoader();
|
|
65
66
|
}
|
|
66
67
|
}
|
|
68
|
+
console.log("Loading skybox: " + url);
|
|
67
69
|
const envMap = await this._loader.loadAsync(url);
|
|
68
70
|
if (!envMap) return;
|
|
69
71
|
if (!this.enabled) return;
|
|
@@ -3,7 +3,7 @@ import * as tests from "../engine/tests/test_utils";
|
|
|
3
3
|
import { createTransformModel, SyncedTransform, SyncedTransformIdentifier } from "./SyncedTransform";
|
|
4
4
|
import * as flatbuffers from 'flatbuffers';
|
|
5
5
|
import { SyncedTransformModel } from "../engine-schemes/synced-transform-model";
|
|
6
|
-
import { Rigidbody } from "./
|
|
6
|
+
import { Rigidbody } from "./RigidBody";
|
|
7
7
|
import { Vector3 } from "three";
|
|
8
8
|
import { IModel } from "../engine/engine_networking_types";
|
|
9
9
|
|
|
@@ -221,14 +221,14 @@ export class WebXR extends Behaviour {
|
|
|
221
221
|
this.context.domElement.append(buttonsContainer);
|
|
222
222
|
|
|
223
223
|
// AR support
|
|
224
|
-
if (this.enableAR && this.createARButton) {
|
|
224
|
+
if (this.enableAR && this.createARButton && arSupported) {
|
|
225
225
|
arButton = WebXR.createARButton(this);
|
|
226
226
|
this._arButton = arButton;
|
|
227
227
|
buttonsContainer.appendChild(arButton);
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
// VR support
|
|
231
|
-
if (this.createVRButton && this.enableVR) {
|
|
231
|
+
if (this.createVRButton && this.enableVR && vrSupported) {
|
|
232
232
|
vrButton = WebXR.createVRButton(this);
|
|
233
233
|
this._vrButton = vrButton;
|
|
234
234
|
buttonsContainer.appendChild(vrButton);
|
|
@@ -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";
|