BC.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #include "../../../../ThirdPartyLibs/begin.h"
  4. #define BC7_LIB_DIRECTX 1
  5. #define BC7_LIB_TEXGENPACK 2 // faster than BC7_LIB_DIRECTX
  6. #define BC7_DEC BC7_LIB_TEXGENPACK
  7. #if BC7_DEC==BC7_LIB_DIRECTX
  8. #include "../../../../ThirdPartyLibs/DirectXMath/include.h"
  9. #if !WINDOWS
  10. #define register
  11. #endif
  12. #include "../../../../ThirdPartyLibs/DirectXTex/BC.h"
  13. //#include "../../../../ThirdPartyLibs/DirectXTex/BC.cpp"
  14. #include "../../../../ThirdPartyLibs/DirectXTex/BC6HBC7.cpp"
  15. #elif BC7_DEC==BC7_LIB_TEXGENPACK
  16. namespace TGP
  17. {
  18. #pragma runtime_checks("", off)
  19. #include "../../../../ThirdPartyLibs/TexGenPack/bptc.c"
  20. #pragma runtime_checks("", restore)
  21. }
  22. #endif
  23. #include "../../../../ThirdPartyLibs/end.h"
  24. namespace EE{
  25. /******************************************************************************/
  26. Bool (*CompressBC7)(C Image &src, Image &dest);
  27. /******************************************************************************/
  28. static inline UInt B15(UInt x) {return (x*255/*+ 7*/)/15;} // scale from 0..15 to 0..255 byte range (this version exactly matches float with Round, +7 is not needed in this case, function will return the same value with or without it)
  29. static inline UInt B31(UInt x) {return (x*255 +15 )/31;} // scale from 0..31 to 0..255 byte range (this version exactly matches float with Round)
  30. static inline UInt B63(UInt x) {return (x*255 +31 )/63;} // scale from 0..63 to 0..255 byte range (this version exactly matches float with Round)
  31. static inline void Col565(Color &color, UShort u) {color.set(B31((u>>11)&0x1F), B63((u>>5)&0x3F), B31(u&0x1F), 255);}
  32. static inline U64 GetU64(CPtr data) {return Unaligned(*(U64*)data);}
  33. /******************************************************************************/
  34. // BLOCK
  35. /******************************************************************************/
  36. static inline void _DecompressBlockBC1(C Byte *b, Color color[4], UInt &cis)
  37. {
  38. UShort c0=*(UShort*)(b ),
  39. c1=*(UShort*)(b+2);
  40. Col565(color[0], c0);
  41. Col565(color[1], c1);
  42. if(c0<=c1)
  43. {
  44. color[2].r=(color[0].r + color[1].r + 1)/2;
  45. color[2].g=(color[0].g + color[1].g + 1)/2;
  46. color[2].b=(color[0].b + color[1].b + 1)/2;
  47. color[2].a=255;
  48. color[3].zero();
  49. }else
  50. {
  51. color[2].r=(color[0].r*2 + color[1].r*1 + 1)/3;
  52. color[2].g=(color[0].g*2 + color[1].g*1 + 1)/3;
  53. color[2].b=(color[0].b*2 + color[1].b*1 + 1)/3;
  54. color[2].a=255;
  55. color[3].r=(color[0].r*1 + color[1].r*2 + 1)/3;
  56. color[3].g=(color[0].g*1 + color[1].g*2 + 1)/3;
  57. color[3].b=(color[0].b*1 + color[1].b*2 + 1)/3;
  58. color[3].a=255;
  59. }
  60. cis=*(UInt*)(b+4);
  61. }
  62. void DecompressBlockBC1(C Byte *b, Color (&block)[4][4])
  63. {
  64. Color color[4]; UInt cis; _DecompressBlockBC1(b, color, cis);
  65. REPD(y, 4)
  66. REPD(x, 4)
  67. {
  68. Int i=x+(y<<2), // pixel index
  69. ci=((cis>>(2*i))&3); // color index
  70. block[y][x]=color[ci];
  71. }
  72. }
  73. void DecompressBlockBC1(C Byte *b, Color *dest, Int pitch)
  74. {
  75. Color color[4]; UInt cis; _DecompressBlockBC1(b, color, cis);
  76. FREPD(y, 4) // move in forward order so 'dest' can be increased by pitch
  77. {
  78. REPD(x, 4)
  79. {
  80. Int i=x+(y<<2), // pixel index
  81. ci=((cis>>(2*i))&3); // color index
  82. dest[x]=color[ci];
  83. }
  84. dest=(Color*)((Byte*)dest+pitch);
  85. }
  86. }
  87. /******************************************************************************/
  88. static inline void _DecompressBlockBC2(C Byte *b, Color color[4], UInt &cis)
  89. {
  90. UShort c0=*(UShort*)(b+ 8),
  91. c1=*(UShort*)(b+10);
  92. Col565(color[0], c0);
  93. Col565(color[1], c1);
  94. color[2].r=(color[0].r*2 + color[1].r*1 + 1)/3;
  95. color[2].g=(color[0].g*2 + color[1].g*1 + 1)/3;
  96. color[2].b=(color[0].b*2 + color[1].b*1 + 1)/3;
  97. color[3].r=(color[0].r*1 + color[1].r*2 + 1)/3;
  98. color[3].g=(color[0].g*1 + color[1].g*2 + 1)/3;
  99. color[3].b=(color[0].b*1 + color[1].b*2 + 1)/3;
  100. cis=*(UInt*)(b+12);
  101. }
  102. void DecompressBlockBC2(C Byte *b, Color (&block)[4][4])
  103. {
  104. Color color[4]; UInt cis; _DecompressBlockBC2(b, color, cis);
  105. ULong alpha=GetU64(b);
  106. REPD(y, 4)
  107. REPD(x, 4)
  108. {
  109. Int i=x+(y<<2), // pixel index
  110. ci=((cis>>(2*i))&3); // color index
  111. Color &col=color[ci];
  112. block[y][x].set(col.r, col.g, col.b, B15((alpha>>(4*i))&15));
  113. }
  114. }
  115. void DecompressBlockBC2(C Byte *b, Color *dest, Int pitch)
  116. {
  117. Color color[4]; UInt cis; _DecompressBlockBC2(b, color, cis);
  118. ULong alpha=GetU64(b);
  119. FREPD(y, 4) // move in forward order so 'dest' can be increased by pitch
  120. {
  121. REPD(x, 4)
  122. {
  123. Int i=x+(y<<2), // pixel index
  124. ci=((cis>>(2*i))&3); // color index
  125. Color &col=color[ci];
  126. dest[x].set(col.r, col.g, col.b, B15((alpha>>(4*i))&15));
  127. }
  128. dest=(Color*)((Byte*)dest+pitch);
  129. }
  130. }
  131. /******************************************************************************/
  132. static inline void _DecompressBlockBC3(C Byte *b, Color color[4], UInt &cis, Byte alpha[8], U64 &ais)
  133. {
  134. _DecompressBlockBC2(b, color, cis);
  135. alpha[0]=b[0];
  136. alpha[1]=b[1];
  137. if(alpha[0]>alpha[1])
  138. {
  139. alpha[2]=(alpha[0]*6 + alpha[1]*1 + 3)/7;
  140. alpha[3]=(alpha[0]*5 + alpha[1]*2 + 3)/7;
  141. alpha[4]=(alpha[0]*4 + alpha[1]*3 + 3)/7;
  142. alpha[5]=(alpha[0]*3 + alpha[1]*4 + 3)/7;
  143. alpha[6]=(alpha[0]*2 + alpha[1]*5 + 3)/7;
  144. alpha[7]=(alpha[0]*1 + alpha[1]*6 + 3)/7;
  145. }else
  146. {
  147. alpha[2]=(alpha[0]*4 + alpha[1]*1 + 2)/5;
  148. alpha[3]=(alpha[0]*3 + alpha[1]*2 + 2)/5;
  149. alpha[4]=(alpha[0]*2 + alpha[1]*3 + 2)/5;
  150. alpha[5]=(alpha[0]*1 + alpha[1]*4 + 2)/5;
  151. alpha[6]= 0;
  152. alpha[7]= 255;
  153. }
  154. ais=GetU64(b+2);
  155. }
  156. void DecompressBlockBC3(C Byte *b, Color (&block)[4][4])
  157. {
  158. Color color[4]; UInt cis; Byte alpha[8]; U64 ais; _DecompressBlockBC3(b, color, cis, alpha, ais);
  159. REPD(y, 4)
  160. REPD(x, 4)
  161. {
  162. Int i=x+(y<<2), // pixel index
  163. ai=((ais>>(3*i))&7), // alpha index
  164. ci=((cis>>(2*i))&3); // color index
  165. Color &col=color[ci];
  166. block[y][x].set(col.r, col.g, col.b, alpha[ai]);
  167. }
  168. }
  169. void DecompressBlockBC3(C Byte *b, Color *dest, Int pitch)
  170. {
  171. Color color[4]; UInt cis; Byte alpha[8]; U64 ais; _DecompressBlockBC3(b, color, cis, alpha, ais);
  172. FREPD(y, 4) // move in forward order so 'dest' can be increased by pitch
  173. {
  174. REPD(x, 4)
  175. {
  176. Int i=x+(y<<2), // pixel index
  177. ai=((ais>>(3*i))&7), // alpha index
  178. ci=((cis>>(2*i))&3); // color index
  179. Color &col=color[ci];
  180. dest[x].set(col.r, col.g, col.b, alpha[ai]);
  181. }
  182. dest=(Color*)((Byte*)dest+pitch);
  183. }
  184. }
  185. /******************************************************************************/
  186. void DecompressBlockBC7(C Byte *b, Color (&block)[4][4])
  187. {
  188. #if BC7_DEC==BC7_LIB_DIRECTX
  189. DirectX::D3DXDecodeBC7(block, b);
  190. #elif BC7_DEC==BC7_LIB_TEXGENPACK
  191. TGP::draw_block4x4_bptc(b, (UInt*)block);
  192. #endif
  193. }
  194. void DecompressBlockBC7(C Byte *b, Color *dest, Int pitch)
  195. {
  196. Color block[4][4];
  197. #if BC7_DEC==BC7_LIB_DIRECTX
  198. DirectX::D3DXDecodeBC7(block, b);
  199. #elif BC7_DEC==BC7_LIB_TEXGENPACK
  200. TGP::draw_block4x4_bptc(b, (UInt*)block);
  201. #endif
  202. FREPD(y, 4) // move in forward order so 'dest' can be increased by pitch
  203. {
  204. CopyFast(dest, block[y], SIZE(Color)*4);
  205. dest=(Color*)((Byte*)dest+pitch);
  206. }
  207. }
  208. /******************************************************************************/
  209. // PIXEL
  210. /******************************************************************************/
  211. Color DecompressPixelBC1(C Byte *b, Int x, Int y)
  212. {
  213. Int i=x+(y<<2), // pixel index
  214. ci=((*(U32*)(b+4)>>(2*i))&3); // color index
  215. // color
  216. Color color[4];
  217. UShort c0=*(UShort*)(b ),
  218. c1=*(UShort*)(b+2);
  219. Col565(color[0], c0);
  220. Col565(color[1], c1);
  221. color[ci].a=255;
  222. if(c0<=c1)
  223. {
  224. if(ci==2)
  225. {
  226. color[2].r=(color[0].r + color[1].r + 1)/2;
  227. color[2].g=(color[0].g + color[1].g + 1)/2;
  228. color[2].b=(color[0].b + color[1].b + 1)/2;
  229. }else
  230. if(ci==3)
  231. {
  232. color[3].zero();
  233. }
  234. }else
  235. {
  236. if(ci==2)
  237. {
  238. color[2].r=(color[0].r*2 + color[1].r*1 + 1)/3;
  239. color[2].g=(color[0].g*2 + color[1].g*1 + 1)/3;
  240. color[2].b=(color[0].b*2 + color[1].b*1 + 1)/3;
  241. }else
  242. if(ci==3)
  243. {
  244. color[3].r=(color[0].r*1 + color[1].r*2 + 1)/3;
  245. color[3].g=(color[0].g*1 + color[1].g*2 + 1)/3;
  246. color[3].b=(color[0].b*1 + color[1].b*2 + 1)/3;
  247. }
  248. }
  249. return color[ci];
  250. }
  251. /******************************************************************************/
  252. Color DecompressPixelBC2(C Byte *b, Int x, Int y)
  253. {
  254. Int i=x+(y<<2), // pixel index
  255. ci=((*(U32*)(b+12)>>(2*i))&3); // color index
  256. // color
  257. Color color[4];
  258. UShort c0=*(UShort*)(b+ 8),
  259. c1=*(UShort*)(b+10);
  260. Col565(color[0], c0);
  261. Col565(color[1], c1);
  262. if(ci==2)
  263. {
  264. color[2].r=(color[0].r*2 + color[1].r*1 + 1)/3;
  265. color[2].g=(color[0].g*2 + color[1].g*1 + 1)/3;
  266. color[2].b=(color[0].b*2 + color[1].b*1 + 1)/3;
  267. }else
  268. if(ci==3)
  269. {
  270. color[3].r=(color[0].r*1 + color[1].r*2 + 1)/3;
  271. color[3].g=(color[0].g*1 + color[1].g*2 + 1)/3;
  272. color[3].b=(color[0].b*1 + color[1].b*2 + 1)/3;
  273. }
  274. color[ci].a=B15((GetU64(b)>>(4*i))&15);
  275. return color[ci];
  276. }
  277. /******************************************************************************/
  278. Color DecompressPixelBC3(C Byte *b, Int x, Int y)
  279. {
  280. U64 ais=GetU64(b+2);
  281. Int i =x+(y<<2), // pixel index
  282. ai =((ais>>(3*i))&7), // alpha index
  283. ci =((*(U32*)(b+12)>>(2*i))&3); // color index
  284. // alpha
  285. Byte alpha[8];
  286. alpha[0]=b[0];
  287. alpha[1]=b[1];
  288. switch(ai)
  289. {
  290. case 2: alpha[2]=((alpha[0]>alpha[1]) ? (alpha[0]*6 + alpha[1]*1 + 3)/7 : (alpha[0]*4 + alpha[1]*1 + 2)/5); break;
  291. case 3: alpha[3]=((alpha[0]>alpha[1]) ? (alpha[0]*5 + alpha[1]*2 + 3)/7 : (alpha[0]*3 + alpha[1]*2 + 2)/5); break;
  292. case 4: alpha[4]=((alpha[0]>alpha[1]) ? (alpha[0]*4 + alpha[1]*3 + 3)/7 : (alpha[0]*2 + alpha[1]*3 + 2)/5); break;
  293. case 5: alpha[5]=((alpha[0]>alpha[1]) ? (alpha[0]*3 + alpha[1]*4 + 3)/7 : (alpha[0]*1 + alpha[1]*4 + 2)/5); break;
  294. case 6: alpha[6]=((alpha[0]>alpha[1]) ? (alpha[0]*2 + alpha[1]*5 + 3)/7 : 0); break;
  295. case 7: alpha[7]=((alpha[0]>alpha[1]) ? (alpha[0]*1 + alpha[1]*6 + 3)/7 : 255); break;
  296. }
  297. // color
  298. Color color[4];
  299. UShort c0=*(UShort*)(b+ 8),
  300. c1=*(UShort*)(b+10);
  301. Col565(color[0], c0);
  302. Col565(color[1], c1);
  303. if(ci==2)
  304. {
  305. color[2].r=(color[0].r*2 + color[1].r*1 + 1)/3;
  306. color[2].g=(color[0].g*2 + color[1].g*1 + 1)/3;
  307. color[2].b=(color[0].b*2 + color[1].b*1 + 1)/3;
  308. }else
  309. if(ci==3)
  310. {
  311. color[3].r=(color[0].r*1 + color[1].r*2 + 1)/3;
  312. color[3].g=(color[0].g*1 + color[1].g*2 + 1)/3;
  313. color[3].b=(color[0].b*1 + color[1].b*2 + 1)/3;
  314. }
  315. color[ci].a=alpha[ai];
  316. return color[ci];
  317. }
  318. /******************************************************************************/
  319. Color DecompressPixelBC7(C Byte *b, Int x, Int y)
  320. {
  321. Color block[4][4]; DecompressBlockBC7(b, block);
  322. return block[y][x];
  323. }
  324. /******************************************************************************/
  325. // COMPRESS
  326. /******************************************************************************/
  327. struct BC1
  328. {
  329. U16 rgb[2]; // 565 colors
  330. U32 bitmap; // 2bpp rgb bitmap
  331. };
  332. struct BC2
  333. {
  334. UInt bitmap[2]; // 4bpp alpha bitmap
  335. BC1 bc1 ; // BC1 rgb data
  336. };
  337. struct BC3
  338. {
  339. Byte alpha[2] ; // alpha values
  340. Byte bitmap[6]; // 3bpp alpha bitmap
  341. BC1 bc1 ; // BC1 rgb data
  342. };
  343. static const Flt fEpsilon =Sqr(0.25f/64);
  344. static const Flt pC3 []={2.0f/2.0f, 1.0f/2.0f, 0.0f/2.0f};
  345. static const Flt pD3 []={0.0f/2.0f, 1.0f/2.0f, 2.0f/2.0f};
  346. static const Flt pC4 []={3.0f/3.0f, 2.0f/3.0f, 1.0f/3.0f, 0.0f/3.0f};
  347. static const Flt pD4 []={0.0f/3.0f, 1.0f/3.0f, 2.0f/3.0f, 3.0f/3.0f};
  348. static const Flt pC6 []={5.0f/5.0f, 4.0f/5.0f, 3.0f/5.0f, 2.0f/5.0f, 1.0f/5.0f, 0.0f/5.0f};
  349. static const Flt pD6 []={0.0f/5.0f, 1.0f/5.0f, 2.0f/5.0f, 3.0f/5.0f, 4.0f/5.0f, 5.0f/5.0f};
  350. static const Flt pC8 []={7.0f/7.0f, 6.0f/7.0f, 5.0f/7.0f, 4.0f/7.0f, 3.0f/7.0f, 2.0f/7.0f, 1.0f/7.0f, 0.0f/7.0f};
  351. static const Flt pD8 []={0.0f/7.0f, 1.0f/7.0f, 2.0f/7.0f, 3.0f/7.0f, 4.0f/7.0f, 5.0f/7.0f, 6.0f/7.0f, 7.0f/7.0f};
  352. static const Int pSteps3[]={0, 2, 1};
  353. static const Int pSteps4[]={0, 2, 3, 1};
  354. static const Int pSteps6[]={0, 2, 3, 4, 5, 1};
  355. static const Int pSteps8[]={0, 2, 3, 4, 5, 6, 7, 1};
  356. static void Decode565(Vec &col, UInt w565)
  357. {
  358. col.set(((w565>>11)&31)/31.0f,
  359. ((w565>> 5)&63)/63.0f,
  360. ((w565>> 0)&31)/31.0f);
  361. }
  362. static UInt Encode565(C Vec &col)
  363. {
  364. return ((col.x<=0) ? 0 : (col.x>=1) ? (31<<11) : (RoundPos(col.x*31)<<11))
  365. | ((col.y<=0) ? 0 : (col.y>=1) ? (63<< 5) : (RoundPos(col.y*63)<< 5))
  366. | ((col.z<=0) ? 0 : (col.z>=1) ? (31<< 0) : (RoundPos(col.z*31)<< 0));
  367. }
  368. static void OptimizeRGB(Vec &color_a, Vec &color_b, Vec4 (&color)[16], Int steps)
  369. {
  370. C Flt *pC, *pD; if(steps==3){pC=pC3; pD=pD3;}else{pC=pC4; pD=pD4;}
  371. Vec min=color[15].xyz, max=min;
  372. REP(15)
  373. {
  374. C Vec &c=color[i].xyz;
  375. MIN(min.x, c.x); MAX(max.x, c.x);
  376. MIN(min.y, c.y); MAX(max.y, c.y);
  377. MIN(min.z, c.z); MAX(max.z, c.z);
  378. }
  379. Vec dir=max-min;
  380. Flt l=dir.length2();
  381. if(l<=FLT_MIN){color_a=min; color_b=max; return;} // Single color block.. no need to root-find
  382. dir/=l;
  383. Vec mid=Avg(min, max);
  384. Flt fDir[4]={0,0,0,0};
  385. FREPA(color)
  386. {
  387. Vec c=color[i].xyz-mid;
  388. c*=dir;
  389. fDir[0]+=Sqr(c.x + c.y + c.z);
  390. fDir[1]+=Sqr(c.x + c.y - c.z);
  391. fDir[2]+=Sqr(c.x - c.y + c.z);
  392. fDir[3]+=Sqr(c.x - c.y - c.z);
  393. }
  394. Int iDirMax=0; Flt fDirMax=fDir[0]; for(Int iDir=1; iDir<4; iDir++)if(fDir[iDir]>fDirMax)fDirMax=fDir[iDirMax=iDir];
  395. if(iDirMax&2)Swap(min.y, max.y);
  396. if(iDirMax&1)Swap(min.z, max.z);
  397. // Two color block.. no need to root-find
  398. if(l<1.0f/4096){color_a=min; color_b=max; return;}
  399. // Use Newton's Method to find local minima of sum-of-squares error
  400. Flt fSteps=steps-1;
  401. REP(16) // original version had 8, but 16 generates better results
  402. {
  403. // Calculate new steps
  404. Vec pSteps[4];
  405. FREP(steps)pSteps[i]=min*pC[i] + max*pD[i];
  406. // Calculate color direction
  407. dir=max-min;
  408. l=dir.length2();
  409. if(l<1.0f/4096)break;
  410. dir*=fSteps/l; // divide by 'l' and not 'Sqrt(l)' because we don't want to use it to calculate unit distances, but fraction distances
  411. // Evaluate function, and derivatives
  412. Flt start=Dot(min, dir), d2X=0, d2Y=0; Vec dX=0, dY=0;
  413. FREPA(color)
  414. {
  415. Flt dot=Dot(color[i].xyz, dir)-start;
  416. Int s;
  417. if(dot<=0 )s= 0;else
  418. if(dot>=fSteps)s=steps-1;else
  419. s=RoundPos(dot);
  420. Vec diff=pSteps[s]-color[i].xyz;
  421. Flt fC=pC[s]/8, fD=pD[s]/8;
  422. d2X+=fC*pC[s];
  423. dX +=fC*diff;
  424. d2Y+=fD*pD[s];
  425. dY +=fD*diff;
  426. }
  427. // Move endpoints
  428. if(d2X>0)min-=dX/d2X;
  429. if(d2Y>0)max-=dY/d2Y;
  430. #if 0 // original
  431. if(Sqr(dX.x)<fEpsilon && Sqr(dX.y)<fEpsilon && Sqr(dX.z)<fEpsilon
  432. && Sqr(dY.x)<fEpsilon && Sqr(dY.y)<fEpsilon && Sqr(dY.z)<fEpsilon)break;
  433. #else
  434. if(dX.length2()<fEpsilon && dY.length2()<fEpsilon)break;
  435. #endif
  436. }
  437. color_a=min;
  438. color_b=max;
  439. }
  440. static void _CompressBC1(BC1 &bc, Vec4 (&color)[16], C Vec *weight, Bool dither_rgb, Bool dither_a, Flt alpha_ref) // !! Warning: 'color' gets modified !!, 'alpha_ref'=use zero to disable alpha encoding
  441. {
  442. Int steps;
  443. if(alpha_ref>0)
  444. {
  445. if(dither_a)
  446. {
  447. Flt error[16]; Zero(error);
  448. FREPA(color)
  449. {
  450. Flt &dest=color[i].w, alpha=dest+error[i];
  451. dest=RoundPos(alpha);
  452. Flt diff=alpha-dest;
  453. if((i&3)!=3)error[i+1]+=diff*(7.0f/16);
  454. if(i<12)
  455. {
  456. if( i&3 )error[i+3]+=diff*(3.0f/16);
  457. error[i+4]+=diff*(5.0f/16);
  458. if((i&3)!=3)error[i+5]+=diff*(1.0f/16);
  459. }
  460. }
  461. }
  462. Int transparent=0;
  463. REPA(color)if(color[i].w<alpha_ref)transparent++;
  464. if(transparent==16)
  465. {
  466. bc.rgb[0]=0x0000;
  467. bc.rgb[1]=0xffff;
  468. bc.bitmap=0xffffffff;
  469. return;
  470. }
  471. steps=(transparent ? 3 : 4);
  472. }else steps=4;
  473. Vec4 col [16];
  474. Vec error[16];
  475. if(dither_rgb)Zero(error);
  476. FREPA(col)
  477. {
  478. Vec clr=color[i].xyz;
  479. if(dither_rgb)clr+=error[i];
  480. col[i].x=RoundPos(clr.x*31)/31.0f;
  481. col[i].y=RoundPos(clr.y*63)/63.0f;
  482. col[i].z=RoundPos(clr.z*31)/31.0f;
  483. if(dither_rgb)
  484. {
  485. Vec diff=clr-col[i].xyz;
  486. if((i&3)!=3)error[i+1]+=diff*(7.0f/16);
  487. if(i<12)
  488. {
  489. if( i&3 )error[i+3]+=diff*(3.0f/16);
  490. error[i+4]+=diff*(5.0f/16);
  491. if((i&3)!=3)error[i+5]+=diff*(1.0f/16);
  492. }
  493. }
  494. if(weight)col[i].xyz*=*weight;
  495. }
  496. Vec color_a, color_b;
  497. OptimizeRGB(color_a, color_b, col, steps);
  498. if(weight)
  499. {
  500. color_a/=*weight;
  501. color_b/=*weight;
  502. }
  503. UInt wColorA=Encode565(color_a), wColorB=Encode565(color_b);
  504. if(steps==4 && wColorA==wColorB)
  505. {
  506. bc.rgb[0]=wColorA;
  507. bc.rgb[1]=wColorB;
  508. bc.bitmap=0x00000000;
  509. return;
  510. }
  511. Decode565(color_a, wColorA);
  512. Decode565(color_b, wColorB);
  513. if(weight)
  514. {
  515. color_a*=*weight;
  516. color_b*=*weight;
  517. }
  518. // Calculate color steps
  519. Vec step[4];
  520. if((steps==3)==(wColorA<=wColorB))
  521. {
  522. bc.rgb[0]=wColorA;
  523. bc.rgb[1]=wColorB;
  524. step[0]=color_a;
  525. step[1]=color_b;
  526. }else
  527. {
  528. bc.rgb[0]=wColorB;
  529. bc.rgb[1]=wColorA;
  530. step[0]=color_b;
  531. step[1]=color_a;
  532. }
  533. const Int *pSteps;
  534. if(steps==3)
  535. {
  536. pSteps=pSteps3;
  537. step[2]=Avg(step[0], step[1]);
  538. }else
  539. {
  540. pSteps=pSteps4;
  541. #if 0
  542. step[2]=Lerp(step[0], step[1], 1.0f/3);
  543. step[3]=Lerp(step[0], step[1], 2.0f/3);
  544. #else
  545. Vec d=(step[1]-step[0])/3;
  546. step[2]=step[0]+d;
  547. step[3]=step[0]+d*2;
  548. #endif
  549. }
  550. // Calculate color direction
  551. Flt fSteps=steps-1;
  552. Vec dir=step[1]-step[0]; if(wColorA!=wColorB)dir*=fSteps/dir.length2(); // divide by 'length2' and not 'length' because we don't want to use it to calculate unit distances, but fraction distances
  553. Flt start=Dot(step[0], dir);
  554. // Encode colors
  555. UInt bitmap=0;
  556. if(dither_rgb)Zero(error);
  557. FREPA(color)
  558. {
  559. if(steps==3 && color[i].w<alpha_ref)bitmap=(3<<30)|(bitmap>>2);else
  560. {
  561. Vec clr=color[i].xyz;
  562. if(weight)clr*=*weight;
  563. if(dither_rgb)clr+=error[i];
  564. Flt dot=Dot(clr, dir)-start;
  565. Int s;
  566. if(dot<=0.0f )s=0;else
  567. if(dot>=fSteps)s=1;else
  568. s=pSteps[RoundPos(dot)];
  569. bitmap=(s<<30)|(bitmap>>2);
  570. if(dither_rgb)
  571. {
  572. Vec diff=clr-step[s];
  573. if((i&3)!=3)error[i+1]+=diff*(7.0f/16);
  574. if(i<12)
  575. {
  576. if( i&3 )error[i+3]+=diff*(3.0f/16);
  577. error[i+4]+=diff*(5.0f/16);
  578. if((i&3)!=3)error[i+5]+=diff*(1.0f/16);
  579. }
  580. }
  581. }
  582. }
  583. bc.bitmap=bitmap;
  584. }
  585. static void CompressBC1(Byte *bc, Vec4 (&color)[16], C Vec *weight, Bool dither_rgb, Bool dither_a) {return _CompressBC1(*(BC1*)bc, color, weight, dither_rgb, dither_a, 0.5f);}
  586. static void CompressBC2(Byte *bc, Vec4 (&color)[16], C Vec *weight, Bool dither_rgb, Bool dither_a)
  587. {
  588. BC2 &bc2=*(BC2*)bc;
  589. _CompressBC1(bc2.bc1, color, weight, dither_rgb, false, 0);
  590. bc2.bitmap[0]=0;
  591. bc2.bitmap[1]=0;
  592. Flt error[16]; if(dither_a)Zero(error);
  593. FREPA(color)
  594. {
  595. Flt alpha=color[i].w;
  596. if(dither_a)alpha+=error[i];
  597. UInt u=RoundPos(alpha*15);
  598. bc2.bitmap[i>>3]>>=4;
  599. bc2.bitmap[i>>3] |=(u<<28);
  600. if(dither_a)
  601. {
  602. Flt diff=alpha-u/15.0f;
  603. if((i&3)!=3)error[i+1]+=diff*(7.0f/16);
  604. if(i<12)
  605. {
  606. if( i&3 )error[i+3]+=diff*(3.0f/16);
  607. error[i+4]+=diff*(5.0f/16);
  608. if((i&3)!=3)error[i+5]+=diff*(1.0f/16);
  609. }
  610. }
  611. }
  612. }
  613. static void OptimizeAlpha(Flt *pX, Flt *pY, const Flt *pPoints, Int cSteps)
  614. {
  615. const Flt *pC=(6==cSteps) ? pC6 : pC8;
  616. const Flt *pD=(6==cSteps) ? pD6 : pD8;
  617. const Flt MIN_VALUE=0;
  618. const Flt MAX_VALUE=1;
  619. // Find Min and Max points, as starting point
  620. Flt fX=MAX_VALUE;
  621. Flt fY=MIN_VALUE;
  622. if(cSteps==8)
  623. {
  624. FREP(16)
  625. {
  626. MIN(fX, pPoints[i]);
  627. MAX(fY, pPoints[i]);
  628. }
  629. }else
  630. {
  631. FREP(16)
  632. {
  633. if(pPoints[i]<fX && pPoints[i]>MIN_VALUE)fX=pPoints[i];
  634. if(pPoints[i]>fY && pPoints[i]<MAX_VALUE)fY=pPoints[i];
  635. }
  636. if(fX==fY)fY=MAX_VALUE;
  637. }
  638. // Use Newton's Method to find local minima of sum-of-squares error
  639. Flt fSteps=cSteps-1;
  640. for(Int iIteration=0; iIteration<8; iIteration++)
  641. {
  642. if(fY-fX < 1.0f/256)break;
  643. Flt fScale=fSteps/(fY-fX);
  644. // Calculate new steps
  645. Flt pSteps[8];
  646. for(Int iStep=0; iStep<cSteps; iStep++)pSteps[iStep]=pC[iStep]*fX + pD[iStep]*fY;
  647. if(cSteps==6)
  648. {
  649. pSteps[6]=MIN_VALUE;
  650. pSteps[7]=MAX_VALUE;
  651. }
  652. // Evaluate function, and derivatives
  653. Flt dX=0, dY=0, d2X=0, d2Y=0;
  654. FREP(16)
  655. {
  656. Flt fDot=(pPoints[i]-fX)*fScale;
  657. Int iStep;
  658. if(fDot<= 0)iStep=(cSteps==6 && (pPoints[i]<= fX *0.5f)) ? 6 : 0;else
  659. if(fDot>=fSteps)iStep=(cSteps==6 && (pPoints[i]>=(fY+1)*0.5f)) ? 7 : (cSteps-1);else
  660. iStep=RoundPos(fDot);
  661. if(iStep<cSteps)
  662. {
  663. Flt diff=pSteps[iStep]-pPoints[i];
  664. dX +=pC[iStep]*diff;
  665. d2X+=pC[iStep]*pC[iStep];
  666. dY +=pD[iStep]*diff;
  667. d2Y+=pD[iStep]*pD[iStep];
  668. }
  669. }
  670. // Move endpoints
  671. if(d2X>0)fX-=dX/d2X;
  672. if(d2Y>0)fY-=dY/d2Y;
  673. if(fX>fY)Swap(fX, fY);
  674. if(Sqr(dX)<1.0f/64 && Sqr(dY)<1.0f/64)break;
  675. }
  676. *pX=Mid(fX, MIN_VALUE, MAX_VALUE);
  677. *pY=Mid(fY, MIN_VALUE, MAX_VALUE);
  678. }
  679. static void CompressBC3(Byte *bc, Vec4 (&color)[16], C Vec *weight, Bool dither_rgb, Bool dither_a)
  680. {
  681. BC3 &bc3=*(BC3*)bc;
  682. _CompressBC1(bc3.bc1, color, weight, dither_rgb, false, 0);
  683. Flt fAlpha[16], error[16], fMinAlpha=color[0].w, fMaxAlpha=color[0].w;
  684. if(dither_a)Zero(error);
  685. FREPA(color)
  686. {
  687. Flt fAlph=color[i].w;
  688. if(dither_a)fAlph+=error[i];
  689. fAlpha[i]=RoundPos(fAlph*255)/255.0f;
  690. if(fAlpha[i]<fMinAlpha)fMinAlpha=fAlpha[i];else
  691. if(fAlpha[i]>fMaxAlpha)fMaxAlpha=fAlpha[i];
  692. if(dither_a)
  693. {
  694. Flt diff=fAlph-fAlpha[i];
  695. if((i&3)!=3)error[i+1]+=diff*(7.0f/16);
  696. if(i<12)
  697. {
  698. if( i&3 )error[i+3]+=diff*(3.0f/16);
  699. error[i+4]+=diff*(5.0f/16);
  700. if((i&3)!=3)error[i+5]+=diff*(1.0f/16);
  701. }
  702. }
  703. }
  704. if(fMinAlpha>=1)
  705. {
  706. bc3.alpha[0]=0xff;
  707. bc3.alpha[1]=0xff;
  708. Zero(bc3.bitmap);
  709. return;
  710. }
  711. // Optimize and Quantize Min and Max values
  712. Int uSteps=((fMinAlpha==0) || (fMaxAlpha==1)) ? 6 : 8;
  713. Flt fAlphaA, fAlphaB; OptimizeAlpha(&fAlphaA, &fAlphaB, fAlpha, uSteps);
  714. Byte bAlphaA=RoundPos(fAlphaA*255); fAlphaA=bAlphaA/255.0f;
  715. Byte bAlphaB=RoundPos(fAlphaB*255); fAlphaB=bAlphaB/255.0f;
  716. // Setup block
  717. if(uSteps==8 && bAlphaA==bAlphaB)
  718. {
  719. bc3.alpha[0]=bAlphaA;
  720. bc3.alpha[1]=bAlphaB;
  721. Zero(bc3.bitmap);
  722. return;
  723. }
  724. const Int *pSteps;
  725. Flt fStep[8];
  726. if(uSteps==6)
  727. {
  728. bc3.alpha[0]=bAlphaA;
  729. bc3.alpha[1]=bAlphaB;
  730. fStep[0]=fAlphaA;
  731. fStep[1]=fAlphaB;
  732. for(Int i=1; i<5; i++)fStep[i+1]=(fStep[0]*(5-i) + fStep[1]*i)/5;
  733. fStep[6]=0;
  734. fStep[7]=1;
  735. pSteps=pSteps6;
  736. }else
  737. {
  738. bc3.alpha[0]=bAlphaB;
  739. bc3.alpha[1]=bAlphaA;
  740. fStep[0]=fAlphaB;
  741. fStep[1]=fAlphaA;
  742. for(Int i=1; i<7; i++)fStep[i+1]=(fStep[0]*(7-i) + fStep[1]*i)/7;
  743. pSteps=pSteps8;
  744. }
  745. // Encode alpha bitmap
  746. Flt fSteps=uSteps-1, fScale=(fStep[0]!=fStep[1]) ? (fSteps/(fStep[1]-fStep[0])) : 0;
  747. if(dither_a)Zero(error);
  748. for(Int iSet=0; iSet<2; iSet++)
  749. {
  750. UInt dw=0;
  751. Int iMin=iSet*8;
  752. Int iLim=iMin+8;
  753. for(Int i=iMin; i<iLim; i++)
  754. {
  755. Flt fAlph=color[i].w;
  756. if(dither_a)fAlph+=error[i];
  757. Flt fDot=(fAlph-fStep[0])*fScale;
  758. Int iStep;
  759. if(fDot<=0 )iStep=(6==uSteps && (fAlph<= fStep[0] *0.5f)) ? 6 : 0;else
  760. if(fDot>=fSteps)iStep=(6==uSteps && (fAlph>=(fStep[1] + 1.0f)*0.5f)) ? 7 : 1;else
  761. iStep=pSteps[RoundPos(fDot)];
  762. dw=(iStep<<21)|(dw>>3);
  763. if(dither_a)
  764. {
  765. Flt diff=fAlph-fStep[iStep];
  766. if((i&3)!=3)error[i+1]+=diff*(7.0f/16);
  767. if(i<12)
  768. {
  769. if( i&3 )error[i+3]+=diff*(3.0f/16);
  770. error[i+4]+=diff*(5.0f/16);
  771. if((i&3)!=3)error[i+5]+=diff*(1.0f/16);
  772. }
  773. }
  774. }
  775. bc3.bitmap[0+iSet*3]=((Byte*)&dw)[0];
  776. bc3.bitmap[1+iSet*3]=((Byte*)&dw)[1];
  777. bc3.bitmap[2+iSet*3]=((Byte*)&dw)[2];
  778. }
  779. }
  780. /******************************************************************************/
  781. static const Vec BCWeights=ColorLumWeight*0.65f;
  782. Bool CompressBC(C Image &src, Image &dest, Bool mtrl_base_1) // no need to store this in a separate CPP file, because its code size is small
  783. {
  784. Bool ok=false;
  785. if(dest.hwType()==IMAGE_BC1 || dest.hwType()==IMAGE_BC2 || dest.hwType()==IMAGE_BC3)
  786. {
  787. #if 1
  788. if(src.lockRead())
  789. {
  790. if(dest.lock(LOCK_WRITE))
  791. {
  792. ok=true;
  793. void (*compress_block)(Byte *bc, Vec4 (&color)[16], C Vec *weight, Bool dither_rgb, Bool dither_a)=((dest.hwType()==IMAGE_BC1) ? CompressBC1 :
  794. (dest.hwType()==IMAGE_BC2) ? CompressBC2 :
  795. (dest.hwType()==IMAGE_BC3) ? CompressBC3 : null);
  796. Int x_blocks=dest.hwW()/4, // operate on HW size to process partial and Pow2Padded blocks too
  797. y_blocks=dest.hwH()/4,
  798. x_mul =((dest.hwType()==IMAGE_BC1) ? 8 : 16);
  799. Vec4 rgba[16];
  800. Vec weight(1, 1, 0.5f); // #MaterialTextureChannelOrder - NrmX, NrmY, Spec, Alpha
  801. REPD( z, dest.d())
  802. REPD(by, y_blocks)
  803. {
  804. Int py=by*4, yo[4]; REPAO(yo)=Min(py+i, src.h()-1); // use clamping to avoid black borders
  805. Byte *dest_data=dest.data() + by*dest.pitch() + z*dest.pitch2();
  806. REPD(bx, x_blocks)
  807. {
  808. Int px=bx*4, xo[4]; REPAO(xo)=Min(px+i, src.w()-1); // use clamping to avoid black borders
  809. src.gather(rgba, xo, Elms(xo), yo, Elms(yo), &z, 1);
  810. if(!mtrl_base_1)
  811. {
  812. Vec4 min, max; MinMax(rgba, 4*4, min, max);
  813. #if 1 // this gave better results
  814. weight=BCWeights + max.xyz + max.xyz-min.xyz; // max + delta = max + (max-min)
  815. #else
  816. weight=LinearToSRGB(ColorLumWeight2);
  817. #endif
  818. }
  819. compress_block(dest_data + bx*x_mul, rgba, &weight, true, true);
  820. }
  821. }
  822. dest.unlock();
  823. }
  824. src.unlock();
  825. }
  826. #elif 1 // Intel ISPC
  827. only BC1 now supported
  828. Image temp; C Image *s=&src;
  829. if(s->hwType()!=IMAGE_R8G8B8A8 || s->w()!=dest.hwW() || s->h()!=dest.hwH())
  830. {
  831. if(s->copyTry(temp, dest.hwW(), dest.hwH(), 1, IMAGE_R8G8B8A8, IMAGE_SOFT, 1, FILTER_NO_STRETCH, true))s=&temp;else return false; // we need to cover the area for entire HW size, to process partial and Pow2Padded blocks too
  832. }
  833. if(s->lockRead())
  834. {
  835. if(dest.lock(LOCK_WRITE))
  836. {
  837. ok=true;
  838. Int x_blocks=dest.hwW()/4, // operate on HW size to process partial and Pow2Padded blocks too
  839. y_blocks=dest.hwH()/4,
  840. x_mul =((dest.hwType()==IMAGE_BC1) ? 8 : 16);
  841. rgba_surface surf;
  842. surf.width =s->w ();
  843. surf.height=s->h ();
  844. surf.stride=s->pitch();
  845. REPD(z, dest.d())
  846. {
  847. surf.ptr=ConstCast(s->data()+z*s->pitch2());
  848. if(dest.pitch()==x_blocks*x_mul)CompressBlocksBC1(&surf, dest.data()+z*dest.pitch2());else
  849. {
  850. split into multiple calls here
  851. }
  852. }
  853. dest.unlock();
  854. }
  855. s->unlock();
  856. }
  857. #else
  858. if(src.d()==1) // use Driver compression if possible (faster and more accurate than Squish library)
  859. {
  860. #if DX9
  861. Image src_surf, dest_surf; if(src.copyTry (src_surf, src .w(), src .h(), src .d(), IMAGE_B8G8R8A8, IMAGE_SURF_SCRATCH)
  862. && dest_surf.createTry( dest.w(), dest.h(), dest.d(), dest.hwType() , IMAGE_SURF_SCRATCH, 1, false))
  863. {
  864. src_surf.dither(dest.hwType());
  865. SyncLockerEx locker(D._lock);
  866. if(OK(D3DXLoadSurfaceFromSurface(dest_surf._surf, null, null, src_surf._surf, null, null, D3DX_FILTER_NONE, 0)))
  867. {
  868. locker.off();
  869. if(dest.injectMipMap(dest_surf, 0))return true;
  870. }
  871. }
  872. #elif DX11
  873. Image src_txtr, dest_txtr; if(src.copyTry (src_txtr, src .w(), src .h(), src .d(), IMAGE_R8G8B8A8, IMAGE_SURF_SCRATCH)
  874. && dest_txtr.createTry( dest.w(), dest.h(), dest.d(), dest.hwType() , IMAGE_SURF_SCRATCH, 1, false))
  875. {
  876. src_txtr.dither(dest.hwType());
  877. D3DX11_TEXTURE_LOAD_INFO info;
  878. info.NumElements=1;
  879. info.NumMips =1;
  880. info.Filter =D3DX11_FILTER_NONE;
  881. SyncLockerEx locker(D._lock);
  882. if(OK(D3DX11LoadTextureFromTexture(D3DC, src_txtr._txtr, &info, dest_txtr._txtr)))
  883. {
  884. locker.off();
  885. if(dest.injectMipMap(dest_txtr, 0))return true;
  886. }
  887. }
  888. #elif GL && !GL_ES // Nvidia OpenGL driver compression is not as good as DX (ATI is unknown)
  889. C Image *s=&src;
  890. Image temp; if(s->copyTry(temp, -1, -1, -1, IMAGE_R8G8B8A8, IMAGE_SOFT, 1))s=&temp.dither(dest.hwType());
  891. Image dest_txtr; if(dest_txtr.createTry(dest.w(), dest.h(), dest.d(), dest.hwType(), IMAGE_2D, 1, false))
  892. {
  893. if(s->lockRead())
  894. {
  895. SyncLocker locker(D._lock);
  896. glGetError(); // clear any previous errors
  897. D.texBind(GL_TEXTURE_2D, dest_txtr._txtr);
  898. glTexImage2D(GL_TEXTURE_2D, 0, ImageTI[dest_txtr.hwType()].format, s->w(), s->h(), 0, SourceGLFormat(s->hwType()), SourceGLType(s->hwType()), s->data());
  899. glFlush(); // to make sure that the data was initialized, in case it'll be accessed on a secondary thread
  900. Bool ok=(glGetError()==GL_NO_ERROR);
  901. s->unlock();
  902. if(ok)if(dest.injectMipMap(dest_txtr, 0))return true;
  903. }
  904. }
  905. #endif
  906. }
  907. if(src.lockRead())
  908. {
  909. if(dest.lock(LOCK_WRITE))
  910. {
  911. ok=true;
  912. Int flags=0;
  913. if(dest.hwType()==IMAGE_BC1)flags|=squish::kDxt1;else
  914. if(dest.hwType()==IMAGE_BC2)flags|=squish::kDxt3;else
  915. if(dest.hwType()==IMAGE_BC3)flags|=squish::kDxt5;
  916. if(quality==0)flags|=squish::kColourRangeFit ;else
  917. if(quality==1)flags|=squish::kColourClusterFit ;else
  918. if(quality==2)flags|=squish::kColourIterativeClusterFit;
  919. if(perceptual)flags|=squish::kColourMetricPerceptual;
  920. else flags|=squish::kColourMetricUniform ;
  921. if(alpha_weight)flags|=squish::kWeightColourByAlpha;
  922. Int x_blocks=dest.w()/4,
  923. y_blocks=dest.h()/4,
  924. x_mul =((dest.hwType()==IMAGE_BC1) ? 8 : 16);
  925. REPD( z, dest.d())
  926. REPD(by, y_blocks)
  927. REPD(bx, x_blocks)
  928. {
  929. Int px=bx*4, py=by*4; // pixel
  930. Color rgba[4][4];
  931. REPD(y, 4)
  932. REPD(x, 4)rgba[y][x]=src.color3D(px+x, py+y, z);
  933. squish::Compress((squish::u8*)rgba, dest.data() + bx*x_mul + by*dest.pitch() + z*dest.pitch2(), flags);
  934. }
  935. dest.unlock();
  936. }
  937. src.unlock();
  938. }
  939. #endif
  940. }
  941. return ok;
  942. }
  943. /******************************************************************************/
  944. }
  945. /******************************************************************************/