2
0

GXS.FileHDR.pas 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.FileHDR;
  5. (* HDR File support *)
  6. interface
  7. uses
  8. Winapi.OpenGL,
  9. Winapi.OpenGLext,
  10. System.Classes,
  11. System.SysUtils,
  12. Stage.VectorTypes,
  13. Stage.VectorGeometry,
  14. Stage.RGBE,
  15. Stage.TextureFormat,
  16. Stage.Strings,
  17. GXS.ApplicationFileIO,
  18. GXS.Context,
  19. GXS.Graphics;
  20. type
  21. TgxHDRImage = class(TgxBaseImage)
  22. private
  23. function GetProgramType: Ansistring;
  24. procedure SetProgramType(aval: Ansistring);
  25. protected
  26. fGamma: Single; // image has already been gamma corrected with
  27. // given gamma. defaults to 1.0 (no correction) */
  28. fExposure: Single; // a value of 1.0 in an image corresponds to
  29. // <exposure> watts/steradian/m^2.
  30. // defaults to 1.0
  31. fProgramType: string[16];
  32. public
  33. class function Capabilities: TDataFileCapabilities; override;
  34. procedure LoadFromFile(const filename: string); override;
  35. procedure LoadFromStream(stream: TStream); override;
  36. procedure AssignFromTexture(textureContext: TgxContext;
  37. const textureHandle: GLuint;
  38. textureTarget: TglTextureTarget;
  39. const CurrentFormat: Boolean;
  40. const intFormat: TglInternalFormat); reintroduce;
  41. property Gamma: Single read fGamma;
  42. property Exposure: Single read fExposure;
  43. property ProgramType: Ansistring read GetProgramType write SetProgramType;
  44. end;
  45. //====================================================================
  46. implementation
  47. //====================================================================
  48. // ------------------
  49. // ------------------ TgxHDRImage ------------------
  50. // ------------------
  51. procedure TgxHDRImage.LoadFromFile(const filename: string);
  52. var
  53. fs: TStream;
  54. begin
  55. if FileStreamExists(filename) then
  56. begin
  57. fs := TFileStream.Create(filename, fmOpenRead);
  58. try
  59. LoadFromStream(fs);
  60. finally
  61. fs.Free;
  62. ResourceName := filename;
  63. end;
  64. end
  65. else
  66. raise EInvalidRasterFile.CreateFmt('File %s not found', [filename]);
  67. end;
  68. procedure TgxHDRImage.LoadFromStream(stream: TStream);
  69. const
  70. cRgbeFormat32bit = 'FORMAT=32-bit_rle_rgbe';
  71. cGamma = 'GAMMA=';
  72. cEXPOSURE = 'EXPOSURE=';
  73. cY = '-Y ';
  74. var
  75. buf: array [0 .. 1023] of AnsiChar;
  76. header: TStringList;
  77. s, sn: string;
  78. lineSize: integer;
  79. tempBuf, top, bottom: PByte;
  80. i, j, err: integer;
  81. formatDefined: Boolean;
  82. function CmpWord(const word: string): Boolean;
  83. var
  84. l: integer;
  85. ts: string;
  86. begin
  87. Result := false;
  88. ts := header.Strings[i];
  89. if Length(word) > Length(ts) then
  90. Exit;
  91. for l := 1 to Length(word) do
  92. if word[l] <> ts[l] then
  93. Exit;
  94. Result := true;
  95. end;
  96. begin
  97. fProgramType := '';
  98. fGamma := 1.0;
  99. fExposure := 1.0;
  100. UnMipmap;
  101. // Read HDR header
  102. stream.Read(buf, Length(buf) * sizeOf(AnsiChar));
  103. header := TStringList.Create;
  104. s := '';
  105. i := 0;
  106. j := 0;
  107. while i < Length(buf) do
  108. begin
  109. if buf[i] = #0 then
  110. Break;
  111. if buf[i] = #10 then
  112. begin
  113. header.Add(s);
  114. s := '';
  115. Inc(i);
  116. j := i;
  117. Continue;
  118. end;
  119. s := s + string(buf[i]);
  120. Inc(i);
  121. end;
  122. if i < Length(buf) then
  123. stream.Position := j
  124. else
  125. raise EInvalidRasterFile.Create('Can''t find HDR header end.');
  126. if (header.Strings[0][1] <> '#') or (header.Strings[0][2] <> '?') then
  127. begin
  128. header.Free;
  129. raise EInvalidRasterFile.Create('Bad HDR initial token.');
  130. end;
  131. // Get program type
  132. SetProgramType(Ansistring(Copy(header.Strings[0], 3, Length(header.Strings[0]) - 2)));
  133. formatDefined := false;
  134. for i := 1 to header.Count - 1 do
  135. begin
  136. if header.Strings[i] = cRgbeFormat32bit then
  137. formatDefined := true
  138. else if CmpWord(cGamma) then
  139. begin
  140. j := Length(cGamma);
  141. s := Copy(header.Strings[i], j + 1, Length(header.Strings[i]) - j);
  142. val(s, fGamma, err);
  143. if err <> 0 then
  144. raise EInvalidRasterFile.Create('Bad HDR header.');
  145. end
  146. else if CmpWord(cEXPOSURE) then
  147. begin
  148. j := Length(cEXPOSURE);
  149. s := Copy(header.Strings[i], j + 1, Length(header.Strings[i]) - j);
  150. val(s, fExposure, err);
  151. if err <> 0 then
  152. raise EInvalidRasterFile.Create('Bad HDR header.');
  153. end
  154. else if CmpWord(cY) then
  155. begin
  156. j := Length(cY);
  157. s := Copy(header.Strings[i], j + 1, Length(header.Strings[i]) - j);
  158. j := Pos(' ', s);
  159. sn := Copy(s, 1, j - 1);
  160. val(sn, FLOD[0].Height, err);
  161. Delete(s, 1, j + 3); // scip '+X '
  162. val(s, FLOD[0].Width, err);
  163. if err <> 0 then
  164. raise EInvalidRasterFile.Create('Bad HDR header.');
  165. end
  166. end; // for i
  167. header.Free;
  168. if not formatDefined then
  169. raise EInvalidRasterFile.Create('no FORMAT specifier found.');
  170. if (FLOD[0].Width = 0) or (FLOD[0].Height = 0) then
  171. raise EInvalidRasterFile.Create('Bad image dimension.');
  172. // set all the parameters
  173. FLOD[0].Depth := 0;
  174. fColorFormat := GL_RGB;
  175. fInternalFormat := tfRGBA_FLOAT32;
  176. fDataType := GL_FLOAT;
  177. fCubeMap := false;
  178. fTextureArray := false;
  179. fElementSize := GetTextureElementSize(tfFLOAT_RGB32);
  180. ReallocMem(fData, DataSize);
  181. LoadRLEpixels(stream, PSingle(fData), FLOD[0].Width, FLOD[0].Height);
  182. // hdr images come in upside down then flip it
  183. lineSize := fElementSize * FLOD[0].Width;
  184. GetMem(tempBuf, lineSize);
  185. top := PByte(fData);
  186. bottom := top;
  187. Inc(bottom, lineSize * (FLOD[0].Height - 1));
  188. for j := 0 to (FLOD[0].Height div 2) - 1 do
  189. begin
  190. Move(top^, tempBuf^, lineSize);
  191. Move(bottom^, top^, lineSize);
  192. Move(tempBuf^, bottom^, lineSize);
  193. Inc(top, lineSize);
  194. Dec(bottom, lineSize);
  195. end;
  196. FreeMem(tempBuf);
  197. end;
  198. function TgxHDRImage.GetProgramType: Ansistring;
  199. begin
  200. Result := fProgramType;
  201. end;
  202. procedure TgxHDRImage.SetProgramType(aval: Ansistring);
  203. var
  204. i: integer;
  205. begin
  206. for i := 1 to Length(fProgramType) do
  207. fProgramType[i] := aval[i];
  208. end;
  209. procedure TgxHDRImage.AssignFromTexture(textureContext: TgxContext; const textureHandle: GLuint;
  210. textureTarget: TglTextureTarget; const CurrentFormat: Boolean; const intFormat: TglInternalFormat);
  211. var
  212. oldContext: TgxContext;
  213. contextActivate: Boolean;
  214. texFormat: Cardinal;
  215. residentFormat: TglInternalFormat;
  216. glTarget: GLEnum;
  217. begin
  218. glTarget := DecodeTextureTarget(textureTarget);
  219. if not((glTarget = GL_TEXTURE_2D) or (glTarget = GL_TEXTURE_RECTANGLE)) then
  220. Exit;
  221. oldContext := CurrentContext;
  222. contextActivate := (oldContext <> textureContext);
  223. if contextActivate then
  224. begin
  225. if Assigned(oldContext) then
  226. oldContext.Deactivate;
  227. textureContext.Activate;
  228. end;
  229. try
  230. textureContext.gxStates.TextureBinding[0, textureTarget] := textureHandle;
  231. fLevelCount := 0;
  232. fCubeMap := false;
  233. fTextureArray := false;
  234. fColorFormat := GL_RGB;
  235. fDataType := GL_FLOAT;
  236. // Check level existence
  237. glGetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_INTERNAL_FORMAT, @texFormat);
  238. if texFormat > 1 then
  239. begin
  240. glGetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_WIDTH, @FLOD[0].Width);
  241. glGetTexLevelParameteriv(glTarget, 0, GL_TEXTURE_HEIGHT, @FLOD[0].Height);
  242. FLOD[0].Depth := 0;
  243. residentFormat := OpenGLFormatToInternalFormat(texFormat);
  244. if CurrentFormat then
  245. fInternalFormat := residentFormat
  246. else
  247. fInternalFormat := intFormat;
  248. Inc(fLevelCount);
  249. end;
  250. if fLevelCount > 0 then
  251. begin
  252. fElementSize := GetTextureElementSize(fColorFormat, fDataType);
  253. ReallocMem(fData, DataSize);
  254. glGetTexImage(glTarget, 0, fColorFormat, fDataType, fData);
  255. end
  256. else
  257. fLevelCount := 1;
  258. /// CheckOpenGLError;
  259. finally
  260. if contextActivate then
  261. begin
  262. textureContext.Deactivate;
  263. if Assigned(oldContext) then
  264. oldContext.Activate;
  265. end;
  266. end;
  267. end;
  268. class function TgxHDRImage.Capabilities: TDataFileCapabilities;
  269. begin
  270. Result := [dfcRead { , dfcWrite } ];
  271. end;
  272. //-------------------------------------------------------------------
  273. initialization
  274. //-------------------------------------------------------------------
  275. RegisterRasterFormat('hdr', 'High Dynamic Range Image', TgxHDRImage);
  276. end.