forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			210 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			210 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
| 
								 | 
							
								package kha.internal;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import haxe.io.UInt8Array;
							 | 
						||
| 
								 | 
							
								import haxe.io.Float32Array;
							 | 
						||
| 
								 | 
							
								import haxe.io.Bytes;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Based on https://github.com/vorg/pragmatic-pbr/blob/master/local_modules/parse-hdr/parse-hdr.js
							 | 
						||
| 
								 | 
							
								class HdrFormat {
							 | 
						||
| 
								 | 
							
									static var radiancePattern = new EReg("#\\?RADIANCE", "i");
							 | 
						||
| 
								 | 
							
									static var commentPattern = new EReg("#.*", "i");
							 | 
						||
| 
								 | 
							
									static var gammaPattern = new EReg("GAMMA=", "i");
							 | 
						||
| 
								 | 
							
									static var exposurePattern = new EReg("EXPOSURE=\\s*([0-9]*[.][0-9]*)", "i");
							 | 
						||
| 
								 | 
							
									static var formatPattern = new EReg("FORMAT=32-bit_rle_rgbe", "i");
							 | 
						||
| 
								 | 
							
									static var widthHeightPattern = new EReg("-Y ([0-9]+) \\+X ([0-9]+)", "i");
							 | 
						||
| 
								 | 
							
									static var buffer: UInt8Array;
							 | 
						||
| 
								 | 
							
									static var bufferLength: Int;
							 | 
						||
| 
								 | 
							
									static var fileOffset: Int;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static function readBuf(buf: UInt8Array): Int {
							 | 
						||
| 
								 | 
							
										var bytesRead = 0;
							 | 
						||
| 
								 | 
							
										do {
							 | 
						||
| 
								 | 
							
											buf[bytesRead++] = buffer[fileOffset];
							 | 
						||
| 
								 | 
							
										} while (++fileOffset < bufferLength && bytesRead < buf.length);
							 | 
						||
| 
								 | 
							
										return bytesRead;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static function readBufOffset(buf: UInt8Array, offset: Int, length: Int): Int {
							 | 
						||
| 
								 | 
							
										var bytesRead = 0;
							 | 
						||
| 
								 | 
							
										do {
							 | 
						||
| 
								 | 
							
											buf[offset + bytesRead++] = buffer[fileOffset];
							 | 
						||
| 
								 | 
							
										} while (++fileOffset < bufferLength && bytesRead < length);
							 | 
						||
| 
								 | 
							
										return bytesRead;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static function readPixelsRaw(buffer: UInt8Array, data: UInt8Array, offset: Int, numpixels: Int) {
							 | 
						||
| 
								 | 
							
										var numExpected = 4 * numpixels;
							 | 
						||
| 
								 | 
							
										var numRead = readBufOffset(data, offset, numExpected);
							 | 
						||
| 
								 | 
							
										if (numRead < numExpected) {
							 | 
						||
| 
								 | 
							
											trace("Error reading raw pixels: got " + numRead + " bytes, expected " + numExpected);
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static function readPixelsRawRLE(buffer: UInt8Array, data: UInt8Array, offset: Int, scanline_width: Int, num_scanlines: Int) {
							 | 
						||
| 
								 | 
							
										var rgbe = new UInt8Array(4);
							 | 
						||
| 
								 | 
							
										var scanline_buffer: UInt8Array = null;
							 | 
						||
| 
								 | 
							
										var ptr: Int;
							 | 
						||
| 
								 | 
							
										var ptr_end: Int;
							 | 
						||
| 
								 | 
							
										var count: Int;
							 | 
						||
| 
								 | 
							
										var buf = new UInt8Array(2);
							 | 
						||
| 
								 | 
							
										// var bufferLength = buffer.length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										while (num_scanlines > 0) {
							 | 
						||
| 
								 | 
							
											if (readBuf(rgbe) < rgbe.length) {
							 | 
						||
| 
								 | 
							
												trace("Error reading bytes: expected " + rgbe.length);
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ((rgbe[0] != 2) || (rgbe[1] != 2) || ((rgbe[2] & 0x80) != 0)) {
							 | 
						||
| 
								 | 
							
												// This file is not run length encoded
							 | 
						||
| 
								 | 
							
												data[offset++] = rgbe[0];
							 | 
						||
| 
								 | 
							
												data[offset++] = rgbe[1];
							 | 
						||
| 
								 | 
							
												data[offset++] = rgbe[2];
							 | 
						||
| 
								 | 
							
												data[offset++] = rgbe[3];
							 | 
						||
| 
								 | 
							
												readPixelsRaw(buffer, data, offset, scanline_width * num_scanlines - 1);
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ((((rgbe[2] & 0xFF) << 8) | (rgbe[3] & 0xFF)) != scanline_width) {
							 | 
						||
| 
								 | 
							
												trace("Wrong scanline width " + (((rgbe[2] & 0xFF) << 8) | (rgbe[3] & 0xFF)) + ", expected " + scanline_width);
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (scanline_buffer == null) {
							 | 
						||
| 
								 | 
							
												scanline_buffer = new UInt8Array(4 * scanline_width);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											ptr = 0;
							 | 
						||
| 
								 | 
							
											// Read each of the four channels for the scanline into the buffer
							 | 
						||
| 
								 | 
							
											for (i in 0...4) {
							 | 
						||
| 
								 | 
							
												ptr_end = (i + 1) * scanline_width;
							 | 
						||
| 
								 | 
							
												while (ptr < ptr_end) {
							 | 
						||
| 
								 | 
							
													if (readBuf(buf) < buf.length) {
							 | 
						||
| 
								 | 
							
														trace("Error reading 2-byte buffer");
							 | 
						||
| 
								 | 
							
														return;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													if ((buf[0] & 0xFF) > 128) {
							 | 
						||
| 
								 | 
							
														// A run of the same value
							 | 
						||
| 
								 | 
							
														count = (buf[0] & 0xFF) - 128;
							 | 
						||
| 
								 | 
							
														if ((count == 0) || (count > ptr_end - ptr)) {
							 | 
						||
| 
								 | 
							
															trace("Bad scanline data");
							 | 
						||
| 
								 | 
							
															return;
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
														while (count-- > 0) {
							 | 
						||
| 
								 | 
							
															scanline_buffer[ptr++] = buf[1];
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													else {
							 | 
						||
| 
								 | 
							
														// A non-run
							 | 
						||
| 
								 | 
							
														count = buf[0] & 0xFF;
							 | 
						||
| 
								 | 
							
														if ((count == 0) || (count > ptr_end - ptr)) {
							 | 
						||
| 
								 | 
							
															trace("Bad scanline data");
							 | 
						||
| 
								 | 
							
															return;
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
														scanline_buffer[ptr++] = buf[1];
							 | 
						||
| 
								 | 
							
														if (--count > 0) {
							 | 
						||
| 
								 | 
							
															if (readBufOffset(scanline_buffer, ptr, count) < count) {
							 | 
						||
| 
								 | 
							
																trace("Error reading non-run data");
							 | 
						||
| 
								 | 
							
																return;
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
															ptr += count;
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Copy byte data to output
							 | 
						||
| 
								 | 
							
											for (i in 0...scanline_width) {
							 | 
						||
| 
								 | 
							
												data[offset + 0] = scanline_buffer[i];
							 | 
						||
| 
								 | 
							
												data[offset + 1] = scanline_buffer[i + scanline_width];
							 | 
						||
| 
								 | 
							
												data[offset + 2] = scanline_buffer[i + 2 * scanline_width];
							 | 
						||
| 
								 | 
							
												data[offset + 3] = scanline_buffer[i + 3 * scanline_width];
							 | 
						||
| 
								 | 
							
												offset += 4;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											num_scanlines--;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static function readLine(): String {
							 | 
						||
| 
								 | 
							
										var buf = "";
							 | 
						||
| 
								 | 
							
										do {
							 | 
						||
| 
								 | 
							
											var b = buffer[fileOffset];
							 | 
						||
| 
								 | 
							
											if (b == 10) { // New line
							 | 
						||
| 
								 | 
							
												++fileOffset;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											buf += String.fromCharCode(b);
							 | 
						||
| 
								 | 
							
										} while (++fileOffset < bufferLength);
							 | 
						||
| 
								 | 
							
										return buf;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function parse(bytes: Bytes) {
							 | 
						||
| 
								 | 
							
										buffer = UInt8Array.fromBytes(bytes);
							 | 
						||
| 
								 | 
							
										bufferLength = buffer.length;
							 | 
						||
| 
								 | 
							
										fileOffset = 0;
							 | 
						||
| 
								 | 
							
										var width = 0;
							 | 
						||
| 
								 | 
							
										var height = 0;
							 | 
						||
| 
								 | 
							
										var exposure = 1.0;
							 | 
						||
| 
								 | 
							
										// var gamma = 1.0;
							 | 
						||
| 
								 | 
							
										var rle = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i in 0...20) {
							 | 
						||
| 
								 | 
							
											var line = readLine();
							 | 
						||
| 
								 | 
							
											if (formatPattern.match(line)) {
							 | 
						||
| 
								 | 
							
												rle = true;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else if (exposurePattern.match(line)) {
							 | 
						||
| 
								 | 
							
												exposure = Std.parseFloat(exposurePattern.matched(1));
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else if (widthHeightPattern.match(line)) {
							 | 
						||
| 
								 | 
							
												height = Std.parseInt(widthHeightPattern.matched(1));
							 | 
						||
| 
								 | 
							
												width = Std.parseInt(widthHeightPattern.matched(2));
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// else if (radiancePattern.match(line)) {}
							 | 
						||
| 
								 | 
							
											// else if (commentPattern.match(line)) {}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!rle) {
							 | 
						||
| 
								 | 
							
											trace("File is not run length encoded!");
							 | 
						||
| 
								 | 
							
											return null;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var data = new UInt8Array(width * height * 4);
							 | 
						||
| 
								 | 
							
										var scanline_width = width;
							 | 
						||
| 
								 | 
							
										var num_scanlines = height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										readPixelsRawRLE(buffer, data, 0, scanline_width, num_scanlines);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// TODO: should be Float16
							 | 
						||
| 
								 | 
							
										var floatData = new Float32Array(width * height * 4);
							 | 
						||
| 
								 | 
							
										var offset = 0;
							 | 
						||
| 
								 | 
							
										while (offset < data.length) {
							 | 
						||
| 
								 | 
							
											var r = data[offset + 0] / 255;
							 | 
						||
| 
								 | 
							
											var g = data[offset + 1] / 255;
							 | 
						||
| 
								 | 
							
											var b = data[offset + 2] / 255;
							 | 
						||
| 
								 | 
							
											var e = data[offset + 3];
							 | 
						||
| 
								 | 
							
											var f = Math.pow(2.0, e - 128.0);
							 | 
						||
| 
								 | 
							
											r *= f;
							 | 
						||
| 
								 | 
							
											g *= f;
							 | 
						||
| 
								 | 
							
											b *= f;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											floatData[offset + 0] = r;
							 | 
						||
| 
								 | 
							
											floatData[offset + 1] = g;
							 | 
						||
| 
								 | 
							
											floatData[offset + 2] = b;
							 | 
						||
| 
								 | 
							
											floatData[offset + 3] = 1.0;
							 | 
						||
| 
								 | 
							
											offset += 4;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return {
							 | 
						||
| 
								 | 
							
											width: width,
							 | 
						||
| 
								 | 
							
											height: height,
							 | 
						||
| 
								 | 
							
											// exposure: exposure,
							 | 
						||
| 
								 | 
							
											// gamma: gamma,
							 | 
						||
| 
								 | 
							
											data: floatData
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |