text: /*
   * Copyright 2015, Gregg Tavares.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *
   *     * Redistributions of source code must retain the above copyright
   * notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above
   * copyright notice, this list of conditions and the following disclaimer
   * in the documentation and/or other materials provided with the
   * distribution.
   *     * Neither the name of Gregg Tavares. nor the names of his
   * contributors may be used to endorse or promote products derived from
   * this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  import * as attributes from './attributes.js';
  import * as textures from './textures.js';
  import * as helper from './helper.js';
  import * as utils from './utils.js';
  
  /**
   * The main TWGL module.
   *
   * For most use cases you shouldn't need anything outside this module.
   * Exceptions between the stuff added to twgl-full (v3, m4, primitives)
   *
   * @module twgl
   * @borrows module:twgl/attributes.setAttribInfoBufferFromArray as setAttribInfoBufferFromArray
   * @borrows module:twgl/attributes.createBufferInfoFromArrays as createBufferInfoFromArrays
   * @borrows module:twgl/attributes.createVertexArrayInfo as createVertexArrayInfo
   * @borrows module:twgl/draw.drawBufferInfo as drawBufferInfo
   * @borrows module:twgl/draw.drawObjectList as drawObjectList
   * @borrows module:twgl/framebuffers.createFramebufferInfo as createFramebufferInfo
   * @borrows module:twgl/framebuffers.resizeFramebufferInfo as resizeFramebufferInfo
   * @borrows module:twgl/framebuffers.bindFramebufferInfo as bindFramebufferInfo
   * @borrows module:twgl/programs.createProgramInfo as createProgramInfo
   * @borrows module:twgl/programs.createUniformBlockInfo as createUniformBlockInfo
   * @borrows module:twgl/programs.bindUniformBlock as bindUniformBlock
   * @borrows module:twgl/programs.setUniformBlock as setUniformBlock
   * @borrows module:twgl/programs.setBlockUniforms as setBlockUniforms
   * @borrows module:twgl/programs.setUniforms as setUniforms
   * @borrows module:twgl/programs.setBuffersAndAttributes as setBuffersAndAttributes
   * @borrows module:twgl/textures.setTextureFromArray as setTextureFromArray
   * @borrows module:twgl/textures.createTexture as createTexture
   * @borrows module:twgl/textures.resizeTexture as resizeTexture
   * @borrows module:twgl/textures.createTextures as createTextures
   */
  
  // make sure we don't see a global gl
  const gl = undefined;  // eslint-disable-line
  const defaults = {
    addExtensionsToContext: true,
  };
  
  /**
   * Various default settings for twgl.
   *
   * Note: You can call this any number of times. Example:
   *
   *     twgl.setDefaults({ textureColor: [1, 0, 0, 1] });
   *     twgl.setDefaults({ attribPrefix: 'a_' });
   *
   * is equivalent to
   *
   *     twgl.setDefaults({
   *       textureColor: [1, 0, 0, 1],
   *       attribPrefix: 'a_',
   *     });
   *
   * @typedef {Object} Defaults
   * @property {string} attribPrefix The prefix to stick on attributes
   *
   *   When writing shaders I prefer to name attributes with `a_`, uniforms with `u_` and varyings with `v_`
   *   as it makes it clear where they came from. But, when building geometry I prefer using unprefixed names.
   *
   *   In otherwords I'll create arrays of geometry like this
   *
   *       const arrays = {
   *         position: ...
   *         normal: ...
   *         texcoord: ...
   *       };
   *
   *   But need those mapped to attributes and my attributes start with `a_`.
   *
   *   Default: `""`
   *
   * @property {number[]} textureColor Array of 4 values in the range 0 to 1
   *
   *   The default texture color is used when loading textures from
   *   urls. Because the URL will be loaded async we'd like to be
   *   able to use the texture immediately. By putting a 1x1 pixel
   *   color in the texture we can start using the texture before
   *   the URL has loaded.
   *
   *   Default: `[0.5, 0.75, 1, 1]`
   *
   * @property {string} crossOrigin
   *
   *   If not undefined sets the crossOrigin attribute on images
   *   that twgl creates when downloading images for textures.
   *
   *   Also see {@link module:twgl.TextureOptions}.
   *
   * @property {bool} addExtensionsToContext
   *
   *   If true, then, when twgl will try to add any supported WebGL extensions
   *   directly to the context under their normal GL names. For example
   *   if ANGLE_instances_arrays exists then twgl would enable it,
   *   add the functions `vertexAttribDivisor`, `drawArraysInstanced`,
   *   `drawElementsInstanced`, and the constant `VERTEX_ATTRIB_ARRAY_DIVISOR`
   *   to the `WebGLRenderingContext`.
   *
   * @memberOf module:twgl
   */
  
  /**
   * Sets various defaults for twgl.
   *
   * In the interest of terseness which is kind of the point
   * of twgl I've integrated a few of the older functions here
   *
   * @param {module:twgl.Defaults} newDefaults The default settings.
   * @memberOf module:twgl
   */
  function setDefaults(newDefaults) {
    helper.copyExistingProperties(newDefaults, defaults);
    attributes.setAttributeDefaults_(newDefaults);  // eslint-disable-line
    textures.setTextureDefaults_(newDefaults);  // eslint-disable-line
  }
  
  const prefixRE = /^(.*?)_/;
  function addExtensionToContext(gl, extensionName) {
    utils.glEnumToString(gl, 0);
    const ext = gl.getExtension(extensionName);
    if (ext) {
      const enums = {};
      const fnSuffix = prefixRE.exec(extensionName)[1];
      const enumSuffix = '_' + fnSuffix;
      for (const key in ext) {
        const value = ext[key];
        const isFunc = typeof (value) === 'function';
        const suffix = isFunc ? fnSuffix : enumSuffix;
        let name = key;
        // examples of where this is not true are WEBGL_compressed_texture_s3tc
        // and WEBGL_compressed_texture_pvrtc
        if (key.endsWith(suffix)) {
          name = key.substring(0, key.length - suffix.length);
        }
        if (gl[name] !== undefined) {
          if (!isFunc && gl[name] !== value) {
            helper.warn(name, gl[name], value, key);
          }
        } else {
          if (isFunc) {
            gl[name] = function(origFn) {
              return function() {
                return origFn.apply(ext, arguments);
              };
            }(value);
          } else {
            gl[name] = value;
            enums[name] = value;
          }
        }
      }
      // pass the modified enums to glEnumToString
      enums.constructor = {
        name: ext.constructor.name,
      };
      utils.glEnumToString(enums, 0);
    }
    return ext;
  }
  
  /*
   * If you're wondering why the code doesn't just iterate
   * over all extensions using `gl.getExtensions` is that it's possible
   * some future extension is incompatible with this code. Rather than
   * have thing suddenly break it seems better to manually add to this
   * list.
   *
   */
  const supportedExtensions = [
    'ANGLE_instanced_arrays',
    'EXT_blend_minmax',
    'EXT_color_buffer_float',
    'EXT_color_buffer_half_float',
    'EXT_disjoint_timer_query',
    'EXT_disjoint_timer_query_webgl2',
    'EXT_frag_depth',
    'EXT_sRGB',
    'EXT_shader_texture_lod',
    'EXT_texture_filter_anisotropic',
    'OES_element_index_uint',
    'OES_standard_derivatives',
    'OES_texture_float',
    'OES_texture_float_linear',
    'OES_texture_half_float',
    'OES_texture_half_float_linear',
    'OES_vertex_array_object',
    'WEBGL_color_buffer_float',
    'WEBGL_compressed_texture_atc',
    'WEBGL_compressed_texture_etc1',
    'WEBGL_compressed_texture_pvrtc',
    'WEBGL_compressed_texture_s3tc',
    'WEBGL_compressed_texture_s3tc_srgb',
    'WEBGL_depth_texture',
    'WEBGL_draw_buffers',
  ];
  
  /**
   * Attempts to enable all of the following extensions
   * and add their functions and constants to the
   * `WebGLRenderingContext` using their normal non-extension like names.
   *
   *      ANGLE_instanced_arrays
   *      EXT_blend_minmax
   *      EXT_color_buffer_float
   *      EXT_color_buffer_half_float
   *      EXT_disjoint_timer_query
   *      EXT_disjoint_timer_query_webgl2
   *      EXT_frag_depth
   *      EXT_sRGB
   *      EXT_shader_texture_lod
   *      EXT_texture_filter_anisotropic
   *      OES_element_index_uint
   *      OES_standard_derivatives
   *      OES_texture_float
   *      OES_texture_float_linear
   *      OES_texture_half_float
   *      OES_texture_half_float_linear
   *      OES_vertex_array_object
   *      WEBGL_color_buffer_float
   *      WEBGL_compressed_texture_atc
   *      WEBGL_compressed_texture_etc1
   *      WEBGL_compressed_texture_pvrtc
   *      WEBGL_compressed_texture_s3tc
   *      WEBGL_compressed_texture_s3tc_srgb
   *      WEBGL_depth_texture
   *      WEBGL_draw_buffers
   *
   * For example if `ANGLE_instanced_arrays` exists then the functions
   * `drawArraysInstanced`, `drawElementsInstanced`, `vertexAttribDivisor`
   * and the constant `VERTEX_ATTRIB_ARRAY_DIVISOR` are added to the
   * `WebGLRenderingContext`.
   *
   * Note that if you want to know if the extension exists you should
   * probably call `gl.getExtension` for each extension. Alternatively
   * you can check for the existance of the functions or constants that
   * are expected to be added. For example
   *
   *    if (gl.drawBuffers) {
   *      // Either WEBGL_draw_buffers was enabled OR you're running in WebGL2
   *      ....
   *
   * @param {WebGLRenderingContext} gl A WebGLRenderingContext
   * @memberOf module:twgl
   */
  function addExtensionsToContext(gl) {
    for (let ii = 0; ii < supportedExtensions.length; ++ii) {
      addExtensionToContext(gl, supportedExtensions[ii]);
    }
  }
  
  /**
   * Creates a webgl context.
   * @param {HTMLCanvasElement} canvas The canvas tag to get
   *     context from. If one is not passed in one will be
   *     created.
   * @return {WebGLRenderingContext} The created context.
   * @private
   */
  function create3DContext(canvas, opt_attribs) {
    const names = ["webgl", "experimental-webgl"];
    let context = null;
    for (let ii = 0; ii < names.length; ++ii) {
      context = canvas.getContext(names[ii], opt_attribs);
      if (context) {
        if (defaults.addExtensionsToContext) {
          addExtensionsToContext(context);
        }
        break;
      }
    }
    return context;
  }
  
  /**
   * Gets a WebGL1 context.
   *
   * Note: Will attempt to enable Vertex Array Objects
   * and add WebGL2 entry points. (unless you first set defaults with
   * `twgl.setDefaults({enableVertexArrayObjects: false})`;
   *
   * @param {HTMLCanvasElement} canvas a canvas element.
   * @param {WebGLContextCreationAttirbutes} [opt_attribs] optional webgl context creation attributes
   * @memberOf module:twgl
   */
  function getWebGLContext(canvas, opt_attribs) {
    const gl = create3DContext(canvas, opt_attribs);
    return gl;
  }
  
  /**
   * Creates a webgl context.
   *
   * Will return a WebGL2 context if possible.
   *
   * You can check if it's WebGL2 with
   *
   *     twgl.isWebGL2(gl);
   *
   * @param {HTMLCanvasElement} canvas The canvas tag to get
   *     context from. If one is not passed in one will be
   *     created.
   * @return {WebGLRenderingContext} The created context.
   */
  function createContext(canvas, opt_attribs) {
    const names = ["webgl2", "webgl", "experimental-webgl"];
    let context = null;
    for (let ii = 0; ii < names.length; ++ii) {
      context = canvas.getContext(names[ii], opt_attribs);
      if (context) {
        if (defaults.addExtensionsToContext) {
          addExtensionsToContext(context);
        }
        break;
      }
    }
    return context;
  }
  
  /**
   * Gets a WebGL context.  Will create a WebGL2 context if possible.
   *
   * You can check if it's WebGL2 with
   *
   *    function isWebGL2(gl) {
   *      return gl.getParameter(gl.VERSION).indexOf("WebGL 2.0 ") == 0;
   *    }
   *
   * Note: For a WebGL1 context will attempt to enable Vertex Array Objects
   * and add WebGL2 entry points. (unless you first set defaults with
   * `twgl.setDefaults({enableVertexArrayObjects: false})`;
   *
   * @param {HTMLCanvasElement} canvas a canvas element.
   * @param {WebGLContextCreationAttirbutes} [opt_attribs] optional webgl context creation attributes
   * @return {WebGLRenderingContext} The created context.
   * @memberOf module:twgl
   */
  function getContext(canvas, opt_attribs) {
    const gl = createContext(canvas, opt_attribs);
    return gl;
  }
  
  /**
   * Resize a canvas to match the size it's displayed.
   * @param {HTMLCanvasElement} canvas The canvas to resize.
   * @param {number} [multiplier] So you can pass in `window.devicePixelRatio` or other scale value if you want to.
   * @return {boolean} true if the canvas was resized.
   * @memberOf module:twgl
   */
  function resizeCanvasToDisplaySize(canvas, multiplier) {
    multiplier = multiplier || 1;
    multiplier = Math.max(0, multiplier);
    const width  = canvas.clientWidth  * multiplier | 0;
    const height = canvas.clientHeight * multiplier | 0;
    if (canvas.width !== width || canvas.height !== height) {
      canvas.width = width;
      canvas.height = height;
      return true;
    }
    return false;
  }
  
  export {
    addExtensionsToContext,
    getContext,
    getWebGLContext,
    resizeCanvasToDisplaySize,
    setDefaults,
  };
  
  // function notPrivate(name) {
  //   return name[name.length - 1] !== '_';
  // }
  //
  // function copyPublicProperties(src, dst) {
  //   Object.keys(src).filter(notPrivate).forEach(function(key) {
  //     dst[key] = src[key];
  //   });
  //   return dst;
  // }
  
  export * from './attributes.js';
  export * from './draw.js';
  export * from './framebuffers.js';
  export * from './programs.js';
  export * from './textures.js';
  export * from './typedarrays.js';
  export * from './utils.js';
  export * from './vertex-arrays.js';
  
  
  