Formatx.TGA.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit Formatx.TGA;
  5. (* Graphic engine friendly loading of TGA image *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. Winapi.OpenGLext,
  11. System.Classes,
  12. System.SysUtils,
  13. GXS.ApplicationFileIO,
  14. Stage.Strings,
  15. GXS.Context,
  16. GXS.Graphics,
  17. Stage.TextureFormat;
  18. type
  19. TgxTGAImage = class(TgxBaseImage)
  20. public
  21. procedure LoadFromFile(const filename: string); override;
  22. procedure SaveToFile(const filename: string); override;
  23. procedure LoadFromStream(stream: TStream); override;
  24. procedure SaveToStream(stream: TStream); override;
  25. class function Capabilities: TDataFileCapabilities; override;
  26. procedure AssignFromTexture(textureContext: TgxContext;
  27. const textureHandle: GLuint;
  28. textureTarget: TglTextureTarget;
  29. const CurrentFormat: boolean;
  30. const intFormat: TglInternalFormat); reintroduce;
  31. end;
  32. //======================================================================
  33. implementation
  34. //======================================================================
  35. type
  36. TTGAFileHeader = packed record
  37. IDLength: Byte;
  38. ColorMapType: Byte;
  39. ImageType: Byte;
  40. ColorMapOrigin: Word;
  41. ColorMapLength: Word;
  42. ColorMapEntrySize: Byte;
  43. XOrigin: Word;
  44. YOrigin: Word;
  45. Width: Word;
  46. Height: Word;
  47. PixelSize: Byte;
  48. ImageDescriptor: Byte;
  49. end;
  50. procedure ReadAndUnPackRLETGA24(stream: TStream; destBuf: PAnsiChar;
  51. totalSize: Integer);
  52. type
  53. TRGB24 = packed record
  54. r, g, b: Byte;
  55. end;
  56. PRGB24 = ^TRGB24;
  57. var
  58. n: Integer;
  59. color: TRGB24;
  60. bufEnd: PAnsiChar;
  61. b: Byte;
  62. begin
  63. bufEnd := @destBuf[totalSize];
  64. while destBuf < bufEnd do
  65. begin
  66. stream.Read(b, 1);
  67. if b >= 128 then
  68. begin
  69. // repetition packet
  70. stream.Read(color, 3);
  71. b := (b and 127) + 1;
  72. while b > 0 do
  73. begin
  74. PRGB24(destBuf)^ := color;
  75. Inc(destBuf, 3);
  76. Dec(b);
  77. end;
  78. end
  79. else
  80. begin
  81. n := ((b and 127) + 1) * 3;
  82. stream.Read(destBuf^, n);
  83. Inc(destBuf, n);
  84. end;
  85. end;
  86. end;
  87. procedure ReadAndUnPackRLETGA32(stream: TStream; destBuf: PAnsiChar;
  88. totalSize: Integer);
  89. type
  90. TRGB32 = packed record
  91. r, g, b, a: Byte;
  92. end;
  93. PRGB32 = ^TRGB32;
  94. var
  95. n: Integer;
  96. color: TRGB32;
  97. bufEnd: PAnsiChar;
  98. b: Byte;
  99. begin
  100. bufEnd := @destBuf[totalSize];
  101. while destBuf < bufEnd do
  102. begin
  103. stream.Read(b, 1);
  104. if b >= 128 then
  105. begin
  106. // repetition packet
  107. stream.Read(color, 4);
  108. b := (b and 127) + 1;
  109. while b > 0 do
  110. begin
  111. PRGB32(destBuf)^ := color;
  112. Inc(destBuf, 4);
  113. Dec(b);
  114. end;
  115. end
  116. else
  117. begin
  118. n := ((b and 127) + 1) * 4;
  119. stream.Read(destBuf^, n);
  120. Inc(destBuf, n);
  121. end;
  122. end;
  123. end;
  124. procedure TgxTGAImage.LoadFromFile(const filename: string);
  125. var
  126. fs: TStream;
  127. begin
  128. if FileStreamExists(fileName) then
  129. begin
  130. fs := TFileStream.Create(fileName, fmOpenRead);
  131. try
  132. LoadFromStream(fs);
  133. finally
  134. fs.Free;
  135. ResourceName := filename;
  136. end;
  137. end
  138. else
  139. raise EInvalidRasterFile.CreateFmt('File %s not found', [filename]);
  140. end;
  141. procedure TgxTGAImage.SaveToFile(const filename: string);
  142. var
  143. fs: TStream;
  144. begin
  145. fs := TFileStream.Create(fileName, fmOpenWrite or fmCreate);
  146. try
  147. SaveToStream(fs);
  148. finally
  149. fs.Free;
  150. end;
  151. ResourceName := filename;
  152. end;
  153. // LoadFromStream
  154. //
  155. procedure TgxTGAImage.LoadFromStream(stream: TStream);
  156. var
  157. LHeader: TTGAFileHeader;
  158. y, rowSize, bufSize: Integer;
  159. verticalFlip: Boolean;
  160. unpackBuf: PAnsiChar;
  161. Ptr: PByte;
  162. begin
  163. stream.Read(LHeader, Sizeof(TTGAFileHeader));
  164. if LHeader.ColorMapType <> 0 then
  165. raise EInvalidRasterFile.Create('ColorMapped TGA unsupported');
  166. UnMipmap;
  167. FLOD[0].Width := LHeader.Width;
  168. FLOD[0].Height := LHeader.Height;
  169. FLOD[0].Depth := 0;
  170. case LHeader.PixelSize of
  171. 24:
  172. begin
  173. FColorFormat := GL_BGR;
  174. FInternalFormat := tfRGB8;
  175. FElementSize := 3;
  176. end;
  177. 32:
  178. begin
  179. FColorFormat := GL_RGBA;
  180. FInternalFormat := tfRGBA8;
  181. FElementSize := 4;
  182. end;
  183. else
  184. raise EInvalidRasterFile.Create('Unsupported TGA ImageType');
  185. end;
  186. FDataType := GL_UNSIGNED_BYTE;
  187. FCubeMap := False;
  188. FTextureArray := False;
  189. ReallocMem(FData, DataSize);
  190. rowSize := GetWidth * FElementSize;
  191. verticalFlip := ((LHeader.ImageDescriptor and $20) <> 1);
  192. if LHeader.IDLength > 0 then
  193. stream.Seek(LHeader.IDLength, soFromCurrent);
  194. case LHeader.ImageType of
  195. 2:
  196. begin // uncompressed RGB/RGBA
  197. if verticalFlip then
  198. begin
  199. Ptr := PByte(FData);
  200. Inc(Ptr, rowSize * (GetHeight - 1));
  201. for y := 0 to GetHeight - 1 do
  202. begin
  203. stream.Read(Ptr^, rowSize);
  204. Dec(Ptr, rowSize);
  205. end;
  206. end
  207. else
  208. stream.Read(FData^, rowSize * GetHeight);
  209. end;
  210. 10:
  211. begin // RLE encoded RGB/RGBA
  212. bufSize := GetHeight * rowSize;
  213. GetMem(unpackBuf, bufSize);
  214. try
  215. // read & unpack everything
  216. if LHeader.PixelSize = 24 then
  217. ReadAndUnPackRLETGA24(stream, unpackBuf, bufSize)
  218. else
  219. ReadAndUnPackRLETGA32(stream, unpackBuf, bufSize);
  220. // fillup bitmap
  221. if verticalFlip then
  222. begin
  223. Ptr := PByte(FData);
  224. Inc(Ptr, rowSize * (GetHeight - 1));
  225. for y := 0 to GetHeight - 1 do
  226. begin
  227. Move(unPackBuf[y * rowSize], Ptr^, rowSize);
  228. Dec(Ptr, rowSize);
  229. end;
  230. end
  231. else
  232. Move(unPackBuf[rowSize * GetHeight], FData^, rowSize * GetHeight);
  233. finally
  234. FreeMem(unpackBuf);
  235. end;
  236. end;
  237. else
  238. raise EInvalidRasterFile.CreateFmt('Unsupported TGA ImageType %d',
  239. [LHeader.ImageType]);
  240. end;
  241. end;
  242. procedure TgxTGAImage.SaveToStream(stream: TStream);
  243. begin
  244. {$MESSAGE Hint 'TgxTGAImage.SaveToStream not yet implemented' }
  245. end;
  246. procedure TgxTGAImage.AssignFromTexture(textureContext: TgxContext;
  247. const textureHandle: GLuint; textureTarget: TglTextureTarget;
  248. const CurrentFormat: boolean; const intFormat: TglInternalFormat);
  249. begin
  250. {$MESSAGE Hint 'TgxTGAImage.AssignFromTexture not yet implemented' }
  251. end;
  252. class function TgxTGAImage.Capabilities: TDataFileCapabilities;
  253. begin
  254. Result := [dfcRead {, dfcWrite}];
  255. end;
  256. //===========================================================
  257. initialization
  258. //===========================================================
  259. RegisterRasterFormat('tga', 'TARGA Image File', TgxTGAImage);
  260. end.