| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 | ( function () {	// http://en.wikipedia.org/wiki/RGBE_image_format	class RGBELoader extends THREE.DataTextureLoader {		constructor( manager ) {			super( manager );			this.type = THREE.HalfFloatType;		} // adapted from http://www.graphics.cornell.edu/~bjw/rgbe.html		parse( buffer ) {			const				/* return codes for rgbe routines */				//RGBE_RETURN_SUCCESS = 0,				RGBE_RETURN_FAILURE = - 1,				/* default error routine.  change this to change error handling */				rgbe_read_error = 1,				rgbe_write_error = 2,				rgbe_format_error = 3,				rgbe_memory_error = 4,				rgbe_error = function ( rgbe_error_code, msg ) {					switch ( rgbe_error_code ) {						case rgbe_read_error:							console.error( 'THREE.RGBELoader Read Error: ' + ( msg || '' ) );							break;						case rgbe_write_error:							console.error( 'THREE.RGBELoader Write Error: ' + ( msg || '' ) );							break;						case rgbe_format_error:							console.error( 'THREE.RGBELoader Bad File Format: ' + ( msg || '' ) );							break;						default:						case rgbe_memory_error:							console.error( 'THREE.RGBELoader: Error: ' + ( msg || '' ) );					}					return RGBE_RETURN_FAILURE;				},				/* offsets to red, green, and blue components in a data (float) pixel */				//RGBE_DATA_RED = 0,				//RGBE_DATA_GREEN = 1,				//RGBE_DATA_BLUE = 2,				/* number of floats per pixel, use 4 since stored in rgba image format */				//RGBE_DATA_SIZE = 4,				/* flags indicating which fields in an rgbe_header_info are valid */				RGBE_VALID_PROGRAMTYPE = 1,				RGBE_VALID_FORMAT = 2,				RGBE_VALID_DIMENSIONS = 4,				NEWLINE = '\n',				fgets = function ( buffer, lineLimit, consume ) {					const chunkSize = 128;					lineLimit = ! lineLimit ? 1024 : lineLimit;					let p = buffer.pos,						i = - 1,						len = 0,						s = '',						chunk = String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) );					while ( 0 > ( i = chunk.indexOf( NEWLINE ) ) && len < lineLimit && p < buffer.byteLength ) {						s += chunk;						len += chunk.length;						p += chunkSize;						chunk += String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) );					}					if ( - 1 < i ) {						/*for (i=l-1; i>=0; i--) {        	byteCode = m.charCodeAt(i);        	if (byteCode > 0x7f && byteCode <= 0x7ff) byteLen++;        	else if (byteCode > 0x7ff && byteCode <= 0xffff) byteLen += 2;        	if (byteCode >= 0xDC00 && byteCode <= 0xDFFF) i--; //trail surrogate        }*/						if ( false !== consume ) buffer.pos += len + i + 1;						return s + chunk.slice( 0, i );					}					return false;				},				/* minimal header reading.  modify if you want to parse more information */				RGBE_ReadHeader = function ( buffer ) {					// regexes to parse header info fields					const magic_token_re = /^#\?(\S+)/,						gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/,						exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/,						format_re = /^\s*FORMAT=(\S+)\s*$/,						dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/,						// RGBE format header struct						header = {							valid: 0,							/* indicate which fields are valid */							string: '',							/* the actual header string */							comments: '',							/* comments found in header */							programtype: 'RGBE',							/* listed at beginning of file to identify it after "#?". defaults to "RGBE" */							format: '',							/* RGBE format, default 32-bit_rle_rgbe */							gamma: 1.0,							/* image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) */							exposure: 1.0,							/* a value of 1.0 in an image corresponds to <exposure> watts/steradian/m^2. defaults to 1.0 */							width: 0,							height: 0							/* image dimensions, width/height */						};					let line, match;					if ( buffer.pos >= buffer.byteLength || ! ( line = fgets( buffer ) ) ) {						return rgbe_error( rgbe_read_error, 'no header found' );					}					/* if you want to require the magic token then uncomment the next line */					if ( ! ( match = line.match( magic_token_re ) ) ) {						return rgbe_error( rgbe_format_error, 'bad initial token' );					}					header.valid |= RGBE_VALID_PROGRAMTYPE;					header.programtype = match[ 1 ];					header.string += line + '\n';					while ( true ) {						line = fgets( buffer );						if ( false === line ) break;						header.string += line + '\n';						if ( '#' === line.charAt( 0 ) ) {							header.comments += line + '\n';							continue; // comment line						}						if ( match = line.match( gamma_re ) ) {							header.gamma = parseFloat( match[ 1 ], 10 );						}						if ( match = line.match( exposure_re ) ) {							header.exposure = parseFloat( match[ 1 ], 10 );						}						if ( match = line.match( format_re ) ) {							header.valid |= RGBE_VALID_FORMAT;							header.format = match[ 1 ]; //'32-bit_rle_rgbe';						}						if ( match = line.match( dimensions_re ) ) {							header.valid |= RGBE_VALID_DIMENSIONS;							header.height = parseInt( match[ 1 ], 10 );							header.width = parseInt( match[ 2 ], 10 );						}						if ( header.valid & RGBE_VALID_FORMAT && header.valid & RGBE_VALID_DIMENSIONS ) break;					}					if ( ! ( header.valid & RGBE_VALID_FORMAT ) ) {						return rgbe_error( rgbe_format_error, 'missing format specifier' );					}					if ( ! ( header.valid & RGBE_VALID_DIMENSIONS ) ) {						return rgbe_error( rgbe_format_error, 'missing image size specifier' );					}					return header;				},				RGBE_ReadPixels_RLE = function ( buffer, w, h ) {					const scanline_width = w;					if ( // run length encoding is not allowed so read flat						scanline_width < 8 || scanline_width > 0x7fff || // this file is not run length encoded      2 !== buffer[ 0 ] || 2 !== buffer[ 1 ] || buffer[ 2 ] & 0x80 ) {						// return the flat buffer						return new Uint8Array( buffer );					}					if ( scanline_width !== ( buffer[ 2 ] << 8 | buffer[ 3 ] ) ) {						return rgbe_error( rgbe_format_error, 'wrong scanline width' );					}					const data_rgba = new Uint8Array( 4 * w * h );					if ( ! data_rgba.length ) {						return rgbe_error( rgbe_memory_error, 'unable to allocate buffer space' );					}					let offset = 0,						pos = 0;					const ptr_end = 4 * scanline_width;					const rgbeStart = new Uint8Array( 4 );					const scanline_buffer = new Uint8Array( ptr_end );					let num_scanlines = h; // read in each successive scanline					while ( num_scanlines > 0 && pos < buffer.byteLength ) {						if ( pos + 4 > buffer.byteLength ) {							return rgbe_error( rgbe_read_error );						}						rgbeStart[ 0 ] = buffer[ pos ++ ];						rgbeStart[ 1 ] = buffer[ pos ++ ];						rgbeStart[ 2 ] = buffer[ pos ++ ];						rgbeStart[ 3 ] = buffer[ pos ++ ];						if ( 2 != rgbeStart[ 0 ] || 2 != rgbeStart[ 1 ] || ( rgbeStart[ 2 ] << 8 | rgbeStart[ 3 ] ) != scanline_width ) {							return rgbe_error( rgbe_format_error, 'bad rgbe scanline format' );						} // read each of the four channels for the scanline into the buffer						// first red, then green, then blue, then exponent						let ptr = 0,							count;						while ( ptr < ptr_end && pos < buffer.byteLength ) {							count = buffer[ pos ++ ];							const isEncodedRun = count > 128;							if ( isEncodedRun ) count -= 128;							if ( 0 === count || ptr + count > ptr_end ) {								return rgbe_error( rgbe_format_error, 'bad scanline data' );							}							if ( isEncodedRun ) {								// a (encoded) run of the same value								const byteValue = buffer[ pos ++ ];								for ( let i = 0; i < count; i ++ ) {									scanline_buffer[ ptr ++ ] = byteValue;								} //ptr += count;							} else {								// a literal-run								scanline_buffer.set( buffer.subarray( pos, pos + count ), ptr );								ptr += count;								pos += count;							}						} // now convert data from buffer into rgba						// first red, then green, then blue, then exponent (alpha)						const l = scanline_width; //scanline_buffer.byteLength;						for ( let i = 0; i < l; i ++ ) {							let off = 0;							data_rgba[ offset ] = scanline_buffer[ i + off ];							off += scanline_width; //1;							data_rgba[ offset + 1 ] = scanline_buffer[ i + off ];							off += scanline_width; //1;							data_rgba[ offset + 2 ] = scanline_buffer[ i + off ];							off += scanline_width; //1;							data_rgba[ offset + 3 ] = scanline_buffer[ i + off ];							offset += 4;						}						num_scanlines --;					}					return data_rgba;				};			const RGBEByteToRGBFloat = function ( sourceArray, sourceOffset, destArray, destOffset ) {				const e = sourceArray[ sourceOffset + 3 ];				const scale = Math.pow( 2.0, e - 128.0 ) / 255.0;				destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale;				destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale;				destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale;			};			const RGBEByteToRGBHalf = function ( sourceArray, sourceOffset, destArray, destOffset ) {				const e = sourceArray[ sourceOffset + 3 ];				const scale = Math.pow( 2.0, e - 128.0 ) / 255.0; // clamping to 65504, the maximum representable value in float16				destArray[ destOffset + 0 ] = THREE.DataUtils.toHalfFloat( Math.min( sourceArray[ sourceOffset + 0 ] * scale, 65504 ) );				destArray[ destOffset + 1 ] = THREE.DataUtils.toHalfFloat( Math.min( sourceArray[ sourceOffset + 1 ] * scale, 65504 ) );				destArray[ destOffset + 2 ] = THREE.DataUtils.toHalfFloat( Math.min( sourceArray[ sourceOffset + 2 ] * scale, 65504 ) );			};			const byteArray = new Uint8Array( buffer );			byteArray.pos = 0;			const rgbe_header_info = RGBE_ReadHeader( byteArray );			if ( RGBE_RETURN_FAILURE !== rgbe_header_info ) {				const w = rgbe_header_info.width,					h = rgbe_header_info.height,					image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h );				if ( RGBE_RETURN_FAILURE !== image_rgba_data ) {					let data, format, type;					let numElements;					switch ( this.type ) {						case THREE.UnsignedByteType:							data = image_rgba_data;							format = THREE.RGBEFormat; // handled as THREE.RGBAFormat in shaders							type = THREE.UnsignedByteType;							break;						case THREE.FloatType:							numElements = image_rgba_data.length / 4;							const floatArray = new Float32Array( numElements * 3 );							for ( let j = 0; j < numElements; j ++ ) {								RGBEByteToRGBFloat( image_rgba_data, j * 4, floatArray, j * 3 );							}							data = floatArray;							format = THREE.RGBFormat;							type = THREE.FloatType;							break;						case THREE.HalfFloatType:							numElements = image_rgba_data.length / 4;							const halfArray = new Uint16Array( numElements * 3 );							for ( let j = 0; j < numElements; j ++ ) {								RGBEByteToRGBHalf( image_rgba_data, j * 4, halfArray, j * 3 );							}							data = halfArray;							format = THREE.RGBFormat;							type = THREE.HalfFloatType;							break;						default:							console.error( 'THREE.RGBELoader: unsupported type: ', this.type );							break;					}					return {						width: w,						height: h,						data: data,						header: rgbe_header_info.string,						gamma: rgbe_header_info.gamma,						exposure: rgbe_header_info.exposure,						format: format,						type: type					};				}			}			return null;		}		setDataType( value ) {			this.type = value;			return this;		}		load( url, onLoad, onProgress, onError ) {			function onLoadCallback( texture, texData ) {				switch ( texture.type ) {					case THREE.UnsignedByteType:						texture.encoding = THREE.RGBEEncoding;						texture.minFilter = THREE.NearestFilter;						texture.magFilter = THREE.NearestFilter;						texture.generateMipmaps = false;						texture.flipY = true;						break;					case THREE.FloatType:						texture.encoding = THREE.LinearEncoding;						texture.minFilter = THREE.LinearFilter;						texture.magFilter = THREE.LinearFilter;						texture.generateMipmaps = false;						texture.flipY = true;						break;					case THREE.HalfFloatType:						texture.encoding = THREE.LinearEncoding;						texture.minFilter = THREE.LinearFilter;						texture.magFilter = THREE.LinearFilter;						texture.generateMipmaps = false;						texture.flipY = true;						break;				}				if ( onLoad ) onLoad( texture, texData );			}			return super.load( url, onLoadCallback, onProgress, onError );		}	}	THREE.RGBELoader = RGBELoader;} )();
 |