pixi-gl-core
Version:
A set of tidy little pixi objects that make working with WebGL simpler
1,655 lines (1,349 loc) • 42.1 kB
JavaScript
/*!
* pixi-gl-core - v1.1.4
* Compiled Mon, 20 Nov 2017 18:13:25 UTC
*
* pixi-gl-core is licensed under the MIT License.
* http://www.opensource.org/licenses/mit-license
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pixiGlCore = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var EMPTY_ARRAY_BUFFER = new ArrayBuffer(0);
/**
* Helper class to create a webGL buffer
*
* @class
* @memberof PIXI.glCore
* @param gl {WebGLRenderingContext} The current WebGL rendering context
* @param type {gl.ARRAY_BUFFER | gl.ELEMENT_ARRAY_BUFFER} @mat
* @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data
* @param drawType {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW}
*/
var Buffer = function(gl, type, data, drawType)
{
/**
* The current WebGL rendering context
*
* @member {WebGLRenderingContext}
*/
this.gl = gl;
/**
* The WebGL buffer, created upon instantiation
*
* @member {WebGLBuffer}
*/
this.buffer = gl.createBuffer();
/**
* The type of the buffer
*
* @member {gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER}
*/
this.type = type || gl.ARRAY_BUFFER;
/**
* The draw type of the buffer
*
* @member {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW}
*/
this.drawType = drawType || gl.STATIC_DRAW;
/**
* The data in the buffer, as a typed array
*
* @member {ArrayBuffer| SharedArrayBuffer|ArrayBufferView}
*/
this.data = EMPTY_ARRAY_BUFFER;
if(data)
{
this.upload(data);
}
this._updateID = 0;
};
/**
* Uploads the buffer to the GPU
* @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data to upload
* @param offset {Number} if only a subset of the data should be uploaded, this is the amount of data to subtract
* @param dontBind {Boolean} whether to bind the buffer before uploading it
*/
Buffer.prototype.upload = function(data, offset, dontBind)
{
// todo - needed?
if(!dontBind) this.bind();
var gl = this.gl;
data = data || this.data;
offset = offset || 0;
if(this.data.byteLength >= data.byteLength)
{
gl.bufferSubData(this.type, offset, data);
}
else
{
gl.bufferData(this.type, data, this.drawType);
}
this.data = data;
};
/**
* Binds the buffer
*
*/
Buffer.prototype.bind = function()
{
var gl = this.gl;
gl.bindBuffer(this.type, this.buffer);
};
Buffer.createVertexBuffer = function(gl, data, drawType)
{
return new Buffer(gl, gl.ARRAY_BUFFER, data, drawType);
};
Buffer.createIndexBuffer = function(gl, data, drawType)
{
return new Buffer(gl, gl.ELEMENT_ARRAY_BUFFER, data, drawType);
};
Buffer.create = function(gl, type, data, drawType)
{
return new Buffer(gl, type, data, drawType);
};
/**
* Destroys the buffer
*
*/
Buffer.prototype.destroy = function(){
this.gl.deleteBuffer(this.buffer);
};
module.exports = Buffer;
},{}],2:[function(require,module,exports){
var Texture = require('./GLTexture');
/**
* Helper class to create a webGL Framebuffer
*
* @class
* @memberof PIXI.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
*/
var Framebuffer = function(gl, width, height)
{
/**
* The current WebGL rendering context
*
* @member {WebGLRenderingContext}
*/
this.gl = gl;
/**
* The frame buffer
*
* @member {WebGLFramebuffer}
*/
this.framebuffer = gl.createFramebuffer();
/**
* The stencil buffer
*
* @member {WebGLRenderbuffer}
*/
this.stencil = null;
/**
* The stencil buffer
*
* @member {PIXI.glCore.GLTexture}
*/
this.texture = null;
/**
* The width of the drawing area of the buffer
*
* @member {Number}
*/
this.width = width || 100;
/**
* The height of the drawing area of the buffer
*
* @member {Number}
*/
this.height = height || 100;
};
/**
* Adds a texture to the frame buffer
* @param texture {PIXI.glCore.GLTexture}
*/
Framebuffer.prototype.enableTexture = function(texture)
{
var gl = this.gl;
this.texture = texture || new Texture(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
*/
Framebuffer.prototype.enableStencil = function()
{
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
*/
Framebuffer.prototype.clear = function( r, g, b, a )
{
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
*/
Framebuffer.prototype.bind = function()
{
var gl = this.gl;
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer );
};
/**
* Unbinds the frame buffer to the WebGL context
*/
Framebuffer.prototype.unbind = function()
{
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
*/
Framebuffer.prototype.resize = function(width, height)
{
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
*/
Framebuffer.prototype.destroy = function()
{
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
*/
Framebuffer.createRGBA = function(gl, width, height, data)
{
var texture = Texture.fromData(gl, null, width, height);
texture.enableNearestScaling();
texture.enableWrapClamp();
//now create the framebuffer object and attach the texture to it.
var fbo = new Framebuffer(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
*/
Framebuffer.createFloat32 = function(gl, width, height, data)
{
// create a new texture..
var texture = new Texture.fromData(gl, data, width, height);
texture.enableNearestScaling();
texture.enableWrapClamp();
//now create the framebuffer object and attach the texture to it.
var fbo = new Framebuffer(gl, width, height);
fbo.enableTexture(texture);
fbo.unbind();
return fbo;
};
module.exports = Framebuffer;
},{"./GLTexture":4}],3:[function(require,module,exports){
var compileProgram = require('./shader/compileProgram'),
extractAttributes = require('./shader/extractAttributes'),
extractUniforms = require('./shader/extractUniforms'),
setPrecision = require('./shader/setPrecision'),
generateUniformAccessObject = require('./shader/generateUniformAccessObject');
/**
* Helper class to create a webGL Shader
*
* @class
* @memberof PIXI.glCore
* @param gl {WebGLRenderingContext}
* @param vertexSrc {string|string[]} The vertex shader source as an array of strings.
* @param fragmentSrc {string|string[]} The fragment shader source as an array of strings.
* @param precision {string} The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'.
* @param attributeLocations {object} A key value pair showing which location eact attribute should sit eg {position:0, uvs:1}
*/
var Shader = function(gl, vertexSrc, fragmentSrc, precision, attributeLocations)
{
/**
* The current WebGL rendering context
*
* @member {WebGLRenderingContext}
*/
this.gl = gl;
if(precision)
{
vertexSrc = setPrecision(vertexSrc, precision);
fragmentSrc = setPrecision(fragmentSrc, precision);
}
/**
* The shader program
*
* @member {WebGLProgram}
*/
// First compile the program..
this.program = compileProgram(gl, vertexSrc, fragmentSrc, attributeLocations);
/**
* The attributes of the shader as an object containing the following properties
* {
* type,
* size,
* location,
* pointer
* }
* @member {Object}
*/
// next extract the attributes
this.attributes = extractAttributes(gl, this.program);
this.uniformData = extractUniforms(gl, this.program);
/**
* The uniforms of the shader as an object containing the following properties
* {
* gl,
* data
* }
* @member {Object}
*/
this.uniforms = generateUniformAccessObject( gl, this.uniformData );
};
/**
* Uses this shader
*
* @return {PIXI.glCore.GLShader} Returns itself.
*/
Shader.prototype.bind = function()
{
this.gl.useProgram(this.program);
return this;
};
/**
* Destroys this shader
* TODO
*/
Shader.prototype.destroy = function()
{
this.attributes = null;
this.uniformData = null;
this.uniforms = null;
var gl = this.gl;
gl.deleteProgram(this.program);
};
module.exports = Shader;
},{"./shader/compileProgram":8,"./shader/extractAttributes":10,"./shader/extractUniforms":11,"./shader/generateUniformAccessObject":12,"./shader/setPrecision":16}],4:[function(require,module,exports){
/**
* 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;
},{}],5:[function(require,module,exports){
// state object//
var setVertexAttribArrays = require( './setVertexAttribArrays' );
/**
* Helper class to work with WebGL VertexArrayObjects (vaos)
* Only works if WebGL extensions are enabled (they usually are)
*
* @class
* @memberof PIXI.glCore
* @param gl {WebGLRenderingContext} The current WebGL rendering context
*/
function VertexArrayObject(gl, state)
{
this.nativeVaoExtension = null;
if(!VertexArrayObject.FORCE_NATIVE)
{
this.nativeVaoExtension = gl.getExtension('OES_vertex_array_object') ||
gl.getExtension('MOZ_OES_vertex_array_object') ||
gl.getExtension('WEBKIT_OES_vertex_array_object');
}
this.nativeState = state;
if(this.nativeVaoExtension)
{
this.nativeVao = this.nativeVaoExtension.createVertexArrayOES();
var maxAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
// VAO - overwrite the state..
this.nativeState = {
tempAttribState: new Array(maxAttribs),
attribState: new Array(maxAttribs)
};
}
/**
* The current WebGL rendering context
*
* @member {WebGLRenderingContext}
*/
this.gl = gl;
/**
* An array of attributes
*
* @member {Array}
*/
this.attributes = [];
/**
* @member {PIXI.glCore.GLBuffer}
*/
this.indexBuffer = null;
/**
* A boolean flag
*
* @member {Boolean}
*/
this.dirty = false;
}
VertexArrayObject.prototype.constructor = VertexArrayObject;
module.exports = VertexArrayObject;
/**
* Some devices behave a bit funny when using the newer extensions (im looking at you ipad 2!)
* If you find on older devices that things have gone a bit weird then set this to true.
*/
/**
* Lets the VAO know if you should use the WebGL extension or the native methods.
* Some devices behave a bit funny when using the newer extensions (im looking at you ipad 2!)
* If you find on older devices that things have gone a bit weird then set this to true.
* @static
* @property {Boolean} FORCE_NATIVE
*/
VertexArrayObject.FORCE_NATIVE = false;
/**
* Binds the buffer
*/
VertexArrayObject.prototype.bind = function()
{
if(this.nativeVao)
{
this.nativeVaoExtension.bindVertexArrayOES(this.nativeVao);
if(this.dirty)
{
this.dirty = false;
this.activate();
return this;
}
if (this.indexBuffer)
{
this.indexBuffer.bind();
}
}
else
{
this.activate();
}
return this;
};
/**
* Unbinds the buffer
*/
VertexArrayObject.prototype.unbind = function()
{
if(this.nativeVao)
{
this.nativeVaoExtension.bindVertexArrayOES(null);
}
return this;
};
/**
* Uses this vao
*/
VertexArrayObject.prototype.activate = function()
{
var gl = this.gl;
var lastBuffer = null;
for (var i = 0; i < this.attributes.length; i++)
{
var attrib = this.attributes[i];
if(lastBuffer !== attrib.buffer)
{
attrib.buffer.bind();
lastBuffer = attrib.buffer;
}
gl.vertexAttribPointer(attrib.attribute.location,
attrib.attribute.size,
attrib.type || gl.FLOAT,
attrib.normalized || false,
attrib.stride || 0,
attrib.start || 0);
}
setVertexAttribArrays(gl, this.attributes, this.nativeState);
if(this.indexBuffer)
{
this.indexBuffer.bind();
}
return this;
};
/**
*
* @param buffer {PIXI.gl.GLBuffer}
* @param attribute {*}
* @param type {String}
* @param normalized {Boolean}
* @param stride {Number}
* @param start {Number}
*/
VertexArrayObject.prototype.addAttribute = function(buffer, attribute, type, normalized, stride, start)
{
this.attributes.push({
buffer: buffer,
attribute: attribute,
location: attribute.location,
type: type || this.gl.FLOAT,
normalized: normalized || false,
stride: stride || 0,
start: start || 0
});
this.dirty = true;
return this;
};
/**
*
* @param buffer {PIXI.gl.GLBuffer}
*/
VertexArrayObject.prototype.addIndex = function(buffer/*, options*/)
{
this.indexBuffer = buffer;
this.dirty = true;
return this;
};
/**
* Unbinds this vao and disables it
*/
VertexArrayObject.prototype.clear = function()
{
// var gl = this.gl;
// TODO - should this function unbind after clear?
// for now, no but lets see what happens in the real world!
if(this.nativeVao)
{
this.nativeVaoExtension.bindVertexArrayOES(this.nativeVao);
}
this.attributes.length = 0;
this.indexBuffer = null;
return this;
};
/**
* @param type {Number}
* @param size {Number}
* @param start {Number}
*/
VertexArrayObject.prototype.draw = function(type, size, start)
{
var gl = this.gl;
if(this.indexBuffer)
{
gl.drawElements(type, size || this.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2 );
}
else
{
// TODO need a better way to calculate size..
gl.drawArrays(type, start, size || this.getSize());
}
return this;
};
/**
* Destroy this vao
*/
VertexArrayObject.prototype.destroy = function()
{
// lose references
this.gl = null;
this.indexBuffer = null;
this.attributes = null;
this.nativeState = null;
if(this.nativeVao)
{
this.nativeVaoExtension.deleteVertexArrayOES(this.nativeVao);
}
this.nativeVaoExtension = null;
this.nativeVao = null;
};
VertexArrayObject.prototype.getSize = function()
{
var attrib = this.attributes[0];
return attrib.buffer.data.length / (( attrib.stride/4 ) || attrib.attribute.size);
};
},{"./setVertexAttribArrays":7}],6:[function(require,module,exports){
/**
* Helper class to create a webGL Context
*
* @class
* @memberof PIXI.glCore
* @param canvas {HTMLCanvasElement} the canvas element that we will get the context from
* @param options {Object} An options object that gets passed in to the canvas element containing the context attributes,
* see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext for the options available
* @return {WebGLRenderingContext} the WebGL context
*/
var createContext = function(canvas, options)
{
var gl = canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
{
// fail, not able to get a context
throw new Error('This browser does not support webGL. Try using the canvas renderer');
}
return gl;
};
module.exports = createContext;
},{}],7:[function(require,module,exports){
// var GL_MAP = {};
/**
* @param gl {WebGLRenderingContext} The current WebGL context
* @param attribs {*}
* @param state {*}
*/
var setVertexAttribArrays = function (gl, attribs, state)
{
var i;
if(state)
{
var tempAttribState = state.tempAttribState,
attribState = state.attribState;
for (i = 0; i < tempAttribState.length; i++)
{
tempAttribState[i] = false;
}
// set the new attribs
for (i = 0; i < attribs.length; i++)
{
tempAttribState[attribs[i].attribute.location] = true;
}
for (i = 0; i < attribState.length; i++)
{
if (attribState[i] !== tempAttribState[i])
{
attribState[i] = tempAttribState[i];
if (state.attribState[i])
{
gl.enableVertexAttribArray(i);
}
else
{
gl.disableVertexAttribArray(i);
}
}
}
}
else
{
for (i = 0; i < attribs.length; i++)
{
var attrib = attribs[i];
gl.enableVertexAttribArray(attrib.attribute.location);
}
}
};
module.exports = setVertexAttribArrays;
},{}],8:[function(require,module,exports){
/**
* @class
* @memberof PIXI.glCore.shader
* @param gl {WebGLRenderingContext} The current WebGL context {WebGLProgram}
* @param vertexSrc {string|string[]} The vertex shader source as an array of strings.
* @param fragmentSrc {string|string[]} The fragment shader source as an array of strings.
* @param attributeLocations {Object} An attribute location map that lets you manually set the attribute locations
* @return {WebGLProgram} the shader program
*/
var compileProgram = function(gl, vertexSrc, fragmentSrc, attributeLocations)
{
var glVertShader = compileShader(gl, gl.VERTEX_SHADER, vertexSrc);
var glFragShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSrc);
var program = gl.createProgram();
gl.attachShader(program, glVertShader);
gl.attachShader(program, glFragShader);
// optionally, set the attributes manually for the program rather than letting WebGL decide..
if(attributeLocations)
{
for(var i in attributeLocations)
{
gl.bindAttribLocation(program, attributeLocations[i], i);
}
}
gl.linkProgram(program);
// if linking fails, then log and cleanup
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
{
console.error('Pixi.js Error: Could not initialize shader.');
console.error('gl.VALIDATE_STATUS', gl.getProgramParameter(program, gl.VALIDATE_STATUS));
console.error('gl.getError()', gl.getError());
// if there is a program info log, log it
if (gl.getProgramInfoLog(program) !== '')
{
console.warn('Pixi.js Warning: gl.getProgramInfoLog()', gl.getProgramInfoLog(program));
}
gl.deleteProgram(program);
program = null;
}
// clean up some shaders
gl.deleteShader(glVertShader);
gl.deleteShader(glFragShader);
return program;
};
/**
* @private
* @param gl {WebGLRenderingContext} The current WebGL context {WebGLProgram}
* @param type {Number} the type, can be either VERTEX_SHADER or FRAGMENT_SHADER
* @param vertexSrc {string|string[]} The vertex shader source as an array of strings.
* @return {WebGLShader} the shader
*/
var compileShader = function (gl, type, src)
{
var shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
{
console.log(gl.getShaderInfoLog(shader));
return null;
}
return shader;
};
module.exports = compileProgram;
},{}],9:[function(require,module,exports){
/**
* @class
* @memberof PIXI.glCore.shader
* @param type {String} Type of value
* @param size {Number}
*/
var defaultValue = function(type, size)
{
switch (type)
{
case 'float':
return 0;
case 'vec2':
return new Float32Array(2 * size);
case 'vec3':
return new Float32Array(3 * size);
case 'vec4':
return new Float32Array(4 * size);
case 'int':
case 'sampler2D':
return 0;
case 'ivec2':
return new Int32Array(2 * size);
case 'ivec3':
return new Int32Array(3 * size);
case 'ivec4':
return new Int32Array(4 * size);
case 'bool':
return false;
case 'bvec2':
return booleanArray( 2 * size);
case 'bvec3':
return booleanArray(3 * size);
case 'bvec4':
return booleanArray(4 * size);
case 'mat2':
return new Float32Array([1, 0,
0, 1]);
case 'mat3':
return new Float32Array([1, 0, 0,
0, 1, 0,
0, 0, 1]);
case 'mat4':
return new Float32Array([1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1]);
}
};
var booleanArray = function(size)
{
var array = new Array(size);
for (var i = 0; i < array.length; i++)
{
array[i] = false;
}
return array;
};
module.exports = defaultValue;
},{}],10:[function(require,module,exports){
var mapType = require('./mapType');
var mapSize = require('./mapSize');
/**
* Extracts the attributes
* @class
* @memberof PIXI.glCore.shader
* @param gl {WebGLRenderingContext} The current WebGL rendering context
* @param program {WebGLProgram} The shader program to get the attributes from
* @return attributes {Object}
*/
var extractAttributes = function(gl, program)
{
var attributes = {};
var totalAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
for (var i = 0; i < totalAttributes; i++)
{
var attribData = gl.getActiveAttrib(program, i);
var type = mapType(gl, attribData.type);
attributes[attribData.name] = {
type:type,
size:mapSize(type),
location:gl.getAttribLocation(program, attribData.name),
//TODO - make an attribute object
pointer: pointer
};
}
return attributes;
};
var pointer = function(type, normalized, stride, start){
// console.log(this.location)
gl.vertexAttribPointer(this.location,this.size, type || gl.FLOAT, normalized || false, stride || 0, start || 0);
};
module.exports = extractAttributes;
},{"./mapSize":14,"./mapType":15}],11:[function(require,module,exports){
var mapType = require('./mapType');
var defaultValue = require('./defaultValue');
/**
* Extracts the uniforms
* @class
* @memberof PIXI.glCore.shader
* @param gl {WebGLRenderingContext} The current WebGL rendering context
* @param program {WebGLProgram} The shader program to get the uniforms from
* @return uniforms {Object}
*/
var extractUniforms = function(gl, program)
{
var uniforms = {};
var totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
for (var i = 0; i < totalUniforms; i++)
{
var uniformData = gl.getActiveUniform(program, i);
var name = uniformData.name.replace(/\[.*?\]/, "");
var type = mapType(gl, uniformData.type );
uniforms[name] = {
type:type,
size:uniformData.size,
location:gl.getUniformLocation(program, name),
value:defaultValue(type, uniformData.size)
};
}
return uniforms;
};
module.exports = extractUniforms;
},{"./defaultValue":9,"./mapType":15}],12:[function(require,module,exports){
/**
* Extracts the attributes
* @class
* @memberof PIXI.glCore.shader
* @param gl {WebGLRenderingContext} The current WebGL rendering context
* @param uniforms {Array} @mat ?
* @return attributes {Object}
*/
var generateUniformAccessObject = function(gl, uniformData)
{
// this is the object we will be sending back.
// an object hierachy will be created for structs
var uniforms = {data:{}};
uniforms.gl = gl;
var uniformKeys= Object.keys(uniformData);
for (var i = 0; i < uniformKeys.length; i++)
{
var fullName = uniformKeys[i];
var nameTokens = fullName.split('.');
var name = nameTokens[nameTokens.length - 1];
var uniformGroup = getUniformGroup(nameTokens, uniforms);
var uniform = uniformData[fullName];
uniformGroup.data[name] = uniform;
uniformGroup.gl = gl;
Object.defineProperty(uniformGroup, name, {
get: generateGetter(name),
set: generateSetter(name, uniform)
});
}
return uniforms;
};
var generateGetter = function(name)
{
return function() {
return this.data[name].value;
};
};
var GLSL_SINGLE_SETTERS = {
float: function setSingleFloat(gl, location, value) { gl.uniform1f(location, value); },
vec2: function setSingleVec2(gl, location, value) { gl.uniform2f(location, value[0], value[1]); },
vec3: function setSingleVec3(gl, location, value) { gl.uniform3f(location, value[0], value[1], value[2]); },
vec4: function setSingleVec4(gl, location, value) { gl.uniform4f(location, value[0], value[1], value[2], value[3]); },
int: function setSingleInt(gl, location, value) { gl.uniform1i(location, value); },
ivec2: function setSingleIvec2(gl, location, value) { gl.uniform2i(location, value[0], value[1]); },
ivec3: function setSingleIvec3(gl, location, value) { gl.uniform3i(location, value[0], value[1], value[2]); },
ivec4: function setSingleIvec4(gl, location, value) { gl.uniform4i(location, value[0], value[1], value[2], value[3]); },
bool: function setSingleBool(gl, location, value) { gl.uniform1i(location, value); },
bvec2: function setSingleBvec2(gl, location, value) { gl.uniform2i(location, value[0], value[1]); },
bvec3: function setSingleBvec3(gl, location, value) { gl.uniform3i(location, value[0], value[1], value[2]); },
bvec4: function setSingleBvec4(gl, location, value) { gl.uniform4i(location, value[0], value[1], value[2], value[3]); },
mat2: function setSingleMat2(gl, location, value) { gl.uniformMatrix2fv(location, false, value); },
mat3: function setSingleMat3(gl, location, value) { gl.uniformMatrix3fv(location, false, value); },
mat4: function setSingleMat4(gl, location, value) { gl.uniformMatrix4fv(location, false, value); },
sampler2D: function setSingleSampler2D(gl, location, value) { gl.uniform1i(location, value); },
};
var GLSL_ARRAY_SETTERS = {
float: function setFloatArray(gl, location, value) { gl.uniform1fv(location, value); },
vec2: function setVec2Array(gl, location, value) { gl.uniform2fv(location, value); },
vec3: function setVec3Array(gl, location, value) { gl.uniform3fv(location, value); },
vec4: function setVec4Array(gl, location, value) { gl.uniform4fv(location, value); },
int: function setIntArray(gl, location, value) { gl.uniform1iv(location, value); },
ivec2: function setIvec2Array(gl, location, value) { gl.uniform2iv(location, value); },
ivec3: function setIvec3Array(gl, location, value) { gl.uniform3iv(location, value); },
ivec4: function setIvec4Array(gl, location, value) { gl.uniform4iv(location, value); },
bool: function setBoolArray(gl, location, value) { gl.uniform1iv(location, value); },
bvec2: function setBvec2Array(gl, location, value) { gl.uniform2iv(location, value); },
bvec3: function setBvec3Array(gl, location, value) { gl.uniform3iv(location, value); },
bvec4: function setBvec4Array(gl, location, value) { gl.uniform4iv(location, value); },
sampler2D: function setSampler2DArray(gl, location, value) { gl.uniform1iv(location, value); },
};
function generateSetter(name, uniform)
{
return function(value) {
this.data[name].value = value;
var location = this.data[name].location;
if (uniform.size === 1)
{
GLSL_SINGLE_SETTERS[uniform.type](this.gl, location, value);
}
else
{
// glslSetArray(gl, location, type, value) {
GLSL_ARRAY_SETTERS[uniform.type](this.gl, location, value);
}
};
}
function getUniformGroup(nameTokens, uniform)
{
var cur = uniform;
for (var i = 0; i < nameTokens.length - 1; i++)
{
var o = cur[nameTokens[i]] || {data:{}};
cur[nameTokens[i]] = o;
cur = o;
}
return cur;
}
module.exports = generateUniformAccessObject;
},{}],13:[function(require,module,exports){
module.exports = {
compileProgram: require('./compileProgram'),
defaultValue: require('./defaultValue'),
extractAttributes: require('./extractAttributes'),
extractUniforms: require('./extractUniforms'),
generateUniformAccessObject: require('./generateUniformAccessObject'),
setPrecision: require('./setPrecision'),
mapSize: require('./mapSize'),
mapType: require('./mapType')
};
},{"./compileProgram":8,"./defaultValue":9,"./extractAttributes":10,"./extractUniforms":11,"./generateUniformAccessObject":12,"./mapSize":14,"./mapType":15,"./setPrecision":16}],14:[function(require,module,exports){
/**
* @class
* @memberof PIXI.glCore.shader
* @param type {String}
* @return {Number}
*/
var mapSize = function(type)
{
return GLSL_TO_SIZE[type];
};
var GLSL_TO_SIZE = {
'float': 1,
'vec2': 2,
'vec3': 3,
'vec4': 4,
'int': 1,
'ivec2': 2,
'ivec3': 3,
'ivec4': 4,
'bool': 1,
'bvec2': 2,
'bvec3': 3,
'bvec4': 4,
'mat2': 4,
'mat3': 9,
'mat4': 16,
'sampler2D': 1
};
module.exports = mapSize;
},{}],15:[function(require,module,exports){
var mapType = function(gl, type)
{
if(!GL_TABLE)
{
var typeNames = Object.keys(GL_TO_GLSL_TYPES);
GL_TABLE = {};
for(var i = 0; i < typeNames.length; ++i)
{
var tn = typeNames[i];
GL_TABLE[ gl[tn] ] = GL_TO_GLSL_TYPES[tn];
}
}
return GL_TABLE[type];
};
var GL_TABLE = null;
var GL_TO_GLSL_TYPES = {
'FLOAT': 'float',
'FLOAT_VEC2': 'vec2',
'FLOAT_VEC3': 'vec3',
'FLOAT_VEC4': 'vec4',
'INT': 'int',
'INT_VEC2': 'ivec2',
'INT_VEC3': 'ivec3',
'INT_VEC4': 'ivec4',
'BOOL': 'bool',
'BOOL_VEC2': 'bvec2',
'BOOL_VEC3': 'bvec3',
'BOOL_VEC4': 'bvec4',
'FLOAT_MAT2': 'mat2',
'FLOAT_MAT3': 'mat3',
'FLOAT_MAT4': 'mat4',
'SAMPLER_2D': 'sampler2D'
};
module.exports = mapType;
},{}],16:[function(require,module,exports){
/**
* Sets the float precision on the shader. If the precision is already present this function will do nothing
* @param {string} src the shader source
* @param {string} precision The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'.
*
* @return {string} modified shader source
*/
var setPrecision = function(src, precision)
{
if(src.substring(0, 9) !== 'precision')
{
return 'precision ' + precision + ' float;\n' + src;
}
return src;
};
module.exports = setPrecision;
},{}],17:[function(require,module,exports){
var gl = {
createContext: require('./createContext'),
setVertexAttribArrays: require('./setVertexAttribArrays'),
GLBuffer: require('./GLBuffer'),
GLFramebuffer: require('./GLFramebuffer'),
GLShader: require('./GLShader'),
GLTexture: require('./GLTexture'),
VertexArrayObject: require('./VertexArrayObject'),
shader: require('./shader')
};
// Export for Node-compatible environments
if (typeof module !== 'undefined' && module.exports)
{
// Export the module
module.exports = gl;
}
// Add to the browser window pixi.gl
if (typeof window !== 'undefined')
{
// add the window object
window.PIXI = window.PIXI || {};
window.PIXI.glCore = gl;
}
},{"./GLBuffer":1,"./GLFramebuffer":2,"./GLShader":3,"./GLTexture":4,"./VertexArrayObject":5,"./createContext":6,"./setVertexAttribArrays":7,"./shader":13}]},{},[17])(17)
});
//# sourceMappingURL=pixi-gl-core.js.map