Image IO.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. #define CC4_GFX CC4('G','F','X',0)
  6. /******************************************************************************/
  7. static IMAGE_TYPE OldImageType1(Byte type)
  8. {
  9. switch(type)
  10. {
  11. default: return IMAGE_NONE;
  12. case 1: return IMAGE_B8G8R8A8;
  13. case 2: return IMAGE_R8G8B8A8;
  14. case 3: return IMAGE_R8G8B8 ;
  15. case 4: return IMAGE_R8G8 ;
  16. case 5: return IMAGE_R8 ;
  17. case 6: return IMAGE_A8 ;
  18. case 7: return IMAGE_L8 ;
  19. case 8: return IMAGE_L8A8;
  20. case 9: return IMAGE_BC2;
  21. case 10: return IMAGE_BC3;
  22. case 11: return IMAGE_I8;
  23. case 12: return IMAGE_I16;
  24. case 13: return IMAGE_I24;
  25. case 14: return IMAGE_I32;
  26. case 15: return IMAGE_F16;
  27. case 16: return IMAGE_F32;
  28. case 17: return IMAGE_F16_2;
  29. case 18: return IMAGE_F32_2;
  30. case 19: return IMAGE_F16_3;
  31. case 20: return IMAGE_F32_3;
  32. case 21: return IMAGE_F16_4;
  33. case 22: return IMAGE_F32_4;
  34. case 23: return IMAGE_PVRTC1_2;
  35. case 24: return IMAGE_PVRTC1_4;
  36. case 25: return IMAGE_ETC1;
  37. }
  38. }
  39. static IMAGE_TYPE OldImageType0(Byte type)
  40. {
  41. switch(type)
  42. {
  43. default: return IMAGE_NONE;
  44. case 1: return IMAGE_B8G8R8A8;
  45. case 2: return IMAGE_B8G8R8A8; // IMAGE_X8R8G8B8
  46. case 3: return IMAGE_R8G8B8 ;
  47. case 4: return IMAGE_NONE ; // IMAGE_A1R5G5B5
  48. case 5: return IMAGE_NONE ; // IMAGE_R5G6B5
  49. case 6: return IMAGE_NONE; // IMAGE_P8
  50. case 7: return IMAGE_A8 ;
  51. case 8: return IMAGE_A8 ; // IMAGE_A8W
  52. case 9: return IMAGE_L8 ;
  53. case 10: return IMAGE_I16 ; // IMAGE_L16
  54. case 11: return IMAGE_NONE; // IMAGE_A4L4
  55. case 12: return IMAGE_L8A8;
  56. case 13: return IMAGE_BC2;
  57. case 14: return IMAGE_BC3;
  58. case 15: return IMAGE_I8 ;
  59. case 16: return IMAGE_I16 ;
  60. case 17: return IMAGE_I24 ;
  61. case 18: return IMAGE_I32 ;
  62. case 19: return IMAGE_F16 ;
  63. case 20: return IMAGE_F32 ;
  64. case 21: return IMAGE_F16_2;
  65. case 22: return IMAGE_F32_2;
  66. case 23: return IMAGE_F16_3;
  67. case 24: return IMAGE_F32_3;
  68. case 25: return IMAGE_F16_4;
  69. case 26: return IMAGE_F32_4;
  70. }
  71. }
  72. /******************************************************************************/
  73. // SAVE / LOAD
  74. /******************************************************************************/
  75. Bool Image::saveData(File &f)C
  76. {
  77. if(mode()!=IMAGE_SOFT && mode()!=IMAGE_SOFT_CUBE && mode()!=IMAGE_2D && mode()!=IMAGE_3D && mode()!=IMAGE_CUBE)return false; // verify that mode is correct
  78. IMAGE_TYPE file_type=T.type(); // set image type as to be stored in the file
  79. if((file_type==IMAGE_BC7 ) && !CompressBC7
  80. || (file_type==IMAGE_ETC1 || file_type==IMAGE_ETC2 || file_type==IMAGE_ETC2_A1 || file_type==IMAGE_ETC2_A8) && !CompressETC
  81. || (file_type==IMAGE_PVRTC1_2 || file_type==IMAGE_PVRTC1_4 ) && !CompressPVRTC
  82. )file_type=T.hwType(); // if compressing to format which isn't supported then store as current 'hwType'
  83. f.putMulti(Byte(4), size3(), Byte(file_type), Byte(mode()), Byte(mipMaps())); // version
  84. if(soft() && hwType()==file_type) // software with matching type, we can save without locking
  85. {
  86. if(hwSize3()==size3())f.put(softData(), memUsage());else // exact size, then we can save entire memory
  87. {
  88. C Byte *data =softData();
  89. Int faces=T.faces();
  90. FREPD(mip, mipMaps()) // iterate all mip maps
  91. {
  92. // here no need to use any "Min" because soft HW sizes are guaranteed to be >= file sizes
  93. Int file_pitch =ImagePitch ( w(), h(), mip, file_type), // use "w(), h()" instead of "hwW(), hwH()" because we want to write only valid pixels
  94. file_blocks_y=ImageBlocksY( w(), h(), mip, file_type), // use "w(), h()" instead of "hwW(), hwH()" because we want to write only valid pixels
  95. image_pitch =ImagePitch (hwW(), hwH(), mip, file_type),
  96. image_blocks_y=ImageBlocksY(hwW(), hwH(), mip, file_type),
  97. file_d = Max(1, d()>>mip) , // use "d()" instead of "hwD()" because we want to write only valid pixels
  98. image_d = Max(1, hwD()>>mip) ,
  99. write = file_blocks_y*file_pitch,
  100. skip =(image_blocks_y-file_blocks_y)*image_pitch,
  101. skip2 =(image_d -file_d )*image_pitch*image_blocks_y;
  102. FREPD(face, faces) // iterate all faces
  103. {
  104. FREPD(z, file_d)
  105. {
  106. if(file_pitch==image_pitch) // if file pitch is the same as image pitch
  107. {
  108. f.put(data, write); data+=write; // we can write both XY in one go
  109. }else
  110. FREPD(y, file_blocks_y){f.put(data, file_pitch); data+=image_pitch;}
  111. data+=skip;
  112. }
  113. data+=skip2;
  114. }
  115. }
  116. }
  117. }else
  118. {
  119. Image soft;
  120. Int faces=T.faces();
  121. FREPD(mip, mipMaps()) // iterate all mip maps
  122. {
  123. Int file_pitch =ImagePitch (w(), h(), mip, file_type), // use "w(), h()" instead of "hwW(), hwH()" because we want to write only valid pixels
  124. file_blocks_y=ImageBlocksY(w(), h(), mip, file_type); // use "w(), h()" instead of "hwW(), hwH()" because we want to write only valid pixels
  125. FREPD(face, faces) // iterate all faces
  126. {
  127. C Image *src=this;
  128. Int src_mip=mip, src_face=face;
  129. if(hwType()!=file_type){if(!extractMipMap(soft, file_type, IMAGE_SOFT, mip, DIR_ENUM(face)))return false; src=&soft; src_mip=0; src_face=0;} // if 'hwType' is different than of file, then convert to 'file_type' IMAGE_SOFT, after extracting the mip map its Pitch and BlocksY may be different than of calculated from base (for example non-power-of-2 images) so write zeros to file to match the expected size
  130. if(!src->lockRead(src_mip, DIR_ENUM(src_face)))return false;
  131. Int write_pitch =Min(src->pitch() , file_pitch ),
  132. write_blocks_y=Min(ImageBlocksY(src->w(), src->h(), src_mip, src->hwType()), file_blocks_y); // use "w(), h()" instead of "hwW(), hwH()" because we want to write only valid pixels
  133. FREPD(z, src->ld())
  134. {
  135. C Byte *src_data_z=src->data() + z*src->pitch2();
  136. if(file_pitch==src->pitch()) // if file pitch is the same as image pitch !! compare 'src->pitch' and not 'write_pitch' !!
  137. f.put(src_data_z, write_blocks_y*write_pitch);else // we can write both XY in one go !! use "write_blocks_y*write_pitch" and not 'pitch2', because 'pitch2' may be bigger !!
  138. {
  139. Int skip=file_pitch-write_pitch;
  140. FREPD(y, write_blocks_y){f.put(src_data_z + y*src->pitch(), write_pitch); f.put(null, skip);} // write each line separately
  141. }
  142. f.put(null, (file_blocks_y-write_blocks_y)*file_pitch); // unwritten blocksY * pitch
  143. }
  144. src->unlock();
  145. }
  146. }
  147. }
  148. return f.ok();
  149. }
  150. /******************************************************************************/
  151. static INLINE Bool SizeFits ( Int src, Int dest) {return src<dest*2;} // this is OK for src=7, dest=4 (7<4*2), but NOT OK for src=8, dest=4 (8<4*2)
  152. static INLINE Bool SizeFits1( Int src, Int dest) {return src>1 && SizeFits(src, dest);} // only if 'src>1', if we don't check this, then 1024x1024x1 src will fit into 16x16x1 dest because of Z=1
  153. static Bool SizeFits (C VecI &src, C VecI &dest) {return SizeFits1(src.x, dest.x) || SizeFits1(src.y, dest.y) || SizeFits1(src.z, dest.z) || (src.x==1 && src.y==1 && src.z==1);}
  154. static Bool Load(Image &image, File &f, C ImageHeader &header, C Str &name, IMAGE_TYPE type_on_fail)
  155. {
  156. if(!f.ok())return false;
  157. ImageHeader want=header;
  158. Int shrink=0;
  159. if(Int (*image_load_shrink)(ImageHeader &image_header, C Str &name)=D.image_load_shrink) // copy to temp variable to avoid multi-threading issues
  160. shrink=image_load_shrink(want, name);
  161. // shrink
  162. for(; --shrink>=0 || (IsHW(want.mode) && want.size.max()>D.maxTexSize() && D.maxTexSize()>0); ) // apply 'D.maxTexSize' only for hardware textures (not for software images)
  163. {
  164. want.size.x =Max(1, want.size.x >>1);
  165. want.size.y =Max(1, want.size.y >>1);
  166. want.size.z =Max(1, want.size.z >>1);
  167. want.mip_maps=Max(1, want.mip_maps-1);
  168. }
  169. const Bool create_from_soft=DX11|GL; // if want to load into SOFT and then create HW from it, to avoid locking 'D._lock', only DX11, GL support this
  170. if(image.createTryEx(want.size.x, want.size.y, want.size.z, want.type, create_from_soft ? (IsCube(want.mode) ? IMAGE_SOFT_CUBE : IMAGE_SOFT) : want.mode, want.mip_maps, 1, type_on_fail)) // don't use 'want' after this call, instead operate on 'image' members
  171. {
  172. const FILTER_TYPE filter=FILTER_BEST;
  173. Image soft; // store outside the loop to avoid overhead
  174. const Bool file_cube =IsCube(header.mode), fast_load=(image.soft() && image.hwType()==header.type && image.cube()==file_cube);
  175. const Int file_faces=(file_cube ? 6 : 1);
  176. Int image_mip =0; // how many mip-maps have already been set in the image
  177. FREPD( file_mip, header.mip_maps) // iterate all mip maps in the file
  178. {
  179. VecI file_mip_size(Max(1, header.size.x>>file_mip), Max(1, header.size.y>>file_mip), Max(1, header.size.z>>file_mip));
  180. Bool mip_fits=SizeFits(file_mip_size, image.size3()); // if this mip-map fits into the image
  181. if(image_mip<image.mipMaps() // if we can set another mip-map, because it fits into 'image' mip map array
  182. && (mip_fits || file_mip==header.mip_maps-1)) // if fits or this is the last mip-map in the file
  183. {
  184. Int mip_count;
  185. VecI image_mip_size(Max(1, image.w()>>image_mip), Max(1, image.h()>>image_mip), Max(1, image.d()>>image_mip));
  186. /*
  187. Watch out for following cases:
  188. image.width=497, image.type=BC1
  189. file.mip0.padded_width=Ceil4(497 )=500
  190. file.mip1.padded_width=Ceil4(497>>1)=248
  191. image.mip0.padded_width=Ceil4(497 )=500
  192. image.mip1.padded_width=Ceil4(500>>1)=252, image mip pitch is calculated based on HW size, so it may be bigger than file mip
  193. */
  194. if(fast_load && image_mip_size==file_mip_size) // if this is a software image with same type/cube and mip size matches
  195. {
  196. if(image_mip_size.x==Max(1, image.hwW()>>image_mip)
  197. && image_mip_size.y==Max(1, image.hwH()>>image_mip)
  198. && image_mip_size.z==Max(1, image.hwD()>>image_mip)) // if image mip size is the same as image HW mip size, then we can read all remaining data in one go
  199. {
  200. mip_count=Min(image.mipMaps()-image_mip, header.mip_maps-file_mip); // how many mip-maps we can read = Min(available in 'image', available in file)
  201. f.getFast(image.softData(image_mip), ImageSize(file_mip_size.x, file_mip_size.y, file_mip_size.z, header.type, header.mode, mip_count));
  202. file_mip+=mip_count-1; // -1 because 1 is already added at the end of FREPD loop
  203. }else
  204. {
  205. mip_count=1;
  206. // here no need to use any "Min" because soft HW sizes are guaranteed to be >= file sizes
  207. const Int file_pitch =ImagePitch (header.size.x, header.size.y, file_mip, header.type),
  208. file_blocks_y=ImageBlocksY(header.size.x, header.size.y, file_mip, header.type),
  209. image_pitch =ImagePitch ( image.hwW() , image.hwH() , image_mip, header.type),
  210. image_blocks_y=ImageBlocksY( image.hwW() , image.hwH() , image_mip, header.type),
  211. file_d = Max(1, header.size.z>> file_mip),
  212. image_d = Max(1, image.hwD() >>image_mip),
  213. zero_pitch = image_pitch -file_pitch,
  214. read = file_blocks_y*file_pitch,
  215. zero =(image_blocks_y-file_blocks_y)*image_pitch, // how much to zero = total - what was set
  216. zero2 =(image_d -file_d )*image_pitch*image_blocks_y;
  217. Byte *data=image.softData(image_mip);
  218. FREPD(face, file_faces) // iterate all faces
  219. {
  220. FREPD(z, file_d)
  221. {
  222. if(file_pitch==image_pitch) // if file pitch is the same as image pitch
  223. { // we can read both XY in one go
  224. f.getFast(data, read);
  225. data+=read;
  226. }else
  227. FREPD(y, file_blocks_y) // read each line separately
  228. {
  229. f.getFast(data, file_pitch);
  230. Zero(data+file_pitch, zero_pitch); // zero remaining data to avoid garbage
  231. data+=image_pitch;
  232. }
  233. Zero(data, zero); data+=zero; // zero remaining data to avoid garbage
  234. }
  235. Zero(data, zero2); data+=zero2; // zero remaining data to avoid garbage
  236. }
  237. }
  238. }else
  239. {
  240. Bool temp=(image.hwType()!=header.type || file_mip_size!=image_mip_size); // we need to load the mip-map into temporary image first, if the hardware types don't match, or if the mip-map size doesn't match
  241. Image *dest; Int dest_mip;
  242. mip_count=1;
  243. if(temp) // if need to use a temporary image
  244. {
  245. if(!soft.createTry(file_mip_size.x, file_mip_size.y, file_mip_size.z, header.type, IMAGE_SOFT, 1, false))return false;
  246. dest=&soft; dest_mip=0;
  247. if(!image_mip) // if file is 64x64 but 'image' is 256x256 then we need to write the first file mip map into 256x256, 128x128, 64x64 'image' mip maps, this check is needed only at the start, when we still haven't written any mip-maps
  248. REP(image.mipMaps()-1) // -1 because we already have 'mip_count'=1
  249. {
  250. image_mip_size.set(Max(1, image_mip_size.x>>1), Max(1, image_mip_size.y>>1), Max(1, image_mip_size.z>>1)); // calculate next image mip size
  251. if(SizeFits(file_mip_size, image_mip_size))mip_count++;else break; // if file mip still fits into the next image mip size, then increase the counter, else stop
  252. }
  253. }else // we can write directly to 'image'
  254. {
  255. dest=&image; dest_mip=image_mip;
  256. }
  257. const Int file_pitch =ImagePitch (header.size.x, header.size.y, file_mip, header.type ),
  258. file_blocks_y=ImageBlocksY(header.size.x, header.size.y, file_mip, header.type ),
  259. dest_blocks_y=ImageBlocksY( dest->hwW(), dest->hwH(), dest_mip, dest->hwType()),
  260. read_blocks_y=Min(dest_blocks_y, file_blocks_y),
  261. read = read_blocks_y*file_pitch, // !! use "read_blocks_y*file_pitch" and not 'pitch2', because 'pitch2' may be bigger !!
  262. skip =(file_blocks_y-read_blocks_y)*file_pitch; // unread blocksY * pitch
  263. FREPD(face, file_faces) // iterate all faces
  264. {
  265. if(!dest->lock(LOCK_WRITE, dest_mip, DIR_ENUM(temp ? 0 : face)))return false;
  266. const Int read_pitch=Min(dest->pitch (), file_pitch),
  267. zero = dest->pitch2()- read_blocks_y*dest->pitch(); // how much to zero = total - what was set
  268. Byte *dest_data = dest->data ();
  269. FREPD(z, dest->ld())
  270. {
  271. if(file_pitch==dest->pitch()) // if file pitch is the same as image pitch !! compare 'dest->pitch' and not 'read_pitch' !!
  272. { // we can read both XY in one go
  273. f.getFast(dest_data, read);
  274. dest_data+=read;
  275. }else
  276. {
  277. const Int skip_pitch= file_pitch -read_pitch, // even though this could be calculated above outside of the loop, most likely this will not be needed because most likely "file_pitch==dest->pitch()" and we can read all in one go
  278. zero_pitch=dest->pitch()-read_pitch;
  279. FREPD(y, read_blocks_y) // read each line separately
  280. {
  281. f.getFast(dest_data, read_pitch); f.skip(skip_pitch);
  282. Zero(dest_data+read_pitch, zero_pitch); // zero remaining data to avoid garbage
  283. dest_data+=dest->pitch();
  284. }
  285. }
  286. f.skip(skip);
  287. Zero(dest_data, zero); // zero remaining data to avoid garbage
  288. dest_data+=zero;
  289. }
  290. dest->unlock();
  291. if(temp)REP(mip_count)if(!image.injectMipMap(*dest, image_mip+i, DIR_ENUM(face), filter))return false;
  292. }
  293. }
  294. image_mip+=mip_count;
  295. }else // skip this mip-map
  296. {
  297. f.skip(ImageMipSize(header.size.x, header.size.y, header.size.z, file_mip, header.type)*file_faces);
  298. }
  299. }
  300. if(image_mip)image.updateMipMaps(filter, true, false, false, image_mip-1); // set any missing mip maps, this is needed for example if file had 1 mip map, but we've requested to create more
  301. else image.clear(); // or if we didn't load anything, then clear to zero
  302. if(image.mode()!=want.mode) // if created as SOFT, then convert to HW
  303. {
  304. Swap(soft, image); // can't create from self
  305. if(!image.createTryEx(soft.w(), soft.h(), soft.d(), soft.type(), want.mode, soft.mipMaps(), soft.samples(), IMAGE_NONE, &soft))
  306. {
  307. if(!type_on_fail || type_on_fail==soft.type() // no alternative type specified, or is the same one
  308. || !soft . copyTry (soft, -1, -1, -1, type_on_fail)
  309. || !image.createTryEx(soft.w(), soft.h(), soft.d(), soft.type(), want.mode, soft.mipMaps(), soft.samples(), IMAGE_NONE, &soft))return false;
  310. image._type=want.type; // adjust wanted type, have to do it here, because there's no other way
  311. }
  312. }
  313. return f.ok();
  314. }
  315. return false;
  316. }
  317. Bool Image::loadData(File &f, IMAGE_TYPE type_on_fail, ImageHeader *header, C Str &name)
  318. {
  319. ImageHeader ih;
  320. switch(f.decUIntV())
  321. {
  322. case 4:
  323. {
  324. #pragma pack(push, 1)
  325. struct ImageHeader4
  326. {
  327. VecI size;
  328. IMAGE_TYPE type;
  329. IMAGE_MODE mode;
  330. Byte mips;
  331. }header4;
  332. #pragma pack(pop)
  333. f>>header4;
  334. Unaligned(ih.size , header4.size);
  335. Unaligned(ih.type , header4.type);
  336. Unaligned(ih.mode , header4.mode);
  337. _Unaligned(ih.mip_maps, header4.mips);
  338. if(header)goto set_header;
  339. if(Load(T, f, ih, name, type_on_fail))goto ok;
  340. }break;
  341. case 3:
  342. {
  343. ih.size.x =f.getInt();
  344. ih.size.y =f.getInt();
  345. ih.size.z =f.getInt();
  346. ih.type =OldImageType1(f.getByte());
  347. ih.mode =IMAGE_MODE (f.getByte());
  348. ih.mip_maps=f.getByte();
  349. if(header)goto set_header;
  350. if(Load(T, f, ih, name, type_on_fail))goto ok;
  351. }break;
  352. case 2:
  353. {
  354. f.getByte(); // old U16 version part
  355. ih.size.x =f.getInt();
  356. ih.size.y =f.getInt();
  357. ih.size.z =f.getInt();
  358. Byte byte_pp =f.getByte();
  359. Byte old_type=f.getByte(); ih.type=OldImageType0(old_type);
  360. ih.mode =IMAGE_MODE(f.getByte()); if(ih.mode==IMAGE_CUBE && ih.size.z==6)ih.size.z=1;
  361. ih.mip_maps= f.getByte();
  362. if(header)goto set_header;
  363. if(old_type==6)f.skip(SIZE(Color)*256); // palette
  364. if(createTryEx(ih.size.x, ih.size.y, ih.size.z, ih.type, ih.mode, ih.mip_maps, 1, type_on_fail))
  365. {
  366. Image soft;
  367. FREPD(mip , ih.mip_maps ) // iterate all mip maps
  368. FREPD(face, (ih.mode==IMAGE_CUBE) ? 6 : 1) // iterate all faces
  369. {
  370. Image *dest=this;
  371. Int dest_mip=mip, dest_face=face;
  372. if(hwType()!=ih.type){if(!soft.createTry(Max(1, ih.size.x>>mip), Max(1, ih.size.y>>mip), Max(1, ih.size.z>>mip), ih.type, IMAGE_SOFT, 1, false))return false; dest=&soft; dest_mip=0; dest_face=0;} // if 'hwType' is different than of file, then load into 'file_type' IMAGE_SOFT, after creating the mip map its Pitch and BlocksY may be different than of calculated from base (for example non-power-of-2 images) so skip some data from file to read only created
  373. if(!dest->lock(LOCK_WRITE, dest_mip, DIR_ENUM(dest_face)))return false;
  374. Int file_pitch =ImagePitch (ih.size.x, ih.size.y, mip, ih.type), dest_pitch =Min(dest->pitch() , file_pitch ),
  375. file_blocks_y=ImageBlocksY(ih.size.x, ih.size.y, mip, ih.type), dest_blocks_y=Min(ImageBlocksY(dest->hwW(), dest->hwH(), dest_mip, dest->hwType()), file_blocks_y);
  376. FREPD(z, dest->ld())
  377. {
  378. FREPD(y, dest_blocks_y){f.getFast(dest->data() + y*dest->pitch() + z*dest->pitch2(), dest_pitch); f.skip(file_pitch-dest_pitch);}
  379. f.skip((file_blocks_y-dest_blocks_y)*file_pitch); // unread blocksY * pitch
  380. }
  381. if(ih.mode==IMAGE_SOFT && ih.type==IMAGE_R8G8B8){Byte *bgr=dest->data(); REP(dest->lw()*dest->lh()*dest->ld()){Swap(bgr[0], bgr[2]); bgr+=3;}}
  382. dest->unlock();
  383. if(hwType()!=ih.type)if(!injectMipMap(*dest, mip, DIR_ENUM(face)))return false;
  384. }
  385. if(f.ok())goto ok;
  386. }
  387. }break;
  388. case 1:
  389. {
  390. f.getByte(); // old U16 version part
  391. ih.size.x=f.getInt();
  392. ih.size.y=f.getInt();
  393. ih.size.z=f.getInt();
  394. Byte byte_pp =f.getByte();
  395. Byte old_type=f.getByte(); ih.type=OldImageType0(old_type);
  396. ih.mode =IMAGE_MODE(f.getByte()); if(ih.mode==IMAGE_CUBE && ih.size.z==6)ih.size.z=1;
  397. ih.mip_maps= f.getByte();
  398. if(header)goto set_header;
  399. if(old_type==6)f.skip(SIZE(Color)*256); // palette
  400. if(createTryEx(ih.size.x, ih.size.y, ih.size.z, ih.type, ih.mode, ih.mip_maps, 1, type_on_fail))
  401. {
  402. Image soft;
  403. FREPD(mip , ih.mip_maps ) // iterate all mip maps
  404. FREPD(face, (ih.mode==IMAGE_CUBE) ? 6 : 1) // iterate all faces
  405. {
  406. Image *dest=this;
  407. Int dest_mip=mip, dest_face=face;
  408. if(hwType()!=ih.type){if(!soft.createTry(Max(1, ih.size.x>>mip), Max(1, ih.size.y>>mip), Max(1, ih.size.z>>mip), ih.type, IMAGE_SOFT, 1, false))return false; dest=&soft; dest_mip=0; dest_face=0;} // if 'hwType' is different than of file, then load into 'file_type' IMAGE_SOFT
  409. if(!dest->lock(LOCK_WRITE, dest_mip, DIR_ENUM(dest_face)))return false;
  410. Int file_pitch =dest->lw(),
  411. file_blocks_y=dest->lh(); if(ImageTI[ih.type].compressed){file_blocks_y=DivCeil4(file_blocks_y); file_pitch*=4; if(file_pitch<16)file_pitch=16;} file_pitch*=ImageTI[ih.type].bit_pp; file_pitch/=8;
  412. Int dest_pitch =Min(dest->pitch() , file_pitch ),
  413. dest_blocks_y=Min(ImageBlocksY(dest->hwW(), dest->hwH(), dest_mip, dest->hwType()), file_blocks_y);
  414. FREPD(z, dest->ld())
  415. {
  416. FREPD(y, dest_blocks_y){f.getFast(dest->data() + y*dest->pitch() + z*dest->pitch2(), dest_pitch); f.skip(file_pitch-dest_pitch);}
  417. f.skip((file_blocks_y-dest_blocks_y)*file_pitch); // unread blocksY * pitch
  418. }
  419. if(ih.mode==IMAGE_SOFT && ih.type==IMAGE_R8G8B8){Byte *bgr=dest->data(); REP(dest->lw()*dest->lh()*dest->ld()){Swap(bgr[0], bgr[2]); bgr+=3;}}
  420. dest->unlock();
  421. if(hwType()!=ih.type)if(!injectMipMap(*dest, mip, DIR_ENUM(face)))return false;
  422. }
  423. if(f.ok())goto ok;
  424. }
  425. }break;
  426. case 0:
  427. {
  428. f.getByte(); // old U16 version part
  429. ih.size.x=f.getInt();
  430. ih.size.y=f.getInt();
  431. ih.size.z=1;
  432. Byte byte_pp =f.getByte();
  433. Byte old_type=f.getByte(); ih.type=OldImageType0(old_type);
  434. ih.mip_maps =f.getByte();
  435. ih.mode =IMAGE_MODE(f.getByte()); if(ih.mode==1)ih.mode=IMAGE_SOFT;else if(ih.mode==0)ih.mode=IMAGE_2D; if(ih.mode==IMAGE_CUBE && ih.size.z==6)ih.size.z=1;
  436. if(header)goto set_header;
  437. if(old_type==6)f.skip(SIZE(Color)*256); // palette
  438. if(createTryEx(ih.size.x, ih.size.y, ih.size.z, ih.type, ih.mode, ih.mip_maps, 1, type_on_fail))
  439. {
  440. Image soft;
  441. FREPD(mip , ih.mip_maps ) // iterate all mip maps
  442. FREPD(face, (ih.mode==IMAGE_CUBE) ? 6 : 1) // iterate all faces
  443. {
  444. Image *dest=this;
  445. Int dest_mip=mip, dest_face=face;
  446. if(hwType()!=ih.type){if(!soft.createTry(Max(1, ih.size.x>>mip), Max(1, ih.size.y>>mip), Max(1, ih.size.z>>mip), ih.type, IMAGE_SOFT, 1, false))return false; dest=&soft; dest_mip=0; dest_face=0;} // if 'hwType' is different than of file, then load into 'file_type' IMAGE_SOFT
  447. if(!dest->lock(LOCK_WRITE, dest_mip, DIR_ENUM(dest_face)))return false;
  448. Int file_pitch =dest->lw(),
  449. file_blocks_y=dest->lh(); if(ImageTI[ih.type].compressed){file_blocks_y=DivCeil4(file_blocks_y); file_pitch*=4; if(file_pitch<16)file_pitch=16;} file_pitch*=ImageTI[ih.type].bit_pp; file_pitch/=8;
  450. Int dest_pitch =Min(dest->pitch() , file_pitch ),
  451. dest_blocks_y=Min(ImageBlocksY(dest->hwW(), dest->hwH(), dest_mip, dest->hwType()), file_blocks_y);
  452. FREPD(z, dest->ld())
  453. {
  454. FREPD(y, dest_blocks_y){f.getFast(dest->data() + y*dest->pitch() + z*dest->pitch2(), dest_pitch); f.skip(file_pitch-dest_pitch);}
  455. f.skip((file_blocks_y-dest_blocks_y)*file_pitch); // unread blocksY * pitch
  456. }
  457. if(ih.mode==IMAGE_SOFT && ih.type==IMAGE_R8G8B8){Byte *bgr=dest->data(); REP(dest->lw()*dest->lh()*dest->ld()){Swap(bgr[0], bgr[2]); bgr+=3;}}
  458. dest->unlock();
  459. if(hwType()!=ih.type)if(!injectMipMap(*dest, mip, DIR_ENUM(face)))return false;
  460. }
  461. if(f.ok())goto ok;
  462. }
  463. }break;
  464. }
  465. error:
  466. if(header)header->zero();
  467. del(); return false;
  468. ok:;
  469. if(App.flag&APP_AUTO_FREE_IMAGE_OPEN_GL_ES_DATA)freeOpenGLESData();
  470. return true;
  471. set_header:;
  472. if(f.ok()){*header=ih; return true;}
  473. goto error;
  474. }
  475. /******************************************************************************/
  476. Bool Image::save(File &f)C
  477. {
  478. f.putUInt(CC4_GFX);
  479. return saveData(f);
  480. }
  481. Bool Image::load(File &f)
  482. {
  483. if(f.getUInt()==CC4_GFX)return loadData(f);
  484. del(); return false;
  485. }
  486. Bool Image::save(C Str &name)C
  487. {
  488. File f; if(f.writeTry(name)){if(save(f) && f.flush())return true; f.del(); FDelFile(name);}
  489. return false;
  490. }
  491. Bool Image::load(C Str &name)
  492. {
  493. File f; if(f.readTry(name) && f.getUInt()==CC4_GFX)return loadData(f, IMAGE_DEFAULT, null, name);
  494. del(); return false;
  495. }
  496. void Image::operator=(C UID &id ) {T=_EncodeFileName(id);}
  497. void Image::operator=(C Str &name)
  498. {
  499. if(!load(name))Exit(MLT(S+"Can't load Image \"" +name+ "\", possible reasons:\n-Video card doesn't support required format\n-File not found\n-Out of memory\n-Engine not yet initialized",
  500. PL,S+u"Nie można wczytać Obrazka \""+name+u"\", możliwe przyczyny:\n-Karta graficzna nie obsługuje wczytywanego formatu\n-Nie odnaleziono pliku\n-Skończyła się pamięć\n-Silnik nie został jeszcze zainicjalizowany"));
  501. }
  502. /******************************************************************************/
  503. // IMPORT
  504. /******************************************************************************
  505. Bool Image::ExportDX(C Str &name, GPU_API(D3DXIMAGE_FILEFORMAT, D3DX11_IMAGE_FILE_FORMAT, UInt) format)C
  506. {
  507. #if DX9 || DX11
  508. if(D.created())
  509. {
  510. C Image *src=this;
  511. Image temp;
  512. if(src->cube()){temp.fromCube(*src, -1, IMAGE_SURF_SCRATCH); src=&temp;}
  513. #if DX9
  514. if(src->type()==IMAGE_A8)
  515. {
  516. Image temp2;
  517. Bool ok=false;
  518. if(!temp2.createTry(src->w(), src->h(), 1, IMAGE_L8, IMAGE_SURF_SCRATCH, 1))return false;
  519. if(src->lockRead())
  520. {
  521. if(temp2.lock(LOCK_WRITE))
  522. {
  523. ok=true;
  524. REPD(y, src->h())
  525. REPD(x, src->w()){Color c=src->color(x, y); temp2.color(x, y, Color(c.a, c.a, c.a));}
  526. temp2.unlock();
  527. }
  528. src->unlock();
  529. }
  530. if(!ok)return false;
  531. Swap(temp, temp2); src=&temp;
  532. }
  533. if(!src->_surf)
  534. {
  535. if(!src->copyTry(temp, -1, -1, 1, -1, IMAGE_SURF_SCRATCH, 1))return false; src=&temp;
  536. }
  537. SyncLocker locker(D._lock);
  538. return OK(D3DXSaveSurfaceToFile(name, format, src->_surf, null, null));
  539. #elif DX11
  540. if(src->type()==IMAGE_A8)
  541. {
  542. Image temp2;
  543. Bool ok=false;
  544. if(!temp2.createTry(src->w(), src->h(), 1, IMAGE_R8G8B8A8, IMAGE_SURF_SCRATCH, 1))return false;
  545. if(src->lockRead())
  546. {
  547. if(temp2.lock(LOCK_WRITE))
  548. {
  549. ok=true;
  550. REPD(y, src->h())
  551. REPD(x, src->w()){Color c=src->color(x, y); temp2.color(x, y, Color(c.a, c.a, c.a));}
  552. temp2.unlock();
  553. }
  554. src->unlock();
  555. }
  556. if(!ok)return false;
  557. Swap(temp, temp2); src=&temp;
  558. }
  559. if(src->type()!=IMAGE_R8G8B8A8 || !src->_txtr)
  560. {
  561. if(!src->copyTry(temp, -1, -1, 1, IMAGE_R8G8B8A8, IMAGE_SURF_SCRATCH, 1))return false; src=&temp;
  562. }
  563. SyncLocker locker(D._lock);
  564. return OK(D3DX11SaveTextureToFile(D3DC, src->_txtr, format, name)); // 'D3DX11SaveTextureToFile' supports only R8G8B8A8
  565. #endif
  566. }
  567. #endif
  568. return false;
  569. }
  570. /******************************************************************************
  571. Bool ImportDX (C Str &name, Int type=-1, Int mode=-1, Int mip_maps=-1); // import using DirectX
  572. Bool Image::ImportDX(C Str &name, Int type, Int mode, Int mip_maps) // 'type, mode, mip_maps' params are only suggestions !!
  573. {
  574. del();
  575. if(name.is())
  576. {
  577. if(mode<0)mode=IMAGE_SOFT;
  578. if(mode==IMAGE_SOFT || mode==IMAGE_2D || mode==IMAGE_CUBE || mode==IMAGE_SURF_SCRATCH || mode==IMAGE_SURF_SYSTEM || mode==IMAGE_SURF)
  579. if(D.created())
  580. {
  581. #if DX9 || DX11
  582. Mems<Byte> file_data;
  583. Str path=name;
  584. if(!FullPath(path))
  585. {
  586. if(C PaksFile *file=Paks.find(path)){File f; if(f.readTry(*file->file, *file->pak))f.get(file_data.setNum(f.size()).data(), f.size());}else
  587. if(DataPath().is() && !FExistSystem(path))path=DataPath()+path;
  588. }
  589. SyncLockerEx locker(D._lock);
  590. #if DX9
  591. D3DXIMAGE_INFO info;
  592. switch(mode)
  593. {
  594. case IMAGE_2D:
  595. if(file_data.elms() ? OK(D3DXCreateTextureFromFileInMemoryEx(D3D, file_data.data(), file_data.elms(), D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, (mip_maps<0) ? D3DX_FROM_FILE : mip_maps, 0, ImageTypeToFormat(type), D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT, 0, &info, null, &_txtr)) // here D3DFMT_UNKNOWN means detect from file but use device compatible if file format is not supported (D3DFMT_FROM_FILE would fail if file format is not supported by device), use 'D3DX_FILTER_NONE' so the image will not get rescaled
  596. : OK(D3DXCreateTextureFromFileEx (D3D, path , D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, (mip_maps<0) ? D3DX_FROM_FILE : mip_maps, 0, ImageTypeToFormat(type), D._no_gpu ? D3DPOOL_SCRATCH : D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT, 0, &info, null, &_txtr))) // here D3DFMT_UNKNOWN means detect from file but use device compatible if file format is not supported (D3DFMT_FROM_FILE would fail if file format is not supported by device), use 'D3DX_FILTER_NONE' so the image will not get rescaled
  597. {
  598. setInfo(info.Width, info.Height, 0, type, IMAGE_MODE(mode));
  599. locker.off();
  600. return (T.type()>=IMAGE_TYPES) ? copyTry(T, -1, -1, -1, IMAGE_B8G8R8A8) : true;
  601. }
  602. break;
  603. case IMAGE_SURF_SCRATCH:
  604. case IMAGE_SURF :
  605. case IMAGE_SURF_SYSTEM :
  606. if(file_data.elms() ? OK(D3DXGetImageInfoFromFileInMemory(file_data.data(), file_data.elms(), &info))
  607. : OK(D3DXGetImageInfoFromFile (path , &info)))
  608. {
  609. if(type<=0)type=ImageFormatToType(info.Format);
  610. if(type<=0 || type>=IMAGE_TYPES)type=IMAGE_B8G8R8A8;
  611. if(OK(D3D->CreateOffscreenPlainSurface(info.Width, info.Height, ImageTI[type ].format, (mode==IMAGE_SURF) ? D3DPOOL_DEFAULT : (mode==IMAGE_SURF_SYSTEM) ? D3DPOOL_SYSTEMMEM : D3DPOOL_SCRATCH, &_surf, null))
  612. || OK(D3D->CreateOffscreenPlainSurface(info.Width, info.Height, ImageTI[IMAGE_B8G8R8A8].format, (mode==IMAGE_SURF) ? D3DPOOL_DEFAULT : (mode==IMAGE_SURF_SYSTEM) ? D3DPOOL_SYSTEMMEM : D3DPOOL_SCRATCH, &_surf, null))) // try bgra on fail
  613. {
  614. if(file_data.elms() ? OK(D3DXLoadSurfaceFromFileInMemory(_surf, null, null, file_data.data(), file_data.elms(), null, D3DX_FILTER_NONE, 0, null)) // use 'D3DX_FILTER_NONE' so the image will not get rescaled
  615. : OK(D3DXLoadSurfaceFromFileW (_surf, null, null, path , null, D3DX_FILTER_NONE, 0, null))) // use 'D3DX_FILTER_NONE' so the image will not get rescaled
  616. {
  617. setInfo(info.Width, info.Height, 0, type, IMAGE_MODE(mode));
  618. return true;
  619. }
  620. }
  621. RELEASE(_surf);
  622. }
  623. break;
  624. case IMAGE_SOFT:
  625. if(file_data.elms() ? OK(D3DXGetImageInfoFromFileInMemory(file_data.data(), file_data.elms(), &info))
  626. : OK(D3DXGetImageInfoFromFile (path , &info)))
  627. {
  628. if(type<=0)type=ImageFormatToType(info.Format);
  629. if(type<=0 || type>=IMAGE_TYPES)type=IMAGE_B8G8R8A8;
  630. Bool ok =false;
  631. IDirect3DSurface9 *surf=null;
  632. if(OK(D3D->CreateOffscreenPlainSurface(info.Width, info.Height, ImageTI[type ].format, D3DPOOL_SCRATCH, &surf, null))
  633. || OK(D3D->CreateOffscreenPlainSurface(info.Width, info.Height, ImageTI[IMAGE_B8G8R8A8].format, D3DPOOL_SCRATCH, &surf, null))) // try bgra on fail
  634. {
  635. if(file_data.elms() ? OK(D3DXLoadSurfaceFromFileInMemory(surf, null, null, file_data.data(), file_data.elms(), null, D3DX_FILTER_NONE, 0, null)) // use 'D3DX_FILTER_NONE' so the image will not get rescaled
  636. : OK(D3DXLoadSurfaceFromFileW (surf, null, null, path , null, D3DX_FILTER_NONE, 0, null))) // use 'D3DX_FILTER_NONE' so the image will not get rescaled
  637. {
  638. D3DLOCKED_RECT lr;
  639. D3DSURFACE_DESC desc;
  640. if(OK(surf->GetDesc (&desc)))
  641. if(OK(surf->LockRect(&lr, null, 0)))
  642. {
  643. if(createSoftTry(info.Width, info.Height, 1, ImageFormatToType(desc.Format))) // use format from surface because we're doing raw copy later
  644. {
  645. ok=true;
  646. REPD(y, ImageBlocksY(hwW(), hwH(), 0, hwType()))CopyFast(data() + y*pitch(), (Byte*)lr.pBits + y*lr.Pitch, pitch());
  647. }
  648. surf->UnlockRect();
  649. }
  650. }
  651. }
  652. RELEASE(surf);
  653. if(ok)return true;
  654. }
  655. break;
  656. case IMAGE_CUBE:
  657. if(file_data.elms() ? OK(D3DXGetImageInfoFromFileInMemory(file_data.data(), file_data.elms(), &info))
  658. : OK(D3DXGetImageInfoFromFile (path , &info)))
  659. {
  660. if(type<=0)type=ImageFormatToType(info.Format);
  661. if(type<=0 || type>=IMAGE_TYPES)type=IMAGE_B8G8R8A8;
  662. if(OK(D3D->CreateOffscreenPlainSurface(info.Width, info.Height, ImageTI[type].compressed ? ImageTI[IMAGE_B8G8R8A8].format : ImageTI[type].format, D3DPOOL_SCRATCH, &_surf, null))
  663. || OK(D3D->CreateOffscreenPlainSurface(info.Width, info.Height, ImageTI[IMAGE_B8G8R8A8].format , D3DPOOL_SCRATCH, &_surf, null))) // try bgra on fail
  664. {
  665. if(file_data.elms() ? OK(D3DXLoadSurfaceFromFileInMemory(_surf, null, null, file_data.data(), file_data.elms(), null, D3DX_FILTER_NONE, 0, null)) // use 'D3DX_FILTER_NONE' so the image will not get rescaled
  666. : OK(D3DXLoadSurfaceFromFileW (_surf, null, null, path , null, D3DX_FILTER_NONE, 0, null))) // use 'D3DX_FILTER_NONE' so the image will not get rescaled
  667. {
  668. setInfo(info.Width, info.Height, 0, type, IMAGE_SURF_SCRATCH);
  669. locker.off();
  670. return toCube(T, -1, type);
  671. }
  672. }
  673. RELEASE(_surf);
  674. }
  675. break;
  676. }
  677. #elif DX11
  678. switch(mode)
  679. {
  680. case IMAGE_2D:
  681. {
  682. D3DX11_IMAGE_LOAD_INFO info;
  683. info.Usage =D3D11_USAGE_DEFAULT;
  684. info.BindFlags=D3D11_BIND_SHADER_RESOURCE;
  685. if(type > 0)info.Format =ImageTypeToFormat(type); if(info.Format==DXGI_FORMAT_UNKNOWN)info.Format=DXGI_FORMAT_FROM_FILE;
  686. if(mip_maps>=0)info.MipLevels=mip_maps;
  687. if(file_data.elms() ? OK(D3DX11CreateTextureFromMemory(D3D, file_data.data(), file_data.elms(), &info, null, (ID3D11Resource**)&_txtr, null))
  688. : OK(D3DX11CreateTextureFromFile (D3D, path , &info, null, (ID3D11Resource**)&_txtr, null)))
  689. {
  690. setInfo(0, 0, 0, type, IMAGE_MODE(mode));
  691. locker.off();
  692. return (T.type()>=IMAGE_TYPES) ? copyTry(T, -1, -1, -1, IMAGE_R8G8B8A8) : true;
  693. }
  694. }break;
  695. case IMAGE_SURF :
  696. case IMAGE_SURF_SYSTEM :
  697. case IMAGE_SURF_SCRATCH:
  698. {
  699. D3DX11_IMAGE_LOAD_INFO info;
  700. info.Usage =D3D11_USAGE_STAGING;
  701. info.BindFlags =0;
  702. info.CpuAccessFlags=D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE;
  703. if(type > 0)info.Format =ImageTypeToFormat(type); if(info.Format==DXGI_FORMAT_UNKNOWN)info.Format=DXGI_FORMAT_FROM_FILE;
  704. if(mip_maps>=0)info.MipLevels =mip_maps;
  705. if(file_data.elms() ? OK(D3DX11CreateTextureFromMemory(D3D, file_data.data(), file_data.elms(), &info, null, (ID3D11Resource**)&_txtr, null))
  706. : OK(D3DX11CreateTextureFromFile (D3D, path , &info, null, (ID3D11Resource**)&_txtr, null)))
  707. {
  708. setInfo(0, 0, 0, type, IMAGE_MODE(mode));
  709. locker.off();
  710. return (T.type()>=IMAGE_TYPES) ? copyTry(T, -1, -1, -1, IMAGE_R8G8B8A8) : true;
  711. }
  712. }break;
  713. case IMAGE_SOFT:
  714. {
  715. D3DX11_IMAGE_LOAD_INFO info;
  716. info.Usage =D3D11_USAGE_STAGING;
  717. info.BindFlags =0;
  718. info.CpuAccessFlags=D3D11_CPU_ACCESS_READ;
  719. if(type>0)info.Format =ImageTypeToFormat(type); if(info.Format==DXGI_FORMAT_UNKNOWN)info.Format=DXGI_FORMAT_FROM_FILE;
  720. info.MipLevels =1;
  721. if(file_data.elms() ? OK(D3DX11CreateTextureFromMemory(D3D, file_data.data(), file_data.elms(), &info, null, (ID3D11Resource**)&_txtr, null))
  722. : OK(D3DX11CreateTextureFromFile (D3D, path , &info, null, (ID3D11Resource**)&_txtr, null)))
  723. {
  724. setInfo(0, 0, 0, type, IMAGE_2D);
  725. locker.off();
  726. return copyTry(T, -1, -1, -1, (T.type()>=IMAGE_TYPES) ? IMAGE_R8G8B8A8 : -1, IMAGE_SOFT, 1);
  727. }
  728. }break;
  729. case IMAGE_CUBE:
  730. {
  731. D3DX11_IMAGE_LOAD_INFO info;
  732. info.Usage =D3D11_USAGE_STAGING;
  733. info.BindFlags =0;
  734. info.CpuAccessFlags=D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE;
  735. if(type > 0)info.Format =ImageTypeToFormat(type); if(info.Format==DXGI_FORMAT_UNKNOWN)info.Format=DXGI_FORMAT_FROM_FILE;
  736. if(mip_maps>=0)info.MipLevels =mip_maps;
  737. if(file_data.elms() ? OK(D3DX11CreateTextureFromMemory(D3D, file_data.data(), file_data.elms(), &info, null, (ID3D11Resource**)&_txtr, null))
  738. : OK(D3DX11CreateTextureFromFile (D3D, path , &info, null, (ID3D11Resource**)&_txtr, null)))
  739. {
  740. setInfo(0, 0, 0, type, IMAGE_SURF_SCRATCH);
  741. locker.off();
  742. return toCube(T, -1, (T.type()>=IMAGE_TYPES) ? IMAGE_R8G8B8A8 : -1);
  743. }
  744. }break;
  745. }
  746. #endif
  747. #endif
  748. }
  749. del(); return false;
  750. }
  751. return true;
  752. }
  753. /******************************************************************************/
  754. Bool Image::Export(C Str &name, Flt rgb_quality, Flt alpha_quality, Flt compression_level, Int sub_sample)C
  755. {
  756. CChar *ext=_GetExt(name);
  757. if(Equal(ext, "img" ))return save (name);
  758. if(Equal(ext, "bmp" ))return ExportBMP (name);
  759. if(Equal(ext, "png" ))return ExportPNG (name, compression_level);
  760. if(Equal(ext, "jpg" ))return ExportJPG (name, rgb_quality, sub_sample);
  761. if(Equal(ext, "webp"))return ExportWEBP(name, rgb_quality, alpha_quality);
  762. if(Equal(ext, "tga" ))return ExportTGA (name);
  763. if(Equal(ext, "tif" ))return ExportTIF (name, compression_level);
  764. if(Equal(ext, "dds" ))return ExportDDS (name);
  765. if(Equal(ext, "ico" ))return ExportICO (name);
  766. if(Equal(ext, "icns"))return ExportICNS(name);
  767. return false;
  768. }
  769. /******************************************************************************/
  770. Bool Image::ImportTry(File &f, Int type, Int mode, Int mip_maps)
  771. {
  772. Long pos=f.pos();
  773. if(load (f))goto ok;
  774. f.pos(pos); if(ImportBMP (f))goto ok;
  775. f.pos(pos); if(ImportPNG (f))goto ok;
  776. f.pos(pos); if(ImportJPG (f))goto ok;
  777. f.pos(pos); if(ImportWEBP(f))goto ok;
  778. f.pos(pos); if(ImportTIF (f))goto ok; // import after PNG/JPG in case LibTIFF tries to decode them too
  779. f.pos(pos); if(ImportDDS (f, type, mode, mip_maps))goto ok;
  780. f.pos(pos); if(ImportPSD (f))goto ok;
  781. f.pos(pos); if(ImportICO (f))goto ok;
  782. // TGA format doesn't contain any special signatures, so we can't check it
  783. del(); return false;
  784. ok:;
  785. return copyTry(T, -1, -1, -1, type, mode, mip_maps);
  786. }
  787. Bool Image::ImportTry(C Str &name, Int type, Int mode, Int mip_maps)
  788. {
  789. if(!name.is()){del(); return true;}
  790. File f; if(f.readTry(name))
  791. {
  792. if(ImportTry(f, type, mode, mip_maps))return true;
  793. CChar *ext=_GetExt(name);
  794. if(Equal(ext, "tga") && f.pos(0) && ImportTGA(f))goto ok; // TGA format doesn't contain any special signatures, so check extension instead
  795. }
  796. del(); return false;
  797. ok:;
  798. return copyTry(T, -1, -1, -1, type, mode, mip_maps);
  799. }
  800. Image& Image::Import(File &f, Int type, Int mode, Int mip_maps)
  801. {
  802. if(!ImportTry(f, type, mode, mip_maps))Exit(MLT(S+"Can't import image", PL,S+u"Nie można zaimportować obrazka"));
  803. return T;
  804. }
  805. Image& Image::Import(C Str &name, Int type, Int mode, Int mip_maps)
  806. {
  807. if(!ImportTry(name, type, mode, mip_maps))Exit(MLT(S+"Can't import image \""+name+'"', PL,S+u"Nie można zaimportować obrazka \""+name+'"'));
  808. return T;
  809. }
  810. /******************************************************************************/
  811. Bool Image::ImportCubeTry(C Image &right, C Image &left, C Image &up, C Image &down, C Image &forward, C Image &back, Int type, Int mip_maps, Bool resize_to_pow2, FILTER_TYPE filter)
  812. {
  813. Int size= Max(right .w(), right .h(), left.w(), left.h()) ;
  814. MAX(size, Max(up .w(), up .h(), down.w(), down.h()));
  815. MAX(size, Max(forward.w(), forward.h(), back.w(), back.h()));
  816. if(createCubeTry(resize_to_pow2 ? NearestPow2(size) : size, IMAGE_TYPE((type<=0) ? right.type() : type), mip_maps))
  817. {
  818. injectMipMap(right , 0, DIR_RIGHT , filter);
  819. injectMipMap(left , 0, DIR_LEFT , filter);
  820. injectMipMap(up , 0, DIR_UP , filter);
  821. injectMipMap(down , 0, DIR_DOWN , filter);
  822. injectMipMap(forward, 0, DIR_FORWARD, filter);
  823. injectMipMap(back , 0, DIR_BACK , filter);
  824. updateMipMaps(); return true;
  825. }
  826. del(); return false;
  827. }
  828. Bool Image::ImportCubeTry(C Str &right, C Str &left, C Str &up, C Str &down, C Str &forward, C Str &back, Int type, Int mip_maps, Bool resize_to_pow2, FILTER_TYPE filter)
  829. {
  830. Image r, l, u, d, f, b;
  831. if(r.ImportTry(right , -1, IMAGE_SOFT, 1) // use OR to proceed if at least one was imported
  832. | l.ImportTry(left , -1, IMAGE_SOFT, 1) // use single OR "|" to call import for all images (double OR "||" would continue on first success)
  833. | u.ImportTry(up , -1, IMAGE_SOFT, 1)
  834. | d.ImportTry(down , -1, IMAGE_SOFT, 1)
  835. | f.ImportTry(forward, -1, IMAGE_SOFT, 1)
  836. | b.ImportTry(back , -1, IMAGE_SOFT, 1))return ImportCubeTry(r, l, u, d, f, b, type, mip_maps, resize_to_pow2, filter);
  837. del(); return false;
  838. }
  839. Image& Image::ImportCube(C Str &right, C Str &left, C Str &up, C Str &down, C Str &forward, C Str &back, Int type, Int mip_maps, Bool resize_to_pow2, FILTER_TYPE filter)
  840. {
  841. if(!ImportCubeTry(right, left, up, down, forward, back, type, mip_maps, resize_to_pow2, filter))Exit(MLT(S+"Can't import images as Cube Texture \"" +right+"\", \""+left+"\", \""+up+"\", \""+down+"\", \""+forward+"\", \""+back+'"',
  842. PL,S+u"Nie można zaimportować obrazków jako Cube Texture \""+right+"\", \""+left+"\", \""+up+"\", \""+down+"\", \""+forward+"\", \""+back+'"'));
  843. return T;
  844. }
  845. /******************************************************************************/
  846. Bool ImageLoadHeader(File &f, ImageHeader &header)
  847. {
  848. Image temp;
  849. Long pos=f.pos(); // remember file position
  850. Bool ok =(f.getUInt()==CC4_GFX && temp.loadData(f, IMAGE_NONE, &header));
  851. f.pos(pos); // reset file position
  852. if(ok)return true;
  853. header.zero(); return false;
  854. }
  855. Bool ImageLoadHeader(C Str &name, ImageHeader &header)
  856. {
  857. File f; if(f.readTry(name))return ImageLoadHeader(f, header);
  858. header.zero(); return false;
  859. }
  860. /******************************************************************************/
  861. }
  862. /******************************************************************************/