WebGLTextures.js 29.9 KB
Newer Older
M
Mr.doob 已提交
1 2 3 4
/**
 * @author mrdoob / http://mrdoob.com/
 */

B
bentok 已提交
5 6
import { LinearFilter, NearestFilter, RGBFormat, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, ClampToEdgeWrapping, NearestMipMapLinearFilter, NearestMipMapNearestFilter } from '../../constants.js';
import { _Math } from '../../math/Math.js';
R
Rich Harris 已提交
7

M
Mugen87 已提交
8
function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
9

M
Mugen87 已提交
10
	var _videoTextures = {};
11
	var _canvas;
12

M
Mr.doob 已提交
13
	//
14

15 16 17 18 19 20 21 22 23 24 25 26
	var useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined';

	function createCanvas( width, height ) {

		// Use OffscreenCanvas when available. Specially needed in web workers

		return useOffscreenCanvas ?
			new OffscreenCanvas( width, height ) :
			document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );

	}

M
Mugen87 已提交
27
	function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
28

M
Mugen87 已提交
29
		var scale = 1;
30

M
Mugen87 已提交
31
		// handle case if texture exceeds max size
32

M
Mugen87 已提交
33
		if ( image.width > maxSize || image.height > maxSize ) {
34

M
Mugen87 已提交
35
			scale = maxSize / Math.max( image.width, image.height );
36

M
Mugen87 已提交
37
		}
38

M
Mugen87 已提交
39
		// only perform resize if necessary
40

M
Mugen87 已提交
41
		if ( scale < 1 || needsPowerOfTwo === true ) {
42

M
Mugen87 已提交
43
			// only perform resize for certain image types
44

45
			if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) {
46

M
Mugen87 已提交
47
				var floor = needsPowerOfTwo ? _Math.floorPowerOfTwo : Math.floor;
48

49 50 51 52 53 54 55 56 57 58 59
				var width = floor( scale * image.width );
				var height = floor( scale * image.height );

				if ( _canvas === undefined ) _canvas = createCanvas( width, height );

				// cube textures can't reuse the same canvas

				var canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;

				canvas.width = width;
				canvas.height = height;
60

M
Mugen87 已提交
61
				var context = canvas.getContext( '2d' );
62
				context.drawImage( image, 0, 0, width, height );
63

64
				console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
65

66
				return useOffscreenCanvas ? canvas.transferToImageBitmap() : canvas;
67

M
Mugen87 已提交
68
			} else {
69

M
Mugen87 已提交
70
				if ( 'data' in image ) {
71

M
Mugen87 已提交
72
					console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
73

M
Mugen87 已提交
74
				}
75

M
Mugen87 已提交
76
				return image;
77

M
Mugen87 已提交
78
			}
79 80 81 82 83 84 85

		}

		return image;

	}

M
Mugen87 已提交
86 87 88 89 90 91
	function isPowerOfTwo( image ) {

		return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );

	}

92 93
	function textureNeedsPowerOfTwo( texture ) {

T
Takahiro 已提交
94
		if ( capabilities.isWebGL2 ) return false;
T
Takahiro 已提交
95

M
Mr.doob 已提交
96 97 98
		return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
			( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );

99 100
	}

101
	function textureNeedsGenerateMipmaps( texture, supportsMips ) {
102

103
		return texture.generateMipmaps && supportsMips &&
104
			texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
105 106 107

	}

108
	function generateMipmap( target, texture, width, height ) {
109 110 111

		_gl.generateMipmap( target );

112
		var textureProperties = properties.get( texture );
A
aardgoose 已提交
113 114

		// Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
115
		textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E;
116 117 118

	}

119 120
	function getInternalFormat( glFormat, glType ) {

T
Takahiro 已提交
121
		if ( ! capabilities.isWebGL2 ) return glFormat;
T
Takahiro 已提交
122

123 124
		var internalFormat = glFormat;

A
artur.trzesiok 已提交
125
		if ( glFormat === _gl.RED ) {
A
artur.trzesiok 已提交
126

127 128 129
			if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;
			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;
			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;
A
artur.trzesiok 已提交
130

A
artur.trzesiok 已提交
131
		}
A
artur.trzesiok 已提交
132

133 134
		if ( glFormat === _gl.RGB ) {

135 136 137
			if ( glType === _gl.FLOAT ) internalFormat = _gl.RGB32F;
			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGB16F;
			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8;
138 139 140 141

		}

		if ( glFormat === _gl.RGBA ) {
T
Takahiro 已提交
142

143 144 145 146 147 148
			if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;
			if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;
			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8;

		}

V
vasco 已提交
149
		if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F ||
150 151 152 153 154 155 156
			internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {

			extensions.get( 'EXT_color_buffer_float' );

		} else if ( internalFormat === _gl.RGB16F || internalFormat === _gl.RGB32F ) {

			console.warn( 'THREE.WebGLRenderer: Floating point textures with RGB format not supported. Please use RGBA instead.' );
T
Takahiro 已提交
157 158

		}
159

160
		return internalFormat;
161 162 163

	}

164 165
	// Fallback filters for non-power-of-2 textures

M
Mr.doob 已提交
166
	function filterFallback( f ) {
167

R
Rich Harris 已提交
168
		if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

			return _gl.NEAREST;

		}

		return _gl.LINEAR;

	}

	//

	function onTextureDispose( event ) {

		var texture = event.target;

		texture.removeEventListener( 'dispose', onTextureDispose );

		deallocateTexture( texture );

M
Mugen87 已提交
188 189 190 191 192
		if ( texture.isVideoTexture ) {

			delete _videoTextures[ texture.id ];

		}
193

M
Mugen87 已提交
194
		info.memory.textures --;
195 196 197 198 199 200 201 202 203 204 205

	}

	function onRenderTargetDispose( event ) {

		var renderTarget = event.target;

		renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );

		deallocateRenderTarget( renderTarget );

M
Mugen87 已提交
206
		info.memory.textures --;
207 208 209 210 211 212 213 214 215

	}

	//

	function deallocateTexture( texture ) {

		var textureProperties = properties.get( texture );

M
Mugen87 已提交
216
		if ( textureProperties.__webglInit === undefined ) return;
217

M
Mugen87 已提交
218
		_gl.deleteTexture( textureProperties.__webglTexture );
219

220
		properties.remove( texture );
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

	}

	function deallocateRenderTarget( renderTarget ) {

		var renderTargetProperties = properties.get( renderTarget );
		var textureProperties = properties.get( renderTarget.texture );

		if ( ! renderTarget ) return;

		if ( textureProperties.__webglTexture !== undefined ) {

			_gl.deleteTexture( textureProperties.__webglTexture );

		}

		if ( renderTarget.depthTexture ) {

			renderTarget.depthTexture.dispose();

		}

243
		if ( renderTarget.isWebGLRenderTargetCube ) {
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

			for ( var i = 0; i < 6; i ++ ) {

				_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
				if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );

			}

		} else {

			_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
			if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );

		}

259 260
		properties.remove( renderTarget.texture );
		properties.remove( renderTarget );
261 262 263 264 265 266 267 268 269 270 271

	}

	//



	function setTexture2D( texture, slot ) {

		var textureProperties = properties.get( texture );

272 273
		if ( texture.isVideoTexture ) updateVideoTexture( texture );

274 275 276 277 278 279
		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {

			var image = texture.image;

			if ( image === undefined ) {

280
				console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' );
281

282
			} else if ( image.complete === false ) {
283

284
				console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
285

286
			} else {
287

288 289
				uploadTexture( textureProperties, texture, slot );
				return;
290

291
			}
292 293 294 295 296 297 298 299

		}

		state.activeTexture( _gl.TEXTURE0 + slot );
		state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );

	}

A
artur.trzesiok 已提交
300
	function setTexture3D( texture, slot ) {
A
artur.trzesiok 已提交
301

A
artur.trzesiok 已提交
302 303 304
		var textureProperties = properties.get( texture );

		if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
A
artur.trzesiok 已提交
305 306 307 308

			uploadTexture( textureProperties, texture, slot );
			return;

A
artur.trzesiok 已提交
309 310 311 312 313 314
		}

		state.activeTexture( _gl.TEXTURE0 + slot );
		state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture );

	}
A
artur.trzesiok 已提交
315

M
Mr.doob 已提交
316
	function setTextureCube( texture, slot ) {
317 318 319 320 321 322 323

		var textureProperties = properties.get( texture );

		if ( texture.image.length === 6 ) {

			if ( texture.version > 0 && textureProperties.__version !== texture.version ) {

M
Mugen87 已提交
324
				initTexture( textureProperties, texture );
325 326

				state.activeTexture( _gl.TEXTURE0 + slot );
M
Mugen87 已提交
327
				state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
328 329 330

				_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );

M
Mr.doob 已提交
331 332
				var isCompressed = ( texture && texture.isCompressedTexture );
				var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
333 334 335 336 337 338 339

				var cubeImage = [];

				for ( var i = 0; i < 6; i ++ ) {

					if ( ! isCompressed && ! isDataTexture ) {

M
Mugen87 已提交
340
						cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize );
341 342 343 344 345 346 347 348 349 350

					} else {

						cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];

					}

				}

				var image = cubeImage[ 0 ],
351
					supportsMips = isPowerOfTwo( image ) || capabilities.isWebGL2,
M
Mugen87 已提交
352
					glFormat = utils.convert( texture.format ),
T
Takahiro 已提交
353 354
					glType = utils.convert( texture.type ),
					glInternalFormat = getInternalFormat( glFormat, glType );
355

356
				setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
357 358 359 360 361 362 363

				for ( var i = 0; i < 6; i ++ ) {

					if ( ! isCompressed ) {

						if ( isDataTexture ) {

T
Takahiro 已提交
364
							state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
365 366 367

						} else {

T
Takahiro 已提交
368
							state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
369 370 371 372 373 374 375 376 377 378 379

						}

					} else {

						var mipmap, mipmaps = cubeImage[ i ].mipmaps;

						for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {

							mipmap = mipmaps[ j ];

R
Rich Harris 已提交
380
							if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
381 382 383

								if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {

T
Takahiro 已提交
384
									state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
385 386 387

								} else {

M
Mugen87 已提交
388
									console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
389 390 391 392 393

								}

							} else {

T
Takahiro 已提交
394
								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
395 396 397 398 399 400 401 402 403

							}

						}

					}

				}

404 405
				if ( ! isCompressed ) {

406
					textureProperties.__maxMipLevel = 0;
407 408 409

				} else {

410
					textureProperties.__maxMipLevel = mipmaps.length - 1;
411 412 413

				}

414
				if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
415

416 417
					// We assume images for cube map have the same size.
					generateMipmap( _gl.TEXTURE_CUBE_MAP, texture, image.width, image.height );
418 419 420 421 422 423 424 425 426 427

				}

				textureProperties.__version = texture.version;

				if ( texture.onUpdate ) texture.onUpdate( texture );

			} else {

				state.activeTexture( _gl.TEXTURE0 + slot );
M
Mugen87 已提交
428
				state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
429 430 431 432 433 434 435

			}

		}

	}

M
Mr.doob 已提交
436
	function setTextureCubeDynamic( texture, slot ) {
437 438 439 440 441 442

		state.activeTexture( _gl.TEXTURE0 + slot );
		state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );

	}

443
	function setTextureParameters( textureType, texture, supportsMips ) {
444 445 446

		var extension;

447
		if ( supportsMips ) {
448

449 450
			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, utils.convert( texture.wrapS ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, utils.convert( texture.wrapT ) );
451

452 453 454 455 456 457
			if ( textureType === _gl.TEXTURE_3D ) {

				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, utils.convert( texture.wrapR ) );

			}

458 459
			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, utils.convert( texture.magFilter ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, utils.convert( texture.minFilter ) );
460 461 462 463 464 465

		} else {

			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
			_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );

466 467 468 469 470 471
			if ( textureType === _gl.TEXTURE_3D ) {

				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE );

			}

R
Rich Harris 已提交
472
			if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
473

474
				console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
475 476 477 478 479 480

			}

			_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
			_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );

R
Rich Harris 已提交
481
			if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
482

483
				console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
484 485 486 487 488 489 490 491 492

			}

		}

		extension = extensions.get( 'EXT_texture_filter_anisotropic' );

		if ( extension ) {

R
Rich Harris 已提交
493
			if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
T
Takahiro 已提交
494
			if ( texture.type === HalfFloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) return;
495 496 497 498 499 500 501 502 503 504 505 506

			if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {

				_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
				properties.get( texture ).__currentAnisotropy = texture.anisotropy;

			}

		}

	}

M
Mugen87 已提交
507
	function initTexture( textureProperties, texture ) {
508 509 510 511 512 513 514 515 516

		if ( textureProperties.__webglInit === undefined ) {

			textureProperties.__webglInit = true;

			texture.addEventListener( 'dispose', onTextureDispose );

			textureProperties.__webglTexture = _gl.createTexture();

M
Mugen87 已提交
517
			info.memory.textures ++;
518 519

		}
A
artur.trzesiok 已提交
520

M
Mugen87 已提交
521
	}
A
artur.trzesiok 已提交
522

M
Mugen87 已提交
523 524 525
	function uploadTexture( textureProperties, texture, slot ) {

		var textureType = ( texture.isDataTexture3D ) ? _gl.TEXTURE_3D : _gl.TEXTURE_2D;
A
artur.trzesiok 已提交
526

M
Mugen87 已提交
527
		initTexture( textureProperties, texture );
A
artur.trzesiok 已提交
528

M
Mugen87 已提交
529 530
		state.activeTexture( _gl.TEXTURE0 + slot );
		state.bindTexture( textureType, textureProperties.__webglTexture );
531 532 533 534 535

		_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
		_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
		_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );

M
Mugen87 已提交
536 537
		var needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
		var image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize );
538

539
		var supportsMips = isPowerOfTwo( image ) || capabilities.isWebGL2,
M
Mugen87 已提交
540
			glFormat = utils.convert( texture.format ),
T
Takahiro 已提交
541 542
			glType = utils.convert( texture.type ),
			glInternalFormat = getInternalFormat( glFormat, glType );
543

544
		setTextureParameters( textureType, texture, supportsMips );
545 546 547

		var mipmap, mipmaps = texture.mipmaps;

548
		if ( texture.isDepthTexture ) {
549 550 551

			// populate depth texture with dummy data

T
Takahiro 已提交
552
			glInternalFormat = _gl.DEPTH_COMPONENT;
553

R
Rich Harris 已提交
554
			if ( texture.type === FloatType ) {
555

T
Takahiro 已提交
556
				if ( ! capabilities.isWebGL2 ) throw new Error( 'Float Depth Texture only supported in WebGL2.0' );
T
Takahiro 已提交
557
				glInternalFormat = _gl.DEPTH_COMPONENT32F;
558

T
Takahiro 已提交
559
			} else if ( capabilities.isWebGL2 ) {
560 561

				// WebGL 2.0 requires signed internalformat for glTexImage2D
T
Takahiro 已提交
562
				glInternalFormat = _gl.DEPTH_COMPONENT16;
563 564 565

			}

T
Takahiro 已提交
566
			if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
T
Takahiro 已提交
567 568 569 570 571 572

				// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
				// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
				// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
				if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {

M
Mugen87 已提交
573
					console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
T
Takahiro 已提交
574 575

					texture.type = UnsignedShortType;
576
					glType = utils.convert( texture.type );
T
Takahiro 已提交
577 578 579 580 581

				}

			}

582 583
			// Depth stencil textures need the DEPTH_STENCIL internal format
			// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
584
			if ( texture.format === DepthStencilFormat ) {
585

T
Takahiro 已提交
586
				glInternalFormat = _gl.DEPTH_STENCIL;
587

T
Takahiro 已提交
588 589 590 591 592
				// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
				// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
				// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
				if ( texture.type !== UnsignedInt248Type ) {

M
Mr.doob 已提交
593
					console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
T
Takahiro 已提交
594 595

					texture.type = UnsignedInt248Type;
596
					glType = utils.convert( texture.type );
T
Takahiro 已提交
597 598 599

				}

600 601
			}

T
Takahiro 已提交
602
			state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
603

604
		} else if ( texture.isDataTexture ) {
605 606 607 608 609

			// use manually created mipmaps if available
			// if there are no manual mipmaps
			// set 0 level mipmap and then use GL to generate other mipmap levels

610
			if ( mipmaps.length > 0 && supportsMips ) {
611 612 613 614

				for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {

					mipmap = mipmaps[ i ];
T
Takahiro 已提交
615
					state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
616 617 618 619

				}

				texture.generateMipmaps = false;
620
				textureProperties.__maxMipLevel = mipmaps.length - 1;
621 622 623

			} else {

T
Takahiro 已提交
624
				state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
625
				textureProperties.__maxMipLevel = 0;
626 627 628

			}

629
		} else if ( texture.isCompressedTexture ) {
630 631 632 633 634

			for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {

				mipmap = mipmaps[ i ];

R
Rich Harris 已提交
635
				if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
636 637 638

					if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {

T
Takahiro 已提交
639
						state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
640 641 642

					} else {

M
Mugen87 已提交
643
						console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
644 645 646 647 648

					}

				} else {

T
Takahiro 已提交
649
					state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
650 651 652 653 654

				}

			}

655
			textureProperties.__maxMipLevel = mipmaps.length - 1;
656

T
Takahiro 已提交
657
		} else if ( texture.isDataTexture3D ) {
A
artur.trzesiok 已提交
658

T
Takahiro 已提交
659
			state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
A
artur.trzesiok 已提交
660 661
			textureProperties.__maxMipLevel = 0;

662 663 664 665 666 667 668 669
		} else {

			// regular Texture (image, video, canvas)

			// use manually created mipmaps if available
			// if there are no manual mipmaps
			// set 0 level mipmap and then use GL to generate other mipmap levels

670
			if ( mipmaps.length > 0 && supportsMips ) {
671 672 673 674

				for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {

					mipmap = mipmaps[ i ];
T
Takahiro 已提交
675
					state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );
676 677 678 679

				}

				texture.generateMipmaps = false;
680
				textureProperties.__maxMipLevel = mipmaps.length - 1;
681 682 683

			} else {

T
Takahiro 已提交
684
				state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );
685
				textureProperties.__maxMipLevel = 0;
686 687 688 689 690

			}

		}

691
		if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
692

693
			generateMipmap( _gl.TEXTURE_2D, texture, image.width, image.height );
694 695

		}
696 697 698 699 700 701 702 703 704 705

		textureProperties.__version = texture.version;

		if ( texture.onUpdate ) texture.onUpdate( texture );

	}

	// Render targets

	// Setup storage for target texture and bind it to correct framebuffer
M
Mr.doob 已提交
706
	function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
707

708 709
		var glFormat = utils.convert( renderTarget.texture.format );
		var glType = utils.convert( renderTarget.texture.type );
T
Takahiro 已提交
710
		var glInternalFormat = getInternalFormat( glFormat, glType );
711
		state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
712 713 714 715 716 717 718
		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
		_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );

	}

	// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
719
	function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
720 721 722 723 724

		_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );

		if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {

725 726 727 728 729 730 731 732 733 734 735 736
			if ( isMultisample ) {

				var samples = getRenderTargetSamples( renderTarget );

				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );

			} else {

				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );

			}

737 738 739 740
			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );

		} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {

741 742 743 744 745 746 747 748 749 750 751 752 753
			if ( isMultisample ) {

				var samples = getRenderTargetSamples( renderTarget );

				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );

			} else {

				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );

			}


754 755 756 757
			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );

		} else {

758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
			var glFormat = utils.convert( renderTarget.texture.format );
			var glType = utils.convert( renderTarget.texture.type );
			var glInternalFormat = getInternalFormat( glFormat, glType );

			if ( isMultisample ) {

				var samples = getRenderTargetSamples( renderTarget );

				_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

			} else {

				_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );

			}
773 774 775 776 777 778 779 780

		}

		_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );

	}

	// Setup resources for a Depth Texture for a FBO (needs an extension)
M
Mr.doob 已提交
781
	function setupDepthTexture( framebuffer, renderTarget ) {
782

783
		var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
M
Mugen87 已提交
784
		if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
785 786 787

		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

M
Mugen87 已提交
788
		if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
789

M
Mugen87 已提交
790
			throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
791 792 793 794

		}

		// upload an empty depth texture with framebuffer size
M
Mugen87 已提交
795
		if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
796 797
				renderTarget.depthTexture.image.width !== renderTarget.width ||
				renderTarget.depthTexture.image.height !== renderTarget.height ) {
M
Mugen87 已提交
798

799 800 801
			renderTarget.depthTexture.image.width = renderTarget.width;
			renderTarget.depthTexture.image.height = renderTarget.height;
			renderTarget.depthTexture.needsUpdate = true;
M
Mugen87 已提交
802

803 804 805 806 807
		}

		setTexture2D( renderTarget.depthTexture, 0 );

		var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
808

809
		if ( renderTarget.depthTexture.format === DepthFormat ) {
810 811 812

			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

813
		} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
814 815 816 817 818

			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

		} else {

M
Mugen87 已提交
819
			throw new Error( 'Unknown depthTexture format' );
820 821

		}
822 823 824 825 826 827 828 829

	}

	// Setup GL resources for a non-texture depth buffer
	function setupDepthRenderbuffer( renderTarget ) {

		var renderTargetProperties = properties.get( renderTarget );

830
		var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
831 832 833

		if ( renderTarget.depthTexture ) {

M
Mugen87 已提交
834
			if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875

			setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );

		} else {

			if ( isCube ) {

				renderTargetProperties.__webglDepthbuffer = [];

				for ( var i = 0; i < 6; i ++ ) {

					_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
					renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
					setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );

				}

			} else {

				_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
				renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
				setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );

			}

		}

		_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );

	}

	// Set up GL resources for the render target
	function setupRenderTarget( renderTarget ) {

		var renderTargetProperties = properties.get( renderTarget );
		var textureProperties = properties.get( renderTarget.texture );

		renderTarget.addEventListener( 'dispose', onRenderTargetDispose );

		textureProperties.__webglTexture = _gl.createTexture();

M
Mugen87 已提交
876
		info.memory.textures ++;
877

878
		var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
879
		var isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
880
		var supportsMips = isPowerOfTwo( renderTarget ) || capabilities.isWebGL2;
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897

		// Setup framebuffer

		if ( isCube ) {

			renderTargetProperties.__webglFramebuffer = [];

			for ( var i = 0; i < 6; i ++ ) {

				renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();

			}

		} else {

			renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();

898 899
			if ( isMultisample ) {

900
				if ( capabilities.isWebGL2 ) {
901

902 903
					renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
					renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
904

905 906 907 908 909 910
					_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer );
					var glFormat = utils.convert( renderTarget.texture.format );
					var glType = utils.convert( renderTarget.texture.type );
					var glInternalFormat = getInternalFormat( glFormat, glType );
					var samples = getRenderTargetSamples( renderTarget );
					_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
911

912 913 914
					_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
					_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer );
					_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
915

916
					if ( renderTarget.depthBuffer ) {
917

918 919 920 921 922 923 924 925 926
						renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
						setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );

					}

					_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );


				} else {
927

928 929 930
					console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );

				}
931 932 933

			}

934 935 936 937 938 939 940
		}

		// Setup color buffer

		if ( isCube ) {

			state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
941
			setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, supportsMips );
942 943 944 945 946 947 948

			for ( var i = 0; i < 6; i ++ ) {

				setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );

			}

949
			if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
950

951
				generateMipmap( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, renderTarget.width, renderTarget.height );
952 953 954

			}

955 956 957 958 959
			state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );

		} else {

			state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
960
			setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, supportsMips );
961 962
			setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );

963
			if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
964

965
				generateMipmap( _gl.TEXTURE_2D, renderTarget.texture, renderTarget.width, renderTarget.height );
966 967 968

			}

969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
			state.bindTexture( _gl.TEXTURE_2D, null );

		}

		// Setup depth and stencil buffers

		if ( renderTarget.depthBuffer ) {

			setupDepthRenderbuffer( renderTarget );

		}

	}

	function updateRenderTargetMipmap( renderTarget ) {

		var texture = renderTarget.texture;
986
		var supportsMips = isPowerOfTwo( renderTarget ) || capabilities.isWebGL2;
987

988
		if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
989

990
			var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
991 992 993
			var webglTexture = properties.get( texture ).__webglTexture;

			state.bindTexture( target, webglTexture );
994
			generateMipmap( target, texture, renderTarget.width, renderTarget.height );
995 996 997 998 999 1000
			state.bindTexture( target, null );

		}

	}

1001 1002 1003 1004
	function updateMultisampleRenderTarget( renderTarget ) {

		if ( renderTarget.isWebGLMultisampleRenderTarget ) {

1005 1006 1007 1008 1009 1010
			if ( capabilities.isWebGL2 ) {

				var renderTargetProperties = properties.get( renderTarget );

				_gl.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
				_gl.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
1011

1012 1013 1014
				var width = renderTarget.width;
				var height = renderTarget.height;
				var mask = _gl.COLOR_BUFFER_BIT;
1015

1016 1017
				if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;
				if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
1018

1019
				_gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );
1020

1021 1022 1023 1024 1025
			} else {

				console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );

			}
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037

		}

	}

	function getRenderTargetSamples( renderTarget ) {

		return ( capabilities.isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
			Math.min( capabilities.maxSamples, renderTarget.samples ) : 0;

	}

1038 1039 1040
	function updateVideoTexture( texture ) {

		var id = texture.id;
M
Mugen87 已提交
1041
		var frame = info.render.frame;
1042 1043

		// Check the last frame we updated the VideoTexture
M
Mugen87 已提交
1044

1045
		if ( _videoTextures[ id ] !== frame ) {
M
Mugen87 已提交
1046

1047 1048
			_videoTextures[ id ] = frame;
			texture.update();
M
Mugen87 已提交
1049 1050 1051 1052 1053

		}

	}

1054
	this.setTexture2D = setTexture2D;
A
artur.trzesiok 已提交
1055
	this.setTexture3D = setTexture3D;
1056 1057 1058 1059
	this.setTextureCube = setTextureCube;
	this.setTextureCubeDynamic = setTextureCubeDynamic;
	this.setupRenderTarget = setupRenderTarget;
	this.updateRenderTargetMipmap = updateRenderTargetMipmap;
1060
	this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
1061

M
Mr.doob 已提交
1062
}
R
Rich Harris 已提交
1063 1064


1065
export { WebGLTextures };