UNPKG

@wonderlandengine/components

Version:

Wonderland Engine's official component library.

143 lines 5.21 kB
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