Source: gfx/core/renderers/webgl/managers/ShaderManager.js

var WebGLManager = require('./WebGLManager'),
  TextureShader = require('../shaders/TextureShader'),
  ComplexPrimitiveShader = require('../shaders/ComplexPrimitiveShader'),
  PrimitiveShader = require('../shaders/PrimitiveShader'),
  utils = require('../../../utils');

/**
 * @class
 * @extends WebGLManager
 * @param renderer {WebGLRenderer} The renderer this manager works for.
 */
function ShaderManager(renderer) {
  WebGLManager.call(this, renderer);

    /**
     * @member {number}
     */
  this.maxAttibs = 10;

    /**
     * @member {any[]}
     */
  this.attribState = [];

    /**
     * @member {any[]}
     */
  this.tempAttribState = [];

  for (var i = 0; i < this.maxAttibs; i++) {
    this.attribState[i] = false;
  }

    /**
     * @member {any[]}
     */
  this.stack = [];

    /**
     * @member {number}
     * @private
     */
  this._currentId = -1;

    /**
     * @member {Shader}
     * @private
     */
  this.currentShader = null;

//    this.initPlugins();
}

ShaderManager.prototype = Object.create(WebGLManager.prototype);
ShaderManager.prototype.constructor = ShaderManager;
utils.pluginTarget.mixin(ShaderManager);

module.exports = ShaderManager;

/**
 * Called when there is a WebGL context change.
 *
 */
ShaderManager.prototype.onContextChange = function() {
  this.initPlugins();

  var gl = this.renderer.gl;

    // get the maximum number of attribute correctly as this tends to vary
  this.maxAttibs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);

  this.attribState = [];

  for (var i = 0; i < this.maxAttibs; i++) {
    this.attribState[i] = false;
  }

    // TODO - Why are these not plugins? We can't decouple primitives unless they are....
  this.defaultShader = new TextureShader(this);
  this.primitiveShader = new PrimitiveShader(this);
  this.complexPrimitiveShader = new ComplexPrimitiveShader(this);
};

/**
 * Takes the attributes given in parameters and uploads them.
 *
 * @param attribs {any[]} attribs
 */
ShaderManager.prototype.setAttribs = function(attribs) {
    // reset temp state
  var i;

  for (i = 0; i < this.tempAttribState.length; i++) {
    this.tempAttribState[i] = false;
  }

    // set the new attribs
  for (var a in attribs) {
    this.tempAttribState[attribs[a]] = true;
  }

  var gl = this.renderer.gl;

  for (i = 0; i < this.attribState.length; i++) {
    if (this.attribState[i] !== this.tempAttribState[i]) {
      this.attribState[i] = this.tempAttribState[i];

      if (this.attribState[i]) {
        gl.enableVertexAttribArray(i);
      }
      else {
        gl.disableVertexAttribArray(i);
      }
    }
  }
};

/**
 * Sets the current shader.
 *
 * @param shader {Shader} the shader to upload
 */
ShaderManager.prototype.setShader = function(shader) {
  if (this._currentId === shader.uid) {
    return false;
  }

  this._currentId = shader.uid;

  this.currentShader = shader;

  this.renderer.gl.useProgram(shader.program);
  this.setAttribs(shader.attributes);

  return true;
};

/**
 * Destroys this object.
 *
 */
ShaderManager.prototype.destroy = function() {
  this.primitiveShader.destroy();
  this.complexPrimitiveShader.destroy();
  WebGLManager.prototype.destroy.call(this);

  this.destroyPlugins();

  this.attribState = null;

  this.tempAttribState = null;
};