Example #1
0
    public byte[] EncodeRgb4Bpp(Color[] pixels, int width, int height)
    {
        if (height != width)
        {
            Debug.LogError("Texture isn't square!");
        }
        if (!((height & (height - 1)) == 0))
        {
            Debug.LogError("Texture resolution must be 2^N!");
        }

        int size      = 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)
            {
                Color32 minColor = Color.white;                 // white is same as all 255, should be same as Color.max
                Color32 maxColor = Color.clear;                 // clear is same as all 0,   should be same as Color.min

                this.GetMinMaxColors(pixels, width, 4 * x, 4 * y, ref minColor, ref maxColor);

                PvrtcPacket packet = packets[this.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[this.GetMortonNumber(x0, y0)];
                        PvrtcPacket p1 = packets[this.GetMortonNumber(x1, y0)];
                        PvrtcPacket p2 = packets[this.GetMortonNumber(x0, y1)];
                        PvrtcPacket p3 = packets[this.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];

                        Color32 pixel = pixels[(4 * x + px) * width + 4 * y + py];
                        //Color32 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[this.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 Texture2D DecodeRgba4Bpp(byte[] data, int width)
    {
        int size      = width;
        int blocks    = size / 4;
        int blockMask = blocks - 1;

        Texture2D returnValue = new Texture2D(size, size, TextureFormat.RGBA32, false, true);

        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[this.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[this.GetMortonNumber(x0, y0)];
                        PvrtcPacket p1 = packets[this.GetMortonNumber(x1, y0)];
                        PvrtcPacket p2 = packets[this.GetMortonNumber(x0, y1)];
                        PvrtcPacket p3 = packets[this.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];
                        Color32 c = Color.white;
                        c.r = (byte)(Mathf.RoundToInt((ca.x * currentWeights[0] + cb.x * currentWeights[1]) >> 7));
                        c.g = (byte)(Mathf.RoundToInt((ca.y * currentWeights[0] + cb.y * currentWeights[1]) >> 7));
                        c.b = (byte)(Mathf.RoundToInt((ca.z * currentWeights[0] + cb.z * currentWeights[1]) >> 7));
                        c.a = (byte)(Mathf.RoundToInt((ca.w * currentWeights[2] + cb.w * currentWeights[3]) >> 7));

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

        returnValue.Apply();
        return(returnValue);
    }