/**
* Helper class to create a WebGL Texture
*
* @class
* @memberof PIXI.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
*/
var Texture = function(gl, width, height, format, type)
{
/**
* The current WebGL rendering context
*
* @member {WebGLRenderingContext}
*/
this.gl = gl;
/**
* The WebGL texture
*
* @member {WebGLTexture}
*/
this.texture = gl.createTexture();
/**
* If mipmapping was used for this texture, enable and disable with enableMipmap()
*
* @member {Boolean}
*/
// some settings..
this.mipmap = false;
/**
* Set to true to enable pre-multiplied alpha
*
* @member {Boolean}
*/
this.premultiplyAlpha = false;
/**
* The width of texture
*
* @member {Number}
*/
this.width = width || -1;
/**
* The height of texture
*
* @member {Number}
*/
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
* @param source {HTMLImageElement|ImageData|HTMLVideoElement} the source image of the texture
*/
Texture.prototype.upload = function(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)
{
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, this.type, source);
}
else
{
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;
};
var FLOATING_POINT_AVAILABLE = false;
/**
* 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
*/
Texture.prototype.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
* @param location
*/
Texture.prototype.bind = function(location)
{
var gl = this.gl;
if(location !== undefined)
{
gl.activeTexture(gl.TEXTURE0 + location);
}
gl.bindTexture(gl.TEXTURE_2D, this.texture);
};
/**
* Unbinds the texture
*/
Texture.prototype.unbind = function()
{
var gl = this.gl;
gl.bindTexture(gl.TEXTURE_2D, null);
};
/**
* @param linear {Boolean} if we want to use linear filtering or nearest neighbour interpolation
*/
Texture.prototype.minFilter = function( linear )
{
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
*/
Texture.prototype.magFilter = function( linear )
{
var gl = this.gl;
this.bind();
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, linear ? gl.LINEAR : gl.NEAREST);
};
/**
* Enables mipmapping
*/
Texture.prototype.enableMipmap = function()
{
var gl = this.gl;
this.bind();
this.mipmap = true;
gl.generateMipmap(gl.TEXTURE_2D);
};
/**
* Enables linear filtering
*/
Texture.prototype.enableLinearScaling = function()
{
this.minFilter(true);
this.magFilter(true);
};
/**
* Enables nearest neighbour interpolation
*/
Texture.prototype.enableNearestScaling = function()
{
this.minFilter(false);
this.magFilter(false);
};
/**
* Enables clamping on the texture so WebGL will not repeat it
*/
Texture.prototype.enableWrapClamp = function()
{
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
*/
Texture.prototype.enableWrapRepeat = function()
{
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);
};
Texture.prototype.enableWrapMirrorRepeat = function()
{
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
*/
Texture.prototype.destroy = function()
{
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
*/
Texture.fromSource = function(gl, source, premultiplyAlpha)
{
var texture = new Texture(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
*/
Texture.fromData = function(gl, data, width, height)
{
//console.log(data, width, height);
var texture = new Texture(gl);
texture.uploadData(data, width, height);
return texture;
};
module.exports = Texture;