FileTGA.pas 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Graphic engine friendly loading of TGA image.
  6. }
  7. unit FileTGA;
  8. interface
  9. {.$I GLScene.inc}
  10. uses
  11. System.Classes,
  12. System.SysUtils,
  13. OpenGLTokens,
  14. GLContext,
  15. GLGraphics,
  16. GLTextureFormat,
  17. GLApplicationFileIO;
  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;
  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 TGLTGAImage.LoadFromFile(const filename: string);
  125. var
  126. fs: TStream;
  127. begin
  128. if FileStreamExists(fileName) then
  129. begin
  130. fs := CreateFileStream(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 TGLTGAImage.SaveToFile(const filename: string);
  142. var
  143. fs: TStream;
  144. begin
  145. fs := CreateFileStream(fileName, fmOpenWrite or fmCreate);
  146. try
  147. SaveToStream(fs);
  148. finally
  149. fs.Free;
  150. end;
  151. ResourceName := filename;
  152. end;
  153. procedure TGLTGAImage.LoadFromStream(stream: TStream);
  154. var
  155. LHeader: TTGAFileHeader;
  156. y, rowSize, bufSize: Integer;
  157. verticalFlip: Boolean;
  158. unpackBuf: PAnsiChar;
  159. Ptr: PByte;
  160. begin
  161. stream.Read(LHeader, Sizeof(TTGAFileHeader));
  162. if LHeader.ColorMapType <> 0 then
  163. raise EInvalidRasterFile.Create('ColorMapped TGA unsupported');
  164. UnMipmap;
  165. FLOD[0].Width := LHeader.Width;
  166. FLOD[0].Height := LHeader.Height;
  167. FLOD[0].Depth := 0;
  168. case LHeader.PixelSize of
  169. 24:
  170. begin
  171. FColorFormat := GL_BGR;
  172. FInternalFormat := tfRGB8;
  173. FElementSize := 3;
  174. end;
  175. 32:
  176. begin
  177. FColorFormat := GL_RGBA;
  178. FInternalFormat := tfRGBA8;
  179. FElementSize := 4;
  180. end;
  181. else
  182. raise EInvalidRasterFile.Create('Unsupported TGA ImageType');
  183. end;
  184. FDataType := GL_UNSIGNED_BYTE;
  185. FCubeMap := False;
  186. FTextureArray := False;
  187. ReallocMem(FData, DataSize);
  188. rowSize := GetWidth * FElementSize;
  189. verticalFlip := ((LHeader.ImageDescriptor and $20) <> 1);
  190. if LHeader.IDLength > 0 then
  191. stream.Seek(LHeader.IDLength, soFromCurrent);
  192. case LHeader.ImageType of
  193. 2:
  194. begin // uncompressed RGB/RGBA
  195. if verticalFlip then
  196. begin
  197. Ptr := PByte(FData);
  198. Inc(Ptr, rowSize * (GetHeight - 1));
  199. for y := 0 to GetHeight - 1 do
  200. begin
  201. stream.Read(Ptr^, rowSize);
  202. Dec(Ptr, rowSize);
  203. end;
  204. end
  205. else
  206. stream.Read(FData^, rowSize * GetHeight);
  207. end;
  208. 10:
  209. begin // RLE encoded RGB/RGBA
  210. bufSize := GetHeight * rowSize;
  211. GetMem(unpackBuf, bufSize);
  212. try
  213. // read & unpack everything
  214. if LHeader.PixelSize = 24 then
  215. ReadAndUnPackRLETGA24(stream, unpackBuf, bufSize)
  216. else
  217. ReadAndUnPackRLETGA32(stream, unpackBuf, bufSize);
  218. // fillup bitmap
  219. if verticalFlip then
  220. begin
  221. Ptr := PByte(FData);
  222. Inc(Ptr, rowSize * (GetHeight - 1));
  223. for y := 0 to GetHeight - 1 do
  224. begin
  225. Move(unPackBuf[y * rowSize], Ptr^, rowSize);
  226. Dec(Ptr, rowSize);
  227. end;
  228. end
  229. else
  230. Move(unPackBuf[rowSize * GetHeight], FData^, rowSize * GetHeight);
  231. finally
  232. FreeMem(unpackBuf);
  233. end;
  234. end;
  235. else
  236. raise EInvalidRasterFile.CreateFmt('Unsupported TGA ImageType %d',
  237. [LHeader.ImageType]);
  238. end;
  239. end;
  240. procedure TGLTGAImage.SaveToStream(stream: TStream);
  241. begin
  242. {$MESSAGE Hint 'TGLTGAImage.SaveToStream not yet implemented' }
  243. end;
  244. procedure TGLTGAImage.AssignFromTexture(textureContext: TGLContext;
  245. const textureHandle: Cardinal; textureTarget: TGLTextureTarget;
  246. const CurrentFormat: boolean; const intFormat: TGLInternalFormat);
  247. begin
  248. {$MESSAGE Hint 'TGLTGAImage.AssignFromTexture not yet implemented' }
  249. end;
  250. class function TGLTGAImage.Capabilities: TGLDataFileCapabilities;
  251. begin
  252. Result := [dfcRead {, dfcWrite}];
  253. end;
  254. //-------------------------------------------
  255. initialization
  256. //-------------------------------------------
  257. { Register this Fileformat-Handler with GLScene }
  258. RegisterRasterFormat('tga', 'TARGA Image File', TGLTGAImage);
  259. end.