private unsafe static void DecodeWeights(byte *input, BlockData *block) { IntSeqData *wSeq = stackalloc IntSeqData[128]; DecodeIntseq(input, 128, WeightPrecTableA[block->weight_range], WeightPrecTableB[block->weight_range], block->weight_num, true, wSeq); int *wv = stackalloc int[128]; if (WeightPrecTableA[block->weight_range] == 0) { switch (WeightPrecTableB[block->weight_range]) { case 1: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits != 0 ? 63 : 0; } break; case 2: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 4 | wSeq[i].bits << 2 | wSeq[i].bits; } break; case 3: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 3 | wSeq[i].bits; } break; case 4: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 2 | wSeq[i].bits >> 2; } break; case 5: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].bits << 1 | wSeq[i].bits >> 4; } break; } for (int i = 0; i < block->weight_num; i++) { if (wv[i] > 32) { ++wv[i]; } } } else if (WeightPrecTableB[block->weight_range] == 0) { int s = WeightPrecTableA[block->weight_range] == 3 ? 32 : 16; for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * s; } } else { if (WeightPrecTableA[block->weight_range] == 3) { switch (WeightPrecTableB[block->weight_range]) { case 1: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 50; } break; case 2: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 23; if ((wSeq[i].bits & 2) != 0) { wv[i] += 0b1000101; } } break; case 3: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 11 + ((wSeq[i].bits << 4 | wSeq[i].bits >> 1) & 0b1100011); } break; } } else if (WeightPrecTableA[block->weight_range] == 5) { switch (WeightPrecTableB[block->weight_range]) { case 1: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 28; } break; case 2: for (int i = 0; i < block->weight_num; i++) { wv[i] = wSeq[i].nonbits * 13; if ((wSeq[i].bits & 2) != 0) { wv[i] += 0b1000010; } } break; } } for (int i = 0; i < block->weight_num; i++) { int a = (wSeq[i].bits & 1) * 0x7f; wv[i] = (a & 0x20) | ((wv[i] ^ a) >> 2); if (wv[i] > 32) { ++wv[i]; } } } int ds = (1024 + block->bw / 2) / (block->bw - 1); int dt = (1024 + block->bh / 2) / (block->bh - 1); int pn = block->dual_plane != 0 ? 2 : 1; for (int t = 0, i = 0; t < block->bh; t++) { for (int s = 0; s < block->bw; s++, i++) { int gs = (ds * s * (block->width - 1) + 32) >> 6; int gt = (dt * t * (block->height - 1) + 32) >> 6; int fs = gs & 0xf; int ft = gt & 0xf; int v = (gs >> 4) + (gt >> 4) * block->width; int w11 = (fs * ft + 8) >> 4; int w10 = ft - w11; int w01 = fs - w11; int w00 = 16 - fs - ft + w11; for (int p = 0; p < pn; p++) { int p00 = wv[v * pn + p]; int p01 = wv[(v + 1) * pn + p]; int p10 = wv[(v + block->width) * pn + p]; int p11 = wv[(v + block->width + 1) * pn + p]; block->weights[i * 2 + p] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4; } } } }
private unsafe static void DecodeIntseq(byte *input, int offset, int a, int b, int count, bool reverse, IntSeqData *_out) { if (count <= 0) { return; } int n = 0; if (a == 3) { int mask = (1 << b) - 1; int block_count = (count + 4) / 5; int last_block_count = (count + 4) % 5 + 1; int block_size = 8 + 5 * b; int last_block_size = (block_size * last_block_count + 4) / 5; if (reverse) { for (int i = 0, p = offset; i < block_count; i++, p -= block_size) { int now_size = (i < block_count - 1) ? block_size : last_block_size; ulong d = BitReverseU64(GetBits64(input, p - now_size, now_size), now_size); int x = (int)((d >> b & 3) | (d >> b * 2 & 0xc) | (d >> b * 3 & 0x10) | (d >> b * 4 & 0x60) | (d >> b * 5 & 0x80)); for (int j = 0; j < 5 && n < count; j++, n++) { _out[n] = new IntSeqData() { bits = (int)(d >> (DImt[j] + b * j)) & mask, nonbits = DITritsTable[j * 256 + x], }; } } } else { for (int i = 0, p = offset; i < block_count; i++, p += block_size) { ulong d = GetBits64(input, p, (i < block_count - 1) ? block_size : last_block_size); int x = (int)((d >> b & 3) | (d >> b * 2 & 0xc) | (d >> b * 3 & 0x10) | (d >> b * 4 & 0x60) | (d >> b * 5 & 0x80)); for (int j = 0; j < 5 && n < count; j++, n++) { _out[n] = new IntSeqData() { bits = unchecked ((int)(d >> (DImt[j] + b * j))) & mask, nonbits = DITritsTable[j * 256 + x], }; } } } } else if (a == 5) { int mask = (1 << b) - 1; int block_count = (count + 2) / 3; int last_block_count = (count + 2) % 3 + 1; int block_size = 7 + 3 * b; int last_block_size = (block_size * last_block_count + 2) / 3; if (reverse) { for (int i = 0, p = offset; i < block_count; i++, p -= block_size) { int now_size = (i < block_count - 1) ? block_size : last_block_size; ulong d = BitReverseU64(GetBits64(input, p - now_size, now_size), now_size); int x = (int)((d >> b & 7) | (d >> b * 2 & 0x18) | (d >> b * 3 & 0x60)); for (int j = 0; j < 3 && n < count; j++, n++) { _out[n] = new IntSeqData() { bits = (int)d >> (DImq[j] + b * j) & mask, nonbits = DIQuintsTable[j * 128 + x], }; } } } else { for (int i = 0, p = offset; i < block_count; i++, p += block_size) { ulong d = GetBits64(input, p, (i < block_count - 1) ? block_size : last_block_size); int x = (int)((d >> b & 7) | (d >> b * 2 & 0x18) | (d >> b * 3 & 0x60)); for (int j = 0; j < 3 && n < count; j++, n++) { _out[n] = new IntSeqData() { bits = (int)d >> (DImq[j] + b * j) & mask, nonbits = DIQuintsTable[j * 128 + x], }; } } } } else { if (reverse) { for (int p = offset - b; n < count; n++, p -= b) { _out[n] = new IntSeqData() { bits = BitReverseU8((byte)GetBits(input, p, b), b), nonbits = 0, }; } } else { for (int p = offset; n < count; n++, p += b) { _out[n] = new IntSeqData() { bits = GetBits(input, p, b), nonbits = 0, }; } } } }
private unsafe static void DecodeEndpoints(byte *input, BlockData *pBlock) { IntSeqData *epSeq = stackalloc IntSeqData[32]; DecodeIntseq(input, pBlock->part_num == 1 ? 17 : 29, CemTableA[pBlock->cem_range], CemTableB[pBlock->cem_range], pBlock->endpoint_value_num, false, epSeq); int *ev = stackalloc int[32]; switch (CemTableA[pBlock->cem_range]) { case 3: for (int i = 0, b = 0, c = DETritsTable[CemTableB[pBlock->cem_range]]; i < pBlock->endpoint_value_num; i++) { int a = (epSeq[i].bits & 1) * 0x1ff; int x = epSeq[i].bits >> 1; switch (CemTableB[pBlock->cem_range]) { case 1: b = 0; break; case 2: b = 0b100010110 * x; break; case 3: b = x << 7 | x << 2 | x; break; case 4: b = x << 6 | x; break; case 5: b = x << 5 | x >> 2; break; case 6: b = x << 4 | x >> 4; break; } ev[i] = (a & 0x80) | ((epSeq[i].nonbits * c + b) ^ a) >> 2; } break; case 5: for (int i = 0, b = 0, c = DEQuintsTable[CemTableB[pBlock->cem_range]]; i < pBlock->endpoint_value_num; i++) { int a = (epSeq[i].bits & 1) * 0x1ff; int x = epSeq[i].bits >> 1; switch (CemTableB[pBlock->cem_range]) { case 1: b = 0; break; case 2: b = 0b100001100 * x; break; case 3: b = x << 7 | x << 1 | x >> 1; break; case 4: b = x << 6 | x >> 1; break; case 5: b = x << 5 | x >> 3; break; } ev[i] = (a & 0x80) | ((epSeq[i].nonbits * c + b) ^ a) >> 2; } break; default: switch (CemTableB[pBlock->cem_range]) { case 1: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits * 0xff; } break; case 2: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits * 0x55; } break; case 3: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 5 | epSeq[i].bits << 2 | epSeq[i].bits >> 1; } break; case 4: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 4 | epSeq[i].bits; } break; case 5: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 3 | epSeq[i].bits >> 2; } break; case 6: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 2 | epSeq[i].bits >> 4; } break; case 7: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits << 1 | epSeq[i].bits >> 6; } break; case 8: for (int i = 0; i < pBlock->endpoint_value_num; i++) { ev[i] = epSeq[i].bits; } break; } break; } int *v = ev; for (int cem = 0, cemOff = 0; cem < pBlock->part_num; v += (pBlock->cem[cem] / 4 + 1) * 2, cem++, cemOff += 8) { switch (pBlock->cem[cem]) { case 0: SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[0], v[0], 255, v[1], v[1], v[1], 255); break; case 1: { int l0 = (v[0] >> 2) | (v[1] & 0xc0); int l1 = Clamp(l0 + (v[1] & 0x3f)); SetEndpoint(&pBlock->endpoints[cemOff], l0, l0, l0, 255, l1, l1, l1, 255); } break; case 4: SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[3]); break; case 5: BitTransferSigned(&v[1], &v[0]); BitTransferSigned(&v[3], &v[2]); v[1] += v[0]; SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[2] + v[3]); break; case 6: SetEndpoint(&pBlock->endpoints[cemOff], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, 255, v[0], v[1], v[2], 255); break; case 8: if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5]) { SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[2], v[4], 255, v[1], v[3], v[5], 255); } else { SetEndpointBlue(&pBlock->endpoints[cemOff], v[1], v[3], v[5], 255, v[0], v[2], v[4], 255); } break; case 9: BitTransferSigned(&v[1], &v[0]); BitTransferSigned(&v[3], &v[2]); BitTransferSigned(&v[5], &v[4]); if (v[1] + v[3] + v[5] >= 0) { SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[2], v[4], 255, v[0] + v[1], v[2] + v[3], v[4] + v[5], 255); } else { SetEndpointBlueClamp(&pBlock->endpoints[cemOff], v[0] + v[1], v[2] + v[3], v[4] + v[5], 255, v[0], v[2], v[4], 255); } break; case 10: SetEndpoint(&pBlock->endpoints[cemOff], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, v[4], v[0], v[1], v[2], v[5]); break; case 12: if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5]) { SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[2], v[4], v[6], v[1], v[3], v[5], v[7]); } else { SetEndpointBlue(&pBlock->endpoints[cemOff], v[1], v[3], v[5], v[7], v[0], v[2], v[4], v[6]); } break; case 13: BitTransferSigned(&v[1], &v[0]); BitTransferSigned(&v[3], &v[2]); BitTransferSigned(&v[5], &v[4]); BitTransferSigned(&v[7], &v[6]); if (v[1] + v[3] + v[5] >= 0) { SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[2], v[4], v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7]); } else { SetEndpointBlueClamp(&pBlock->endpoints[cemOff], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7], v[0], v[2], v[4], v[6]); } break; } } }