TGA.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. enum TGA_FORMAT : Byte
  6. {
  7. TGA_NULL = 0,
  8. TGA_Map = 1,
  9. TGA_RGB = 2,
  10. TGA_Mono = 3,
  11. TGA_RLEMap = 9,
  12. TGA_RLERGB =10,
  13. TGA_RLEMono =11,
  14. TGA_CompMap =32,
  15. TGA_CompMap4=33,
  16. };
  17. #pragma pack(push, 1)
  18. struct TgaHeader
  19. {
  20. Byte IdLength; // Image ID Field Length
  21. Byte CmapType; // Color Map Type
  22. TGA_FORMAT ImageType; // Image Type
  23. UShort CmapIndex; // First Entry Index
  24. UShort CmapLength; // Color Map Length
  25. Byte CmapEntrySize; // Color Map Entry Size
  26. UShort X_Origin; // X-origin of Image
  27. UShort Y_Origin; // Y-origin of Image
  28. UShort ImageWidth; // Image Width
  29. UShort ImageHeight; // Image Height
  30. Byte PixelDepth; // Pixel Depth
  31. Byte ImagDesc; // Image Descriptor
  32. };
  33. #pragma pack(pop)
  34. struct TGA
  35. {
  36. Bool mono;
  37. UInt bit_pp;
  38. MemtN<Color, 256> palette;
  39. void readUncompressed(Image &image, File &f, Int y, Int x_offset, Int width)
  40. {
  41. switch(bit_pp)
  42. {
  43. case 8:
  44. {
  45. if(palette.elms())FREPD(x, width)
  46. {
  47. Byte pixel; f>>pixel;
  48. image.color(x+x_offset, y, InRange(pixel, palette) ? palette[pixel] : TRANSPARENT);
  49. }else
  50. if(image.bytePP()==1)f.get(image.data() + x_offset + y*image.pitch(), width);else
  51. FREPD(x, width)
  52. {
  53. Byte pixel; f>>pixel;
  54. image.color(x+x_offset, y, Color(pixel, pixel, pixel));
  55. }
  56. }break;
  57. case 15:
  58. case 16:
  59. {
  60. FREPD(x, width)
  61. {
  62. UShort pixel; f>>pixel;
  63. image.color(x+x_offset, y, Color((pixel>>7)&0xF8, (pixel>>2)&0xF8, (pixel&0x1F)<<3));
  64. }
  65. }break;
  66. case 24:
  67. {
  68. if(image.hwType()==IMAGE_R8G8B8 || image.hwType()==IMAGE_B8G8R8)
  69. {
  70. Byte *data=image.data() + x_offset*3 + y*image.pitch();
  71. f.get(data, width*3);
  72. if(image.hwType()==IMAGE_R8G8B8)REP(width)Swap(data[i*3+0], data[i*3+2]); // swap Red with Blue
  73. }else
  74. if(image.hwType()==IMAGE_B8G8R8A8)
  75. {
  76. VecB4 *data=(VecB4*)(image.data() + x_offset*4 + y*image.pitch());
  77. FREPD(x, width)
  78. {
  79. Byte pixel[3]; f>>pixel;
  80. (data++)->set(pixel[0], pixel[1], pixel[2], 255);
  81. }
  82. }else
  83. FREPD(x, width)
  84. {
  85. Byte pixel[3]; f>>pixel;
  86. image.color(x+x_offset, y, Color(pixel[2], pixel[1], pixel[0], 255));
  87. }
  88. }break;
  89. case 32:
  90. {
  91. if(image.hwType()==IMAGE_R8G8B8A8 || image.hwType()==IMAGE_B8G8R8A8)
  92. {
  93. Byte *data=image.data() + x_offset*4 + y*image.pitch();
  94. f.get(data, width*4);
  95. if(image.hwType()==IMAGE_R8G8B8A8)REP(width)Swap(data[i*4+0], data[i*4+2]); // swap Red with Blue
  96. }else
  97. FREPD(x, width)
  98. {
  99. VecB4 pixel; f>>pixel;
  100. image.color(x+x_offset, y, Color(pixel.z, pixel.y, pixel.x, pixel.w));
  101. }
  102. }break;
  103. }
  104. }
  105. Byte readCompressed(Image &image, File &f, Int y, Byte rleLeftover)
  106. {
  107. Byte rle;
  108. Int filePos=0;
  109. for(int x=0; x<image.w(); )
  110. {
  111. if(rleLeftover==255)f>>rle;else
  112. {
  113. rle=rleLeftover;
  114. rleLeftover=255;
  115. }
  116. if(rle&128) // RLE-encoded packet
  117. {
  118. rle-=127; // calculate real repeat count
  119. if(x+rle>image.w())
  120. {
  121. rleLeftover=Byte(128+(rle-(image.w()-x)-1));
  122. filePos=f.pos();
  123. rle=Byte(image.w()-x);
  124. }
  125. switch(bit_pp)
  126. {
  127. case 32:
  128. {
  129. VecB4 pixel; f>>pixel; Color color(pixel.z, pixel.y, pixel.x, pixel.w);
  130. REP(rle)image.color(x+i, y, color);
  131. }break;
  132. case 24:
  133. {
  134. Byte pixel[3]; f>>pixel; Color color(pixel[2], pixel[1], pixel[0], 255);
  135. REP(rle)image.color(x+i, y, color);
  136. }break;
  137. case 15:
  138. case 16:
  139. {
  140. UShort pixel; f>>pixel; Color color((pixel>>7)&0xF8, (pixel>>2)&0xF8, (pixel&0x1F)<<3);
  141. REP(rle)image.color(x+i, y, color);
  142. }break;
  143. case 8:
  144. {
  145. Byte pixel; f>>pixel;
  146. if(palette.elms()){Color c=(InRange(pixel, palette) ? palette[pixel] : TRANSPARENT); REP(rle)image.color(x+i, y, c);}else
  147. if(image.bytePP()==1)REP(rle)image.pixel(x+i, y, pixel);else{Color c(pixel, pixel, pixel); REP(rle)image.color(x+i, y, c);}
  148. }break;
  149. }
  150. if(rleLeftover!=255)f.pos(filePos);
  151. }else // raw packet
  152. {
  153. rle++; // calculate real repeat count
  154. if(x+rle>image.w())
  155. {
  156. rleLeftover=Byte(rle-(image.w()-x)-1);
  157. rle=Byte(image.w()-x);
  158. }
  159. readUncompressed(image, f, y, x, rle);
  160. }
  161. x+=rle;
  162. }
  163. return rleLeftover;
  164. }
  165. };
  166. /******************************************************************************/
  167. Bool Image::ImportTGA(File &f, Int type, Int mode, Int mip_maps)
  168. {
  169. if(mode!=IMAGE_2D && mode!=IMAGE_SOFT)mode=IMAGE_SOFT;
  170. if(mip_maps<0)mip_maps=1;
  171. TGA tga;
  172. TgaHeader header; f>>header;
  173. Bool compressed, map;
  174. switch(Unaligned(header.ImageType))
  175. {
  176. case TGA_Map : map=true ; tga.mono=false; compressed=false; break;
  177. case TGA_RGB : map=false; tga.mono=false; compressed=false; break;
  178. case TGA_Mono: map=false; tga.mono=true ; compressed=false; break;
  179. case TGA_RLEMap : map=true ; tga.mono=false; compressed=true; break;
  180. case TGA_RLERGB : map=false; tga.mono=false; compressed=true; break;
  181. case TGA_RLEMono: map=false; tga.mono=true ; compressed=true; break;
  182. default: return false;
  183. }
  184. if( Unaligned(header.ImageWidth)==0 || Unaligned(header.ImageHeight )==0)return false;
  185. if( Unaligned(header.PixelDepth)!=8 && Unaligned(header.PixelDepth )!=15 && Unaligned(header.PixelDepth)!=16 && Unaligned(header.PixelDepth)!=24 && Unaligned(header.PixelDepth)!=32)return false;
  186. if( Unaligned(header.CmapType )!=0 && Unaligned(header.CmapType )!=1 )return false; // only 0 and 1 types are supported
  187. if( Unaligned(header.CmapType ) && Unaligned(header.CmapEntrySize)!=24)return false; // if color map exists but entry is not 24-bit
  188. if((Unaligned(header.CmapType )!=0) != map )return false; // if color map existence is different than map type
  189. if((Unaligned(header.CmapType )!=0) != (Unaligned(header.CmapLength )!=0))return false; // if color map existence is different than map length
  190. f.skip(Unaligned(header.IdLength)); // skip descriptor
  191. tga.bit_pp=Unaligned(header.PixelDepth);
  192. tga.palette.setNum(Unaligned(header.CmapLength));
  193. FREPA(tga.palette){Color &c=tga.palette[i]; f>>c.b>>c.g>>c.r; c.a=255;}
  194. Bool mirror_x=FlagTest(Unaligned(header.ImagDesc), 16),
  195. mirror_y=FlagTest(Unaligned(header.ImagDesc), 32);
  196. if(type<=0)if(map)type=IMAGE_R8G8B8;else switch(Unaligned(header.PixelDepth))
  197. {
  198. case 15:
  199. case 16: type=(tga.mono ? IMAGE_I16 : IMAGE_R8G8B8 ); break;
  200. case 24: type=(tga.mono ? IMAGE_I24 : IMAGE_R8G8B8 ); break;
  201. case 32: type=(tga.mono ? IMAGE_I32 : IMAGE_B8G8R8A8); break; // TGA uses BGRA order
  202. case 8 : type= IMAGE_L8 ; break;
  203. }
  204. if(createTry(Unaligned(header.ImageWidth), Unaligned(header.ImageHeight), 1, ImageTI[type].compressed ? IMAGE_B8G8R8A8 : IMAGE_TYPE(type), IMAGE_MODE(mode), ImageTI[type].compressed ? 1 : mip_maps) // TGA uses BGRA order
  205. && lock(LOCK_WRITE))
  206. {
  207. Byte rleLeftover=255;
  208. FREPD(y, T.h())
  209. {
  210. if(f.end())return false;
  211. Int dy=(mirror_y ? y : T.h()-y-1);
  212. if(compressed)rleLeftover=tga. readCompressed(T, f, dy, rleLeftover);
  213. else tga.readUncompressed(T, f, dy, 0, T.w());
  214. }
  215. if(mirror_x)mirrorX();
  216. unlock();
  217. if(ImageTI[type].compressed)
  218. {
  219. if(!copyTry(T, -1, -1, -1, type, -1, mip_maps))goto error;
  220. }else updateMipMaps();
  221. return true;
  222. }
  223. error:
  224. del(); return false;
  225. }
  226. /******************************************************************************/
  227. Bool Image::ExportTGA(File &f)C
  228. {
  229. Image temp;
  230. C Image *src=this;
  231. IMAGE_TYPE uncompressed_type=src->type(); if(ImageTI[uncompressed_type].compressed)uncompressed_type=IMAGE_B8G8R8A8; // TGA uses BGRA order
  232. if(src->cube ()){ temp.fromCube(*src , uncompressed_type, IMAGE_SOFT ); src=&temp;}
  233. if(src->compressed()){if(src->copyTry ( temp, -1, -1, -1, uncompressed_type, IMAGE_SOFT, 1)) src=&temp;else return false;}
  234. Bool ok=false;
  235. if(src->lockRead())
  236. {
  237. Byte byte_pp=((ImageTI[T.type()].channels==1) ? 1 : ImageTI[T.type()].a ? 4 : 3); // use T.type to have precise information about source type
  238. TgaHeader header; Zero(header);
  239. Unaligned(header.ImageType , (byte_pp<=1) ? TGA_Mono : TGA_RGB);
  240. _Unaligned(header.ImageWidth , src->w());
  241. _Unaligned(header.ImageHeight, src->h());
  242. _Unaligned(header.PixelDepth , byte_pp*8);
  243. _Unaligned(header.ImagDesc , 32); // mirror_y
  244. f<<header;
  245. FREPD(y, src->h())switch(byte_pp)
  246. {
  247. case 1:
  248. {
  249. if(src->bytePP()==1)f.put(src->data() + y*src->pitch(), src->w());else
  250. FREPD(x, src->w())f.putByte(FltToByte(src->pixelF(x, y)));
  251. }break;
  252. case 3:
  253. {
  254. if(src->hwType()==IMAGE_B8G8R8)f.put(src->data() + y*src->pitch(), src->w()*3);else
  255. FREPD(x, src->w()){Color c=src->color(x, y); Byte pixel[3]={c.b, c.g, c.r}; f<<pixel;}
  256. }break;
  257. case 4:
  258. {
  259. if(src->hwType()==IMAGE_B8G8R8A8)f.put(src->data() + y*src->pitch(), src->w()*4);else
  260. FREPD(x, src->w()){Color c=src->color(x, y); Swap(c.r, c.b); f<<c;}
  261. }break;
  262. }
  263. ok=f.ok();
  264. src->unlock();
  265. }
  266. return ok;
  267. }
  268. /******************************************************************************/
  269. Bool Image::ImportTGA( File &f ) {return ImportTGA(f , -1);}
  270. Bool Image::ImportTGA(C Str &name) {return ImportTGA(name, -1);}
  271. Bool Image::ExportTGA(C Str &name)C
  272. {
  273. File f; if(f.writeTry(name)){if(ExportTGA(f) && f.flush())return true; f.del(); FDelFile(name);}
  274. return false;
  275. }
  276. Bool Image::ImportTGA(C Str &name, Int type, Int mode, Int mip_maps)
  277. {
  278. File f; if(f.readTry(name))return ImportTGA(f, type, mode, mip_maps);
  279. del(); return false;
  280. }
  281. /******************************************************************************/
  282. }
  283. /******************************************************************************/