import { array_copy } from "../../../../../../core/collection/array/array_copy.js";
import { generate_halton_jitter } from "../../../../../../core/math/random/generate_halton_jitter.js";
import { EnginePlugin } from "../../../../../plugin/EnginePlugin.js";

export class TemporalSupersamplingRenderPlugin extends EnginePlugin {
    constructor() {
        super();

        /**
         *
         * @type {number}
         * @private
         */
        this.__frame_index = 0;

        this.__sample_count = 16;
        this.__jitter_offset = generate_halton_jitter(this.__sample_count);


        this.__projection_modifier = {
            /**
             *
             * @param {number[]} input
             * @param {number[]} output
             */
            transform: (input, output) => {

                const viewport_width = this.engine.graphics.viewport.size.x;
                const viewport_height = this.engine.graphics.viewport.size.y;

                // apply jitter to projection matrix
                const jitter_index = this.__frame_index % this.__sample_count;

                const jitter_offset_x = this.__jitter_offset[jitter_index * 2];
                const jitter_offset_y = this.__jitter_offset[jitter_index * 2 + 1];

                array_copy(input, 0, output, 0, 16);

                output[8] = jitter_offset_x / viewport_width;
                output[9] = jitter_offset_y / viewport_height;
            }
        };
    }

    __hook_post_render() {

        // increment frame index
        this.__frame_index++;
    }

    initialize(engine) {
        super.initialize(engine);
    }

    finalize() {
        super.finalize();
    }

    async startup() {
        // modify projection matrix
        this.engine.graphics.main_view.addProjectionModifier(this.__projection_modifier);


        this.engine.graphics.on.postRender.add(this.__hook_post_render, this);

        // reset frame counter
        this.__frame_index = 0;

        return super.startup();
    }

    async shutdown() {
        this.engine.graphics.main_view.removeProjectionModifier(this.__projection_modifier);
        this.engine.graphics.on.postRender.remove(this.__hook_post_render, this);

        return super.shutdown();
    }
}
