Example #1
0
        public static byte[] EncodeRgb4Bpp(Bitmap bitmap)
        {
            if (bitmap.Height != bitmap.Width)
            {
                throw new Exception("Texture isn't square!");
            }
            if (!((bitmap.Height & (bitmap.Height - 1)) == 0))
            {
                throw new Exception("Texture resolution must be 2^N!");
            }

            int size      = bitmap.Width;
            int blocks    = size / 4;
            int blockMask = blocks - 1;

            PvrtcPacket[] packets = new PvrtcPacket[blocks * blocks];
            for (int i = 0; i < packets.Length; i++)
            {
                packets[i] = new PvrtcPacket();
            }

            for (int y = 0; y < blocks; ++y)
            {
                for (int x = 0; x < blocks; ++x)
                {
                    Color minColor = Color.White; // white is same as all 255, should be same as Color.max
                    Color maxColor = Color.Black; // clear is same as all 0,   should be same as Color.min

                    GetMinMaxColors(bitmap, 4 * x, 4 * y, ref minColor, ref maxColor);

                    PvrtcPacket packet = packets[GetMortonNumber(x, y)];
                    packet.SetPunchthroughAlpha(false);
                    packet.SetColorA(minColor.R, minColor.G, minColor.B);
                    packet.SetColorB(maxColor.R, maxColor.G, maxColor.B);
                }
            }

            int currentFactorIndex = 0;

            for (int y = 0; y < blocks; ++y)
            {
                for (int x = 0; x < blocks; ++x)
                {
                    currentFactorIndex = 0;

                    uint modulationData = 0;

                    for (int py = 0; py < 4; ++py)
                    {
                        int yOffset = (py < 2) ? -1 : 0;
                        int y0      = (y + yOffset) & blockMask;
                        int y1      = (y0 + 1) & blockMask;

                        for (int px = 0; px < 4; ++px)
                        {
                            int xOffset = (px < 2) ? -1 : 0;
                            int x0      = (x + xOffset) & blockMask;
                            int x1      = (x0 + 1) & blockMask;

                            PvrtcPacket p0 = packets[GetMortonNumber(x0, y0)];
                            PvrtcPacket p1 = packets[GetMortonNumber(x1, y0)];
                            PvrtcPacket p2 = packets[GetMortonNumber(x0, y1)];
                            PvrtcPacket p3 = packets[GetMortonNumber(x1, y1)];

                            byte[] currentFactors = PvrtcPacket.BILINEAR_FACTORS[currentFactorIndex];

                            Vector3Int ca = p0.GetColorRgbA() * currentFactors[0] +
                                            p1.GetColorRgbA() * currentFactors[1] +
                                            p2.GetColorRgbA() * currentFactors[2] +
                                            p3.GetColorRgbA() * currentFactors[3];

                            Vector3Int cb = p0.GetColorRgbB() * currentFactors[0] +
                                            p1.GetColorRgbB() * currentFactors[1] +
                                            p2.GetColorRgbB() * currentFactors[2] +
                                            p3.GetColorRgbB() * currentFactors[3];

                            Color pixel = bitmap.GetPixel(4 * x + px, 4 * y + py);

                            Vector3Int d = cb - ca;
                            Vector3Int p = new Vector3Int(pixel.R * 16, pixel.G * 16, pixel.B * 16);
                            Vector3Int v = p - ca;

                            // PVRTC uses weightings of 0, 3/8, 5/8 and 1
                            // The boundaries for these are 3/16, 1/2 (=8/16), 13/16
                            int projection    = (v % d) * 16; // Mathf.RoundToInt(Vector3.Dot(v, d)) * 16;
                            int lengthSquared = d % d;        //Mathf.RoundToInt(Vector3.Dot(d,d));
                            if (projection > 3 * lengthSquared)
                            {
                                modulationData++;
                            }
                            if (projection > 8 * lengthSquared)
                            {
                                modulationData++;
                            }
                            if (projection > 13 * lengthSquared)
                            {
                                modulationData++;
                            }

                            modulationData = RotateRight(modulationData, 2);

                            currentFactorIndex++;
                        }
                    }

                    PvrtcPacket packet = packets[GetMortonNumber(x, y)];
                    packet.SetModulationData(modulationData);
                }
            }

            byte[] returnValue = new byte[size * size / 2];

            // Create final byte array from PVRTC packets
            for (int i = 0; i < packets.Length; i++)
            {
                byte[] tempArray = packets[i].GetAsByteArray();
                Buffer.BlockCopy(tempArray, 0, returnValue, 8 * i, 8);
            }

            return(returnValue);
        }
Example #2
0
        // This function assumes that input texture is square! (width == height)
        public static Bitmap DecodeRgb4Bpp(byte[] data, int width)
        {
            int size      = width;
            int blocks    = size / 4;
            int blockMask = blocks - 1;

            Bitmap returnValue = new Bitmap(size, size, PixelFormat.Format24bppRgb);

            PvrtcPacket[] packets    = new PvrtcPacket[blocks * blocks];
            byte[]        eightBytes = new byte[8];
            for (int i = 0; i < packets.Length; i++)
            {
                packets[i] = new PvrtcPacket();
                Buffer.BlockCopy(data, i * 8, eightBytes, 0, 8);
                packets[i].InitFromBytes(eightBytes);
            }

            int currentFactorIndex = 0;

            for (int y = 0; y < blocks; ++y)
            {
                for (int x = 0; x < blocks; ++x)
                {
                    currentFactorIndex = 0;

                    PvrtcPacket packet = packets[GetMortonNumber(x, y)];

                    uint mod = packet.GetModulationData();

                    for (int py = 0; py < 4; ++py)
                    {
                        int yOffset = (py < 2) ? -1 : 0;
                        int y0      = (y + yOffset) & blockMask;
                        int y1      = (y0 + 1) & blockMask;

                        for (int px = 0; px < 4; ++px)
                        {
                            int xOffset = (px < 2) ? -1 : 0;
                            int x0      = (x + xOffset) & blockMask;
                            int x1      = (x0 + 1) & blockMask;

                            PvrtcPacket p0 = packets[GetMortonNumber(x0, y0)];
                            PvrtcPacket p1 = packets[GetMortonNumber(x1, y0)];
                            PvrtcPacket p2 = packets[GetMortonNumber(x0, y1)];
                            PvrtcPacket p3 = packets[GetMortonNumber(x1, y1)];

                            byte[] currentFactors = PvrtcPacket.BILINEAR_FACTORS[currentFactorIndex];

                            Vector3Int ca = p0.GetColorRgbA() * currentFactors[0] +
                                            p1.GetColorRgbA() * currentFactors[1] +
                                            p2.GetColorRgbA() * currentFactors[2] +
                                            p3.GetColorRgbA() * currentFactors[3];

                            Vector3Int cb = p0.GetColorRgbB() * currentFactors[0] +
                                            p1.GetColorRgbB() * currentFactors[1] +
                                            p2.GetColorRgbB() * currentFactors[2] +
                                            p3.GetColorRgbB() * currentFactors[3];

                            byte[] currentWeights = PvrtcPacket.WEIGHTS[4 * packet.GetPunchthroughAlpha() + mod & 3];

                            Color c = Color.White;
                            c = Color.FromArgb(c.A,
                                               (byte)((int)(Math.Round((decimal)(ca.x * currentWeights[0] + cb.x * currentWeights[1]), MidpointRounding.AwayFromZero)) >> 7),
                                               (byte)((int)(Math.Round((decimal)(ca.y * currentWeights[0] + cb.y * currentWeights[1]), MidpointRounding.AwayFromZero)) >> 7),
                                               (byte)((int)(Math.Round((decimal)(ca.z * currentWeights[0] + cb.z * currentWeights[1]), MidpointRounding.AwayFromZero)) >> 7));

                            returnValue.SetPixel((px + x * 4), (py + y * 4), c);
                            mod >>= 2;
                            currentFactorIndex++;
                        }
                    }
                }
            }

            return(returnValue);
        }