babylon.tools.hdr.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /// <reference path="../../../dist/preview release/babylon.d.ts"/>
  2. module BABYLON.Internals {
  3. export interface HDRInfo {
  4. height: number;
  5. width: number;
  6. dataPosition: number;
  7. };
  8. export class HDRTools {
  9. private static Ldexp(mantissa: number, exponent: number): number {
  10. if (exponent > 1023) {
  11. return mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023);
  12. }
  13. if (exponent < -1074) {
  14. return mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074);
  15. }
  16. return mantissa * Math.pow(2, exponent);
  17. }
  18. private static Rgbe2float(float32array: Float32Array,
  19. red: number, green: number, blue: number, exponent: number,
  20. index: number)
  21. {
  22. if (exponent > 0) { /*nonzero pixel*/
  23. exponent = this.Ldexp(1.0, exponent - (128 + 8));
  24. float32array[index + 0] = red * exponent;
  25. float32array[index + 1] = green * exponent;
  26. float32array[index + 2] = blue * exponent;
  27. }
  28. else {
  29. float32array[index + 0] = 0;
  30. float32array[index + 1] = 0;
  31. float32array[index + 2] = 0;
  32. }
  33. }
  34. private static readStringLine(uint8array: Uint8Array, startIndex: number): string {
  35. var line = "";
  36. var character = "";
  37. for(var i = startIndex; i < uint8array.length - startIndex; i++) {
  38. character = String.fromCharCode(uint8array[i]);
  39. if (character == "\n") {
  40. break;
  41. }
  42. line += character;
  43. }
  44. return line;
  45. }
  46. /* minimal header reading. modify if you want to parse more information */
  47. public static RGBE_ReadHeader(uint8array: Uint8Array) : HDRInfo {
  48. var height: number = 0;
  49. var width: number = 0;
  50. var line = this.readStringLine(uint8array, 0);
  51. if (line[0] != '#' || line[1] != '?') {
  52. throw "Bad HDR Format.";
  53. }
  54. var endOfHeader = false;
  55. var findFormat = false;
  56. var lineIndex:number = 0;
  57. do {
  58. lineIndex += (line.length + 1);
  59. line = this.readStringLine(uint8array, lineIndex);
  60. if (line == "FORMAT=32-bit_rle_rgbe") {
  61. findFormat = true;
  62. }
  63. else if (line.length == 0) {
  64. endOfHeader = true;
  65. }
  66. } while (!endOfHeader);
  67. if (!findFormat) {
  68. throw "HDR Bad header format, unsupported FORMAT";
  69. }
  70. lineIndex += (line.length + 1);
  71. line = this.readStringLine(uint8array, lineIndex);
  72. var sizeRegexp = /^\-Y (.*) \+X (.*)$/g;
  73. var match = sizeRegexp.exec(line);
  74. // TODO. Support +Y and -X if needed.
  75. if (match.length < 3) {
  76. throw "HDR Bad header format, no size";
  77. }
  78. width = parseInt(match[2]);
  79. height = parseInt(match[1]);
  80. if (width < 8 || width > 0x7fff) {
  81. throw "HDR Bad header format, unsupported size";
  82. }
  83. lineIndex += (line.length + 1);
  84. return {
  85. height: height,
  86. width: width,
  87. dataPosition: lineIndex
  88. };
  89. }
  90. public static GetCubeMapTextureData(buffer: ArrayBuffer, size: number) : CubeMapInfo {
  91. var uint8array = new Uint8Array(buffer);
  92. var hdrInfo = this.RGBE_ReadHeader(uint8array);
  93. var data = this.RGBE_ReadPixels_RLE(uint8array, hdrInfo);
  94. var cubeMapData = PanoramaToCubeMapTools.ConvertPanoramaToCubemap(data, hdrInfo.width, hdrInfo.height, size);
  95. return cubeMapData;
  96. }
  97. public static RGBE_ReadPixels(uint8array:Uint8Array, hdrInfo:HDRInfo): Float32Array {
  98. // Keep for multi format supports.
  99. return this.RGBE_ReadPixels_RLE(uint8array, hdrInfo);
  100. }
  101. private static RGBE_ReadPixels_RLE(uint8array:Uint8Array, hdrInfo:HDRInfo): Float32Array {
  102. var num_scanlines = hdrInfo.height;
  103. var scanline_width = hdrInfo.width;
  104. var a: number, b: number, c: number, d: number, count: number;
  105. var dataIndex = hdrInfo.dataPosition;
  106. var index = 0, endIndex = 0, i = 0;
  107. var scanLineArrayBuffer = new ArrayBuffer(scanline_width * 4); // four channel R G B E
  108. var scanLineArray = new Uint8Array(scanLineArrayBuffer);
  109. // 3 channels of 4 bytes per pixel in float.
  110. var resultBuffer = new ArrayBuffer(hdrInfo.width * hdrInfo.height * 4 * 3);
  111. var resultArray = new Float32Array(resultBuffer);
  112. // read in each successive scanline
  113. while(num_scanlines > 0) {
  114. a = uint8array[dataIndex++];
  115. b = uint8array[dataIndex++];
  116. c = uint8array[dataIndex++];
  117. d = uint8array[dataIndex++];
  118. if (a != 2 || b != 2 || (c & 0x80)) {
  119. // this file is not run length encoded
  120. throw "HDR Bad header format, not RLE";
  121. }
  122. if (((c<<8) | d) != scanline_width) {
  123. throw "HDR Bad header format, wrong scan line width";
  124. }
  125. index = 0;
  126. // read each of the four channels for the scanline into the buffer
  127. for(i = 0; i < 4; i++) {
  128. endIndex = (i + 1) * scanline_width;
  129. while(index < endIndex) {
  130. a = uint8array[dataIndex++];
  131. b = uint8array[dataIndex++];
  132. if (a > 128) {
  133. // a run of the same value
  134. count = a - 128;
  135. if ((count == 0) || (count > endIndex - index)) {
  136. throw "HDR Bad Format, bad scanline data (run)";
  137. }
  138. while(count-- > 0) {
  139. scanLineArray[index++] = b;
  140. }
  141. }
  142. else {
  143. // a non-run
  144. count = a;
  145. if ((count == 0) || (count > endIndex - index)) {
  146. throw "HDR Bad Format, bad scanline data (non-run)";
  147. }
  148. scanLineArray[index++] = b;
  149. if (--count > 0) {
  150. for (var j = 0; j < count; j++) {
  151. scanLineArray[index++] = uint8array[dataIndex++];
  152. }
  153. }
  154. }
  155. }
  156. }
  157. // now convert data from buffer into floats
  158. for(i = 0; i < scanline_width; i++) {
  159. a = scanLineArray[i];
  160. b = scanLineArray[i + scanline_width];
  161. c = scanLineArray[i + 2 * scanline_width];
  162. d = scanLineArray[i + 3 * scanline_width];
  163. this.Rgbe2float(resultArray,
  164. a, b, c, d,
  165. (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
  166. }
  167. num_scanlines--;
  168. }
  169. return resultArray;
  170. }
  171. }
  172. }