Stage.RGBE.pas 5.6 KB

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