Texture.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. * @author alteredq / http://alteredqualia.com/
  4. * @author szimek / https://github.com/szimek/
  5. */
  6. import { EventDispatcher } from '../core/EventDispatcher.js';
  7. import {
  8. MirroredRepeatWrapping,
  9. ClampToEdgeWrapping,
  10. RepeatWrapping,
  11. LinearEncoding,
  12. UnsignedByteType,
  13. RGBAFormat,
  14. LinearMipMapLinearFilter,
  15. LinearFilter,
  16. UVMapping
  17. } from '../constants.js';
  18. import { _Math } from '../math/Math.js';
  19. import { Vector2 } from '../math/Vector2.js';
  20. import { Matrix3 } from '../math/Matrix3.js';
  21. import { ImageUtils } from '../extras/ImageUtils.js';
  22. var textureId = 0;
  23. function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
  24. Object.defineProperty( this, 'id', { value: textureId ++ } );
  25. this.uuid = _Math.generateUUID();
  26. this.name = '';
  27. this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
  28. this.mipmaps = [];
  29. this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
  30. this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
  31. this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
  32. this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
  33. this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
  34. this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
  35. this.format = format !== undefined ? format : RGBAFormat;
  36. this.type = type !== undefined ? type : UnsignedByteType;
  37. this.offset = new Vector2( 0, 0 );
  38. this.repeat = new Vector2( 1, 1 );
  39. this.center = new Vector2( 0, 0 );
  40. this.rotation = 0;
  41. this.matrixAutoUpdate = true;
  42. this.matrix = new Matrix3();
  43. this.generateMipmaps = true;
  44. this.premultiplyAlpha = false;
  45. this.flipY = true;
  46. this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
  47. // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
  48. //
  49. // Also changing the encoding after already used by a Material will not automatically make the Material
  50. // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
  51. this.encoding = encoding !== undefined ? encoding : LinearEncoding;
  52. this.version = 0;
  53. this.onUpdate = null;
  54. }
  55. Texture.DEFAULT_IMAGE = undefined;
  56. Texture.DEFAULT_MAPPING = UVMapping;
  57. Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
  58. constructor: Texture,
  59. isTexture: true,
  60. updateMatrix: function () {
  61. this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
  62. },
  63. clone: function () {
  64. return new this.constructor().copy( this );
  65. },
  66. copy: function ( source ) {
  67. this.name = source.name;
  68. this.image = source.image;
  69. this.mipmaps = source.mipmaps.slice( 0 );
  70. this.mapping = source.mapping;
  71. this.wrapS = source.wrapS;
  72. this.wrapT = source.wrapT;
  73. this.magFilter = source.magFilter;
  74. this.minFilter = source.minFilter;
  75. this.anisotropy = source.anisotropy;
  76. this.format = source.format;
  77. this.type = source.type;
  78. this.offset.copy( source.offset );
  79. this.repeat.copy( source.repeat );
  80. this.center.copy( source.center );
  81. this.rotation = source.rotation;
  82. this.matrixAutoUpdate = source.matrixAutoUpdate;
  83. this.matrix.copy( source.matrix );
  84. this.generateMipmaps = source.generateMipmaps;
  85. this.premultiplyAlpha = source.premultiplyAlpha;
  86. this.flipY = source.flipY;
  87. this.unpackAlignment = source.unpackAlignment;
  88. this.encoding = source.encoding;
  89. return this;
  90. },
  91. toJSON: function ( meta ) {
  92. var isRootObject = ( meta === undefined || typeof meta === 'string' );
  93. if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
  94. return meta.textures[ this.uuid ];
  95. }
  96. var output = {
  97. metadata: {
  98. version: 4.5,
  99. type: 'Texture',
  100. generator: 'Texture.toJSON'
  101. },
  102. uuid: this.uuid,
  103. name: this.name,
  104. mapping: this.mapping,
  105. repeat: [ this.repeat.x, this.repeat.y ],
  106. offset: [ this.offset.x, this.offset.y ],
  107. center: [ this.center.x, this.center.y ],
  108. rotation: this.rotation,
  109. wrap: [ this.wrapS, this.wrapT ],
  110. format: this.format,
  111. type: this.type,
  112. encoding: this.encoding,
  113. minFilter: this.minFilter,
  114. magFilter: this.magFilter,
  115. anisotropy: this.anisotropy,
  116. flipY: this.flipY,
  117. premultiplyAlpha: this.premultiplyAlpha,
  118. unpackAlignment: this.unpackAlignment
  119. };
  120. if ( this.image !== undefined ) {
  121. // TODO: Move to THREE.Image
  122. var image = this.image;
  123. if ( image.uuid === undefined ) {
  124. image.uuid = _Math.generateUUID(); // UGH
  125. }
  126. if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
  127. var url;
  128. if ( Array.isArray( image ) ) {
  129. // process array of images e.g. CubeTexture
  130. url = [];
  131. for ( var i = 0, l = image.length; i < l; i ++ ) {
  132. url.push( ImageUtils.getDataURL( image[ i ] ) );
  133. }
  134. } else {
  135. // process single image
  136. url = ImageUtils.getDataURL( image );
  137. }
  138. meta.images[ image.uuid ] = {
  139. uuid: image.uuid,
  140. url: url
  141. };
  142. }
  143. output.image = image.uuid;
  144. }
  145. if ( ! isRootObject ) {
  146. meta.textures[ this.uuid ] = output;
  147. }
  148. return output;
  149. },
  150. dispose: function () {
  151. this.dispatchEvent( { type: 'dispose' } );
  152. },
  153. transformUv: function ( uv ) {
  154. if ( this.mapping !== UVMapping ) return uv;
  155. uv.applyMatrix3( this.matrix );
  156. if ( uv.x < 0 || uv.x > 1 ) {
  157. switch ( this.wrapS ) {
  158. case RepeatWrapping:
  159. uv.x = uv.x - Math.floor( uv.x );
  160. break;
  161. case ClampToEdgeWrapping:
  162. uv.x = uv.x < 0 ? 0 : 1;
  163. break;
  164. case MirroredRepeatWrapping:
  165. if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
  166. uv.x = Math.ceil( uv.x ) - uv.x;
  167. } else {
  168. uv.x = uv.x - Math.floor( uv.x );
  169. }
  170. break;
  171. }
  172. }
  173. if ( uv.y < 0 || uv.y > 1 ) {
  174. switch ( this.wrapT ) {
  175. case RepeatWrapping:
  176. uv.y = uv.y - Math.floor( uv.y );
  177. break;
  178. case ClampToEdgeWrapping:
  179. uv.y = uv.y < 0 ? 0 : 1;
  180. break;
  181. case MirroredRepeatWrapping:
  182. if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
  183. uv.y = Math.ceil( uv.y ) - uv.y;
  184. } else {
  185. uv.y = uv.y - Math.floor( uv.y );
  186. }
  187. break;
  188. }
  189. }
  190. if ( this.flipY ) {
  191. uv.y = 1 - uv.y;
  192. }
  193. return uv;
  194. }
  195. } );
  196. Object.defineProperty( Texture.prototype, "needsUpdate", {
  197. set: function ( value ) {
  198. if ( value === true ) this.version ++;
  199. }
  200. } );
  201. export { Texture };