예제 #1
0
        private ulong FindClosest(Bc4BlockData data)
        {
            ulong ret = 0;

            for (int i = 0; i < data.Values.Length; ++i)
            {
                var v = data.Values[i];

                int   iBest     = 0;
                float bestDelta = Math.Abs(data.InterpretedValues[0] - v);

                for (int j = 1; j < data.InterpretedValues.Length; j++)
                {
                    float delta = Math.Abs(data.InterpretedValues[j] - v);

                    if (delta < bestDelta)
                    {
                        iBest     = j;
                        bestDelta = delta;
                    }
                }

                int shift = 16 + 3 * i;
                ret |= (ulong)iBest << shift;
            }

            return(ret);
        }
예제 #2
0
        /// <summary>
        /// Encode a block of unsigned Values.
        /// </summary>
        /// <returns></returns>
        public BC4UBlock EncodeUnsigned(Bc4BlockData data)
        {
            //load the input and scan for the boundary condition

            ClampAndFindRange(data, 0F, 1F);

            var hasEndPoint = data.MinValue == 0F || data.MaxValue == 1F;

            //find a span across the space
            SpanValues(hasEndPoint, false, data, out var r0, out var r1);

            //roundtrip it through integer format

            var ret = new BC4UBlock
            {
                R0 = Helpers.FloatToUNorm(r0),
                R1 = Helpers.FloatToUNorm(r1)
            };


            ret.GetPalette(data.InterpretedValues);

            ret.PackedValue |= FindClosest(data);

            return(ret);
        }
예제 #3
0
        private void ClampAndFindRange(Bc4BlockData data, float clampMin, float clampMax)
        {
            var target = data.Values;

            var v0 = target[0];

            if (v0 < clampMin)
            {
                target[0] = v0 = clampMin;
            }
            else if (v0 > clampMax)
            {
                target[0] = v0 = clampMax;
            }

            data.MinValue = data.MaxValue = v0;

            for (int i = 1; i < target.Length; i++)
            {
                var v = target[i];

                if (v < clampMin)
                {
                    target[i] = v = clampMin;
                }
                else if (v > clampMax)
                {
                    target[i] = v = clampMax;
                }

                if (v < data.MinValue)
                {
                    data.MinValue = v;
                }
                else if (v > data.MaxValue)
                {
                    data.MaxValue = v;
                }
            }
        }
예제 #4
0
        private void SpanValues(bool isSixPointInterpreter, bool isSigned, Bc4BlockData data, out float r0, out float r1)
        {
            //pulled from the original OptimizeAlpha code in the D3DX sample code

            float[] pC, pD;
            if (isSixPointInterpreter)
            {
                pC = pC6;
                pD = pD6;
            }
            else
            {
                pC = pC8;
                pD = pD8;
            }

            float       rangeMin = isSigned ? -1F : 0F;
            const float rangeMax = 1F;

            //find min and max points as a starting solution

            float vMin, vMax;

            if (isSixPointInterpreter)
            {
                vMin = rangeMax;
                vMax = rangeMin;

                for (int i = 0; i < data.Values.Length; i++)
                {
                    var v = data.Values[i];

                    if (v == rangeMin || v == rangeMax)
                    {
                        continue;
                    }

                    if (v < vMin)
                    {
                        vMin = v;
                    }
                    if (v > vMax)
                    {
                        vMax = v;
                    }
                }

                if (vMin == vMax)
                {
                    vMax = rangeMax;
                }
            }
            else
            {
                vMin = data.MinValue;
                vMax = data.MaxValue;
            }

            // Use Newton's Method to find local minima of sum-of-squares Error.

            int   numSteps = isSixPointInterpreter ? 6 : 8;
            float fSteps   = numSteps - 1;

            for (int iteration = 0; iteration < 8; iteration++)
            {
                if ((vMax - vMin) < (1.0f / 256.0f))
                {
                    break;
                }

                float fScale = fSteps / (vMax - vMin);

                // Calculate new steps

                for (int i = 0; i < numSteps; i++)
                {
                    data.InterpretedValues[i] = pC[i] * vMin + pD[i] * vMax;
                }

                if (isSixPointInterpreter)
                {
                    data.InterpretedValues[6] = rangeMin;
                    data.InterpretedValues[7] = rangeMax;
                }

                // Evaluate function, and derivatives
                float dX  = 0F;
                float dY  = 0F;
                float d2X = 0F;
                float d2Y = 0F;

                for (int iPoint = 0; iPoint < data.Values.Length; iPoint++)
                {
                    float dot = (data.Values[iPoint] - vMin) * fScale;

                    int iStep;
                    if (dot <= 0.0f)
                    {
                        iStep = ((6 == numSteps) && (data.Values[iPoint] <= vMin * 0.5f)) ? 6 : 0;
                    }
                    else if (dot >= fSteps)
                    {
                        iStep = ((6 == numSteps) && (data.Values[iPoint] >= (vMax + 1.0f) * 0.5f)) ? 7 : (numSteps - 1);
                    }
                    else
                    {
                        iStep = (int)(dot + 0.5f);
                    }


                    if (iStep < numSteps)
                    {
                        // D3DX had this computation backwards (pPoints[iPoint] - pSteps[iStep])
                        // this fix improves RMS of the alpha component
                        float fDiff = data.InterpretedValues[iStep] - data.Values[iPoint];

                        dX  += pC[iStep] * fDiff;
                        d2X += pC[iStep] * pC[iStep];

                        dY  += pD[iStep] * fDiff;
                        d2Y += pD[iStep] * pD[iStep];
                    }
                }

                // Move endpoints

                if (d2X > 0.0f)
                {
                    vMin -= dX / d2X;
                }

                if (d2Y > 0.0f)
                {
                    vMax -= dY / d2Y;
                }

                if (vMin > vMax)
                {
                    float f = vMin; vMin = vMax; vMax = f;
                }

                if ((dX * dX < (1.0f / 64.0f)) && (dY * dY < (1.0f / 64.0f)))
                {
                    break;
                }
            }

            vMin = (vMin < rangeMin) ? rangeMin : (vMin > rangeMax) ? rangeMax : vMin;
            vMax = (vMax < rangeMin) ? rangeMin : (vMax > rangeMax) ? rangeMax : vMax;

            if (isSixPointInterpreter)
            {
                r0 = vMin;
                r1 = vMax;
            }
            else
            {
                r0 = vMax;
                r1 = vMin;
            }
        }