
import { GLTexture } from './GLTexture';

/**
 * Helper class to create a webGL Framebuffer
 * 帧缓存，暂时不使用，renderTarget里用，主要用于滤镜处理
 *
 * @class
 * @memberof glCore
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 * @param width {Number} the width of the drawing area of the frame buffer
 * @param height {Number} the height of the drawing area of the frame buffer
 */
export class GLFramebuffer {
    /**
     * 当前渲染上下文
     */
    gl: WebGLRenderingContext;
    /**
     * 帧缓存
     */
    framebuffer: WebGLFramebuffer;
    /**
     * 模板缓存
     */
    stencil: WebGLRenderbuffer;

    texture: GLTexture;
    width: number;
    height: number;
    constructor(gl: WebGLRenderingContext, width: number, height: number) {
        this.gl = gl;
        this.framebuffer = gl.createFramebuffer();
        this.stencil = null;
        this.texture = null;
        this.width = width || 100;
        this.height = height || 100;
    };
    /**
     * Adds a texture to the frame buffer
     * @param texture {glCore.GLTexture}
     */
    public enableTexture(texture?: GLTexture) {
        var gl = this.gl;

        this.texture = texture || new GLTexture(gl);

        this.texture.bind();

        //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,  this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

        this.bind();

        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture.texture, 0);
    };

    /**
     * Initialises the stencil buffer
     */
    public enableStencil() {
        if (this.stencil) return;

        var gl = this.gl;

        this.stencil = gl.createRenderbuffer();

        gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencil);

        // TODO.. this is depth AND stencil?
        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencil);
        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, this.width, this.height);


    };

    /**
     * Erases the drawing area and fills it with a colour
     * @param  r {Number} the red value of the clearing colour
     * @param  g {Number} the green value of the clearing colour
     * @param  b {Number} the blue value of the clearing colour
     * @param  a {Number} the alpha value of the clearing colour
     */
    public clear(r: number, g: number, b: number, a: number) {
        this.bind();

        var gl = this.gl;

        gl.clearColor(r, g, b, a);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    };

    /**
     * Binds the frame buffer to the WebGL context
     */
    public bind() {
        var gl = this.gl;
        gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
    };

    /**
     * Unbinds the frame buffer to the WebGL context
     */
    public unbind() {
        var gl = this.gl;
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    };
    /**
     * Resizes the drawing area of the buffer to the given width and height
     * @param  width  {Number} the new width
     * @param  height {Number} the new height
     */
    public resize(width: number, height: number) {
        var gl = this.gl;

        this.width = width;
        this.height = height;

        if (this.texture) {
            this.texture.uploadData(null, width, height);
        }

        if (this.stencil) {
            // update the stencil buffer width and height
            gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencil);
            gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
        }
    };

    /**
     * Destroys this buffer
     */
    public destroy() {
        var gl = this.gl;

        //TODO
        if (this.texture) {
            this.texture.destroy();
        }

        gl.deleteFramebuffer(this.framebuffer);

        this.gl = null;

        this.stencil = null;
        this.texture = null;
    };

    /**
     * Creates a frame buffer with a texture containing the given data
     * @static
     * @param gl {WebGLRenderingContext} The current WebGL rendering context
     * @param width {Number} the width of the drawing area of the frame buffer
     * @param height {Number} the height of the drawing area of the frame buffer
     * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data
     */
    public static createRGBA(gl: WebGLRenderingContext, width: number, height: number, data?) {
        var texture = GLTexture.fromData(gl, null, width, height);
        texture.enableNearestScaling();
        texture.enableWrapClamp();

        //now create the framebuffer object and attach the texture to it.
        var fbo = new GLFramebuffer(gl, width, height);
        fbo.enableTexture(texture);
        //fbo.enableStencil(); // get this back on soon!

        //fbo.enableStencil(); // get this back on soon!

        fbo.unbind();

        return fbo;
    };

    /**
     * Creates a frame buffer with a texture containing the given data
     * @static
     * @param gl {WebGLRenderingContext} The current WebGL rendering context
     * @param width {Number} the width of the drawing area of the frame buffer
     * @param height {Number} the height of the drawing area of the frame buffer
     * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data
     */
    public static createFloat32(gl: WebGLRenderingContext, width: number, height: number, data:any) {
        // create a new texture..
        var texture = GLTexture.fromData(gl, data, width, height);
        texture.enableNearestScaling();
        texture.enableWrapClamp();

        //now create the framebuffer object and attach the texture to it.
        var fbo = new GLFramebuffer(gl, width, height);
        fbo.enableTexture(texture);

        fbo.unbind();

        return fbo;
    };


}




