@wonderlandengine/components
Version:
Wonderland Engine's official component library.
143 lines • 5.21 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Component } from '@wonderlandengine/api';
import { setFirstMaterialTexture } from './utils/utils.js';
import { property } from '@wonderlandengine/api/decorators.js';
/**
* Downloads a video from URL and applies it as `diffuseTexture` or `flatTexture`
* on given material.
*
* Video textures need to be updated regularly whenever
* a new frame is available. This component handles the
* detection of a new frame and updates the texture to
* reflect the video's current frame.
*
* Materials from the following shaders are supported:
* - "Phong Opaque Textured"
* - "Flat Opaque Textured"
* - "Background"
* - "Physical Opaque Textured"
* - "Foliage"
*
* The video can be accessed through `this.video`:
*
* ```js
* let videoTexture = this.object.getComponent('video-texture');
* videoTexture.video.play();
* videoTexture.video.pause();
* ```
*
* See [Video Example](/showcase/video).
*/
class VideoTexture extends Component {
static TypeName = 'video-texture';
/** URL to download video from */
url;
/** Material to apply the video texture to */
material;
/** Whether to loop the video */
loop;
/** Whether to automatically start playing the video */
autoplay;
/** Whether to mute sound */
muted;
/** Name of the texture property to set */
textureProperty;
loaded = false;
frameUpdateRequested = true;
video;
texture;
start() {
this.video = document.createElement('video');
this.video.src = this.url;
this.video.crossOrigin = 'anonymous';
this.video.playsInline = true;
this.video.loop = this.loop;
this.video.muted = this.muted;
this.video.addEventListener('playing', () => {
this.loaded = true;
});
if (this.autoplay) {
/* Muted videos are allowed to play immediately. Videos with sound
* need to await a user gesture. */
if (this.muted) {
this.video?.play();
}
else {
window.addEventListener('click', this.playAfterUserGesture);
window.addEventListener('touchstart', this.playAfterUserGesture);
}
}
}
onDestroy() {
this.video?.remove();
this.texture?.destroy();
if (this.autoplay && !this.muted) {
/* In case not removed yet, we remove the autoplay gestures here.
* If already removed, these have no effect. */
window.removeEventListener('click', this.playAfterUserGesture);
window.removeEventListener('touchstart', this.playAfterUserGesture);
}
}
applyTexture() {
const mat = this.material;
const pipeline = mat.pipeline;
const texture = (this.texture = this.engine.textures.create(this.video));
if (!setFirstMaterialTexture(mat, texture, this.textureProperty)) {
console.error('Pipeline', pipeline, 'not supported by video-texture');
}
if ('requestVideoFrameCallback' in this.video) {
this.video.requestVideoFrameCallback(this.updateVideo.bind(this));
}
else {
this.video.addEventListener('timeupdate', () => {
this.frameUpdateRequested = true;
});
}
}
update(dt) {
if (this.loaded && this.frameUpdateRequested) {
if (this.texture) {
this.texture.update();
}
else {
/* Apply texture on first frame update request */
this.applyTexture();
}
this.frameUpdateRequested = false;
}
}
updateVideo() {
this.frameUpdateRequested = true;
this.video.requestVideoFrameCallback(this.updateVideo.bind(this));
}
playAfterUserGesture = () => {
this.video?.play();
window.removeEventListener('click', this.playAfterUserGesture);
window.removeEventListener('touchstart', this.playAfterUserGesture);
};
}
__decorate([
property.string()
], VideoTexture.prototype, "url", void 0);
__decorate([
property.material({ required: true })
], VideoTexture.prototype, "material", void 0);
__decorate([
property.bool(true)
], VideoTexture.prototype, "loop", void 0);
__decorate([
property.bool(true)
], VideoTexture.prototype, "autoplay", void 0);
__decorate([
property.bool(true)
], VideoTexture.prototype, "muted", void 0);
__decorate([
property.string('auto')
], VideoTexture.prototype, "textureProperty", void 0);
export { VideoTexture };
//# sourceMappingURL=video-texture.js.map