Formats.TGA.pas 6.3 KB

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