@needle-tools/engine 3.2.8-alpha → 3.2.9-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 +7 -0
- package/dist/needle-engine.js +8516 -8472
- package/dist/needle-engine.min.js +164 -127
- package/dist/needle-engine.umd.cjs +171 -134
- package/lib/engine/engine_addressables.d.ts +1 -0
- package/lib/engine/engine_addressables.js +14 -9
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_element_loading.js +7 -0
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_license.js +67 -22
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine-components/Component.js +2 -2
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ScreenCapture.d.ts +2 -0
- package/lib/engine-components/ScreenCapture.js +6 -0
- package/lib/engine-components/ScreenCapture.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +8 -6
- package/lib/engine-components/VideoPlayer.js +59 -31
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/engine_addressables.ts +13 -9
- package/src/engine/engine_element_loading.ts +10 -1
- package/src/engine/engine_license.ts +69 -23
- package/src/engine/engine_serialization_builtin_serializer.ts +1 -1
- package/src/engine-components/Component.ts +2 -2
- package/src/engine-components/ScreenCapture.ts +7 -0
- package/src/engine-components/VideoPlayer.ts +58 -35
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.9-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,7 +1,7 @@
|
|
|
1
1
|
import { getParam, resolveUrl } from "../engine/engine_utils";
|
|
2
2
|
import { SerializationContext, TypeSerializer } from "./engine_serialization_core";
|
|
3
3
|
import { Context } from "./engine_setup";
|
|
4
|
-
import { Group, Object3D, Texture } from "three";
|
|
4
|
+
import { Group, Object3D, Texture, TextureLoader } from "three";
|
|
5
5
|
import { processNewScripts } from "./engine_mainloop_utils";
|
|
6
6
|
import { registerPrefabProvider, syncInstantiate } from "./engine_networking_instantiate";
|
|
7
7
|
import { download } from "./engine_web_api";
|
|
@@ -372,15 +372,19 @@ export class ImageReference {
|
|
|
372
372
|
return img;
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
+
private loader: TextureLoader | null = null;
|
|
375
376
|
createTexture(): Promise<Texture | null> {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
377
|
+
if (!this.loader) this.loader = new TextureLoader();
|
|
378
|
+
this.loader.setCrossOrigin("anonymous");
|
|
379
|
+
return this.loader.loadAsync(this.url);
|
|
380
|
+
// return this.getBitmap().then((bitmap) => {
|
|
381
|
+
// if (bitmap) {
|
|
382
|
+
// const texture = new Texture(bitmap);
|
|
383
|
+
// texture.needsUpdate = true;
|
|
384
|
+
// return texture;
|
|
385
|
+
// }
|
|
386
|
+
// return null;
|
|
387
|
+
// });
|
|
384
388
|
}
|
|
385
389
|
|
|
386
390
|
/** Loads the bitmap data of the image */
|
|
@@ -253,13 +253,14 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
253
253
|
}
|
|
254
254
|
loadingBarContainer.appendChild(logo);
|
|
255
255
|
|
|
256
|
+
|
|
256
257
|
this._loadingBar = document.createElement("div");
|
|
257
258
|
loadingBarContainer.appendChild(this._loadingBar);
|
|
258
259
|
const getGradientPos = function (t: number): string {
|
|
259
260
|
return Mathf.lerp(maxWidth * .5, 100 - maxWidth * .5, t) + "%";
|
|
260
261
|
}
|
|
261
262
|
this._loadingBar.style.background =
|
|
262
|
-
|
|
263
|
+
`linear-gradient(90deg, #02022B ${getGradientPos(0)}, #0BA398 ${getGradientPos(.4)}, #99CC33 ${getGradientPos(.5)}, #D7DB0A ${getGradientPos(1)})`;
|
|
263
264
|
this._loadingBar.style.backgroundAttachment = "fixed";
|
|
264
265
|
this._loadingBar.style.width = "0%";
|
|
265
266
|
this._loadingBar.style.height = "100%";
|
|
@@ -301,6 +302,14 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
301
302
|
}
|
|
302
303
|
}
|
|
303
304
|
|
|
305
|
+
if (!hasLicense) {
|
|
306
|
+
const nonCommercialContainer = document.createElement("div");
|
|
307
|
+
nonCommercialContainer.style.paddingTop = ".6em";
|
|
308
|
+
nonCommercialContainer.style.fontSize = ".8em";
|
|
309
|
+
nonCommercialContainer.innerText = "NON COMMERCIAL";
|
|
310
|
+
this._loadingElement.appendChild(nonCommercialContainer);
|
|
311
|
+
}
|
|
312
|
+
|
|
304
313
|
return this._loadingElement;
|
|
305
314
|
}
|
|
306
315
|
}
|
|
@@ -30,22 +30,18 @@ async function showLicenseInfo(ctx: IContext) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
const _licenseText = "🌵 <span class=\"text\">Made with <a href=\"https://needle.tools\" target=\"_blank\">Needle</a></span>";
|
|
34
33
|
const licenseElementIdentifier = "needle-license-element";
|
|
35
34
|
const licenseDuration = 30000;
|
|
36
35
|
const licenseDelay = 600;
|
|
37
36
|
|
|
38
37
|
function onNonCommercialVersionDetected(ctx: IContext) {
|
|
39
|
-
insertNonCommercialUseHint(ctx);
|
|
40
|
-
|
|
38
|
+
setTimeout(() => insertNonCommercialUseHint(ctx), 2000);
|
|
39
|
+
sendUsageMessageToAnalyticsBackend();
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
function insertNonCommercialUseHint(ctx: IContext) {
|
|
44
43
|
|
|
45
|
-
let licenseText = _licenseText;
|
|
46
44
|
const licenseElement = createLicenseElement();
|
|
47
|
-
licenseElement.innerHTML = licenseText;
|
|
48
|
-
|
|
49
45
|
const style = createLicenseStyle();
|
|
50
46
|
|
|
51
47
|
const interval = setInterval(() => {
|
|
@@ -59,9 +55,21 @@ function insertNonCommercialUseHint(ctx: IContext) {
|
|
|
59
55
|
logNonCommercialUse();
|
|
60
56
|
|
|
61
57
|
let svg = `<img class="logo" src="${logoSVG}" style="width: 40px; height: 40px; margin-right: 2px; vertical-align: middle; margin-bottom: 2px;"/>`;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
const logoElement = document.createElement("div");
|
|
59
|
+
logoElement.innerHTML = svg;
|
|
60
|
+
logoElement.classList.add("logo");
|
|
61
|
+
licenseElement.appendChild(logoElement);
|
|
62
|
+
|
|
63
|
+
const textElement = document.createElement("div");
|
|
64
|
+
textElement.classList.add("text");
|
|
65
|
+
textElement.innerHTML = "Needle Engine<br/><span class=\"non-commercial\">Non Commercial</span>";
|
|
66
|
+
licenseElement.appendChild(textElement);
|
|
67
|
+
|
|
68
|
+
licenseElement.title = "Needle Engine — non commercial version";
|
|
69
|
+
licenseElement.addEventListener("click", () => {
|
|
70
|
+
console.log("CLICK")
|
|
71
|
+
globalThis.open("https://needle.tools", "_blank");
|
|
72
|
+
});
|
|
65
73
|
|
|
66
74
|
const removeDelay = licenseDuration + licenseDelay;
|
|
67
75
|
setTimeout(() => {
|
|
@@ -110,6 +118,13 @@ function createLicenseStyle() {
|
|
|
110
118
|
${selector} {
|
|
111
119
|
font-family: 'Roboto', sans-serif !important;
|
|
112
120
|
font-weight: 300;
|
|
121
|
+
transition: all 0.1s ease-in-out !important;
|
|
122
|
+
pointer-events: all;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
${selector}:hover {
|
|
126
|
+
cursor: pointer;
|
|
127
|
+
transition: all 0.1s ease-in-out !important;
|
|
113
128
|
}
|
|
114
129
|
|
|
115
130
|
${selector}, ${selector} > * {
|
|
@@ -118,22 +133,51 @@ function createLicenseStyle() {
|
|
|
118
133
|
background: none !important;
|
|
119
134
|
border: none !important;
|
|
120
135
|
text-decoration: none !important;
|
|
136
|
+
vertical-align: middle !important;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@keyframes license-animation {
|
|
140
|
+
1% {
|
|
141
|
+
opacity: 0;
|
|
142
|
+
}
|
|
143
|
+
2.5% {
|
|
144
|
+
opacity: 1;
|
|
145
|
+
}
|
|
146
|
+
98% {
|
|
147
|
+
opacity: 1;
|
|
148
|
+
}
|
|
149
|
+
99% {
|
|
150
|
+
opacity: 0;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
${selector} .text {
|
|
154
|
+
opacity: 0;
|
|
155
|
+
animation: license-animation;
|
|
156
|
+
animation-iteration-count: 1;
|
|
157
|
+
animation-duration: ${(licenseDuration / 1000)}s;
|
|
158
|
+
animation-delay: ${licenseDelay / 1000}s;
|
|
159
|
+
animation-easing: ease-in-out;
|
|
160
|
+
mix-blend-mode: difference;
|
|
161
|
+
color: rgb(40, 40, 40);
|
|
162
|
+
mix-blend-mode: difference;
|
|
163
|
+
line-height: 1em;
|
|
164
|
+
margin-left: -3px;
|
|
121
165
|
}
|
|
122
166
|
|
|
123
|
-
${selector}
|
|
124
|
-
|
|
125
|
-
font-weight:
|
|
167
|
+
${selector} .text .non-commercial {
|
|
168
|
+
font-size: 0.8em;
|
|
169
|
+
font-weight: 600;
|
|
170
|
+
text-transform: uppercase;
|
|
126
171
|
}
|
|
127
172
|
|
|
128
|
-
@keyframes
|
|
173
|
+
@keyframes logo-animation {
|
|
129
174
|
0% {
|
|
130
175
|
transform: translate(0px, 10px);
|
|
131
|
-
opacity: 0;
|
|
132
176
|
pointer-events: none;
|
|
133
177
|
}
|
|
134
178
|
1% {
|
|
135
179
|
transform: translate(0, -5px);
|
|
136
|
-
opacity:
|
|
180
|
+
opacity: 1;
|
|
137
181
|
}
|
|
138
182
|
2% {
|
|
139
183
|
transform: translate(0, 2.5px);
|
|
@@ -141,7 +185,6 @@ function createLicenseStyle() {
|
|
|
141
185
|
3% {
|
|
142
186
|
transform: translate(0, 0px);
|
|
143
187
|
pointer-events: all;
|
|
144
|
-
opacity: 1;
|
|
145
188
|
}
|
|
146
189
|
4% {
|
|
147
190
|
transform: scale(1)
|
|
@@ -161,14 +204,15 @@ function createLicenseStyle() {
|
|
|
161
204
|
transform: scale(1)
|
|
162
205
|
}
|
|
163
206
|
100% {
|
|
164
|
-
opacity: 0;
|
|
165
207
|
pointer-events: none;
|
|
208
|
+
opacity: 0;
|
|
166
209
|
}
|
|
167
210
|
}
|
|
168
|
-
|
|
211
|
+
|
|
212
|
+
${selector} .logo {
|
|
169
213
|
opacity: 0;
|
|
170
214
|
pointer-events: none;
|
|
171
|
-
animation:
|
|
215
|
+
animation: logo-animation;
|
|
172
216
|
animation-iteration-count: 1;
|
|
173
217
|
animation-duration: ${(licenseDuration / 1000)}s;
|
|
174
218
|
animation-delay: ${licenseDelay / 1000}s;
|
|
@@ -184,8 +228,9 @@ function createLicenseStyle() {
|
|
|
184
228
|
transition: all 0.1s ease-in-out !important;
|
|
185
229
|
}
|
|
186
230
|
|
|
187
|
-
${selector} .logo
|
|
188
|
-
|
|
231
|
+
${selector}:hover .logo {
|
|
232
|
+
transition: all 0.1s ease-in-out !important;
|
|
233
|
+
transform: scale(1.1) !important;
|
|
189
234
|
cursor: pointer !important;
|
|
190
235
|
}
|
|
191
236
|
`
|
|
@@ -193,7 +238,7 @@ function createLicenseStyle() {
|
|
|
193
238
|
}
|
|
194
239
|
|
|
195
240
|
|
|
196
|
-
async function
|
|
241
|
+
async function sendUsageMessageToAnalyticsBackend() {
|
|
197
242
|
try {
|
|
198
243
|
const analyticsBackendUrlForward = "https://urls.needle.tools/analytics-endpoint";
|
|
199
244
|
const res = await fetch(analyticsBackendUrlForward);
|
|
@@ -207,7 +252,8 @@ async function sendNonCommercialUsageMessageToAnalyticsBackend() {
|
|
|
207
252
|
|
|
208
253
|
let endpoint = "api/v1/register/web-request";
|
|
209
254
|
if (!analyticsUrl.endsWith("/")) endpoint = "/" + endpoint;
|
|
210
|
-
const
|
|
255
|
+
const type = hasProLicense() ? "commercial" : "non-commercial";
|
|
256
|
+
const finalUrl = `${analyticsUrl}${endpoint}?type=${type}&url=${encodeURIComponent(currentUrl)}&hostname=${encodeURIComponent(window.location.hostname)}&pathname=${encodeURIComponent(window.location.pathname)}&search=${encodeURIComponent(window.location.search)}&hash=${encodeURIComponent(window.location.hash)}`;
|
|
211
257
|
if (debug) console.log("Sending non-commercial usage message to analytics backend", finalUrl);
|
|
212
258
|
|
|
213
259
|
|
|
@@ -362,7 +362,7 @@ export class UriSerializer extends TypeSerializer {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
onDeserialize(data: string, _context: SerializationContext) {
|
|
365
|
-
if (typeof data === "string") {
|
|
365
|
+
if (typeof data === "string" && data.length > 0) {
|
|
366
366
|
return resolveUrl(_context.gltfId, data);
|
|
367
367
|
}
|
|
368
368
|
return undefined;
|
|
@@ -486,8 +486,8 @@ export class Component implements IComponent, EventTarget {
|
|
|
486
486
|
}
|
|
487
487
|
// console.trace("INTERNAL ENABLE");
|
|
488
488
|
this.__didEnable = true;
|
|
489
|
-
this.onEnable();
|
|
490
489
|
this.__isEnabled = true;
|
|
490
|
+
this.onEnable();
|
|
491
491
|
return true;
|
|
492
492
|
}
|
|
493
493
|
|
|
@@ -501,8 +501,8 @@ export class Component implements IComponent, EventTarget {
|
|
|
501
501
|
return;
|
|
502
502
|
}
|
|
503
503
|
this.__didEnable = false;
|
|
504
|
-
this.onDisable();
|
|
505
504
|
this.__isEnabled = false;
|
|
505
|
+
this.onDisable();
|
|
506
506
|
}
|
|
507
507
|
|
|
508
508
|
/** @internal */
|
|
@@ -40,6 +40,13 @@ declare type ScreenCaptureOptions = {
|
|
|
40
40
|
|
|
41
41
|
export class ScreenCapture extends Behaviour implements IPointerClickHandler {
|
|
42
42
|
|
|
43
|
+
onPointerEnter() {
|
|
44
|
+
this.context.input.setCursorPointer();
|
|
45
|
+
}
|
|
46
|
+
onPointerExit() {
|
|
47
|
+
this.context.input.setCursorNormal();
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
onPointerClick(evt : PointerEventData) {
|
|
44
51
|
if(evt && evt.pointerId !== 0) return;
|
|
45
52
|
if(this.context.connection.isInRoom === false) return;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Behaviour, GameObject } from "./Component";
|
|
2
|
-
import * as THREE from "three";
|
|
3
2
|
import { serializable } from "../engine/engine_serialization_decorator";
|
|
4
|
-
import {
|
|
3
|
+
import { Material, Mesh, Object3D, ShaderMaterial, sRGBEncoding, Texture, Vector2, Vector4, VideoTexture } from "three";
|
|
5
4
|
import { awaitInput } from "../engine/engine_input_utils";
|
|
6
|
-
import { getParam
|
|
5
|
+
import { getParam } from "../engine/engine_utils";
|
|
7
6
|
import { Renderer } from "./Renderer";
|
|
8
7
|
import { getWorldScale } from "../engine/engine_three_utils";
|
|
9
8
|
import { ObjectUtils, PrimitiveType } from "../engine/engine_create_objects";
|
|
10
9
|
import { Context } from "../engine/engine_setup";
|
|
10
|
+
import { isDevEnvironment } from "../engine/debug";
|
|
11
11
|
|
|
12
12
|
const debug = getParam("debugvideo");
|
|
13
13
|
|
|
@@ -46,7 +46,7 @@ export enum VideoRenderMode {
|
|
|
46
46
|
export class VideoPlayer extends Behaviour {
|
|
47
47
|
|
|
48
48
|
@serializable(Object3D)
|
|
49
|
-
renderer:
|
|
49
|
+
renderer: Object3D | null = null;
|
|
50
50
|
@serializable()
|
|
51
51
|
playOnAwake: boolean = true;
|
|
52
52
|
|
|
@@ -149,18 +149,29 @@ export class VideoPlayer extends Behaviour {
|
|
|
149
149
|
}
|
|
150
150
|
private _muted: boolean = false;
|
|
151
151
|
|
|
152
|
+
@serializable()
|
|
153
|
+
private set audioOutputMode(mode: VideoAudioOutputMode) {
|
|
154
|
+
if (mode !== this._audioOutputMode) {
|
|
155
|
+
if (mode === VideoAudioOutputMode.AudioSource && isDevEnvironment()) console.warn("VideoAudioOutputMode.AudioSource is not yet implemented");
|
|
156
|
+
this._audioOutputMode = mode;
|
|
157
|
+
this.updateVideoElementSettings();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
private get audioOutputMode() { return this._audioOutputMode; }
|
|
161
|
+
|
|
162
|
+
private _audioOutputMode: VideoAudioOutputMode = VideoAudioOutputMode.Direct;
|
|
163
|
+
|
|
152
164
|
/** Set this to false to pause video playback while the tab is not active */
|
|
153
165
|
playInBackground: boolean = true;
|
|
154
166
|
|
|
155
167
|
private _crossOrigin: string | null = "anonymous";
|
|
156
168
|
|
|
157
|
-
private audioOutputMode: VideoAudioOutputMode = VideoAudioOutputMode.AudioSource;
|
|
158
169
|
|
|
159
170
|
private source!: VideoSource;
|
|
160
171
|
private url?: string | null = null;
|
|
161
172
|
|
|
162
173
|
private _videoElement: HTMLVideoElement | null = null;
|
|
163
|
-
private _videoTexture:
|
|
174
|
+
private _videoTexture: VideoTexture | null = null;
|
|
164
175
|
private _videoMaterial: Material | null = null;
|
|
165
176
|
|
|
166
177
|
private _isPlaying: boolean = false;
|
|
@@ -195,27 +206,11 @@ export class VideoPlayer extends Behaviour {
|
|
|
195
206
|
}
|
|
196
207
|
}
|
|
197
208
|
|
|
198
|
-
awake(): void {
|
|
199
|
-
this.create(this.playOnAwake);
|
|
200
|
-
|
|
201
|
-
window.addEventListener('visibilitychange', _evt => {
|
|
202
|
-
switch (document.visibilityState) {
|
|
203
|
-
case "hidden":
|
|
204
|
-
if(!this.playInBackground){
|
|
205
|
-
this.wasPlaying = this._isPlaying;
|
|
206
|
-
this.pause();
|
|
207
|
-
}
|
|
208
|
-
break;
|
|
209
|
-
case "visible":
|
|
210
|
-
if (this.wasPlaying && !this._isPlaying) this.play();
|
|
211
|
-
break;
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
209
|
onEnable(): void {
|
|
210
|
+
window.addEventListener('visibilitychange', this.visibilityChanged);
|
|
211
|
+
|
|
217
212
|
if (this.playOnAwake === true) {
|
|
218
|
-
this.
|
|
213
|
+
this.create(true);
|
|
219
214
|
}
|
|
220
215
|
if (this.screenspace) {
|
|
221
216
|
this._overlay?.start();
|
|
@@ -224,9 +219,24 @@ export class VideoPlayer extends Behaviour {
|
|
|
224
219
|
}
|
|
225
220
|
|
|
226
221
|
onDisable(): void {
|
|
222
|
+
window.removeEventListener('visibilitychange', this.visibilityChanged);
|
|
227
223
|
this.pause();
|
|
228
224
|
}
|
|
229
225
|
|
|
226
|
+
private visibilityChanged = (_: Event) => {
|
|
227
|
+
switch (document.visibilityState) {
|
|
228
|
+
case "hidden":
|
|
229
|
+
if (!this.playInBackground) {
|
|
230
|
+
this.wasPlaying = this._isPlaying;
|
|
231
|
+
this.pause();
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
case "visible":
|
|
235
|
+
if (this.wasPlaying && !this._isPlaying) this.play();
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
230
240
|
onDestroy(): void {
|
|
231
241
|
if (this._videoElement) {
|
|
232
242
|
this._videoElement.parentElement?.removeChild(this._videoElement);
|
|
@@ -258,12 +268,15 @@ export class VideoPlayer extends Behaviour {
|
|
|
258
268
|
}
|
|
259
269
|
|
|
260
270
|
play() {
|
|
271
|
+
if (!this._videoElement) this.create(false);
|
|
261
272
|
if (!this._videoElement) return;
|
|
262
273
|
if (this._isPlaying && !this._videoElement?.ended && !this._videoElement?.paused) return;
|
|
263
274
|
this._isPlaying = true;
|
|
264
275
|
if (!this._receivedInput) this._videoElement.muted = true;
|
|
265
276
|
this.updateVideoElementSettings();
|
|
266
|
-
this._videoElement
|
|
277
|
+
this._videoElement.currentTime = this.time;
|
|
278
|
+
this._videoElement.play().catch(err => {
|
|
279
|
+
console.log(err);
|
|
267
280
|
// https://developer.chrome.com/blog/play-request-was-interrupted/
|
|
268
281
|
if (debug)
|
|
269
282
|
console.error("Error playing video", err, "CODE=" + err.code, this.videoElement?.src, this);
|
|
@@ -272,19 +285,23 @@ export class VideoPlayer extends Behaviour {
|
|
|
272
285
|
this.play();
|
|
273
286
|
}, 1000);
|
|
274
287
|
});
|
|
275
|
-
if (debug) console.log("play", this._videoElement);
|
|
288
|
+
if (debug) console.log("play", this._videoElement, this.time);
|
|
276
289
|
}
|
|
277
290
|
|
|
278
291
|
stop() {
|
|
279
292
|
this._isPlaying = false;
|
|
293
|
+
this.time = 0;
|
|
280
294
|
if (!this._videoElement) return;
|
|
281
295
|
this._videoElement.currentTime = 0;
|
|
282
296
|
this._videoElement.pause();
|
|
297
|
+
if (debug) console.log("STOP", this);
|
|
283
298
|
}
|
|
284
299
|
|
|
285
300
|
pause(): void {
|
|
301
|
+
this.time = this._videoElement?.currentTime ?? 0;
|
|
286
302
|
this._isPlaying = false;
|
|
287
303
|
this._videoElement?.pause();
|
|
304
|
+
if (debug) console.log("PAUSE", this, this.currentTime);
|
|
288
305
|
}
|
|
289
306
|
|
|
290
307
|
|
|
@@ -301,30 +318,36 @@ export class VideoPlayer extends Behaviour {
|
|
|
301
318
|
|
|
302
319
|
if (!src) return;
|
|
303
320
|
|
|
304
|
-
// console.log(src, this);
|
|
305
321
|
|
|
306
322
|
if (!this._videoElement) {
|
|
323
|
+
if (debug)
|
|
324
|
+
console.warn("Create VideoElement", this);
|
|
307
325
|
this._videoElement = this.createVideoElement();
|
|
308
326
|
this.context.domElement?.prepend(this._videoElement);
|
|
309
327
|
// hide it because otherwise it would overlay the website with default css
|
|
310
328
|
this.updateVideoElementStyles();
|
|
311
329
|
}
|
|
330
|
+
|
|
312
331
|
if (typeof src === "string") {
|
|
332
|
+
if (debug) console.log("Set Video src", src);
|
|
313
333
|
this._videoElement.src = src;
|
|
314
|
-
|
|
315
|
-
|
|
334
|
+
// Nor sure why we did this here, but with this code the video does not restart when being paused / enable toggled
|
|
335
|
+
// const str = this._videoElement["captureStream"]?.call(this._videoElement);
|
|
336
|
+
// this.clip = str;
|
|
316
337
|
}
|
|
317
|
-
else
|
|
338
|
+
else {
|
|
339
|
+
if (debug) console.log("Set Video srcObject", src);
|
|
318
340
|
this._videoElement.srcObject = src;
|
|
341
|
+
}
|
|
319
342
|
|
|
320
343
|
|
|
321
344
|
if (!this._videoTexture)
|
|
322
|
-
this._videoTexture = new
|
|
345
|
+
this._videoTexture = new VideoTexture(this._videoElement);
|
|
323
346
|
this._videoTexture.flipY = false;
|
|
324
|
-
this._videoTexture.encoding =
|
|
347
|
+
this._videoTexture.encoding = sRGBEncoding;
|
|
325
348
|
this.handleBeginPlaying(playAutomatically);
|
|
326
349
|
if (debug)
|
|
327
|
-
console.log(this);
|
|
350
|
+
console.log(this, playAutomatically);
|
|
328
351
|
}
|
|
329
352
|
|
|
330
353
|
updateAspect() {
|
|
@@ -354,7 +377,7 @@ export class VideoPlayer extends Behaviour {
|
|
|
354
377
|
const video = document.createElement("video") as HTMLVideoElement;
|
|
355
378
|
if (this._crossOrigin)
|
|
356
379
|
video.setAttribute("crossorigin", this._crossOrigin);
|
|
357
|
-
if (debug) console.log("
|
|
380
|
+
if (debug) console.log("created video element", video);
|
|
358
381
|
return video;
|
|
359
382
|
}
|
|
360
383
|
|