
/**
 * Helper class to create a WebGL Texture
 * 用于创建WebGL Texture
 * @class
 * @memberof glCore
 * @param gl {WebGLRenderingContext} The current WebGL context
 * @param width {number} the width of the texture
 * @param height {number} the height of the texture
 * @param format {number} the pixel format of the texture. defaults to gl.RGBA
 * @param type {number} the gl type of the texture. defaults to gl.UNSIGNED_BYTE
 */
export class GLTexture {
	/**
	 * 当前上下文
	 * The current WebGL rendering context
	 */
	gl: WebGLRenderingContext;
	texture: WebGLTexture;
	/**
	 * If mipmapping was used for this texture, enable and disable with enableMipmap()
	 * 是否对纹理进行存储缩小的各种尺寸纹理，比如原图1024*1024，存储512*512，256*256，128*128等一直到1*1;为了纹理的缩放时处理，是取相邻或线性插值
	 */
	mipmap: boolean;
	/**
	 * Set to true to enable pre-multiplied alpha
	 * 设置纹理预乘透明值，为true，https://blog.csdn.net/mydreamremindme/article/details/50817294
	 */
	premultiplyAlpha;
	/**
	 * 纹理宽度
	 */
	width: number;
	/**
	 * 纹理高度
	 */
	height: number;
	/**
	 * {number} the pixel format of the texture. defaults to gl.RGBA
	 * 纹理格式，默认gl.RGBA  还有gl.RGB
	 */
	format: any;
	/**
	 * {number} the gl type of the texture. defaults to gl.UNSIGNED_BYTE
	 * 纹理类型，默认gl.UNSIGNED_BYTE   //https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/texImage2D
	 */
	type: any;
	constructor(gl: WebGLRenderingContext, width?: number, height?: number, format?, type?) {

		this.gl = gl;

		this.texture = gl.createTexture();

		// some settings..
		this.mipmap = false;

		this.premultiplyAlpha = false;

		this.width = width || -1;

		this.height = height || -1;

		/**
		 * The pixel format of the texture. defaults to gl.RGBA
		 *
		 * @member {Number}
		 */
		this.format = format || gl.RGBA;

		/**
		 * The gl type of the texture. defaults to gl.UNSIGNED_BYTE
		 *
		 * @member {Number}
		 */
		this.type = type || gl.UNSIGNED_BYTE;
	};


	/**
	 * Uploads this texture to the GPU
	 * GPU存储纹理数据
	 * @param source {HTMLImageElement|ImageData|HTMLVideoElement} the source image of the texture
	 */
	public upload(source) {

		this.bind();

		var gl = this.gl;

		//设置是否对纹理进行预乘透明通道
		gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha);

		var newWidth = source.videoWidth || source.width;
		var newHeight = source.videoHeight || source.height;

		if (newHeight !== this.height || newWidth !== this.width) {
			//https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/texImage2D
			gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, this.type, source);
		}
		else {
			//https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texSubImage2D
			gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.format, this.type, source);
		}

		// if the source is a video, we need to use the videoWidth / videoHeight properties as width / height will be incorrect.
		this.width = newWidth;
		this.height = newHeight;
	};

	/**
	 * Use a data source and uploads this texture to the GPU
	 * 数据类型的纹理
	 * @param data {TypedArray} the data to upload to the texture
	 * @param width {number} the new width of the texture
	 * @param height {number} the new height of the texture
	 */
	public uploadData = function (data, width, height) {
		this.bind();

		var gl = this.gl;


		if (data instanceof Float32Array) {
			if (!FLOATING_POINT_AVAILABLE) {
				var ext = gl.getExtension("OES_texture_float");

				if (ext) {
					FLOATING_POINT_AVAILABLE = true;
				}
				else {
					throw new Error('floating point textures not available');
				}
			}

			this.type = gl.FLOAT;
		}
		else {
			// TODO support for other types
			this.type = this.type || gl.UNSIGNED_BYTE;
		}

		// what type of data?
		gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha);


		if (width !== this.width || height !== this.height) {
			gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.format, this.type, data || null);
		}
		else {
			gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, this.format, this.type, data || null);
		}

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


		//	texSubImage2D
	};

	/**
	 * Binds the texture
	 * 绑定纹理，不传location表示不激活额外纹理，绑定的纹理位置与原状态相同
	 * @param  location
	 */
	public bind(location?: number) {
		var gl = this.gl;

		if (location !== undefined) {
			gl.activeTexture(gl.TEXTURE0 + location);
		}

		gl.bindTexture(gl.TEXTURE_2D, this.texture);
	};

	/**
	 * Unbinds the texture
	 * 解除纹理绑定，解除位置与原状态相同
	 */
	public unbind() {
		var gl = this.gl;
		gl.bindTexture(gl.TEXTURE_2D, null);
	};

	/**
	 * @param linear {Boolean} if we want to use linear filtering or nearest neighbour interpolation
	 * 缩小的纹理像素 按线性插值，还是按钮邻近原则
	 */
	public minFilter(linear: boolean) {
		var gl = this.gl;

		this.bind();

		if (this.mipmap) {
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, linear ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
		}
		else {
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, linear ? gl.LINEAR : gl.NEAREST);
		}
	};

	/**
	 * @param linear {Boolean} if we want to use linear filtering or nearest neighbour interpolation
	 * 放大的纹理像素 按线性插值，还是按钮邻近原则
	 */
	public magFilter(linear: boolean) {
		var gl = this.gl;

		this.bind();

		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, linear ? gl.LINEAR : gl.NEAREST);
	};

	/**
	 * Enables mipmapping
	 * 生成缩小的纹理集，只能在图片宽高满足2的指数时使用
	 */
	public enableMipmap() {
		var gl = this.gl;

		this.bind();

		this.mipmap = true;

		gl.generateMipmap(gl.TEXTURE_2D);
	};

	/**
	 * Enables linear filtering
	 * 设置线性
	 */
	public enableLinearScaling() {
		this.minFilter(true);
		this.magFilter(true);
	};

	/**
	 * Enables nearest neighbour interpolation
	 * 设置邻近
	 */
	public enableNearestScaling() {
		this.minFilter(false);
		this.magFilter(false);
	};

	/**
	 * Enables clamping on the texture so WebGL will not repeat it
	 * 如果纹理不满足2的指数时必设，以边缘像素延申
	 */
	public enableWrapClamp() {
		var gl = this.gl;

		this.bind();

		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	};

	/**
	 * Enable tiling on the texture
	 * 允许纹理重复，地砖模式
	 */
	public enableWrapRepeat() {
		var gl = this.gl;

		this.bind();

		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
	};
	/**
	 * 镜像形式重复
	 */
	public enableWrapMirrorRepeat() {
		var gl = this.gl;

		this.bind();

		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
	};


	/**
	 * Destroys this texture
	 */
	public destroy() {
		var gl = this.gl;
		//TODO
		gl.deleteTexture(this.texture);
	};

	/**
	 * 从图片数据创建纹理
     * @static
     * @param gl {WebGLRenderingContext} The current WebGL context
     * @param source {HTMLImageElement|ImageData} the source image of the texture
     * @param premultiplyAlpha {Boolean} If we want to use pre-multiplied alpha
     */
	public static fromSource(gl: WebGLRenderingContext, source: HTMLImageElement | ImageData, premultiplyAlpha?: boolean) {
		var texture: GLTexture = new GLTexture(gl);
		texture.premultiplyAlpha = premultiplyAlpha || false;
		texture.upload(source);
		return texture;
	};

	/**
	 * @static
	 * @param gl {WebGLRenderingContext} The current WebGL context
	 * @param data {TypedArray} the data to upload to the texture
	 * @param width {number} the new width of the texture
	 * @param height {number} the new height of the texture
	 */
	public static fromData(gl, data, width, height) {
		//console.log(data, width, height);
		var texture = new GLTexture(gl);
		texture.uploadData(data, width, height);

		return texture;
	};

}



var FLOATING_POINT_AVAILABLE = false;







