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 level = options.level || 0;
	    var internalFormat = options.internalFormat || options.format || gl.RGBA;
	    var formatType = getFormatAndTypeForInternalFormat(internalFormat);
	    var format = options.format || formatType.format;
	    var type = options.type || getTextureTypeForArrayType(gl, src, formatType.type);
	    if (!isArrayBuffer(src)) {
	      var Type = typedArrays.getTypedArrayTypeForGLType(type);
	      src = new Type(src);
	    } else {
	      if (src instanceof Uint8ClampedArray) {
	        src = new Uint8Array(src.buffer);
	      }
	    }
	    var bytesPerElement = getBytesPerElementForInternalFormat(internalFormat, type);
	    var numElements = src.byteLength / bytesPerElement; // TODO: check UNPACK_ALIGNMENT?
	    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;
	    }
	    gl.pixelStorei(gl.UNPACK_ALIGNMENT, options.unpackAlignment || 1);
	    savePackState(gl, options);
	    if (target === gl.TEXTURE_CUBE_MAP) {
	      (function () {
	        var elementsPerElement = bytesPerElement / src.BYTES_PER_ELEMENT;
	        var faceSize = numElements / 6 * elementsPerElement;

	        getCubeFacesWithNdx(gl, options).forEach(function (f) {
	          var offset = faceSize * f.ndx;
	          var data = src.subarray(offset, offset + faceSize);
	          gl.texImage2D(f.face, level, internalFormat, width, height, 0, format, type, data);
	        });
	      })();
	    } else if (target === gl.TEXTURE_3D) {
	      gl.texImage3D(target, level, internalFormat, width, height, depth, 0, format, type, src);
	    } else {
	      gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, src);
	    }
	    restorePackState(gl, options);
	    return {
	      width: width,
	      height: height,
	      depth: depth,
	      type: type
	    };
	  }
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[]|ArrayBufferView)} 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