UNPKG

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
/*! * 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