Formats.TGA.pas 6.5 KB

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