/// <summary> /// Given a block, extract the colour information and convert to 5554 formats /// </summary> private void Unpack5554Colour(AmtcBlock block, int[,] abColors) { // extract A and B // 15 bits (shifted up by one) m_rawBits[0] = block.PackedData1 & (0xFFFE); // 16 bits m_rawBits[1] = block.PackedData1 >> 16; // step through both colours for (int i = 0; i < 2; i++) { // if completely opaque if ((m_rawBits[i] & (1 << 15)) != 0) { // extract R and G (both 5 bit) abColors[i, 0] = (int)((m_rawBits[i] >> 10) & 0x1F); abColors[i, 1] = (int)((m_rawBits[i] >> 5) & 0x1F); // The precision of Blue depends on A or B. If A then we need to replicate the top bit to get 5 bits in total abColors[i, 2] = (int)(m_rawBits[i] & 0x1F); if (i == 0) { abColors[0, 2] |= abColors[0, 2] >> 4; } // set 4bit alpha fully on... abColors[i, 3] = 0xF; } // else if colour has variable translucency else { // extract R and G (both 4 bit). Leave a space on the end for the replication of bits abColors[i, 0] = (int)((m_rawBits[i] >> (8 - 1)) & 0x1E); abColors[i, 1] = (int)((m_rawBits[i] >> (4 - 1)) & 0x1E); // replicate bits to truly expand to 5 bits abColors[i, 0] |= abColors[i, 0] >> 4; abColors[i, 1] |= abColors[i, 1] >> 4; // grab the 3(+padding) or 4 bits of blue and add an extra padding bit abColors[i, 2] = (int)((m_rawBits[i] & 0xF) << 1); // expand from 3 to 5 bits if this is from colour A, or 4 to 5 bits if from colour B if (i == 0) { abColors[0, 2] |= abColors[0, 2] >> 3; } else { abColors[0, 2] |= abColors[0, 2] >> 4; } // set the alpha bits to be 3 + a zero on the end abColors[i, 3] = (int)((m_rawBits[i] >> 11) & 0xE); } } }
private static AmtcBlock[] GenerateBlocks(byte[] input) { AmtcBlock[] blocks = new AmtcBlock[input.Length / 8]; using (MemoryStream ms = new MemoryStream(input)) { using (BinaryReader reader = new BinaryReader(ms)) { int i = 0; while (reader.BaseStream.Position != reader.BaseStream.Length) { uint v0 = reader.ReadUInt32(); uint v1 = reader.ReadUInt32(); AmtcBlock block = new AmtcBlock(v0, v1); blocks[i++] = block; } } } return(blocks); }
/// <summary> /// Given the block and the texture type and it's relative position in the 2x2 group of blocks, extract the bit patterns for the fully defined pixels. /// </summary> private static void UnpackModulations(AmtcBlock block, bool do2bitMode, int[,] modulationVals, int[,] modulationModes, int startX, int startY) { int blockModMode = (int)(block.PackedData1 & 1); uint modulationBits = block.PackedData0; // if it's in an interpolated mode if (do2bitMode && (blockModMode != 0)) { // run through all the pixels in the block. Note we can now treat all the "stored" values as if they have 2bits (even when they didn't!) for (int y = 0; y < BlockYSize; y++) { for (int x = 0; x < BlockX2bpp; x++) { modulationModes[y + startY, x + startX] = blockModMode; // if this is a stored value... if (((x ^ y) & 1) == 0) { modulationVals[y + startY, x + startX] = (int)(modulationBits & 3); modulationBits >>= 2; } } } } // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel else if (do2bitMode) { for (int y = 0; y < BlockYSize; y++) { for (int x = 0; x < BlockX2bpp; x++) { modulationModes[y + startY, x + startX] = blockModMode; // double the bits so 0=> 00, and 1=>11 if ((modulationBits & 1) != 0) { modulationVals[y + startY, x + startX] = 0x3; } else { modulationVals[y + startY, x + startX] = 0x0; } modulationBits >>= 1; } } } // else its the 4bpp mode so each value has 2 bits else { for (int y = 0; y < BlockYSize; y++) { for (int x = 0; x < BlockX4bpp; x++) { modulationModes[y + startY, x + startX] = blockModMode; modulationVals[y + startY, x + startX] = (int)(modulationBits & 3); modulationBits >>= 2; } } } // make sure nothing is left over if (modulationBits != 0) { throw new Exception("Something is left over"); } }