/ src / Ryujinx.Graphics.Texture / BC6Decoder.cs
BC6Decoder.cs
  1  using Ryujinx.Graphics.Texture.Utils;
  2  using System;
  3  using System.Runtime.InteropServices;
  4  
  5  namespace Ryujinx.Graphics.Texture
  6  {
  7      static class BC6Decoder
  8      {
  9          private const int HalfOne = 0x3C00;
 10  
 11          public static void Decode(Span<byte> output, ReadOnlySpan<byte> data, int width, int height, bool signed)
 12          {
 13              ReadOnlySpan<Block> blocks = MemoryMarshal.Cast<byte, Block>(data);
 14  
 15              Span<ulong> output64 = MemoryMarshal.Cast<byte, ulong>(output);
 16  
 17              int wInBlocks = (width + 3) / 4;
 18              int hInBlocks = (height + 3) / 4;
 19  
 20              for (int y = 0; y < hInBlocks; y++)
 21              {
 22                  int y2 = y * 4;
 23                  int bh = Math.Min(4, height - y2);
 24  
 25                  for (int x = 0; x < wInBlocks; x++)
 26                  {
 27                      int x2 = x * 4;
 28                      int bw = Math.Min(4, width - x2);
 29  
 30                      DecodeBlock(blocks[y * wInBlocks + x], output64[(y2 * width + x2)..], bw, bh, width, signed);
 31                  }
 32              }
 33          }
 34  
 35          private static void DecodeBlock(Block block, Span<ulong> output, int w, int h, int width, bool signed)
 36          {
 37              int mode = (int)(block.Low & 3);
 38              if ((mode & 2) != 0)
 39              {
 40                  mode = (int)(block.Low & 0x1f);
 41              }
 42  
 43              Span<RgbaColor32> endPoints = stackalloc RgbaColor32[4];
 44              int subsetCount = DecodeEndPoints(ref block, endPoints, mode, signed);
 45              if (subsetCount == 0)
 46              {
 47                  // Mode is invalid, the spec mandates that hardware fills the block with
 48                  // a opaque black color.
 49                  for (int ty = 0; ty < h; ty++)
 50                  {
 51                      int baseOffs = ty * width;
 52  
 53                      for (int tx = 0; tx < w; tx++)
 54                      {
 55                          output[baseOffs + tx] = (ulong)HalfOne << 48;
 56                      }
 57                  }
 58  
 59                  return;
 60              }
 61  
 62              int partition;
 63              int indexBitCount;
 64              ulong indices;
 65  
 66              if (subsetCount > 1)
 67              {
 68                  partition = (int)((block.High >> 13) & 0x1F);
 69                  indexBitCount = 3;
 70  
 71                  int fixUpIndex = BC67Tables.FixUpIndices[subsetCount - 1][partition][1] * 3;
 72                  ulong lowMask = (ulong.MaxValue >> (65 - fixUpIndex)) << 3;
 73                  ulong highMask = ulong.MaxValue << (fixUpIndex + 3);
 74  
 75                  indices = ((block.High >> 16) & highMask) | ((block.High >> 17) & lowMask) | ((block.High >> 18) & 3);
 76              }
 77              else
 78              {
 79                  partition = 0;
 80                  indexBitCount = 4;
 81                  indices = (block.High & ~0xFUL) | ((block.High >> 1) & 7);
 82              }
 83  
 84              ulong indexMask = (1UL << indexBitCount) - 1;
 85  
 86              for (int ty = 0; ty < h; ty++)
 87              {
 88                  int baseOffs = ty * width;
 89  
 90                  for (int tx = 0; tx < w; tx++)
 91                  {
 92                      int offs = baseOffs + tx;
 93                      int index = (int)(indices & indexMask);
 94                      int endPointBase = BC67Tables.PartitionTable[subsetCount - 1][partition][ty * 4 + tx] << 1;
 95  
 96                      RgbaColor32 color1 = endPoints[endPointBase];
 97                      RgbaColor32 color2 = endPoints[endPointBase + 1];
 98  
 99                      RgbaColor32 color = BC67Utils.Interpolate(color1, color2, index, indexBitCount);
100  
101                      output[offs] =
102                          (ulong)FinishUnquantize(color.R, signed) |
103                          ((ulong)FinishUnquantize(color.G, signed) << 16) |
104                          ((ulong)FinishUnquantize(color.B, signed) << 32) |
105                          ((ulong)HalfOne << 48);
106  
107                      indices >>= indexBitCount;
108                  }
109              }
110          }
111  
112          private static int DecodeEndPoints(ref Block block, Span<RgbaColor32> endPoints, int mode, bool signed)
113          {
114              ulong low = block.Low;
115              ulong high = block.High;
116  
117              int r0 = 0, g0 = 0, b0 = 0, r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0, r3 = 0, g3 = 0, b3 = 0;
118              int subsetCount;
119  
120              switch (mode)
121              {
122                  case 0:
123                      r0 = (int)(low >> 5) & 0x3FF;
124                      g0 = (int)(low >> 15) & 0x3FF;
125                      b0 = (int)(low >> 25) & 0x3FF;
126  
127                      if (signed)
128                      {
129                          r0 = SignExtend(r0, 10);
130                          g0 = SignExtend(g0, 10);
131                          b0 = SignExtend(b0, 10);
132                      }
133  
134                      r1 = r0 + SignExtend((int)(low >> 35), 5);
135                      g1 = g0 + SignExtend((int)(low >> 45), 5);
136                      b1 = b0 + SignExtend((int)(low >> 55), 5);
137  
138                      r2 = r0 + SignExtend((int)(high >> 1), 5);
139                      g2 = g0 + SignExtend((int)(((low << 2) & 0x10) | ((low >> 41) & 0xF)), 5);
140                      b2 = b0 + SignExtend((int)(((low << 1) & 0x10) | ((high << 3) & 0x08) | (low >> 61)), 5);
141  
142                      r3 = r0 + SignExtend((int)(high >> 7), 5);
143                      g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
144                      b3 = b0 + SignExtend((int)(
145                          ((low) & 0x10) |
146                          ((high >> 9) & 0x08) |
147                          ((high >> 4) & 0x04) |
148                          ((low >> 59) & 0x02) |
149                          ((low >> 50) & 0x01)), 5);
150  
151                      r0 = Unquantize(r0, 10, signed);
152                      g0 = Unquantize(g0, 10, signed);
153                      b0 = Unquantize(b0, 10, signed);
154  
155                      r1 = Unquantize(r1 & 0x3FF, 10, signed);
156                      g1 = Unquantize(g1 & 0x3FF, 10, signed);
157                      b1 = Unquantize(b1 & 0x3FF, 10, signed);
158  
159                      r2 = Unquantize(r2 & 0x3FF, 10, signed);
160                      g2 = Unquantize(g2 & 0x3FF, 10, signed);
161                      b2 = Unquantize(b2 & 0x3FF, 10, signed);
162  
163                      r3 = Unquantize(r3 & 0x3FF, 10, signed);
164                      g3 = Unquantize(g3 & 0x3FF, 10, signed);
165                      b3 = Unquantize(b3 & 0x3FF, 10, signed);
166  
167                      subsetCount = 2;
168                      break;
169                  case 1:
170                      r0 = (int)(low >> 5) & 0x7F;
171                      g0 = (int)(low >> 15) & 0x7F;
172                      b0 = (int)(low >> 25) & 0x7F;
173  
174                      if (signed)
175                      {
176                          r0 = SignExtend(r0, 7);
177                          g0 = SignExtend(g0, 7);
178                          b0 = SignExtend(b0, 7);
179                      }
180  
181                      r1 = r0 + SignExtend((int)(low >> 35), 6);
182                      g1 = g0 + SignExtend((int)(low >> 45), 6);
183                      b1 = b0 + SignExtend((int)(low >> 55), 6);
184  
185                      r2 = r0 + SignExtend((int)(high >> 1), 6);
186                      g2 = g0 + SignExtend((int)(((low << 3) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0x0F)), 6);
187                      b2 = b0 + SignExtend((int)(
188                          ((low >> 17) & 0x20) |
189                          ((low >> 10) & 0x10) |
190                          ((high << 3) & 0x08) |
191                          (low >> 61)), 6);
192  
193                      r3 = r0 + SignExtend((int)(high >> 7), 6);
194                      g3 = g0 + SignExtend((int)(((low << 1) & 0x30) | ((low >> 51) & 0xF)), 6);
195                      b3 = b0 + SignExtend((int)(
196                          ((low >> 28) & 0x20) |
197                          ((low >> 30) & 0x10) |
198                          ((low >> 29) & 0x08) |
199                          ((low >> 21) & 0x04) |
200                          ((low >> 12) & 0x03)), 6);
201  
202                      r0 = Unquantize(r0, 7, signed);
203                      g0 = Unquantize(g0, 7, signed);
204                      b0 = Unquantize(b0, 7, signed);
205  
206                      r1 = Unquantize(r1 & 0x7F, 7, signed);
207                      g1 = Unquantize(g1 & 0x7F, 7, signed);
208                      b1 = Unquantize(b1 & 0x7F, 7, signed);
209  
210                      r2 = Unquantize(r2 & 0x7F, 7, signed);
211                      g2 = Unquantize(g2 & 0x7F, 7, signed);
212                      b2 = Unquantize(b2 & 0x7F, 7, signed);
213  
214                      r3 = Unquantize(r3 & 0x7F, 7, signed);
215                      g3 = Unquantize(g3 & 0x7F, 7, signed);
216                      b3 = Unquantize(b3 & 0x7F, 7, signed);
217  
218                      subsetCount = 2;
219                      break;
220                  case 2:
221                      r0 = (int)(((low >> 30) & 0x400) | ((low >> 5) & 0x3FF));
222                      g0 = (int)(((low >> 39) & 0x400) | ((low >> 15) & 0x3FF));
223                      b0 = (int)(((low >> 49) & 0x400) | ((low >> 25) & 0x3FF));
224  
225                      if (signed)
226                      {
227                          r0 = SignExtend(r0, 11);
228                          g0 = SignExtend(g0, 11);
229                          b0 = SignExtend(b0, 11);
230                      }
231  
232                      r1 = r0 + SignExtend((int)(low >> 35), 5);
233                      g1 = g0 + SignExtend((int)(low >> 45), 4);
234                      b1 = b0 + SignExtend((int)(low >> 55), 4);
235  
236                      r2 = r0 + SignExtend((int)(high >> 1), 5);
237                      g2 = g0 + SignExtend((int)(low >> 41), 4);
238                      b2 = b0 + SignExtend((int)(((high << 3) & 8) | (low >> 61)), 4);
239  
240                      r3 = r0 + SignExtend((int)(high >> 7), 5);
241                      g3 = g0 + SignExtend((int)(low >> 51), 4);
242                      b3 = b0 + SignExtend((int)(
243                          ((high >> 9) & 8) |
244                          ((high >> 4) & 4) |
245                          ((low >> 59) & 2) |
246                          ((low >> 50) & 1)), 4);
247  
248                      r0 = Unquantize(r0, 11, signed);
249                      g0 = Unquantize(g0, 11, signed);
250                      b0 = Unquantize(b0, 11, signed);
251  
252                      r1 = Unquantize(r1 & 0x7FF, 11, signed);
253                      g1 = Unquantize(g1 & 0x7FF, 11, signed);
254                      b1 = Unquantize(b1 & 0x7FF, 11, signed);
255  
256                      r2 = Unquantize(r2 & 0x7FF, 11, signed);
257                      g2 = Unquantize(g2 & 0x7FF, 11, signed);
258                      b2 = Unquantize(b2 & 0x7FF, 11, signed);
259  
260                      r3 = Unquantize(r3 & 0x7FF, 11, signed);
261                      g3 = Unquantize(g3 & 0x7FF, 11, signed);
262                      b3 = Unquantize(b3 & 0x7FF, 11, signed);
263  
264                      subsetCount = 2;
265                      break;
266                  case 3:
267                      r0 = (int)(low >> 5) & 0x3FF;
268                      g0 = (int)(low >> 15) & 0x3FF;
269                      b0 = (int)(low >> 25) & 0x3FF;
270  
271                      r1 = (int)(low >> 35) & 0x3FF;
272                      g1 = (int)(low >> 45) & 0x3FF;
273                      b1 = (int)(((high << 9) & 0x200) | (low >> 55));
274  
275                      if (signed)
276                      {
277                          r0 = SignExtend(r0, 10);
278                          g0 = SignExtend(g0, 10);
279                          b0 = SignExtend(b0, 10);
280  
281                          r1 = SignExtend(r1, 10);
282                          g1 = SignExtend(g1, 10);
283                          b1 = SignExtend(b1, 10);
284                      }
285  
286                      r0 = Unquantize(r0, 10, signed);
287                      g0 = Unquantize(g0, 10, signed);
288                      b0 = Unquantize(b0, 10, signed);
289  
290                      r1 = Unquantize(r1, 10, signed);
291                      g1 = Unquantize(g1, 10, signed);
292                      b1 = Unquantize(b1, 10, signed);
293  
294                      subsetCount = 1;
295                      break;
296                  case 6:
297                      r0 = (int)(((low >> 29) & 0x400) | ((low >> 5) & 0x3FF));
298                      g0 = (int)(((low >> 40) & 0x400) | ((low >> 15) & 0x3FF));
299                      b0 = (int)(((low >> 49) & 0x400) | ((low >> 25) & 0x3FF));
300  
301                      if (signed)
302                      {
303                          r0 = SignExtend(r0, 11);
304                          g0 = SignExtend(g0, 11);
305                          b0 = SignExtend(b0, 11);
306                      }
307  
308                      r1 = r0 + SignExtend((int)(low >> 35), 4);
309                      g1 = g0 + SignExtend((int)(low >> 45), 5);
310                      b1 = b0 + SignExtend((int)(low >> 55), 4);
311  
312                      r2 = r0 + SignExtend((int)(high >> 1), 4);
313                      g2 = g0 + SignExtend((int)(((high >> 7) & 0x10) | ((low >> 41) & 0x0F)), 5);
314                      b2 = b0 + SignExtend((int)(((high << 3) & 0x08) | ((low >> 61))), 4);
315  
316                      r3 = r0 + SignExtend((int)(high >> 7), 4);
317                      g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0x0F)), 5);
318                      b3 = b0 + SignExtend((int)(
319                          ((high >> 9) & 8) |
320                          ((high >> 4) & 4) |
321                          ((low >> 59) & 2) |
322                          ((high >> 5) & 1)), 4);
323  
324                      r0 = Unquantize(r0, 11, signed);
325                      g0 = Unquantize(g0, 11, signed);
326                      b0 = Unquantize(b0, 11, signed);
327  
328                      r1 = Unquantize(r1 & 0x7FF, 11, signed);
329                      g1 = Unquantize(g1 & 0x7FF, 11, signed);
330                      b1 = Unquantize(b1 & 0x7FF, 11, signed);
331  
332                      r2 = Unquantize(r2 & 0x7FF, 11, signed);
333                      g2 = Unquantize(g2 & 0x7FF, 11, signed);
334                      b2 = Unquantize(b2 & 0x7FF, 11, signed);
335  
336                      r3 = Unquantize(r3 & 0x7FF, 11, signed);
337                      g3 = Unquantize(g3 & 0x7FF, 11, signed);
338                      b3 = Unquantize(b3 & 0x7FF, 11, signed);
339  
340                      subsetCount = 2;
341                      break;
342                  case 7:
343                      r0 = (int)(((low >> 34) & 0x400) | ((low >> 5) & 0x3FF));
344                      g0 = (int)(((low >> 44) & 0x400) | ((low >> 15) & 0x3FF));
345                      b0 = (int)(((high << 10) & 0x400) | ((low >> 25) & 0x3FF));
346  
347                      if (signed)
348                      {
349                          r0 = SignExtend(r0, 11);
350                          g0 = SignExtend(g0, 11);
351                          b0 = SignExtend(b0, 11);
352                      }
353  
354                      r1 = (r0 + SignExtend((int)(low >> 35), 9)) & 0x7FF;
355                      g1 = (g0 + SignExtend((int)(low >> 45), 9)) & 0x7FF;
356                      b1 = (b0 + SignExtend((int)(low >> 55), 9)) & 0x7FF;
357  
358                      r0 = Unquantize(r0, 11, signed);
359                      g0 = Unquantize(g0, 11, signed);
360                      b0 = Unquantize(b0, 11, signed);
361  
362                      r1 = Unquantize(r1, 11, signed);
363                      g1 = Unquantize(g1, 11, signed);
364                      b1 = Unquantize(b1, 11, signed);
365  
366                      subsetCount = 1;
367                      break;
368                  case 10:
369                      r0 = (int)(((low >> 29) & 0x400) | ((low >> 5) & 0x3FF));
370                      g0 = (int)(((low >> 39) & 0x400) | ((low >> 15) & 0x3FF));
371                      b0 = (int)(((low >> 50) & 0x400) | ((low >> 25) & 0x3FF));
372  
373                      if (signed)
374                      {
375                          r0 = SignExtend(r0, 11);
376                          g0 = SignExtend(g0, 11);
377                          b0 = SignExtend(b0, 11);
378                      }
379  
380                      r1 = r0 + SignExtend((int)(low >> 35), 4);
381                      g1 = g0 + SignExtend((int)(low >> 45), 4);
382                      b1 = b0 + SignExtend((int)(low >> 55), 5);
383  
384                      r2 = r0 + SignExtend((int)(high >> 1), 4);
385                      g2 = g0 + SignExtend((int)(low >> 41), 4);
386                      b2 = b0 + SignExtend((int)(((low >> 36) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);
387  
388                      r3 = r0 + SignExtend((int)(high >> 7), 4);
389                      g3 = g0 + SignExtend((int)(low >> 51), 4);
390                      b3 = b0 + SignExtend((int)(
391                          ((high >> 7) & 0x10) |
392                          ((high >> 9) & 0x08) |
393                          ((high >> 4) & 0x06) |
394                          ((low >> 50) & 0x01)), 5);
395  
396                      r0 = Unquantize(r0, 11, signed);
397                      g0 = Unquantize(g0, 11, signed);
398                      b0 = Unquantize(b0, 11, signed);
399  
400                      r1 = Unquantize(r1 & 0x7FF, 11, signed);
401                      g1 = Unquantize(g1 & 0x7FF, 11, signed);
402                      b1 = Unquantize(b1 & 0x7FF, 11, signed);
403  
404                      r2 = Unquantize(r2 & 0x7FF, 11, signed);
405                      g2 = Unquantize(g2 & 0x7FF, 11, signed);
406                      b2 = Unquantize(b2 & 0x7FF, 11, signed);
407  
408                      r3 = Unquantize(r3 & 0x7FF, 11, signed);
409                      g3 = Unquantize(g3 & 0x7FF, 11, signed);
410                      b3 = Unquantize(b3 & 0x7FF, 11, signed);
411  
412                      subsetCount = 2;
413                      break;
414                  case 11:
415                      r0 = (int)(((low >> 32) & 0x800) | ((low >> 34) & 0x400) | ((low >> 5) & 0x3FF));
416                      g0 = (int)(((low >> 42) & 0x800) | ((low >> 44) & 0x400) | ((low >> 15) & 0x3FF));
417                      b0 = (int)(((low >> 52) & 0x800) | ((high << 10) & 0x400) | ((low >> 25) & 0x3FF));
418  
419                      if (signed)
420                      {
421                          r0 = SignExtend(r0, 12);
422                          g0 = SignExtend(g0, 12);
423                          b0 = SignExtend(b0, 12);
424                      }
425  
426                      r1 = (r0 + SignExtend((int)(low >> 35), 8)) & 0xFFF;
427                      g1 = (g0 + SignExtend((int)(low >> 45), 8)) & 0xFFF;
428                      b1 = (b0 + SignExtend((int)(low >> 55), 8)) & 0xFFF;
429  
430                      r0 = Unquantize(r0, 12, signed);
431                      g0 = Unquantize(g0, 12, signed);
432                      b0 = Unquantize(b0, 12, signed);
433  
434                      r1 = Unquantize(r1, 12, signed);
435                      g1 = Unquantize(g1, 12, signed);
436                      b1 = Unquantize(b1, 12, signed);
437  
438                      subsetCount = 1;
439                      break;
440                  case 14:
441                      r0 = (int)(low >> 5) & 0x1FF;
442                      g0 = (int)(low >> 15) & 0x1FF;
443                      b0 = (int)(low >> 25) & 0x1FF;
444  
445                      if (signed)
446                      {
447                          r0 = SignExtend(r0, 9);
448                          g0 = SignExtend(g0, 9);
449                          b0 = SignExtend(b0, 9);
450                      }
451  
452                      r1 = r0 + SignExtend((int)(low >> 35), 5);
453                      g1 = g0 + SignExtend((int)(low >> 45), 5);
454                      b1 = b0 + SignExtend((int)(low >> 55), 5);
455  
456                      r2 = r0 + SignExtend((int)(high >> 1), 5);
457                      g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
458                      b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);
459  
460                      r3 = r0 + SignExtend((int)(high >> 7), 5);
461                      g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
462                      b3 = b0 + SignExtend((int)(
463                          ((low >> 30) & 0x10) |
464                          ((high >> 9) & 0x08) |
465                          ((high >> 4) & 0x04) |
466                          ((low >> 59) & 0x02) |
467                          ((low >> 50) & 0x01)), 5);
468  
469                      r0 = Unquantize(r0, 9, signed);
470                      g0 = Unquantize(g0, 9, signed);
471                      b0 = Unquantize(b0, 9, signed);
472  
473                      r1 = Unquantize(r1 & 0x1FF, 9, signed);
474                      g1 = Unquantize(g1 & 0x1FF, 9, signed);
475                      b1 = Unquantize(b1 & 0x1FF, 9, signed);
476  
477                      r2 = Unquantize(r2 & 0x1FF, 9, signed);
478                      g2 = Unquantize(g2 & 0x1FF, 9, signed);
479                      b2 = Unquantize(b2 & 0x1FF, 9, signed);
480  
481                      r3 = Unquantize(r3 & 0x1FF, 9, signed);
482                      g3 = Unquantize(g3 & 0x1FF, 9, signed);
483                      b3 = Unquantize(b3 & 0x1FF, 9, signed);
484  
485                      subsetCount = 2;
486                      break;
487                  case 15:
488                      r0 = (BitReverse6((int)(low >> 39) & 0x3F) << 10) | ((int)(low >> 5) & 0x3FF);
489                      g0 = (BitReverse6((int)(low >> 49) & 0x3F) << 10) | ((int)(low >> 15) & 0x3FF);
490                      b0 = ((BitReverse6((int)(low >> 59)) | (int)(high & 1)) << 10) | ((int)(low >> 25) & 0x3FF);
491  
492                      if (signed)
493                      {
494                          r0 = SignExtend(r0, 16);
495                          g0 = SignExtend(g0, 16);
496                          b0 = SignExtend(b0, 16);
497                      }
498  
499                      r1 = (r0 + SignExtend((int)(low >> 35), 4)) & 0xFFFF;
500                      g1 = (g0 + SignExtend((int)(low >> 45), 4)) & 0xFFFF;
501                      b1 = (b0 + SignExtend((int)(low >> 55), 4)) & 0xFFFF;
502  
503                      subsetCount = 1;
504                      break;
505                  case 18:
506                      r0 = (int)(low >> 5) & 0xFF;
507                      g0 = (int)(low >> 15) & 0xFF;
508                      b0 = (int)(low >> 25) & 0xFF;
509  
510                      if (signed)
511                      {
512                          r0 = SignExtend(r0, 8);
513                          g0 = SignExtend(g0, 8);
514                          b0 = SignExtend(b0, 8);
515                      }
516  
517                      r1 = r0 + SignExtend((int)(low >> 35), 6);
518                      g1 = g0 + SignExtend((int)(low >> 45), 5);
519                      b1 = b0 + SignExtend((int)(low >> 55), 5);
520  
521                      r2 = r0 + SignExtend((int)(high >> 1), 6);
522                      g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
523                      b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);
524  
525                      r3 = r0 + SignExtend((int)(high >> 7), 6);
526                      g3 = g0 + SignExtend((int)(((low >> 9) & 0x10) | ((low >> 51) & 0xF)), 5);
527                      b3 = b0 + SignExtend((int)(
528                          ((low >> 30) & 0x18) |
529                          ((low >> 21) & 0x04) |
530                          ((low >> 59) & 0x02) |
531                          ((low >> 50) & 0x01)), 5);
532  
533                      r0 = Unquantize(r0, 8, signed);
534                      g0 = Unquantize(g0, 8, signed);
535                      b0 = Unquantize(b0, 8, signed);
536  
537                      r1 = Unquantize(r1 & 0xFF, 8, signed);
538                      g1 = Unquantize(g1 & 0xFF, 8, signed);
539                      b1 = Unquantize(b1 & 0xFF, 8, signed);
540  
541                      r2 = Unquantize(r2 & 0xFF, 8, signed);
542                      g2 = Unquantize(g2 & 0xFF, 8, signed);
543                      b2 = Unquantize(b2 & 0xFF, 8, signed);
544  
545                      r3 = Unquantize(r3 & 0xFF, 8, signed);
546                      g3 = Unquantize(g3 & 0xFF, 8, signed);
547                      b3 = Unquantize(b3 & 0xFF, 8, signed);
548  
549                      subsetCount = 2;
550                      break;
551                  case 22:
552                      r0 = (int)(low >> 5) & 0xFF;
553                      g0 = (int)(low >> 15) & 0xFF;
554                      b0 = (int)(low >> 25) & 0xFF;
555  
556                      if (signed)
557                      {
558                          r0 = SignExtend(r0, 8);
559                          g0 = SignExtend(g0, 8);
560                          b0 = SignExtend(b0, 8);
561                      }
562  
563                      r1 = r0 + SignExtend((int)(low >> 35), 5);
564                      g1 = g0 + SignExtend((int)(low >> 45), 6);
565                      b1 = b0 + SignExtend((int)(low >> 55), 5);
566  
567                      r2 = r0 + SignExtend((int)(high >> 1), 5);
568                      g2 = g0 + SignExtend((int)(((low >> 18) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 6);
569                      b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 0x08) | (low >> 61)), 5);
570  
571                      r3 = r0 + SignExtend((int)(high >> 7), 5);
572                      g3 = g0 + SignExtend((int)(((low >> 28) & 0x20) | ((low >> 36) & 0x10) | ((low >> 51) & 0x0F)), 6);
573                      b3 = b0 + SignExtend((int)(
574                          ((low >> 30) & 0x10) |
575                          ((high >> 9) & 0x08) |
576                          ((high >> 4) & 0x04) |
577                          ((low >> 59) & 0x02) |
578                          ((low >> 13) & 0x01)), 5);
579  
580                      r0 = Unquantize(r0, 8, signed);
581                      g0 = Unquantize(g0, 8, signed);
582                      b0 = Unquantize(b0, 8, signed);
583  
584                      r1 = Unquantize(r1 & 0xFF, 8, signed);
585                      g1 = Unquantize(g1 & 0xFF, 8, signed);
586                      b1 = Unquantize(b1 & 0xFF, 8, signed);
587  
588                      r2 = Unquantize(r2 & 0xFF, 8, signed);
589                      g2 = Unquantize(g2 & 0xFF, 8, signed);
590                      b2 = Unquantize(b2 & 0xFF, 8, signed);
591  
592                      r3 = Unquantize(r3 & 0xFF, 8, signed);
593                      g3 = Unquantize(g3 & 0xFF, 8, signed);
594                      b3 = Unquantize(b3 & 0xFF, 8, signed);
595  
596                      subsetCount = 2;
597                      break;
598                  case 26:
599                      r0 = (int)(low >> 5) & 0xFF;
600                      g0 = (int)(low >> 15) & 0xFF;
601                      b0 = (int)(low >> 25) & 0xFF;
602  
603                      if (signed)
604                      {
605                          r0 = SignExtend(r0, 8);
606                          g0 = SignExtend(g0, 8);
607                          b0 = SignExtend(b0, 8);
608                      }
609  
610                      r1 = r0 + SignExtend((int)(low >> 35), 5);
611                      g1 = g0 + SignExtend((int)(low >> 45), 5);
612                      b1 = b0 + SignExtend((int)(low >> 55), 6);
613  
614                      r2 = r0 + SignExtend((int)(high >> 1), 5);
615                      g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
616                      b2 = b0 + SignExtend((int)(
617                          ((low >> 18) & 0x20) |
618                          ((low >> 10) & 0x10) |
619                          ((high << 3) & 0x08) |
620                          (low >> 61)), 6);
621  
622                      r3 = r0 + SignExtend((int)(high >> 7), 5);
623                      g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
624                      b3 = b0 + SignExtend((int)(
625                          ((low >> 28) & 0x20) |
626                          ((low >> 30) & 0x10) |
627                          ((high >> 9) & 0x08) |
628                          ((high >> 4) & 0x04) |
629                          ((low >> 12) & 0x02) |
630                          ((low >> 50) & 0x01)), 6);
631  
632                      r0 = Unquantize(r0, 8, signed);
633                      g0 = Unquantize(g0, 8, signed);
634                      b0 = Unquantize(b0, 8, signed);
635  
636                      r1 = Unquantize(r1 & 0xFF, 8, signed);
637                      g1 = Unquantize(g1 & 0xFF, 8, signed);
638                      b1 = Unquantize(b1 & 0xFF, 8, signed);
639  
640                      r2 = Unquantize(r2 & 0xFF, 8, signed);
641                      g2 = Unquantize(g2 & 0xFF, 8, signed);
642                      b2 = Unquantize(b2 & 0xFF, 8, signed);
643  
644                      r3 = Unquantize(r3 & 0xFF, 8, signed);
645                      g3 = Unquantize(g3 & 0xFF, 8, signed);
646                      b3 = Unquantize(b3 & 0xFF, 8, signed);
647  
648                      subsetCount = 2;
649                      break;
650                  case 30:
651                      r0 = (int)(low >> 5) & 0x3F;
652                      g0 = (int)(low >> 15) & 0x3F;
653                      b0 = (int)(low >> 25) & 0x3F;
654  
655                      r1 = (int)(low >> 35) & 0x3F;
656                      g1 = (int)(low >> 45) & 0x3F;
657                      b1 = (int)(low >> 55) & 0x3F;
658  
659                      r2 = (int)(high >> 1) & 0x3F;
660                      g2 = (int)(((low >> 16) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0xF));
661                      b2 = (int)(((low >> 17) & 0x20) | ((low >> 10) & 0x10) | ((high << 3) & 0x08) | (low >> 61));
662  
663                      r3 = (int)(high >> 7) & 0x3F;
664                      g3 = (int)(((low >> 26) & 0x20) | ((low >> 7) & 0x10) | ((low >> 51) & 0xF));
665                      b3 = (int)(
666                          ((low >> 28) & 0x20) |
667                          ((low >> 30) & 0x10) |
668                          ((low >> 29) & 0x08) |
669                          ((low >> 21) & 0x04) |
670                          ((low >> 12) & 0x03));
671  
672                      if (signed)
673                      {
674                          r0 = SignExtend(r0, 6);
675                          g0 = SignExtend(g0, 6);
676                          b0 = SignExtend(b0, 6);
677  
678                          r1 = SignExtend(r1, 6);
679                          g1 = SignExtend(g1, 6);
680                          b1 = SignExtend(b1, 6);
681  
682                          r2 = SignExtend(r2, 6);
683                          g2 = SignExtend(g2, 6);
684                          b2 = SignExtend(b2, 6);
685  
686                          r3 = SignExtend(r3, 6);
687                          g3 = SignExtend(g3, 6);
688                          b3 = SignExtend(b3, 6);
689                      }
690  
691                      r0 = Unquantize(r0, 6, signed);
692                      g0 = Unquantize(g0, 6, signed);
693                      b0 = Unquantize(b0, 6, signed);
694  
695                      r1 = Unquantize(r1, 6, signed);
696                      g1 = Unquantize(g1, 6, signed);
697                      b1 = Unquantize(b1, 6, signed);
698  
699                      r2 = Unquantize(r2, 6, signed);
700                      g2 = Unquantize(g2, 6, signed);
701                      b2 = Unquantize(b2, 6, signed);
702  
703                      r3 = Unquantize(r3, 6, signed);
704                      g3 = Unquantize(g3, 6, signed);
705                      b3 = Unquantize(b3, 6, signed);
706  
707                      subsetCount = 2;
708                      break;
709                  default:
710                      subsetCount = 0;
711                      break;
712              }
713  
714              if (subsetCount > 0)
715              {
716                  endPoints[0] = new RgbaColor32(r0, g0, b0, HalfOne);
717                  endPoints[1] = new RgbaColor32(r1, g1, b1, HalfOne);
718  
719                  if (subsetCount > 1)
720                  {
721                      endPoints[2] = new RgbaColor32(r2, g2, b2, HalfOne);
722                      endPoints[3] = new RgbaColor32(r3, g3, b3, HalfOne);
723                  }
724              }
725  
726              return subsetCount;
727          }
728  
729          private static int SignExtend(int value, int bits)
730          {
731              int shift = 32 - bits;
732              return (value << shift) >> shift;
733          }
734  
735          private static int Unquantize(int value, int bits, bool signed)
736          {
737              if (signed)
738              {
739                  if (bits >= 16)
740                  {
741                      return value;
742                  }
743                  else
744                  {
745                      bool sign = value < 0;
746  
747                      if (sign)
748                      {
749                          value = -value;
750                      }
751  
752                      if (value == 0)
753                      {
754                          return value;
755                      }
756                      else if (value >= ((1 << (bits - 1)) - 1))
757                      {
758                          value = 0x7FFF;
759                      }
760                      else
761                      {
762                          value = ((value << 15) + 0x4000) >> (bits - 1);
763                      }
764  
765                      if (sign)
766                      {
767                          value = -value;
768                      }
769                  }
770              }
771              else
772              {
773                  if (bits >= 15 || value == 0)
774                  {
775                      return value;
776                  }
777                  else if (value == ((1 << bits) - 1))
778                  {
779                      return 0xFFFF;
780                  }
781                  else
782                  {
783                      return ((value << 16) + 0x8000) >> bits;
784                  }
785              }
786  
787              return value;
788          }
789  
790          private static ushort FinishUnquantize(int value, bool signed)
791          {
792              if (signed)
793              {
794                  value = value < 0 ? -((-value * 31) >> 5) : (value * 31) >> 5;
795  
796                  int sign = 0;
797                  if (value < 0)
798                  {
799                      sign = 0x8000;
800                      value = -value;
801                  }
802  
803                  return (ushort)(sign | value);
804              }
805              else
806              {
807                  return (ushort)((value * 31) >> 6);
808              }
809          }
810  
811          private static int BitReverse6(int value)
812          {
813              value = ((value >> 1) & 0x55) | ((value << 1) & 0xaa);
814              value = ((value >> 2) & 0x33) | ((value << 2) & 0xcc);
815              value = ((value >> 4) & 0x0f) | ((value << 4) & 0xf0);
816              return value >> 2;
817          }
818      }
819  }