@@ -1,5 +1,7 @@
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
2
2
|
|
3
|
+
let didLogCanNotFindConfig = false;
|
4
|
+
|
3
5
|
/** the codegen meta file */
|
4
6
|
export async function loadConfig(path) {
|
5
7
|
try {
|
@@ -21,7 +23,12 @@
|
|
21
23
|
const meta = JSON.parse(text);
|
22
24
|
return meta;
|
23
25
|
}
|
24
|
-
else
|
26
|
+
else {
|
27
|
+
if(!didLogCanNotFindConfig){
|
28
|
+
didLogCanNotFindConfig = true;
|
29
|
+
console.error("Could not find config file at " + path);
|
30
|
+
}
|
31
|
+
}
|
25
32
|
return null;
|
26
33
|
}
|
27
34
|
catch (err) {
|
@@ -27,7 +27,7 @@
|
|
27
27
|
if (!viteConfig.define) viteConfig.define = {};
|
28
28
|
viteConfig.define.NEEDLE_ENGINE_META = {
|
29
29
|
version: tryGetNeedleEngineVersion(),
|
30
|
-
generator: needleEngineConfig
|
30
|
+
generator: needleEngineConfig?.generator,
|
31
31
|
}
|
32
32
|
|
33
33
|
if (useRapier && userSettings?.useRapier !== true) {
|
@@ -32,7 +32,10 @@
|
|
32
32
|
}
|
33
33
|
}
|
34
34
|
else {
|
35
|
-
|
35
|
+
if (!didLog) {
|
36
|
+
didLog = true;
|
37
|
+
console.log("No config found - can not apply license");
|
38
|
+
}
|
36
39
|
}
|
37
40
|
}
|
38
41
|
}
|
@@ -16,14 +16,15 @@
|
|
16
16
|
scene.add(cameraObject);
|
17
17
|
|
18
18
|
const camInstance = new Camera();
|
19
|
-
const cam = addNewComponent(cameraObject, camInstance, true) as ICamera
|
19
|
+
const cam = addNewComponent(cameraObject, camInstance, true) as ICamera;
|
20
20
|
cam.sourceId = srcId;
|
21
21
|
cam.clearFlags = 2;
|
22
22
|
cam.backgroundColor = new RGBAColor(0.5, 0.5, 0.5, 1);
|
23
23
|
|
24
|
-
cameraObject.position.x =
|
25
|
-
cameraObject.position.y =
|
24
|
+
cameraObject.position.x = 0;
|
25
|
+
cameraObject.position.y = 1;
|
26
26
|
cameraObject.position.z = 2;
|
27
|
+
|
27
28
|
return cam;
|
28
29
|
});
|
29
30
|
|
@@ -46,6 +47,9 @@
|
|
46
47
|
if (cameraObject) {
|
47
48
|
const orbit = addNewComponent(cameraObject, new OrbitControls(), false) as OrbitControls;
|
48
49
|
orbit.sourceId = "unknown";
|
50
|
+
setTimeout(() => {
|
51
|
+
orbit.fitCameraToObjects(evt.context.scene.children, 1);
|
52
|
+
}, 100);
|
49
53
|
}
|
50
54
|
else {
|
51
55
|
console.warn("Missing camera object, can not add orbit controls")
|
@@ -185,7 +185,7 @@
|
|
185
185
|
* @param go component to move the component to
|
186
186
|
* @param instance component to move to the GO
|
187
187
|
*/
|
188
|
-
public static addComponent(go: IGameObject, instance: Component): void {
|
188
|
+
public static addComponent(go: IGameObject | Object3D, instance: Component): void {
|
189
189
|
return this.moveComponent(go, instance);
|
190
190
|
}
|
191
191
|
|
@@ -194,7 +194,7 @@
|
|
194
194
|
* @param go component to move the component to
|
195
195
|
* @param instance component to move to the GO
|
196
196
|
*/
|
197
|
-
public static moveComponent(go: IGameObject, instance: Component): void {
|
197
|
+
public static moveComponent(go: IGameObject | Object3D, instance: Component): void {
|
198
198
|
moveComponentInstance(go, instance as any);
|
199
199
|
}
|
200
200
|
|
@@ -104,7 +104,9 @@
|
|
104
104
|
|
105
105
|
const currentMessages = new Set<string>();
|
106
106
|
|
107
|
-
function showMessage(type: LogType, element: HTMLElement, msg: string) {
|
107
|
+
function showMessage(type: LogType, element: HTMLElement, msg: string | null | undefined) {
|
108
|
+
if (msg === null || msg === undefined) return;
|
109
|
+
|
108
110
|
const container = getLogsContainer(element);
|
109
111
|
if (container.childElementCount >= 20) {
|
110
112
|
const last = container.lastElementChild;
|
@@ -117,8 +119,9 @@
|
|
117
119
|
const msgcontainer = getMessageContainer(type, msg);
|
118
120
|
container.prepend(msgcontainer);
|
119
121
|
|
122
|
+
const _msg = msg;
|
120
123
|
setTimeout(() => {
|
121
|
-
currentMessages.delete(
|
124
|
+
currentMessages.delete(_msg);
|
122
125
|
returnMessageContainer(msgcontainer);
|
123
126
|
}, 10000);
|
124
127
|
}
|
@@ -2,7 +2,7 @@
|
|
2
2
|
BufferGeometry, Camera, Clock, Color, DepthTexture, Group,
|
3
3
|
Material, NearestFilter, NoToneMapping, Object3D, PCFSoftShadowMap,
|
4
4
|
PerspectiveCamera, RGBAFormat, Scene, sRGBEncoding,
|
5
|
-
Texture, WebGLRenderer, WebGLRenderTarget
|
5
|
+
Texture, WebGLRenderer, WebGLRendererParameters, WebGLRenderTarget
|
6
6
|
} from 'three'
|
7
7
|
import { Input } from './engine_input';
|
8
8
|
import { Physics } from './engine_physics';
|
@@ -259,10 +259,16 @@
|
|
259
259
|
this.isManagedExternally = true;
|
260
260
|
}
|
261
261
|
else {
|
262
|
-
|
263
|
-
antialias: true
|
264
|
-
}
|
262
|
+
const params: WebGLRendererParameters = {
|
263
|
+
antialias: true,
|
264
|
+
};
|
265
|
+
|
266
|
+
// get canvas already configured in the Needle Engine Web Component
|
267
|
+
const canvas = args?.domElement?.shadowRoot?.querySelector("canvas");
|
268
|
+
if (canvas) params.canvas = canvas;
|
265
269
|
|
270
|
+
this.renderer = new WebGLRenderer(params);
|
271
|
+
|
266
272
|
// some tonemapping other than "NONE" is required for adjusting exposure with EXR environments
|
267
273
|
this.renderer.toneMappingExposure = 1; // range [0...inf] instead of the usual -15..15
|
268
274
|
this.renderer.toneMapping = NoToneMapping; // could also set to LinearToneMapping, ACESFilmicToneMapping
|
@@ -551,7 +557,7 @@
|
|
551
557
|
|
552
558
|
// console.log(prepare_succeeded);
|
553
559
|
|
554
|
-
if (!this.isManagedExternally)
|
560
|
+
if (!this.isManagedExternally && !this.domElement.shadowRoot)
|
555
561
|
this.domElement.prepend(this.renderer.domElement);
|
556
562
|
|
557
563
|
Context.Current = this;
|
@@ -73,14 +73,15 @@
|
|
73
73
|
}
|
74
74
|
|
75
75
|
onLoadingBegin(message?: string) {
|
76
|
+
const _element = this._element.shadowRoot || this._element;
|
76
77
|
if (debug) console.warn("Begin Loading")
|
77
78
|
if (!this._loadingElement) {
|
78
|
-
for (let i = 0; i <
|
79
|
-
const el =
|
79
|
+
for (let i = 0; i < _element.children.length; i++) {
|
80
|
+
const el = _element.children[i] as HTMLElement;
|
80
81
|
if (el.classList.contains(EngineLoadingView.LoadingContainerClassName)) {
|
81
82
|
if (!this._allowCustomLoadingElement) {
|
82
83
|
if (debug) console.warn("Remove custom loading container")
|
83
|
-
|
84
|
+
_element.removeChild(el);
|
84
85
|
continue;
|
85
86
|
}
|
86
87
|
this._loadingElement = this.createLoadingElement(el);
|
@@ -92,7 +93,7 @@
|
|
92
93
|
this._progress = 0;
|
93
94
|
this.loadingProgress = 0;
|
94
95
|
this._loadingElement.style.display = "flex";
|
95
|
-
|
96
|
+
_element.appendChild(this._loadingElement);
|
96
97
|
this.smoothProgressLoop();
|
97
98
|
this.setMessage(message ?? "");
|
98
99
|
}
|
@@ -141,7 +142,7 @@
|
|
141
142
|
if (typeof debugRendering === "number") dt *= debugRendering;
|
142
143
|
}
|
143
144
|
this._progressLoop = setInterval(() => {
|
144
|
-
//
|
145
|
+
// increase loading speed when almost done
|
145
146
|
if (this.loadingProgress >= .95 && !debugRendering) dt = .9;
|
146
147
|
this._progress = Mathf.lerp(this._progress, this.loadingProgress, dt * this.loadingProgress);
|
147
148
|
this.updateDisplay();
|
@@ -229,15 +230,12 @@
|
|
229
230
|
else
|
230
231
|
loadingBarContainer.style.backgroundColor = "rgba(255,255,255,.2)"
|
231
232
|
// loadingBarContainer.style.alignItems = "center";
|
232
|
-
this._loadingElement.appendChild(loadingBarContainer);
|
233
233
|
|
234
234
|
const logo = document.createElement("img");
|
235
235
|
const logoSize = 64;
|
236
236
|
logo.style.width = `${logoSize}px`;
|
237
237
|
logo.style.height = `${logoSize}px`;
|
238
|
-
logo.style.
|
239
|
-
logo.style.left = "50%";
|
240
|
-
logo.style.transform = `translate(-${logoSize * .5}px, -${logoSize + 32}px)`;
|
238
|
+
logo.style.marginBottom = "20px";
|
241
239
|
logo.addEventListener("click", () => window.open("https://needle.tools", "_blank"));
|
242
240
|
logo.style.cursor = "pointer";
|
243
241
|
logo.style.userSelect = "none";
|
@@ -250,7 +248,8 @@
|
|
250
248
|
logo.src = customLogo;
|
251
249
|
}
|
252
250
|
}
|
253
|
-
|
251
|
+
this._loadingElement.appendChild(logo);
|
252
|
+
this._loadingElement.appendChild(loadingBarContainer);
|
254
253
|
|
255
254
|
|
256
255
|
this._loadingBar = document.createElement("div");
|
@@ -276,18 +276,22 @@
|
|
276
276
|
if (currentHash !== null && currentHash !== undefined)
|
277
277
|
this._context.hash = currentHash;
|
278
278
|
this._context.alias = alias;
|
279
|
-
|
279
|
+
const contextWasCreated = this._context.isCreated;
|
280
|
+
if (!contextWasCreated) {
|
280
281
|
await this._context.onCreate(loadFunction);
|
282
|
+
}
|
281
283
|
else {
|
282
284
|
await loadFunction(this._context);
|
283
285
|
}
|
284
286
|
|
285
287
|
|
286
288
|
|
287
|
-
|
289
|
+
console.log("Needle Engine: finished loading", alias ?? "")
|
288
290
|
this._loadingProgress01 = 1;
|
289
|
-
if (useDefaultLoading)
|
291
|
+
if (useDefaultLoading) {
|
290
292
|
this._loadingView?.onLoadingUpdate(1, "creating scene");
|
293
|
+
if (contextWasCreated) this.onReady();
|
294
|
+
}
|
291
295
|
this.classList.remove("loading");
|
292
296
|
this.classList.add("loading-finished");
|
293
297
|
if (debug)
|
@@ -301,6 +305,7 @@
|
|
301
305
|
|
302
306
|
}
|
303
307
|
|
308
|
+
/** called by the context when the first frame has been rendered */
|
304
309
|
private onReady = () => this._loadingView?.onLoadingFinished();
|
305
310
|
|
306
311
|
|
@@ -64,9 +64,10 @@
|
|
64
64
|
|
65
65
|
const interval = setInterval(() => {
|
66
66
|
if (!licenseElement) return;
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
const parent = ctx.domElement.shadowRoot || ctx.domElement;
|
68
|
+
if (licenseElement.parentNode !== parent) {
|
69
|
+
parent.appendChild(licenseElement);
|
70
|
+
if (style) parent.appendChild(style);
|
70
71
|
}
|
71
72
|
}, 100);
|
72
73
|
|
@@ -121,7 +122,7 @@
|
|
121
122
|
function createLicenseElement() {
|
122
123
|
const licenseElement = document.createElement("div");
|
123
124
|
licenseElement.setAttribute(licenseElementIdentifier, "");
|
124
|
-
licenseElement.style.position = "
|
125
|
+
licenseElement.style.position = "absolute";
|
125
126
|
licenseElement.style.bottom = "12px";
|
126
127
|
licenseElement.style.right = "15px";
|
127
128
|
|
@@ -21,6 +21,7 @@
|
|
21
21
|
import { Mathf } from './engine_math';
|
22
22
|
import { SphereOverlapResult } from './engine_types';
|
23
23
|
import { ContextEvent, ContextRegistry } from './engine_context_registry';
|
24
|
+
import { isDevEnvironment } from './debug/debug';
|
24
25
|
|
25
26
|
const debugPhysics = getParam("debugphysics");
|
26
27
|
const debugColliderPlacement = getParam("debugphysicscolliders");
|
@@ -61,48 +62,49 @@
|
|
61
62
|
export class RapierPhysics implements IPhysicsEngine {
|
62
63
|
|
63
64
|
removeBody(obj: IComponent) {
|
65
|
+
if (!obj) return;
|
64
66
|
this.validate();
|
65
67
|
const body = obj[$bodyKey];
|
66
68
|
obj[$bodyKey] = null;
|
67
69
|
if (body && this.world) {
|
68
70
|
const index = this.objects.findIndex(o => o === obj);
|
69
71
|
if (index >= 0) {
|
70
|
-
const
|
72
|
+
const rapierBody = this.bodies[index];
|
73
|
+
// Remove references
|
71
74
|
this.bodies.splice(index, 1);
|
72
75
|
this.objects.splice(index, 1);
|
73
76
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
+
// Remove the collider from the physics world
|
78
|
+
if (rapierBody instanceof Collider) {
|
79
|
+
const rapierCollider = rapierBody as Collider;
|
80
|
+
this.world?.removeCollider(rapierCollider, true);
|
77
81
|
|
78
|
-
// remove the rigidbody if it doesnt have colliders anymore
|
79
|
-
const
|
80
|
-
if (
|
81
|
-
|
82
|
+
// also remove the rigidbody if it doesnt have colliders anymore
|
83
|
+
const rapierRigidbody: RigidBody | null = rapierCollider.parent();
|
84
|
+
if (rapierRigidbody && rapierRigidbody.numColliders() <= 0) {
|
85
|
+
const rigidbody = rapierRigidbody[$componentKey] as IRigidbody;
|
86
|
+
this.removeBody(rigidbody);
|
82
87
|
}
|
83
88
|
}
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
89
|
+
// Remove the rigidbody from the physics world
|
90
|
+
else if (rapierBody instanceof RigidBody) {
|
91
|
+
if (rapierBody.numColliders() <= 0) {
|
92
|
+
this.world?.removeRigidBody(rapierBody);
|
93
|
+
}
|
94
|
+
else {
|
95
|
+
if (isDevEnvironment()) {
|
96
|
+
if (!rapierBody["did_log_removing"]) {
|
97
|
+
setTimeout(() => {
|
98
|
+
if (rapierBody.numColliders() > 0) {
|
99
|
+
rapierBody["did_log_removing"] = true;
|
100
|
+
console.warn("RapierPhysics: removing rigidbody with colliders from the physics world is not possible right now, please remove the colliders first");
|
101
|
+
}
|
102
|
+
}, 1);
|
103
|
+
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
96
107
|
}
|
97
|
-
|
98
|
-
// check if we need to remove the rigidbody too
|
99
|
-
// const col = obj as ICollider;
|
100
|
-
// if (col.isCollider && col.attachedRigidbody) {
|
101
|
-
// const rb = col.attachedRigidbody[$bodyKey] as RigidBody;
|
102
|
-
// if (rb && rb.numColliders() <= 0) {
|
103
|
-
// // this.world?.removeRigidBody(rb);
|
104
|
-
// }
|
105
|
-
// }
|
106
108
|
}
|
107
109
|
}
|
108
110
|
}
|
@@ -128,7 +130,7 @@
|
|
128
130
|
|
129
131
|
updateProperties(rigidbody: IRigidbody) {
|
130
132
|
this.validate();
|
131
|
-
const physicsBody = rigidbody
|
133
|
+
const physicsBody = this.internal_getRigidbody(rigidbody);
|
132
134
|
if (physicsBody) {
|
133
135
|
this.internalUpdateProperties(rigidbody, physicsBody);
|
134
136
|
}
|
@@ -206,7 +208,7 @@
|
|
206
208
|
|
207
209
|
private async internalInitialization() {
|
208
210
|
// NEEDLE_PHYSICS_INIT_START
|
209
|
-
// use .env file with VITE_NEEDLE_USE_RAPIER=false to
|
211
|
+
// use .env file with VITE_NEEDLE_USE_RAPIER=false to treeshake rapier
|
210
212
|
// @ts-ignore
|
211
213
|
if ("env" in import.meta && import.meta.env.VITE_NEEDLE_USE_RAPIER === "false") {
|
212
214
|
return false;
|
@@ -87,7 +87,7 @@
|
|
87
87
|
if (camGo && !this.setFromTargetPosition()) {
|
88
88
|
if (this.debugLog)
|
89
89
|
console.log("NO TARGET");
|
90
|
-
const forward = new Vector3(0, 0, -
|
90
|
+
const forward = new Vector3(0, 0, -10).applyMatrix4(camGo.cam.matrixWorld);
|
91
91
|
this.setTarget(forward, true);
|
92
92
|
}
|
93
93
|
}
|
@@ -161,6 +161,14 @@
|
|
161
161
|
private _spriteSheet?: SpriteData;
|
162
162
|
private _currentSprite?: THREE.Mesh;
|
163
163
|
|
164
|
+
// additional data
|
165
|
+
@serializable()
|
166
|
+
transparent: boolean = true;
|
167
|
+
@serializable()
|
168
|
+
cutoutThreshold: number = 0;
|
169
|
+
@serializable()
|
170
|
+
castShadows: boolean = false;
|
171
|
+
|
164
172
|
awake(): void {
|
165
173
|
this._currentSprite = undefined;
|
166
174
|
if(debug) {
|
@@ -221,6 +229,11 @@
|
|
221
229
|
this._currentSprite.layers.set(this.layer)
|
222
230
|
}
|
223
231
|
|
232
|
+
if (this.sharedMaterial) {
|
233
|
+
this.sharedMaterial.alphaTest = this.cutoutThreshold;
|
234
|
+
this.sharedMaterial.transparent = this.transparent;
|
235
|
+
}
|
236
|
+
this._currentSprite.castShadow = this.castShadows;
|
224
237
|
this._spriteSheet?.update();
|
225
238
|
}
|
226
239
|
}
|