function setTextureFromArray(gl, tex, src, options) {
    options = options || defaults.textureOptions;
    var target = options.target || gl.TEXTURE_2D;
    gl.bindTexture(target, tex);
    var width = options.width;
    var height = options.height;
    var depth = options.depth;
    var format = options.format || gl.RGBA;
    var internalFormat = options.internalFormat || format;
    var type = options.type || getTextureTypeForArrayType(gl, src);
    var numComponents = getNumComponentsForFormat(format);
    var numElements = src.length / numComponents;
    if (numElements % 1) {
      throw "length wrong size for format: " + glEnumToString(gl, format);
    }
    var dimensions;
    if (target === gl.TEXTURE_3D) {
      if (!width && !height && !depth) {
        var size = Math.cbrt(numElements);
        if (size % 1 !== 0) {
          throw "can't guess cube size of array of numElements: " + numElements;
        }
        width = size;
        height = size;
        depth = size;
      } else if (width && (!height || !depth)) {
        dimensions = guessDimensions(gl, target, height, depth, numElements / width);
        height = dimensions.width;
        depth = dimensions.height;
      } else if (height && (!width || !depth)) {
        dimensions = guessDimensions(gl, target, width, depth, numElements / height);
        width = dimensions.width;
        depth = dimensions.height;
      } else {
        dimensions = guessDimensions(gl, target, width, height, numElements / depth);
        width = dimensions.width;
        height = dimensions.height;
      }
    } else {
      dimensions = guessDimensions(gl, target, width, height, numElements);
      width = dimensions.width;
      height = dimensions.height;
    }
    if (!isArrayBuffer(src)) {
      var Type = typedArrays.getTypedArrayTypeForGLType(type);
      src = new Type(src);
    } else {
      if (src instanceof Uint8ClampedArray) {
        src = new Uint8Array(src.buffer);
      }
    }
    gl.pixelStorei(gl.UNPACK_ALIGNMENT, options.unpackAlignment || 1);
    savePackState(gl, options);
    if (target === gl.TEXTURE_CUBE_MAP) {
      var faceSize = numElements / 6 * numComponents;
      getCubeFacesWithNdx(gl, options).forEach(function(f) {
        var offset = faceSize * f.ndx;
        var data = src.subarray(offset, offset + faceSize);
        gl.texImage2D(f.face, 0, internalFormat, width, height, 0, format, type, data);
      });
    } else if (target === gl.TEXTURE_3D) {
      gl.texImage3D(target, 0, internalFormat, width, height, depth, 0, format, type, src);
    } else {
      gl.texImage2D(target, 0, internalFormat, width, height, 0, format, type, src);
    }
    restorePackState(gl, options);
    return {
      width: width,
      height: height,
      depth: depth,
    };
  }
Sets a texture from an array or typed array. If the width or height is not provided will attempt to
guess the size. See {@link module:twgl.TextureOptions}.
@param {WebGLRenderingContext} gl the WebGLRenderingContext
@param {WebGLTexture} tex the WebGLTexture to set parameters for
@param {(number[]|ArrayBuffer)} src An array or typed arry with texture data.
@param {module:twgl.TextureOptions} [options] A TextureOptions object with whatever parameters you want set.
  This is often the same options you passed in when you created the texture.
@memberOf module:twgl/textures