text: /*
   * Copyright 2003-2006, 2009, 2017, 2020 United States Government, as represented
   * by the Administrator of the National Aeronautics and Space Administration.
   * All rights reserved.
   *
   * The NASAWorldWind/WebWorldWind platform is licensed under the Apache License,
   * Version 2.0 (the "License"); you may not use this file except in compliance
   * with the License. You may obtain a copy of the License
   * at http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software distributed
   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
   * specific language governing permissions and limitations under the License.
   *
   * NASAWorldWind/WebWorldWind also contains the following 3rd party Open Source
   * software:
   *
   *    ES6-Promise – under MIT License
   *    libtess.js – SGI Free Software License B
   *    Proj4 – under MIT License
   *    JSZip – under MIT License
   *
   * A complete listing of 3rd Party software notices and licenses included in
   * WebWorldWind can be found in the WebWorldWind 3rd-party notices and licenses
   * PDF found in code  directory.
   */
  /**
   * @exports Texture
   */
  define([
          '../error/ArgumentError',
          '../util/Logger',
          '../util/WWMath'
      ],
      function (ArgumentError,
                Logger,
                WWMath) {
          "use strict";
  
          /**
           * Constructs a texture for a specified image.
           * @alias Texture
           * @constructor
           * @classdesc Represents a WebGL texture. Applications typically do not interact with this class.
           * @param {WebGLRenderingContext} gl The current WebGL rendering context.
           * @param {Image} image The texture's image.
           * @param {GLenum} wrapMode Optional. Specifies the wrap mode of the texture. Defaults to gl.CLAMP_TO_EDGE
           * @throws {ArgumentError} If the specified WebGL context or image is null or undefined.
           */
          var Texture = function (gl, image, wrapMode) {
  
              if (!gl) {
                  throw new ArgumentError(Logger.logMessage(Logger.LEVEL_SEVERE, "Texture", "constructor",
                      "missingGlContext"));
              }
  
              if (!image) {
                  throw new ArgumentError(Logger.logMessage(Logger.LEVEL_SEVERE, "Texture", "constructor",
                      "missingImage"));
              }
  
              if (!wrapMode) {
                  wrapMode = gl.CLAMP_TO_EDGE;
              }
  
              var textureId = gl.createTexture(),
                  isPowerOfTwo = (WWMath.isPowerOfTwo(image.width) && WWMath.isPowerOfTwo(image.height));
  
              this.originalImageWidth = image.width;
              this.originalImageHeight = image.height;
  
              if (wrapMode === gl.REPEAT && !isPowerOfTwo) {
                  image = this.resizeImage(image);
                  isPowerOfTwo = true;
              }
  
              this.imageWidth = image.width;
              this.imageHeight = image.height;
              this.size = image.width * image.height * 4;
  
              gl.bindTexture(gl.TEXTURE_2D, textureId);
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
                  isPowerOfTwo ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
  
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapMode);
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapMode);
  
              gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
              gl.texImage2D(gl.TEXTURE_2D, 0,
                  gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
              gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0);
  
              if (isPowerOfTwo) {
                  gl.generateMipmap(gl.TEXTURE_2D);
              }
  
              this.textureId = textureId;
  
              /**
               * The time at which this texture was created.
               * @type {Date}
               */
              this.creationTime = new Date();
  
              // Internal use only. Intentionally not documented.
              this.texParameters = {};
  
              // Internal use only. Intentionally not documented.
              // https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotrop
              this.anisotropicFilterExt = (gl.getExtension("EXT_texture_filter_anisotropic") ||
                                           gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic"));
          };
  
          /**
           * Sets a texture parameter to apply when binding this texture.
           *
           * Currently only gl.TEXTURE_MAG_FILTER has an effect.
           *
           * @param {Glenum} name The name of the parameter
           * @param {GLint} value The value for this parameter
           */
          Texture.prototype.setTexParameter = function (name, value) {
              this.texParameters[name] = value;
          };
  
          /**
           * Returns the value of a texture parameter to be assigned to this texture.
           * @param {Glenum} name The name of the parameter
           * @returns {GLint} The value for this parameter
           */
          Texture.prototype.getTexParameter = function (name) {
              return this.texParameters[name];
          };
  
          /**
           * Clears the list of texture parameters to apply when binding this texture.
           */
          Texture.prototype.clearTexParameters = function () {
              this.texParameters = {};
          };
  
          /**
           * Disposes of the WebGL texture object associated with this texture.
           * @param gl
           */
          Texture.prototype.dispose = function (gl) {
              gl.deleteTexture(this.textureId);
              delete this.textureId;
          };
  
          /**
           * Binds this texture in the current WebGL graphics context.
           * @param {DrawContext} dc The current draw context.
           */
          Texture.prototype.bind = function (dc) {
              var gl = dc.currentGlContext;
  
              gl.bindTexture(gl.TEXTURE_2D, this.textureId);
  
              this.applyTexParameters(dc);
  
              dc.frameStatistics.incrementTextureLoadCount(1);
              return true;
          };
  
          /**
           * Applies the configured texture parameters to the OpenGL context.
           * @param {DrawContext} dc The current draw context.
           */
          Texture.prototype.applyTexParameters = function (dc) {
              var gl = dc.currentGlContext;
  
              // Configure the OpenGL texture magnification function. Use linear by default.
              var textureMagFilter = this.texParameters[gl.TEXTURE_MAG_FILTER] || gl.LINEAR;
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, textureMagFilter);
  
              // Try to enable the anisotropic texture filtering only if we have a linear magnification filter.
              // This can't be enabled all the time because Windows seems to ignore the TEXTURE_MAG_FILTER parameter when
              // this extension is enabled.
              if (textureMagFilter === gl.LINEAR) {
                  // Setup 4x anisotropic texture filtering when this feature is available.
                  if (this.anisotropicFilterExt) {
                      gl.texParameteri(gl.TEXTURE_2D, this.anisotropicFilterExt.TEXTURE_MAX_ANISOTROPY_EXT, 4);
                  }
              }
          };
  
          /**
           * Resizes an image to a power of two.
           * @param {Image} image The image to resize.
           */
          Texture.prototype.resizeImage = function (image) {
              var canvas = document.createElement("canvas");
              canvas.width = WWMath.powerOfTwoFloor(image.width);
              canvas.height = WWMath.powerOfTwoFloor(image.height);
              var ctx = canvas.getContext("2d");
              ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
              return canvas;
          };
  
  
          return Texture;
      });