Source: render/Texture.js

  1. /*
  2. * Copyright 2003-2006, 2009, 2017, 2020 United States Government, as represented
  3. * by the Administrator of the National Aeronautics and Space Administration.
  4. * All rights reserved.
  5. *
  6. * The NASAWorldWind/WebWorldWind platform is licensed under the Apache License,
  7. * Version 2.0 (the "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License
  9. * at http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed
  12. * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  13. * CONDITIONS OF ANY KIND, either express or implied. See the License for the
  14. * specific language governing permissions and limitations under the License.
  15. *
  16. * NASAWorldWind/WebWorldWind also contains the following 3rd party Open Source
  17. * software:
  18. *
  19. * ES6-Promise – under MIT License
  20. * libtess.js – SGI Free Software License B
  21. * Proj4 – under MIT License
  22. * JSZip – under MIT License
  23. *
  24. * A complete listing of 3rd Party software notices and licenses included in
  25. * WebWorldWind can be found in the WebWorldWind 3rd-party notices and licenses
  26. * PDF found in code directory.
  27. */
  28. /**
  29. * @exports Texture
  30. */
  31. define([
  32. '../error/ArgumentError',
  33. '../util/Logger',
  34. '../util/WWMath'
  35. ],
  36. function (ArgumentError,
  37. Logger,
  38. WWMath) {
  39. "use strict";
  40. /**
  41. * Constructs a texture for a specified image.
  42. * @alias Texture
  43. * @constructor
  44. * @classdesc Represents a WebGL texture. Applications typically do not interact with this class.
  45. * @param {WebGLRenderingContext} gl The current WebGL rendering context.
  46. * @param {Image} image The texture's image.
  47. * @param {GLenum} wrapMode Optional. Specifies the wrap mode of the texture. Defaults to gl.CLAMP_TO_EDGE
  48. * @throws {ArgumentError} If the specified WebGL context or image is null or undefined.
  49. */
  50. var Texture = function (gl, image, wrapMode) {
  51. if (!gl) {
  52. throw new ArgumentError(Logger.logMessage(Logger.LEVEL_SEVERE, "Texture", "constructor",
  53. "missingGlContext"));
  54. }
  55. if (!image) {
  56. throw new ArgumentError(Logger.logMessage(Logger.LEVEL_SEVERE, "Texture", "constructor",
  57. "missingImage"));
  58. }
  59. if (!wrapMode) {
  60. wrapMode = gl.CLAMP_TO_EDGE;
  61. }
  62. var textureId = gl.createTexture(),
  63. isPowerOfTwo = (WWMath.isPowerOfTwo(image.width) && WWMath.isPowerOfTwo(image.height));
  64. this.originalImageWidth = image.width;
  65. this.originalImageHeight = image.height;
  66. if (wrapMode === gl.REPEAT && !isPowerOfTwo) {
  67. image = this.resizeImage(image);
  68. isPowerOfTwo = true;
  69. }
  70. this.imageWidth = image.width;
  71. this.imageHeight = image.height;
  72. this.size = image.width * image.height * 4;
  73. gl.bindTexture(gl.TEXTURE_2D, textureId);
  74. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
  75. isPowerOfTwo ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
  76. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapMode);
  77. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapMode);
  78. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
  79. gl.texImage2D(gl.TEXTURE_2D, 0,
  80. gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  81. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0);
  82. if (isPowerOfTwo) {
  83. gl.generateMipmap(gl.TEXTURE_2D);
  84. }
  85. this.textureId = textureId;
  86. /**
  87. * The time at which this texture was created.
  88. * @type {Date}
  89. */
  90. this.creationTime = new Date();
  91. // Internal use only. Intentionally not documented.
  92. this.texParameters = {};
  93. // Internal use only. Intentionally not documented.
  94. // https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotrop
  95. this.anisotropicFilterExt = (gl.getExtension("EXT_texture_filter_anisotropic") ||
  96. gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic"));
  97. };
  98. /**
  99. * Sets a texture parameter to apply when binding this texture.
  100. *
  101. * Currently only gl.TEXTURE_MAG_FILTER has an effect.
  102. *
  103. * @param {Glenum} name The name of the parameter
  104. * @param {GLint} value The value for this parameter
  105. */
  106. Texture.prototype.setTexParameter = function (name, value) {
  107. this.texParameters[name] = value;
  108. };
  109. /**
  110. * Returns the value of a texture parameter to be assigned to this texture.
  111. * @param {Glenum} name The name of the parameter
  112. * @returns {GLint} The value for this parameter
  113. */
  114. Texture.prototype.getTexParameter = function (name) {
  115. return this.texParameters[name];
  116. };
  117. /**
  118. * Clears the list of texture parameters to apply when binding this texture.
  119. */
  120. Texture.prototype.clearTexParameters = function () {
  121. this.texParameters = {};
  122. };
  123. /**
  124. * Disposes of the WebGL texture object associated with this texture.
  125. * @param gl
  126. */
  127. Texture.prototype.dispose = function (gl) {
  128. gl.deleteTexture(this.textureId);
  129. delete this.textureId;
  130. };
  131. /**
  132. * Binds this texture in the current WebGL graphics context.
  133. * @param {DrawContext} dc The current draw context.
  134. */
  135. Texture.prototype.bind = function (dc) {
  136. var gl = dc.currentGlContext;
  137. gl.bindTexture(gl.TEXTURE_2D, this.textureId);
  138. this.applyTexParameters(dc);
  139. dc.frameStatistics.incrementTextureLoadCount(1);
  140. return true;
  141. };
  142. /**
  143. * Applies the configured texture parameters to the OpenGL context.
  144. * @param {DrawContext} dc The current draw context.
  145. */
  146. Texture.prototype.applyTexParameters = function (dc) {
  147. var gl = dc.currentGlContext;
  148. // Configure the OpenGL texture magnification function. Use linear by default.
  149. var textureMagFilter = this.texParameters[gl.TEXTURE_MAG_FILTER] || gl.LINEAR;
  150. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, textureMagFilter);
  151. // Try to enable the anisotropic texture filtering only if we have a linear magnification filter.
  152. // This can't be enabled all the time because Windows seems to ignore the TEXTURE_MAG_FILTER parameter when
  153. // this extension is enabled.
  154. if (textureMagFilter === gl.LINEAR) {
  155. // Setup 4x anisotropic texture filtering when this feature is available.
  156. if (this.anisotropicFilterExt) {
  157. gl.texParameteri(gl.TEXTURE_2D, this.anisotropicFilterExt.TEXTURE_MAX_ANISOTROPY_EXT, 4);
  158. }
  159. }
  160. };
  161. /**
  162. * Resizes an image to a power of two.
  163. * @param {Image} image The image to resize.
  164. */
  165. Texture.prototype.resizeImage = function (image) {
  166. var canvas = document.createElement("canvas");
  167. canvas.width = WWMath.powerOfTwoFloor(image.width);
  168. canvas.height = WWMath.powerOfTwoFloor(image.height);
  169. var ctx = canvas.getContext("2d");
  170. ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
  171. return canvas;
  172. };
  173. return Texture;
  174. });