예제 #1
0
        static RGBColour ReadColourFromTexel(byte[] texel, int i, bool premultiply)
        {
            // Pull out rgb from texel
            // Create current pixel colour
            RGBColour current = new RGBColour();

            // Check that texel is big enough
            if (i + 3 >= texel.Length)
                return current;  // Fully transparent colour

            current.a = texel[i + 3] / 255f;
            current.r = (texel[i + 2] / 255f) * (premultiply ? current.a : 1.0f);
            current.g = (texel[i + 1] / 255f) * (premultiply ? current.a : 1.0f);
            current.b = (texel[i] / 255f) * (premultiply ? current.a : 1.0f);

            return current;
        }
예제 #2
0
 static uint Encode565(RGBColour colour)
 {
     RGBColour temp = new RGBColour()
     {
         r = (colour.r < 0f) ? 0f : (colour.r > 1f) ? 1f : colour.r,
         g = (colour.g < 0f) ? 0f : (colour.g > 1f) ? 1f : colour.g,
         b = (colour.b < 0f) ? 0f : (colour.b > 1f) ? 1f : colour.b
     };
     return (uint)(temp.r * 31f + 0.5f) << 11 | (uint)(temp.g * 63f + 0.5f) << 5 | (uint)(temp.b * 31f + 0.5f);
 }
예제 #3
0
        private static RGBColour[] OptimiseRGB(RGBColour[] Colour, int uSteps)
        {
            float[] pC = uSteps == 3 ? pC3 : pC4;
            float[] pD = uSteps == 3 ? pD3 : pD4;

            // Find min max
            RGBColour X = Luminance;
            RGBColour Y = new RGBColour();

            for (int i = 0; i < Colour.Length; i++)
            {
                RGBColour current = Colour[i];

                // X = min, Y = max
                if (current.r < X.r)
                    X.r = current.r;

                if (current.g < X.g)
                    X.g = current.g;

                if (current.b < X.b)
                    X.b = current.b;

                if (current.r > Y.r)
                    Y.r = current.r;

                if (current.g > Y.g)
                    Y.g = current.g;

                if (current.b > Y.b)
                    Y.b = current.b;
            }

            // Diagonal axis - starts with difference between min and max
            RGBColour diag = new RGBColour()
            {
                r = Y.r - X.r,
                g = Y.g - X.g,
                b = Y.b - X.b
            };
            float fDiag = diag.r * diag.r + diag.g * diag.g + diag.b * diag.b;
            if (fDiag < 1.175494351e-38F)
            {
                RGBColour min1 = new RGBColour()
                {
                    r = X.r,
                    g = X.g,
                    b = X.b
                };
                RGBColour max1 = new RGBColour()
                {
                    r = Y.r,
                    g = Y.g,
                    b = Y.b
                };
                return new RGBColour[] { min1, max1 };
            }

            float FdiagInv = 1f / fDiag;

            RGBColour Dir = new RGBColour()
            {
                r = diag.r * FdiagInv,
                g = diag.g * FdiagInv,
                b = diag.b * FdiagInv
            };
            RGBColour Mid = new RGBColour()
            {
                r = (X.r + Y.r) * .5f,
                g = (X.g + Y.g) * .5f,
                b = (X.b + Y.b) * .5f
            };
            float[] fDir = new float[4];

            for (int i = 0; i < Colour.Length; i++)
            {
                RGBColour pt = new RGBColour()
                {
                    r = Dir.r * (Colour[i].r - Mid.r),
                    g = Dir.g * (Colour[i].g - Mid.g),
                    b = Dir.b * (Colour[i].b - Mid.b)
                };
                float f = 0;
                f = pt.r + pt.g + pt.b;
                fDir[0] += f * f;

                f = pt.r + pt.g - pt.b;
                fDir[1] += f * f;

                f = pt.r - pt.g + pt.b;
                fDir[2] += f * f;

                f = pt.r - pt.g - pt.b;
                fDir[3] += f * f;
            }

            float fDirMax = fDir[0];
            int iDirMax = 0;
            for (int iDir = 1; iDir < 4; iDir++)
            {
                if (fDir[iDir] > fDirMax)
                {
                    fDirMax = fDir[iDir];
                    iDirMax = iDir;
                }
            }

            if ((iDirMax & 2) != 0)
            {
                float f = X.g;
                X.g = Y.g;
                Y.g = f;
            }

            if ((iDirMax & 1) != 0)
            {
                float f = X.b;
                X.b = Y.b;
                Y.b = f;
            }

            if (fDiag < 1f / 4096f)
            {
                RGBColour min1 = new RGBColour()
                {
                    r = X.r,
                    g = X.g,
                    b = X.b
                };
                RGBColour max1 = new RGBColour()
                {
                    r = Y.r,
                    g = Y.g,
                    b = Y.b
                };
                return new RGBColour[] { min1, max1 };
            }

            // newtons method for local min of sum of squares error.
            float fsteps = uSteps - 1;
            for (int iteration = 0; iteration < 8; iteration++)
            {
                RGBColour[] pSteps = new RGBColour[4];

                for (int iStep = 0; iStep < uSteps; iStep++)
                {
                    pSteps[iStep].r = X.r * pC[iStep] + Y.r * pD[iStep];
                    pSteps[iStep].g = X.g * pC[iStep] + Y.g * pD[iStep];
                    pSteps[iStep].b = X.b * pC[iStep] + Y.b * pD[iStep];
                }

                // colour direction
                Dir.r = Y.r - X.r;
                Dir.g = Y.g - X.g;
                Dir.b = Y.b - X.b;

                float fLen = Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b;

                if (fLen < (1f / 4096f))
                    break;

                float fScale = fsteps / fLen;
                Dir.r *= fScale;
                Dir.g *= fScale;
                Dir.b *= fScale;

                // Evaluate function and derivatives
                float d2X = 0, d2Y = 0;
                RGBColour dX, dY;
                dX = new RGBColour();
                dY = new RGBColour();

                for (int i = 0; i < Colour.Length; i++)
                {
                    RGBColour current = Colour[i];

                    float fDot = (current.r - X.r) * Dir.r + (current.g - X.g) * Dir.g + (current.b - X.b) * Dir.b;

                    int iStep = 0;
                    if (fDot <= 0)
                        iStep = 0;
                    else if (fDot >= fsteps)
                        iStep = uSteps - 1;
                    else
                        iStep = (int)(fDot + .5f);

                    RGBColour diff = new RGBColour()
                    {
                        r = pSteps[iStep].r - current.r,
                        g = pSteps[iStep].g - current.g,
                        b = pSteps[iStep].b - current.b
                    };
                    float fC = pC[iStep] * 1f / 8f;
                    float fD = pD[iStep] * 1f / 8f;

                    d2X += fC * pC[iStep];
                    dX.r += fC * diff.r;
                    dX.g += fC * diff.g;
                    dX.b += fC * diff.b;

                    d2Y += fD * pD[iStep];
                    dY.r += fD * diff.r;
                    dY.g += fD * diff.g;
                    dY.b += fD * diff.b;
                }

                // Move endpoints
                if (d2X > 0f)
                {
                    float f = -1f / d2X;
                    X.r += dX.r * f;
                    X.g += dX.g * f;
                    X.b += dX.b * f;
                }

                if (d2Y > 0f)
                {
                    float f = -1f / d2Y;
                    Y.r += dY.r * f;
                    Y.g += dY.g * f;
                    Y.b += dY.b * f;
                }

                float fEpsilon = (0.25f / 64.0f) * (0.25f / 64.0f);
                if ((dX.r * dX.r < fEpsilon) && (dX.g * dX.g < fEpsilon) && (dX.b * dX.b < fEpsilon) &&
                    (dY.r * dY.r < fEpsilon) && (dY.g * dY.g < fEpsilon) && (dY.b * dY.b < fEpsilon))
                {
                    break;
                }
            }

            RGBColour min = new RGBColour()
            {
                r = X.r,
                g = X.g,
                b = X.b
            };
            RGBColour max = new RGBColour()
            {
                r = Y.r,
                g = Y.g,
                b = Y.b
            };
            return new RGBColour[] { min, max };
        }
예제 #4
0
        static void DoSomeDithering(RGBColour current, int index, RGBColour[] InnerColour, int InnerIndex, RGBColour[] Error)
        {
            if (true)  // Dither
            {
                // Calculate difference between current pixel colour and adapted pixel colour?
                RGBColour diff = new RGBColour()
                {
                    r = current.a * (byte)(current.r - InnerColour[InnerIndex].r),
                    g = current.a * (byte)(current.g - InnerColour[InnerIndex].g),
                    b = current.a * (byte)(current.b - InnerColour[InnerIndex].b)
                };

                // If current pixel is not at the end of a row
                if ((index & 3) != 3)
                {
                    Error[index + 1].r += diff.r * (7f / 16f);
                    Error[index + 1].g += diff.g * (7f / 16f);
                    Error[index + 1].b += diff.b * (7f / 16f);
                }

                // If current pixel is not in bottom row
                if (index < 12)
                {
                    // If current pixel IS at end of row
                    if ((index & 3) != 0)
                    {
                        Error[index + 3].r += diff.r * (3f / 16f);
                        Error[index + 3].g += diff.g * (3f / 16f);
                        Error[index + 3].b += diff.b * (3f / 16f);
                    }

                    Error[index + 4].r += diff.r * (5f / 16f);
                    Error[index + 4].g += diff.g * (5f / 16f);
                    Error[index + 4].b += diff.b * (5f / 16f);

                    // If current pixel is not at end of row
                    if ((index & 3) != 3)
                    {
                        Error[index + 5].r += diff.r * (1f / 16f);
                        Error[index + 5].g += diff.g * (1f / 16f);
                        Error[index + 5].b += diff.b * (1f / 16f);
                    }
                }
            }
        }
예제 #5
0
        static RGBColour[] DoSomethingWithPalette(int uSteps, uint wColourA, uint wColourB, RGBColour ColourA, RGBColour ColourB)
        {
            // Create palette colours
            RGBColour[] step = new RGBColour[4];

            if ((uSteps == 3) == (wColourA <= wColourB))
            {
                step[0] = ColourA;
                step[1] = ColourB;
            }
            else
            {
                step[0] = ColourB;
                step[1] = ColourA;
            }

            if (uSteps == 3)
            {
                step[2].r = step[0].r + (1f / 2f) * (step[1].r - step[0].r);
                step[2].g = step[0].g + (1f / 2f) * (step[1].g - step[0].g);
                step[2].b = step[0].b + (1f / 2f) * (step[1].b - step[0].b);
            }
            else
            {
                // "step" appears to be the palette as this is the interpolation
                step[2].r = step[0].r + (1f / 3f) * (step[1].r - step[0].r);
                step[2].g = step[0].g + (1f / 3f) * (step[1].g - step[0].g);
                step[2].b = step[0].b + (1f / 3f) * (step[1].b - step[0].b);

                step[3].r = step[0].r + (2f / 3f) * (step[1].r - step[0].r);
                step[3].g = step[0].g + (2f / 3f) * (step[1].g - step[0].g);
                step[3].b = step[0].b + (2f / 3f) * (step[1].b - step[0].b);
            }

            return step;
        }
예제 #6
0
        /// <summary>
        /// Not exactly sure what this does or why.
        /// </summary>
        static void DoColourFixErrorCorrection(RGBColour[] Colour, byte[] imgData, int sourcePosition, int sourceLineLength, AlphaSettings alphaSetting)
        {
            RGBColour[] Error = new RGBColour[16];
            for (int i = 0; i < 4; i++)
            {
                int position = sourcePosition + sourceLineLength * i;

                for (int j = 0; j < 4; j++)
                {
                    int index = (i << 2) + j;
                    RGBColour current = ReadColourFromTexel(imgData, position, alphaSetting == AlphaSettings.Premultiply);

                    if (true)  // Dither
                    {
                        // Adjust for accumulated error
                        // This works by figuring out the error between the current pixel colour and the adjusted colour? Dunno what the adjustment is. Looks like a 5:6:5 range adaptation
                        // Then, this error is distributed across the "next" few pixels and not the previous.
                        current.r += Error[index].r;
                        current.g += Error[index].g;
                        current.b += Error[index].b;
                    }

                    // 5:6:5 range adaptation?
                    Colour[index].r = (int)(current.r * 31f + .5f) * (1f / 31f);
                    Colour[index].g = (int)(current.g * 63f + .5f) * (1f / 63f);
                    Colour[index].b = (int)(current.b * 31f + .5f) * (1f / 31f);

                    DoSomeDithering(current, index, Colour, index, Error);

                    Colour[index].r *= Luminance.r;
                    Colour[index].g *= Luminance.g;
                    Colour[index].b *= Luminance.b;

                    position += 4;
                }
            }
        }
예제 #7
0
        static uint DoOtherColourFixErrorCorrection(byte[] imgData, int sourcePosition, int sourceLineLength, int uSteps, double alphaRef, AlphaSettings alphaSetting, RGBColour[] step, RGBColour Dir)
        {
            uint dw = 0;
            RGBColour[] Error = new RGBColour[16];

            uint[] psteps = uSteps == 3 ? psteps3 : psteps4;

            for (int i = 0; i < 4; i++)
            {
                int position = sourcePosition + sourceLineLength * i;

                for (int j = 0; j < 4; j++)
                {

                    int index = (i << 2) + j;
                    RGBColour current = ReadColourFromTexel(imgData, position, alphaSetting == AlphaSettings.Premultiply);

                    if ((uSteps == 3) && (current.a < alphaRef))
                    {
                        dw = (uint)((3 << 30) | (dw >> 2));
                        continue;
                    }

                    current.r *= Luminance.r;
                    current.g *= Luminance.g;
                    current.b *= Luminance.b;

                    if (true) // dither
                    {
                        // Error again
                        current.r += Error[index].r;
                        current.g += Error[index].g;
                        current.b += Error[index].b;
                    }

                    float fdot = (current.r - step[0].r) * Dir.r + (current.g - step[0].g) * Dir.g + (current.b - step[0].b) * Dir.b;

                    uint iStep = 0;
                    if (fdot <= 0f)
                        iStep = 0;
                    else if (fdot >= (uSteps - 1))
                        iStep = 1;
                    else
                        iStep = psteps[(int)(fdot + .5f)];

                    dw = (iStep << 30) | (dw >> 2);   // THIS  IS THE MAGIC here. This is the "list" of indicies. Somehow...

                    DoSomeDithering(current, index, step, (int)iStep, Error);

                    position += 4;
                }
            }

            return dw;
        }
예제 #8
0
 static RGBColour Decode565(uint wColour)
 {
     RGBColour colour = new RGBColour()
     {
         r = ((wColour >> 11) & 31) * (1f / 31f),
         g = ((wColour >> 5) & 63) * (1f / 63f),
         b = ((wColour >> 0) & 31) * (1f / 31f),
         a = 1f
     };
     return colour;
 }
예제 #9
0
        internal static void CompressRGBTexel(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, bool isDXT1, double alphaRef, AlphaSettings alphaSetting)
        {
            int uSteps = 4;

            // Determine if texel is fully and entirely transparent. If so, can set to white and continue.
            if (isDXT1)
            {
                uSteps = CheckDXT1TexelFullTransparency(imgData, sourcePosition, sourceLineLength, destination, destPosition, alphaSetting, alphaRef);
                if (uSteps == -1)
                    return;
            }

            RGBColour[] Colour = new RGBColour[16];

            // Some kind of colour adjustment. Not sure what it does, especially if it wasn't dithering...
            DoColourFixErrorCorrection(Colour, imgData, sourcePosition, sourceLineLength, alphaSetting);

            // Palette colours
            RGBColour ColourA, ColourB, ColourC, ColourD;
            ColourA = new RGBColour();
            ColourB = new RGBColour();
            ColourC = new RGBColour();
            ColourD = new RGBColour();

            // OPTIMISER
            RGBColour[] minmax = OptimiseRGB(Colour, uSteps);
            ColourA = minmax[0];
            ColourB = minmax[1];

            // Create interstitial colours?
            ColourC.r = ColourA.r * LuminanceInv.r;
            ColourC.g = ColourA.g * LuminanceInv.g;
            ColourC.b = ColourA.b * LuminanceInv.b;

            ColourD.r = ColourB.r * LuminanceInv.r;
            ColourD.g = ColourB.g * LuminanceInv.g;
            ColourD.b = ColourB.b * LuminanceInv.b;

            // Yeah...dunno
            uint wColourA = Encode565(ColourC);
            uint wColourB = Encode565(ColourD);

            // Min max are equal - only interpolate 4 interstitial colours
            if (uSteps == 4 && wColourA == wColourB)
            {
                var c2 = BitConverter.GetBytes(wColourA);
                var c1 = BitConverter.GetBytes(wColourB);  ///////////////////// MIN MAX

                destination[destPosition] = c2[0];
                destination[destPosition + 1] = c2[1];

                destination[destPosition + 2] = c1[0];
                destination[destPosition + 3] = c1[1];
                return;
            }

            // Interpolate 6 colours or something
            ColourC = Decode565(wColourA);
            ColourD = Decode565(wColourB);

            ColourA.r = ColourC.r * Luminance.r;
            ColourA.g = ColourC.g * Luminance.g;
            ColourA.b = ColourC.b * Luminance.b;

            ColourB.r = ColourD.r * Luminance.r;
            ColourB.g = ColourD.g * Luminance.g;
            ColourB.b = ColourD.b * Luminance.b;

            var step = DoSomethingWithPalette(uSteps, wColourA, wColourB, ColourA, ColourB);

            // Calculating colour direction apparently
            RGBColour Dir = new RGBColour()
            {
                r = step[1].r - step[0].r,
                g = step[1].g - step[0].g,
                b = step[1].b - step[0].b
            };
            float fscale = (wColourA != wColourB) ? ((uSteps - 1) / (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b)) : 0.0f;
            Dir.r *= fscale;
            Dir.g *= fscale;
            Dir.b *= fscale;

            // Encoding colours apparently
            uint dw = DoOtherColourFixErrorCorrection(imgData, sourcePosition, sourceLineLength, uSteps, alphaRef, alphaSetting, step, Dir);

            uint Min = (uSteps == 3) == (wColourA <= wColourB) ? wColourA : wColourB;
            uint Max = (uSteps == 3) == (wColourA <= wColourB) ? wColourB : wColourA;

            var colour1 = BitConverter.GetBytes(Min);
            var colour2 = BitConverter.GetBytes(Max);

            destination[destPosition] = colour1[0];
            destination[destPosition + 1] = colour1[1];

            destination[destPosition + 2] = colour2[0];
            destination[destPosition + 3] = colour2[1];

            var indicies = BitConverter.GetBytes(dw);
            destination[destPosition + 4] = indicies[0];
            destination[destPosition + 5] = indicies[1];
            destination[destPosition + 6] = indicies[2];
            destination[destPosition + 7] = indicies[3];
        }
예제 #10
0
 private RGBColour ExtractRGBColour(string[] rgb)
 {
     return(RGBColour.FromRGB(double.Parse(rgb[0]), double.Parse(rgb[1]), double.Parse(rgb[2])));
 }
예제 #11
0
 private void SetPanelBackColor(Panel pnl, RGBColour colour)
 {
     pnl.BackColor = Color.FromArgb(255, (int)colour.R, (int)colour.G, (int)colour.B);
 }
예제 #12
0
 ///<exclude/>
 public bool Equals(RGBColour other)
 {
     if (ReferenceEquals(null, other)) return false;
     if (ReferenceEquals(this, other)) return true;
     return other._R.Equals(_R) && other._G.Equals(_G) && other._B.Equals(_B);
 }