text: /**
   * The MIT License (MIT)
   *
   * Copyright (c) 2015 Famous Industries Inc.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   * THE SOFTWARE.
   */
  'use strict';
  
  var types = {
    1: 'float ',
    2: 'vec2 ',
    3: 'vec3 ',
    4: 'vec4 '
  };
  
  /**
   * Traverses material to create a string of glsl code to be applied in
   * the vertex or fragment shader.
   *
   * @method
   *
   * @param {Object} material Material to be compiled.
   * @param {Number} textureSlot Next available texture slot for Mesh.
   *
   * @return {undefined} undefined
   */
  function compileMaterial(material, textureSlot) {
    var glsl = '';
    var uniforms = {};
    var varyings = {};
    var attributes = {};
    var defines = [];
    var textures = [];
  
    material.traverse(function(node, depth) {
      if (!node.chunk) return;
  
      var type = types[_getOutputLength(node)];
      var label = _makeLabel(node);
      var output = _processGLSL(node.chunk.glsl, node.inputs, textures.length + textureSlot);
  
      glsl += type + label + ' = ' + output + '\n ';
  
      if (node.uniforms) _extend(uniforms, node.uniforms);
      if (node.varyings) _extend(varyings, node.varyings);
      if (node.attributes) _extend(attributes, node.attributes);
      if (node.chunk.defines) defines.push(node.chunk.defines);
      if (node.texture) textures.push(node.texture);
    });
  
    return {
      _id: material._id,
      glsl: glsl + 'return ' + _makeLabel(material) + ';',
      defines: defines.join('\n'),
      uniforms: uniforms,
      varyings: varyings,
      attributes: attributes,
      textures: textures
    };
  }
  
  // Helper function used to infer length of the output
  // from a given material node.
  function _getOutputLength(node) {
  
    // Handle constant values
  
    if (typeof node === 'number') return 1;
    if (Array.isArray(node)) return node.length;
  
    // Handle materials
  
    var output = node.chunk.output;
    if (typeof output === 'number') return output;
  
    // Handle polymorphic output
  
    var key = node.inputs.map(function recurse(node) {
      return _getOutputLength(node);
    }).join(',');
  
    return output[key];
  }
  
  // Helper function to run replace inputs and texture tags with
  // correct glsl.
  function _processGLSL(str, inputs, textureSlot) {
    return str
      .replace(/%\d/g, function(s) {
        return _makeLabel(inputs[s[1] - 1]);
      })
      .replace(/\$TEXTURE/, 'u_textures[' + textureSlot + ']');
  }
  
  // Helper function used to create glsl definition of the
  // input material node.
  function _makeLabel(n) {
    if (Array.isArray(n)) return _arrayToVec(n);
    if (typeof n === 'object') return 'fa_' + (n._id);
    else return n.toFixed(6);
  }
  
  // Helper to copy the properties of an object onto another object.
  function _extend(a, b) {
    for (var k in b) a[k] = b[k];
  }
  
  // Helper to create glsl vector representation of a javascript array.
  function _arrayToVec(array) {
    var len = array.length;
    return 'vec' + len + '(' + array.join(',') + ')';
  }
  
  export { compileMaterial };
  