Exemplo n.º 1
0
        public BC1Block Encode()
        {
            BC1Block ret;

            if( alphaMask == 0xFFFF )
            {
                ret.PackedValue = BC1Block.TransparentValue;
                return ret;
            }

            QuantizeValues();

            RgbF32 r0, r1;
            SpanValues( out r0, out r1 );

            //quantize the endpoints

            bool weightValues = !UseUniformWeighting;

            if( weightValues )
            {
                r0.R *= RInvWeight;
                r0.G *= GInvWeight;
                r0.B *= BInvWeight;

                r1.R *= RInvWeight;
                r1.G *= GInvWeight;
                r1.B *= BInvWeight;
            }

            var pr0 = Rgb565.Pack( r0 );
            var pr1 = Rgb565.Pack( r1 );

            if( alphaMask == 0 && pr0.PackedValue == pr1.PackedValue )
                return new BC1Block( pr0, pr1 );

            pr0.Unpack( out r0 );
            pr1.Unpack( out r1 );

            if( weightValues )
            {
                r0.R *= RWeight;
                r0.G *= GWeight;
                r0.B *= BWeight;

                r1.R *= RWeight;
                r1.G *= GWeight;
                r1.B *= BWeight;
            }

            //interp out the steps

            RgbF32 s0;

            if( (alphaMask != 0) == (pr0.PackedValue <= pr1.PackedValue) )
            {
                ret = new BC1Block( pr0, pr1 );
                interpValues[0] = s0 = r0;
                interpValues[1] = r1;
            }
            else
            {
                ret = new BC1Block( pr1, pr0 );
                interpValues[0] = s0 = r1;
                interpValues[1] = r0;
            }

            uint[] pSteps;

            if( alphaMask != 0 )
            {
                pSteps = pSteps3;

                RgbF32.Lerp( out interpValues[2], interpValues[0], interpValues[1], 0.5F );
            }
            else
            {
                pSteps = pSteps4;

                RgbF32.Lerp( out interpValues[2], interpValues[0], interpValues[1], 1.0F / 3.0F );
                RgbF32.Lerp( out interpValues[3], interpValues[0], interpValues[1], 2.0F / 3.0F );
            }

            //find the best values

            RgbF32 dir;

            dir.R = interpValues[1].R - s0.R;
            dir.G = interpValues[1].G - s0.G;
            dir.B = interpValues[1].B - s0.B;

            float fSteps = alphaMask != 0 ? 2 : 3;
            float fScale = (pr0.PackedValue != pr1.PackedValue) ?
                (fSteps / (dir.R * dir.R + dir.G * dir.G + dir.B * dir.B)) : 0.0F;

            dir.R *= fScale;
            dir.G *= fScale;
            dir.B *= fScale;

            bool dither = DitherRgb;

            if( dither )
            {
                if( error == null )
                    error = new RgbF32[16];
                else
                    Array.Clear( error, 0, 16 );
            }

            for( int i = 0; i < values.Length; i++ )
            {
                if( (alphaMask & (1 << i)) != 0 )
                {
                    ret.PackedValue |= 3U << (32 + i * 2);
                }
                else
                {
                    var cl = values[i];

                    if( weightValues )
                    {
                        cl.R *= RWeight;
                        cl.G *= GWeight;
                        cl.B *= BWeight;
                    }

                    if( dither )
                    {
                        var e = error[i];

                        cl.R += e.R;
                        cl.G += e.G;
                        cl.B += e.B;
                    }

                    float fDot =
                        (cl.R - s0.R) * dir.R +
                        (cl.G - s0.G) * dir.G +
                        (cl.B - s0.B) * dir.B;

                    uint iStep;

                    if( fDot <= 0 )
                        iStep = 0;
                    else if( fDot >= fSteps )
                        iStep = 1;
                    else
                        iStep = pSteps[(int)(fDot + 0.5F)];

                    ret.PackedValue |= (ulong)iStep << (32 + i * 2);

                    if( dither )
                    {
                        RgbF32 e, d, interp = interpValues[iStep];

                        d.R = cl.R - interp.R;
                        d.G = cl.G - interp.G;
                        d.B = cl.B - interp.B;

                        if( (i & 3) != 3 )
                        {
                            e = error[i + 1];

                            e.R += d.R * (7.0F / 16.0F);
                            e.G += d.G * (7.0F / 16.0F);
                            e.B += d.B * (7.0F / 16.0F);

                            error[i + 1] = e;
                        }

                        if( i < 12 )
                        {
                            if( (i & 3) != 0 )
                            {
                                e = error[i + 3];

                                e.R += d.R * (3.0F / 16.0F);
                                e.G += d.G * (3.0F / 16.0F);
                                e.B += d.B * (3.0F / 16.0F);

                                error[i + 3] = e;
                            }

                            e = error[i + 4];

                            e.R += d.R * (5.0F / 16.0F);
                            e.G += d.G * (5.0F / 16.0F);
                            e.B += d.B * (5.0F / 16.0F);

                            error[i + 4] = e;

                            if( 3 != (i & 3) )
                            {
                                e = error[i + 5];

                                e.R += d.R * (1.0F / 16.0F);
                                e.G += d.G * (1.0F / 16.0F);
                                e.B += d.B * (1.0F / 16.0F);

                                error[i + 5] = e;
                            }
                        }
                    }
                }
            }

            return ret;
        }
Exemplo n.º 2
0
        public BC1Block Encode()
        {
            BC1Block ret;

            if (alphaMask == 0xFFFF)
            {
                ret.PackedValue = BC1Block.TransparentValue;
                return(ret);
            }

            QuantizeValues();

            RgbF32 r0, r1;

            SpanValues(out r0, out r1);

            //quantize the endpoints

            bool weightValues = !UseUniformWeighting;

            if (weightValues)
            {
                r0.R *= RInvWeight;
                r0.G *= GInvWeight;
                r0.B *= BInvWeight;

                r1.R *= RInvWeight;
                r1.G *= GInvWeight;
                r1.B *= BInvWeight;
            }

            var pr0 = Rgb565.Pack(r0);
            var pr1 = Rgb565.Pack(r1);

            if (alphaMask == 0 && pr0.PackedValue == pr1.PackedValue)
            {
                return(new BC1Block(pr0, pr1));
            }

            pr0.Unpack(out r0);
            pr1.Unpack(out r1);

            if (weightValues)
            {
                r0.R *= RWeight;
                r0.G *= GWeight;
                r0.B *= BWeight;

                r1.R *= RWeight;
                r1.G *= GWeight;
                r1.B *= BWeight;
            }

            //interp out the steps

            RgbF32 s0;

            if ((alphaMask != 0) == (pr0.PackedValue <= pr1.PackedValue))
            {
                ret             = new BC1Block(pr0, pr1);
                interpValues[0] = s0 = r0;
                interpValues[1] = r1;
            }
            else
            {
                ret             = new BC1Block(pr1, pr0);
                interpValues[0] = s0 = r1;
                interpValues[1] = r0;
            }

            uint[] pSteps;

            if (alphaMask != 0)
            {
                pSteps = pSteps3;

                RgbF32.Lerp(out interpValues[2], interpValues[0], interpValues[1], 0.5F);
            }
            else
            {
                pSteps = pSteps4;

                RgbF32.Lerp(out interpValues[2], interpValues[0], interpValues[1], 1.0F / 3.0F);
                RgbF32.Lerp(out interpValues[3], interpValues[0], interpValues[1], 2.0F / 3.0F);
            }

            //find the best values

            RgbF32 dir;

            dir.R = interpValues[1].R - s0.R;
            dir.G = interpValues[1].G - s0.G;
            dir.B = interpValues[1].B - s0.B;

            float fSteps = alphaMask != 0 ? 2 : 3;
            float fScale = (pr0.PackedValue != pr1.PackedValue) ?
                           (fSteps / (dir.R * dir.R + dir.G * dir.G + dir.B * dir.B)) : 0.0F;

            dir.R *= fScale;
            dir.G *= fScale;
            dir.B *= fScale;

            bool dither = DitherRgb;

            if (dither)
            {
                if (error == null)
                {
                    error = new RgbF32[16];
                }
                else
                {
                    Array.Clear(error, 0, 16);
                }
            }

            for (int i = 0; i < values.Length; i++)
            {
                if ((alphaMask & (1 << i)) != 0)
                {
                    ret.PackedValue |= 3U << (32 + i * 2);
                }
                else
                {
                    var cl = values[i];

                    if (weightValues)
                    {
                        cl.R *= RWeight;
                        cl.G *= GWeight;
                        cl.B *= BWeight;
                    }

                    if (dither)
                    {
                        var e = error[i];

                        cl.R += e.R;
                        cl.G += e.G;
                        cl.B += e.B;
                    }

                    float fDot =
                        (cl.R - s0.R) * dir.R +
                        (cl.G - s0.G) * dir.G +
                        (cl.B - s0.B) * dir.B;

                    uint iStep;

                    if (fDot <= 0)
                    {
                        iStep = 0;
                    }
                    else if (fDot >= fSteps)
                    {
                        iStep = 1;
                    }
                    else
                    {
                        iStep = pSteps[(int)(fDot + 0.5F)];
                    }

                    ret.PackedValue |= (ulong)iStep << (32 + i * 2);

                    if (dither)
                    {
                        RgbF32 e, d, interp = interpValues[iStep];

                        d.R = cl.R - interp.R;
                        d.G = cl.G - interp.G;
                        d.B = cl.B - interp.B;

                        if ((i & 3) != 3)
                        {
                            e = error[i + 1];

                            e.R += d.R * (7.0F / 16.0F);
                            e.G += d.G * (7.0F / 16.0F);
                            e.B += d.B * (7.0F / 16.0F);

                            error[i + 1] = e;
                        }

                        if (i < 12)
                        {
                            if ((i & 3) != 0)
                            {
                                e = error[i + 3];

                                e.R += d.R * (3.0F / 16.0F);
                                e.G += d.G * (3.0F / 16.0F);
                                e.B += d.B * (3.0F / 16.0F);

                                error[i + 3] = e;
                            }

                            e = error[i + 4];

                            e.R += d.R * (5.0F / 16.0F);
                            e.G += d.G * (5.0F / 16.0F);
                            e.B += d.B * (5.0F / 16.0F);

                            error[i + 4] = e;

                            if (3 != (i & 3))
                            {
                                e = error[i + 5];

                                e.R += d.R * (1.0F / 16.0F);
                                e.G += d.G * (1.0F / 16.0F);
                                e.B += d.B * (1.0F / 16.0F);

                                error[i + 5] = e;
                            }
                        }
                    }
                }
            }

            return(ret);
        }