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