Ejemplo n.º 1
0
        public static byte[] EncodeRgba4Bpp(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();
            }

            List <Color> tempColor32Array = new List <Color>();

            for (int y = 0; y < bitmap.Height; y++)
            {
                for (int x = 0; x < bitmap.Width; x++)
                {
                    tempColor32Array.Add(bitmap.GetPixel(x, y));
                }
            }

            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
                    GetMinMaxColorsWithAlpha(tempColor32Array, size, 4 * x, 4 * y, ref minColor, ref maxColor);

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

            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];

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

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

                            Color      pixel = tempColor32Array[4 * x + px + (4 * y + py) * size]; //(Color32)bitmap.GetPixel(4*x + px, 4*y + py);
                            Vector4Int d     = cb - ca;
                            Vector4Int p     = new Vector4Int(pixel.R * 16, pixel.G * 16, pixel.B * 16, pixel.A * 16);
                            Vector4Int 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(Vector4.Dot(v, d)) * 16;
                            int lengthSquared = d % d;        //Mathf.RoundToInt(Vector4.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);
        }
Ejemplo n.º 2
0
        // This function assumes that input texture is square! (width == height)
        public static Bitmap DecodeRgba4Bpp(byte[] data, int width)
        {
            int size      = width;
            int blocks    = size / 4;
            int blockMask = blocks - 1;

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

            Color[] tempColor32Array = new Color[size * size];

            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];

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

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

                            byte[] currentWeights = PvrtcPacket.WEIGHTS[4 * packet.GetPunchthroughAlpha() + mod & 3];
                            Color  c = Color.White;
                            c = Color.FromArgb(
                                (int)(Math.Round((decimal)(ca.w * currentWeights[2] + cb.w * currentWeights[3]), MidpointRounding.AwayFromZero)) >> 7,
                                (int)(Math.Round((decimal)(ca.x * currentWeights[0] + cb.x * currentWeights[1]), MidpointRounding.AwayFromZero)) >> 7,
                                (int)(Math.Round((decimal)(ca.y * currentWeights[0] + cb.y * currentWeights[1]), MidpointRounding.AwayFromZero)) >> 7,
                                (int)(Math.Round((decimal)(ca.z * currentWeights[0] + cb.z * currentWeights[1]), MidpointRounding.AwayFromZero)) >> 7);

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

            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size; x++)
                {
                    returnValue.SetPixel(x, y, tempColor32Array[y * size + x]);
                }
            }

            return(returnValue);
        }