Texture.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. import { EventDispatcher } from '../core/EventDispatcher.js';
  2. import {
  3. MirroredRepeatWrapping,
  4. ClampToEdgeWrapping,
  5. RepeatWrapping,
  6. UnsignedByteType,
  7. RGBAFormat,
  8. LinearMipmapLinearFilter,
  9. LinearFilter,
  10. UVMapping,
  11. sRGBEncoding,
  12. SRGBColorSpace,
  13. NoColorSpace,
  14. LinearEncoding
  15. } from '../constants.js';
  16. import * as MathUtils from '../math/MathUtils.js';
  17. import { Vector2 } from '../math/Vector2.js';
  18. import { Matrix3 } from '../math/Matrix3.js';
  19. import { Source } from './Source.js';
  20. import { warnOnce } from '../utils.js';
  21. let _textureId = 0;
  22. class Texture extends EventDispatcher {
  23. constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) {
  24. super();
  25. this.isTexture = true;
  26. Object.defineProperty( this, 'id', { value: _textureId ++ } );
  27. this.uuid = MathUtils.generateUUID();
  28. this.name = '';
  29. this.source = new Source( image );
  30. this.mipmaps = [];
  31. this.mapping = mapping;
  32. this.channel = 0;
  33. this.wrapS = wrapS;
  34. this.wrapT = wrapT;
  35. this.magFilter = magFilter;
  36. this.minFilter = minFilter;
  37. this.anisotropy = anisotropy;
  38. this.format = format;
  39. this.internalFormat = null;
  40. this.type = type;
  41. this.offset = new Vector2( 0, 0 );
  42. this.repeat = new Vector2( 1, 1 );
  43. this.center = new Vector2( 0, 0 );
  44. this.rotation = 0;
  45. this.matrixAutoUpdate = true;
  46. this.matrix = new Matrix3();
  47. this.generateMipmaps = true;
  48. this.premultiplyAlpha = false;
  49. this.flipY = true;
  50. this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
  51. if ( typeof colorSpace === 'string' ) {
  52. this.colorSpace = colorSpace;
  53. } else { // @deprecated, r152
  54. warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
  55. this.colorSpace = colorSpace === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
  56. }
  57. this.userData = {};
  58. this.version = 0;
  59. this.onUpdate = null;
  60. this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not
  61. this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures)
  62. }
  63. get image() {
  64. return this.source.data;
  65. }
  66. set image( value = null ) {
  67. this.source.data = value;
  68. }
  69. updateMatrix() {
  70. this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
  71. }
  72. clone() {
  73. return new this.constructor().copy( this );
  74. }
  75. copy( source ) {
  76. this.name = source.name;
  77. this.source = source.source;
  78. this.mipmaps = source.mipmaps.slice( 0 );
  79. this.mapping = source.mapping;
  80. this.channel = source.channel;
  81. this.wrapS = source.wrapS;
  82. this.wrapT = source.wrapT;
  83. this.magFilter = source.magFilter;
  84. this.minFilter = source.minFilter;
  85. this.anisotropy = source.anisotropy;
  86. this.format = source.format;
  87. this.internalFormat = source.internalFormat;
  88. this.type = source.type;
  89. this.offset.copy( source.offset );
  90. this.repeat.copy( source.repeat );
  91. this.center.copy( source.center );
  92. this.rotation = source.rotation;
  93. this.matrixAutoUpdate = source.matrixAutoUpdate;
  94. this.matrix.copy( source.matrix );
  95. this.generateMipmaps = source.generateMipmaps;
  96. this.premultiplyAlpha = source.premultiplyAlpha;
  97. this.flipY = source.flipY;
  98. this.unpackAlignment = source.unpackAlignment;
  99. this.colorSpace = source.colorSpace;
  100. this.userData = JSON.parse( JSON.stringify( source.userData ) );
  101. this.needsUpdate = true;
  102. return this;
  103. }
  104. toJSON( meta ) {
  105. const isRootObject = ( meta === undefined || typeof meta === 'string' );
  106. if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
  107. return meta.textures[ this.uuid ];
  108. }
  109. const output = {
  110. metadata: {
  111. version: 4.6,
  112. type: 'Texture',
  113. generator: 'Texture.toJSON'
  114. },
  115. uuid: this.uuid,
  116. name: this.name,
  117. image: this.source.toJSON( meta ).uuid,
  118. mapping: this.mapping,
  119. channel: this.channel,
  120. repeat: [ this.repeat.x, this.repeat.y ],
  121. offset: [ this.offset.x, this.offset.y ],
  122. center: [ this.center.x, this.center.y ],
  123. rotation: this.rotation,
  124. wrap: [ this.wrapS, this.wrapT ],
  125. format: this.format,
  126. internalFormat: this.internalFormat,
  127. type: this.type,
  128. colorSpace: this.colorSpace,
  129. minFilter: this.minFilter,
  130. magFilter: this.magFilter,
  131. anisotropy: this.anisotropy,
  132. flipY: this.flipY,
  133. generateMipmaps: this.generateMipmaps,
  134. premultiplyAlpha: this.premultiplyAlpha,
  135. unpackAlignment: this.unpackAlignment
  136. };
  137. if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData;
  138. if ( ! isRootObject ) {
  139. meta.textures[ this.uuid ] = output;
  140. }
  141. return output;
  142. }
  143. dispose() {
  144. this.dispatchEvent( { type: 'dispose' } );
  145. }
  146. transformUv( uv ) {
  147. if ( this.mapping !== UVMapping ) return uv;
  148. uv.applyMatrix3( this.matrix );
  149. if ( uv.x < 0 || uv.x > 1 ) {
  150. switch ( this.wrapS ) {
  151. case RepeatWrapping:
  152. uv.x = uv.x - Math.floor( uv.x );
  153. break;
  154. case ClampToEdgeWrapping:
  155. uv.x = uv.x < 0 ? 0 : 1;
  156. break;
  157. case MirroredRepeatWrapping:
  158. if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
  159. uv.x = Math.ceil( uv.x ) - uv.x;
  160. } else {
  161. uv.x = uv.x - Math.floor( uv.x );
  162. }
  163. break;
  164. }
  165. }
  166. if ( uv.y < 0 || uv.y > 1 ) {
  167. switch ( this.wrapT ) {
  168. case RepeatWrapping:
  169. uv.y = uv.y - Math.floor( uv.y );
  170. break;
  171. case ClampToEdgeWrapping:
  172. uv.y = uv.y < 0 ? 0 : 1;
  173. break;
  174. case MirroredRepeatWrapping:
  175. if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
  176. uv.y = Math.ceil( uv.y ) - uv.y;
  177. } else {
  178. uv.y = uv.y - Math.floor( uv.y );
  179. }
  180. break;
  181. }
  182. }
  183. if ( this.flipY ) {
  184. uv.y = 1 - uv.y;
  185. }
  186. return uv;
  187. }
  188. set needsUpdate( value ) {
  189. if ( value === true ) {
  190. this.version ++;
  191. this.source.needsUpdate = true;
  192. }
  193. }
  194. get encoding() { // @deprecated, r152
  195. warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
  196. return this.colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding;
  197. }
  198. set encoding( encoding ) { // @deprecated, r152
  199. warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
  200. this.colorSpace = encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
  201. }
  202. }
  203. Texture.DEFAULT_IMAGE = null;
  204. Texture.DEFAULT_MAPPING = UVMapping;
  205. Texture.DEFAULT_ANISOTROPY = 1;
  206. export { Texture };