GLS.RGBE.pas 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.RGBE;
  5. (* GLScene RGBE utils *)
  6. interface
  7. uses
  8. System.Classes,
  9. System.SysUtils,
  10. System.Math,
  11. GLS.VectorTypes,
  12. GLS.VectorGeometry;
  13. procedure Float2rgbe(var RGBE: TVector4b; const Red, Green, Blue: Single);
  14. procedure Rgbe2float(var Red, Green, Blue: Single; const RGBE: TVector4b);
  15. procedure LoadRLEpixels(Stream: TStream; Dst: PSingle;
  16. Scanline_width, Num_scanlines: Integer);
  17. procedure LoadRGBEpixels(Stream: TStream; Dst: PSingle; Numpixels: Integer);
  18. //====================================================================
  19. implementation
  20. //====================================================================
  21. type
  22. ERGBEexception = class(Exception);
  23. // Extract exponent and mantissa from X
  24. procedure Frexp(X: Extended; var Mantissa: Extended; var Exponent: Integer);
  25. begin
  26. Exponent := 0;
  27. if (X <> 0) then
  28. if (Abs(X) < 0.5) then
  29. repeat
  30. X := X * 2;
  31. Dec(Exponent);
  32. until (Abs(X) >= 0.5)
  33. else
  34. while (Abs(X) >= 1) do
  35. begin
  36. X := X / 2;
  37. Inc(Exponent);
  38. end;
  39. Mantissa := X;
  40. end;
  41. function Ldexp(X: Extended; const P: Integer): Extended;
  42. begin
  43. Ldexp := X * PowerSingle(2.0, P); // Result := X * (2^P)
  44. end;
  45. // standard conversion from float pixels to rgbe pixels
  46. procedure Float2rgbe(var RGBE: TVector4b; const Red, Green, Blue: Single);
  47. var
  48. V, M: Extended;
  49. E: Integer;
  50. begin
  51. V := Red;
  52. if (Green > V) then
  53. V := Green;
  54. if (Blue > V) then
  55. V := Blue;
  56. if (V < 1E-32) then
  57. begin
  58. RGBE.X := 0;
  59. RGBE.Y := 0;
  60. RGBE.Z := 0;
  61. RGBE.W := 0;
  62. end
  63. else
  64. begin
  65. FrExp(V, M, E);
  66. M := M * 256 / V;
  67. RGBE.X := Floor(Red * V);
  68. RGBE.Y := Floor(Green * V);
  69. RGBE.Z := Floor(Blue * V);
  70. RGBE.W := Floor(E + 128);
  71. end;
  72. end;
  73. // standard conversion from rgbe to float pixels
  74. // note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels
  75. // in the range [0,1] to map back into the range [0,1].
  76. procedure Rgbe2float(var Red, Green, Blue: Single; const RGBE: TVector4b);
  77. var
  78. F: Single;
  79. begin
  80. if RGBE.W <> 0 then // nonzero pixel
  81. begin
  82. F := Ldexp(1.0, RGBE.W - (128 + 8));
  83. Red := RGBE.X * F;
  84. Green := RGBE.Y * F;
  85. Blue := RGBE.Z * F;
  86. end
  87. else
  88. begin
  89. Red := 0;
  90. Green := 0;
  91. Blue := 0;
  92. end;
  93. end;
  94. procedure LoadRLEpixels(Stream: TStream; Dst: PSingle;
  95. Scanline_width, Num_scanlines: Integer);
  96. var
  97. RgbeTemp: TVector4b;
  98. Buf: TVector2b;
  99. Rf, Gf, Bf: Single;
  100. Scanline_buffer: PByteArray;
  101. Ptr, Ptr_end: PByte;
  102. I: Integer;
  103. Count: Cardinal;
  104. begin
  105. if (Scanline_width < 8) or (Scanline_width > $7FFF) then
  106. begin
  107. // run length encoding is not allowed so read flat
  108. LoadRGBEPixels(Stream, Dst, Scanline_width * Num_scanlines);
  109. Exit;
  110. end;
  111. Scanline_buffer := nil;
  112. while Num_scanlines > 0 do
  113. begin
  114. Stream.Read(RgbeTemp, SizeOf(TVector4b));
  115. if (RgbeTemp.X <> 2) or (RgbeTemp.Y <> 2) or
  116. (RgbeTemp.Z and $80 <> 0) then
  117. begin
  118. // this file is not run length encoded
  119. Rgbe2float(Rf, Gf, Bf, RgbeTemp);
  120. Dst^ := Rf;
  121. Inc(Dst);
  122. Dst^ := Gf;
  123. Inc(Dst);
  124. Dst^ := Bf;
  125. Inc(Dst);
  126. if Assigned(Scanline_buffer) then
  127. FreeMem(Scanline_buffer);
  128. LoadRGBEpixels(Stream, Dst, Scanline_width * Num_scanlines - 1);
  129. Exit;
  130. end;
  131. if ((Integer(RgbeTemp.Z) shl 8) or RgbeTemp.W) <> Scanline_width
  132. then
  133. begin
  134. if Assigned(Scanline_buffer) then
  135. FreeMem(Scanline_buffer);
  136. raise ERGBEexception.Create('Wrong scanline width.');
  137. end;
  138. if not Assigned(Scanline_buffer) then
  139. ReallocMem(Scanline_buffer, 4 * Scanline_width);
  140. Ptr := PByte(Scanline_buffer);
  141. // read each of the four channels for the scanline into the buffer
  142. for I := 0 to 3 do
  143. begin
  144. Ptr_end := @Scanline_buffer[(I + 1) * Scanline_width];
  145. while Cardinal(Ptr) < Cardinal(Ptr_end) do
  146. begin
  147. Stream.Read(Buf, SizeOf(TVector2b));
  148. if Buf.X > 128 then
  149. begin // a run of the same value
  150. Count := Buf.X - 128;
  151. if (Count = 0) or (Count > Cardinal(Ptr_end) - Cardinal(Ptr)) then
  152. begin
  153. FreeMem(Scanline_buffer);
  154. raise ERGBEexception.Create('Bad HDR scanline data.');
  155. end;
  156. while Count > 0 do
  157. begin
  158. Ptr^ := Buf.Y;
  159. Dec(Count);
  160. Inc(Ptr);
  161. end;
  162. end
  163. else
  164. begin // a non-run
  165. Count := Buf.X;
  166. if (Count = 0) or (Count > Cardinal(Ptr_end) - Cardinal(Ptr)) then
  167. begin
  168. FreeMem(Scanline_buffer);
  169. raise ERGBEexception.Create('Bad HDR scanline data.');
  170. end;
  171. Ptr^ := Buf.Y;
  172. Dec(Count);
  173. Inc(Ptr);
  174. if Count > 0 then
  175. Stream.Read(Ptr^, Count);
  176. Inc(Ptr, Count);
  177. end;
  178. end;
  179. end;
  180. // now convert data from buffer into floats
  181. for I := 0 to Scanline_width - 1 do
  182. begin
  183. RgbeTemp.X := Scanline_buffer[I];
  184. RgbeTemp.Y := Scanline_buffer[I + Scanline_width];
  185. RgbeTemp.Z := Scanline_buffer[I + 2 * Scanline_width];
  186. RgbeTemp.W := Scanline_buffer[I + 3 * Scanline_width];
  187. Rgbe2float(Rf, Gf, Bf, RgbeTemp);
  188. Dst^ := Rf;
  189. Inc(Dst);
  190. Dst^ := Gf;
  191. Inc(Dst);
  192. Dst^ := Bf;
  193. Inc(Dst);
  194. end;
  195. Dec(Num_scanlines);
  196. end;
  197. if Assigned(Scanline_buffer) then
  198. FreeMem(Scanline_buffer);
  199. end;
  200. procedure LoadRGBEpixels(Stream: TStream; Dst: PSingle; Numpixels: Integer);
  201. var
  202. RgbeTemp: TVector4b;
  203. Rf, Gf, Bf: Single;
  204. begin
  205. while Numpixels > 0 do
  206. begin
  207. Stream.Read(RgbeTemp, SizeOf(TVector4b));
  208. Rgbe2float(Rf, Gf, Bf, RgbeTemp);
  209. Dst^ := Rf;
  210. Inc(Dst);
  211. Dst^ := Gf;
  212. Inc(Dst);
  213. Dst^ := Bf;
  214. Inc(Dst);
  215. Dec(Numpixels);
  216. end;
  217. end;
  218. end.