BCn.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. using System;
  2. using System.Drawing;
  3. namespace Ryujinx.Graphics.Gpu
  4. {
  5. static class BCn
  6. {
  7. public static byte[] DecodeBC1(NsGpuTexture Tex, int Offset)
  8. {
  9. int W = (Tex.Width + 3) / 4;
  10. int H = (Tex.Height + 3) / 4;
  11. byte[] Output = new byte[W * H * 64];
  12. SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8);
  13. for (int Y = 0; Y < H; Y++)
  14. {
  15. for (int X = 0; X < W; X++)
  16. {
  17. int IOffs = Offset + Swizzle.GetSwizzledAddress64(X, Y) * 8;
  18. byte[] Tile = BCnDecodeTile(Tex.Data, IOffs, true);
  19. int TOffset = 0;
  20. for (int TY = 0; TY < 4; TY++)
  21. {
  22. for (int TX = 0; TX < 4; TX++)
  23. {
  24. int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
  25. Output[OOffset + 0] = Tile[TOffset + 0];
  26. Output[OOffset + 1] = Tile[TOffset + 1];
  27. Output[OOffset + 2] = Tile[TOffset + 2];
  28. Output[OOffset + 3] = Tile[TOffset + 3];
  29. TOffset += 4;
  30. }
  31. }
  32. }
  33. }
  34. return Output;
  35. }
  36. public static byte[] DecodeBC2(NsGpuTexture Tex, int Offset)
  37. {
  38. int W = (Tex.Width + 3) / 4;
  39. int H = (Tex.Height + 3) / 4;
  40. byte[] Output = new byte[W * H * 64];
  41. SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4);
  42. for (int Y = 0; Y < H; Y++)
  43. {
  44. for (int X = 0; X < W; X++)
  45. {
  46. int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16;
  47. byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false);
  48. int AlphaLow = Get32(Tex.Data, IOffs + 0);
  49. int AlphaHigh = Get32(Tex.Data, IOffs + 4);
  50. ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32;
  51. int TOffset = 0;
  52. for (int TY = 0; TY < 4; TY++)
  53. {
  54. for (int TX = 0; TX < 4; TX++)
  55. {
  56. ulong Alpha = (AlphaCh >> (TY * 16 + TX * 4)) & 0xf;
  57. int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
  58. Output[OOffset + 0] = Tile[TOffset + 0];
  59. Output[OOffset + 1] = Tile[TOffset + 1];
  60. Output[OOffset + 2] = Tile[TOffset + 2];
  61. Output[OOffset + 3] = (byte)(Alpha | (Alpha << 4));
  62. TOffset += 4;
  63. }
  64. }
  65. }
  66. }
  67. return Output;
  68. }
  69. public static byte[] DecodeBC3(NsGpuTexture Tex, int Offset)
  70. {
  71. int W = (Tex.Width + 3) / 4;
  72. int H = (Tex.Height + 3) / 4;
  73. byte[] Output = new byte[W * H * 64];
  74. SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4);
  75. for (int Y = 0; Y < H; Y++)
  76. {
  77. for (int X = 0; X < W; X++)
  78. {
  79. int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16;
  80. byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false);
  81. byte[] Alpha = new byte[8];
  82. Alpha[0] = Tex.Data[IOffs + 0];
  83. Alpha[1] = Tex.Data[IOffs + 1];
  84. CalculateBC3Alpha(Alpha);
  85. int AlphaLow = Get32(Tex.Data, IOffs + 2);
  86. int AlphaHigh = Get16(Tex.Data, IOffs + 6);
  87. ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32;
  88. int TOffset = 0;
  89. for (int TY = 0; TY < 4; TY++)
  90. {
  91. for (int TX = 0; TX < 4; TX++)
  92. {
  93. int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
  94. byte AlphaPx = Alpha[(AlphaCh >> (TY * 12 + TX * 3)) & 7];
  95. Output[OOffset + 0] = Tile[TOffset + 0];
  96. Output[OOffset + 1] = Tile[TOffset + 1];
  97. Output[OOffset + 2] = Tile[TOffset + 2];
  98. Output[OOffset + 3] = AlphaPx;
  99. TOffset += 4;
  100. }
  101. }
  102. }
  103. }
  104. return Output;
  105. }
  106. public static byte[] DecodeBC4(NsGpuTexture Tex, int Offset)
  107. {
  108. int W = (Tex.Width + 3) / 4;
  109. int H = (Tex.Height + 3) / 4;
  110. byte[] Output = new byte[W * H * 64];
  111. SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8);
  112. for (int Y = 0; Y < H; Y++)
  113. {
  114. for (int X = 0; X < W; X++)
  115. {
  116. int IOffs = Swizzle.GetSwizzledAddress64(X, Y) * 8;
  117. byte[] Red = new byte[8];
  118. Red[0] = Tex.Data[IOffs + 0];
  119. Red[1] = Tex.Data[IOffs + 1];
  120. CalculateBC3Alpha(Red);
  121. int RedLow = Get32(Tex.Data, IOffs + 2);
  122. int RedHigh = Get16(Tex.Data, IOffs + 6);
  123. ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32;
  124. int TOffset = 0;
  125. for (int TY = 0; TY < 4; TY++)
  126. {
  127. for (int TX = 0; TX < 4; TX++)
  128. {
  129. int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
  130. byte RedPx = Red[(RedCh >> (TY * 12 + TX * 3)) & 7];
  131. Output[OOffset + 0] = RedPx;
  132. Output[OOffset + 1] = RedPx;
  133. Output[OOffset + 2] = RedPx;
  134. Output[OOffset + 3] = 0xff;
  135. TOffset += 4;
  136. }
  137. }
  138. }
  139. }
  140. return Output;
  141. }
  142. public static byte[] DecodeBC5(NsGpuTexture Tex, int Offset, bool SNorm)
  143. {
  144. int W = (Tex.Width + 3) / 4;
  145. int H = (Tex.Height + 3) / 4;
  146. byte[] Output = new byte[W * H * 64];
  147. SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4);
  148. for (int Y = 0; Y < H; Y++)
  149. {
  150. for (int X = 0; X < W; X++)
  151. {
  152. int IOffs = Swizzle.GetSwizzledAddress128(X, Y) * 16;
  153. byte[] Red = new byte[8];
  154. byte[] Green = new byte[8];
  155. Red[0] = Tex.Data[IOffs + 0];
  156. Red[1] = Tex.Data[IOffs + 1];
  157. Green[0] = Tex.Data[IOffs + 8];
  158. Green[1] = Tex.Data[IOffs + 9];
  159. if (SNorm)
  160. {
  161. CalculateBC3AlphaS(Red);
  162. CalculateBC3AlphaS(Green);
  163. }
  164. else
  165. {
  166. CalculateBC3Alpha(Red);
  167. CalculateBC3Alpha(Green);
  168. }
  169. int RedLow = Get32(Tex.Data, IOffs + 2);
  170. int RedHigh = Get16(Tex.Data, IOffs + 6);
  171. int GreenLow = Get32(Tex.Data, IOffs + 10);
  172. int GreenHigh = Get16(Tex.Data, IOffs + 14);
  173. ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32;
  174. ulong GreenCh = (uint)GreenLow | (ulong)GreenHigh << 32;
  175. int TOffset = 0;
  176. if (SNorm)
  177. {
  178. for (int TY = 0; TY < 4; TY++)
  179. {
  180. for (int TX = 0; TX < 4; TX++)
  181. {
  182. int Shift = TY * 12 + TX * 3;
  183. int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
  184. byte RedPx = Red [(RedCh >> Shift) & 7];
  185. byte GreenPx = Green[(GreenCh >> Shift) & 7];
  186. RedPx += 0x80;
  187. GreenPx += 0x80;
  188. float NX = (RedPx / 255f) * 2 - 1;
  189. float NY = (GreenPx / 255f) * 2 - 1;
  190. float NZ = (float)Math.Sqrt(1 - (NX * NX + NY * NY));
  191. Output[OOffset + 0] = Clamp((NZ + 1) * 0.5f);
  192. Output[OOffset + 1] = Clamp((NY + 1) * 0.5f);
  193. Output[OOffset + 2] = Clamp((NX + 1) * 0.5f);
  194. Output[OOffset + 3] = 0xff;
  195. TOffset += 4;
  196. }
  197. }
  198. }
  199. else
  200. {
  201. for (int TY = 0; TY < 4; TY++)
  202. {
  203. for (int TX = 0; TX < 4; TX++)
  204. {
  205. int Shift = TY * 12 + TX * 3;
  206. int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4;
  207. byte RedPx = Red [(RedCh >> Shift) & 7];
  208. byte GreenPx = Green[(GreenCh >> Shift) & 7];
  209. Output[OOffset + 0] = RedPx;
  210. Output[OOffset + 1] = RedPx;
  211. Output[OOffset + 2] = RedPx;
  212. Output[OOffset + 3] = GreenPx;
  213. TOffset += 4;
  214. }
  215. }
  216. }
  217. }
  218. }
  219. return Output;
  220. }
  221. private static byte Clamp(float Value)
  222. {
  223. if (Value > 1)
  224. {
  225. return 0xff;
  226. }
  227. else if (Value < 0)
  228. {
  229. return 0;
  230. }
  231. else
  232. {
  233. return (byte)(Value * 0xff);
  234. }
  235. }
  236. private static void CalculateBC3Alpha(byte[] Alpha)
  237. {
  238. for (int i = 2; i < 8; i++)
  239. {
  240. if (Alpha[0] > Alpha[1])
  241. {
  242. Alpha[i] = (byte)(((8 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7);
  243. }
  244. else if (i < 6)
  245. {
  246. Alpha[i] = (byte)(((6 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7);
  247. }
  248. else if (i == 6)
  249. {
  250. Alpha[i] = 0;
  251. }
  252. else /* i == 7 */
  253. {
  254. Alpha[i] = 0xff;
  255. }
  256. }
  257. }
  258. private static void CalculateBC3AlphaS(byte[] Alpha)
  259. {
  260. for (int i = 2; i < 8; i++)
  261. {
  262. if ((sbyte)Alpha[0] > (sbyte)Alpha[1])
  263. {
  264. Alpha[i] = (byte)(((8 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7);
  265. }
  266. else if (i < 6)
  267. {
  268. Alpha[i] = (byte)(((6 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7);
  269. }
  270. else if (i == 6)
  271. {
  272. Alpha[i] = 0x80;
  273. }
  274. else /* i == 7 */
  275. {
  276. Alpha[i] = 0x7f;
  277. }
  278. }
  279. }
  280. private static byte[] BCnDecodeTile(
  281. byte[] Input,
  282. int Offset,
  283. bool IsBC1)
  284. {
  285. Color[] CLUT = new Color[4];
  286. int c0 = Get16(Input, Offset + 0);
  287. int c1 = Get16(Input, Offset + 2);
  288. CLUT[0] = DecodeRGB565(c0);
  289. CLUT[1] = DecodeRGB565(c1);
  290. CLUT[2] = CalculateCLUT2(CLUT[0], CLUT[1], c0, c1, IsBC1);
  291. CLUT[3] = CalculateCLUT3(CLUT[0], CLUT[1], c0, c1, IsBC1);
  292. int Indices = Get32(Input, Offset + 4);
  293. int IdxShift = 0;
  294. byte[] Output = new byte[4 * 4 * 4];
  295. int OOffset = 0;
  296. for (int TY = 0; TY < 4; TY++)
  297. {
  298. for (int TX = 0; TX < 4; TX++)
  299. {
  300. int Idx = (Indices >> IdxShift) & 3;
  301. IdxShift += 2;
  302. Color Pixel = CLUT[Idx];
  303. Output[OOffset + 0] = Pixel.R;
  304. Output[OOffset + 1] = Pixel.G;
  305. Output[OOffset + 2] = Pixel.B;
  306. Output[OOffset + 3] = Pixel.A;
  307. OOffset += 4;
  308. }
  309. }
  310. return Output;
  311. }
  312. private static Color CalculateCLUT2(Color C0, Color C1, int c0, int c1, bool IsBC1)
  313. {
  314. if (c0 > c1 || !IsBC1)
  315. {
  316. return Color.FromArgb(
  317. (2 * C0.R + C1.R) / 3,
  318. (2 * C0.G + C1.G) / 3,
  319. (2 * C0.B + C1.B) / 3);
  320. }
  321. else
  322. {
  323. return Color.FromArgb(
  324. (C0.R + C1.R) / 2,
  325. (C0.G + C1.G) / 2,
  326. (C0.B + C1.B) / 2);
  327. }
  328. }
  329. private static Color CalculateCLUT3(Color C0, Color C1, int c0, int c1, bool IsBC1)
  330. {
  331. if (c0 > c1 || !IsBC1)
  332. {
  333. return
  334. Color.FromArgb(
  335. (2 * C1.R + C0.R) / 3,
  336. (2 * C1.G + C0.G) / 3,
  337. (2 * C1.B + C0.B) / 3);
  338. }
  339. return Color.Transparent;
  340. }
  341. private static Color DecodeRGB565(int Value)
  342. {
  343. int B = ((Value >> 0) & 0x1f) << 3;
  344. int G = ((Value >> 5) & 0x3f) << 2;
  345. int R = ((Value >> 11) & 0x1f) << 3;
  346. return Color.FromArgb(
  347. R | (R >> 5),
  348. G | (G >> 6),
  349. B | (B >> 5));
  350. }
  351. private static int Get16(byte[] Data, int Address)
  352. {
  353. return
  354. Data[Address + 0] << 0 |
  355. Data[Address + 1] << 8;
  356. }
  357. private static int Get32(byte[] Data, int Address)
  358. {
  359. return
  360. Data[Address + 0] << 0 |
  361. Data[Address + 1] << 8 |
  362. Data[Address + 2] << 16 |
  363. Data[Address + 3] << 24;
  364. }
  365. }
  366. }