예제 #1
0
        public ClusterFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // set the iteration count
            m_iterationCount = ((m_flags & SquishFlags.ColourIterativeClusterFit) != 0) ? kMaxIterations : 1;

            // initialise the best error
            m_besterror = new Vec4(float.MaxValue);

            // initialise the metric
            bool perceptual = ((m_flags & SquishFlags.ColourMetricPerceptual) != 0);
            if (perceptual)
                m_metric = new Vec4(0.2126f, 0.7152f, 0.0722f, 0.0f);
            else
                m_metric = new Vec4(1.0f);

            // cache some values
            int count = m_colours.GetCount();
            Vec3[] values = m_colours.GetPoints();

            // get the covariance matrix
            Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, m_colours.GetWeights());
            // compute the principle component
            m_principle = Sym3x3.ComputePrincipleComponent(covariance);
        }
예제 #2
0
        public static unsafe void WriteColourBlock4(Vec3 start, Vec3 end, byte* indices, byte* block)
        {
            // get the packed values
            int a = FloatTo565(start);
            int b = FloatTo565(end);

            // remap the indices
            byte[] remapped = new byte[16];

            if (a < b)
            {
                // swap a and b
                CMath.Swap<int>(ref a, ref b);
                for (int i = 0; i < 16; ++i)
                    remapped[i] = (byte)((indices[i] ^ 0x1) & 0x3);
            }
            else if (a == b)
            {
                // use index 0
                for (int i = 0; i < 16; ++i)
                    remapped[i] = 0;
            }
            else
            {
                // use the indices directly
                for (int i = 0; i < 16; ++i)
                    remapped[i] = indices[i];
            }

            fixed (byte* fixRemapped = remapped)
            {
                // write the block
                WriteColourBlock(a, b, fixRemapped, block);
            }
        }
예제 #3
0
        public static Vec3 Truncate( Vec3 v )
	    {
		    return new Vec3(
			    v.X() > 0.0f ? CMath.Floor( v.X() ) : CMath.Ceil( v.X() ), 
			    v.Y() > 0.0f ? CMath.Floor( v.Y() ) : CMath.Ceil( v.Y() ),
                v.Z() > 0.0f ? CMath.Floor(v.Z()) : CMath.Ceil(v.Z())
		    );
	    }
예제 #4
0
 public static Vec3 Max(Vec3 a, Vec3 b)
 {
     return new Vec3(
         Math.Max(a.X(), b.X()),
         Math.Max(a.Y(), b.Y()),
         Math.Max(a.Z(), b.Z())
     );
 }
예제 #5
0
        public static int FloatTo565(Vec3 colour)
        {
            // get the components in the correct range
            int r = CMath.FloatToInt(31.0f * colour.X(), 31);
            int g = CMath.FloatToInt(63.0f * colour.Y(), 63);
            int b = CMath.FloatToInt(31.0f * colour.Z(), 31);

            // pack into a single value
            return (r << 11) | (g << 5) | b;
        }
예제 #6
0
        private bool ConstructOrdering(Vec3 axis, int iteration)
        {
            // cache some values
            int count = m_colours.GetCount();
            Vec3[] values = m_colours.GetPoints();

            // build the list of dot products
            float[] dps = new float[16];
            int orderIndex = 16 * iteration;
            for (int i = 0; i < count; ++i)
            {
                dps[i] = Vec3.Dot(values[i], axis);
                m_order[orderIndex + i] = (byte)i;
            }
            // stable sort using them
            for (int i = 0; i < count; ++i)
            {
                for (int j = i; j > 0 && dps[j] < dps[j - 1]; --j)
                {
                    CMath.Swap<float>(ref dps[j], ref dps[j - 1]);
                    CMath.Swap<byte>(ref m_order[orderIndex + j], ref m_order[orderIndex + (j - 1)]);
                }
            }
            // check this ordering is unique
            for (int it = 0; it < iteration; ++it)
            {
                int prevIndex = 16 * it;
                bool same = true;
                for (int i = 0; i < count; ++i)
                {
                    if (m_order[orderIndex + i] != m_order[prevIndex + i])
                    {
                        same = false;
                        break;
                    }
                }
                if (same)
                    return false;
            }
            // copy the ordering and weight all the points
            Vec3[] unweighted = m_colours.GetPoints();
            float[] weights = m_colours.GetWeights();
            m_xsum_wsum = new Vec4(0.0f);
            for (int i = 0; i < count; ++i)
            {
                int j = m_order[orderIndex + i];
                Vec4 p = new Vec4(unweighted[j].X(), unweighted[j].Y(), unweighted[j].Z(), 1.0f);
                Vec4 w = new Vec4(weights[j]);
                Vec4 x = p * w;
                m_points_weights[i] = x;
                m_xsum_wsum += x;
            }
            return true;
        }
예제 #7
0
        protected override unsafe void Compress3(byte* block)
        {
            // cache some values
            int count = m_colours.GetCount();
            Vec3[] values = m_colours.GetPoints();

            // create a codebook
            Vec3[] codes = new Vec3[3];
            codes[0] = m_start;
            codes[1] = m_end;
            codes[2] = 0.5f * m_start + 0.5f * m_end;

            // match each point to the closest code
	        byte[] closest = new byte[16];
	        float error = 0.0f;
            for (int i = 0; i < count; ++i)
            {
                // find the closest code
                float dist = float.MaxValue;
                int idx = 0;
                for (int j = 0; j < 3; ++j)
                {
                    float d = Vec3.LengthSquared(m_metric * (values[i] - codes[j]));
                    if (d < dist)
                    {
                        dist = d;
                        idx = j;
                    }
                }

                // save the index
                closest[i] = (byte)idx;
                // accumulate the error
                error += dist;
            }
	        // save this scheme if it wins
	        if( error < m_besterror )
	        {
		        // remap the indices
		        byte[] indices = new byte[16];
                fixed (byte* fixClosest = closest, fixIndices = indices)
                {
                    m_colours.RemapIndices(fixClosest, fixIndices);
                    // save the block
                    ColourBlock.WriteColourBlock3(m_start, m_end, fixIndices, block);
                }
		        // save the error
		        m_besterror = error;
	        }
        }
예제 #8
0
        public RangeFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // initialise the metric
            bool perceptual = ((m_flags & SquishFlags.ColourMetricPerceptual) != 0);
            if (perceptual)
                m_metric = new Vec3(0.2126f, 0.7152f, 0.0722f);
            else
                m_metric = new Vec3(1.0f);

            // initialise the best error
            m_besterror = float.MaxValue;

            // cache some values
            int count = m_colours.GetCount();
            Vec3[] values = m_colours.GetPoints();
            float[] weights = m_colours.GetWeights();

            // get the covariance matrix
            Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, weights);

            // compute the principle component
            Vec3 principle = Sym3x3.ComputePrincipleComponent(covariance);

            // get the min and max range as the codebook endpoints
            Vec3 start = new Vec3(0.0f);
            Vec3 end = new Vec3(0.0f);

            if (count > 0)
            {
                float min, max;

                // compute the range
                start = end = values[0];
                min = max = Vec3.Dot(values[0], principle);
                for (int i = 1; i < count; ++i)
                {
                    float val = Vec3.Dot(values[i], principle);
                    if (val < min)
                    {
                        start = values[i];
                        min = val;
                    }
                    else if (val > max)
                    {
                        end = values[i];
                        max = val;
                    }
                }
            }
            // clamp the output to [0, 1]
            Vec3 one = new Vec3(1.0f);
            Vec3 zero = new Vec3(0.0f);
            start = Vec3.Min(one, Vec3.Max(zero, start));
            end = Vec3.Min(one, Vec3.Max(zero, end));

            // clamp to the grid and save
            Vec3 grid = new Vec3(31.0f, 63.0f, 31.0f);
            Vec3 gridrcp = new Vec3(1.0f / 31.0f, 1.0f / 63.0f, 1.0f / 31.0f);
            Vec3 half = new Vec3(0.5f);
            m_start = Vec3.Truncate(grid * start + half) * gridrcp;
            m_end = Vec3.Truncate(grid * end + half) * gridrcp;
        }
예제 #9
0
        private void ComputeEndPoints(SingleColourLookup[][] lookups)
        {
            // check each index combination (endpoint or intermediate)
            m_error = int.MaxValue;
            for (int index = 0; index < 2; ++index)
            {
                // check the error for this codebook index
		        SourceBlock[] sources = new SourceBlock[3];
		        int error = 0;
		        for( int channel = 0; channel < 3; ++channel )
		        {
                    // grab the lookup table and index for this channel
			        SingleColourLookup[] lookup = lookups[channel];
			        int target = m_colour[channel];
                    // store a pointer to the source for this channel
                    sources[channel] = lookup[target].sources[index]/* + index*/;
                    
                    // accumulate the error
                    int diff = sources[channel].error;
                    error += diff * diff;	
                }

                // keep it if the error is lower
                if (error < m_error)
                {
                    m_start = new Vec3(
                        (float)sources[0].start / 31.0f,
                        (float)sources[1].start / 63.0f,
                        (float)sources[2].start / 31.0f
                    );
                    m_end = new Vec3(
                        (float)sources[0].end / 31.0f,
                        (float)sources[1].end / 63.0f,
                        (float)sources[2].end / 31.0f
                    );
                    m_index = (byte)(2 * index);
                    m_error = error;
                }
            }
        }
예제 #10
0
 public static float LengthSquared(Vec3 v)
 {
     return Dot(v, v);
 }
예제 #11
0
 public static float Dot(Vec3 a, Vec3 b)
 {
     return a.X() * b.X() + a.Y()* b.Y() + a.Z() * b.Z();
 }
예제 #12
0
        public static Sym3x3 ComputeWeightedCovariance(int n, Vec3[] points, float[] weights)
        {
            // compute the centroid
            float total = 0.0f;
            Vec3 centroid = new Vec3(0.0f);
            for (int i = 0; i < n; ++i)
            {
                total += weights[i];
                centroid += weights[i] * points[i];
            }
            centroid /= total;

            // accumulate the covariance matrix
            Sym3x3 covariance = new Sym3x3(0.0f);
            for (int i = 0; i < n; ++i)
            {
                Vec3 a = points[i] - centroid;
                Vec3 b = weights[i] * a;

                covariance[0] += a.X() * b.X();
                covariance[1] += a.X() * b.Y();
                covariance[2] += a.X() * b.Z();
                covariance[3] += a.Y() * b.Y();
                covariance[4] += a.Y() * b.Z();
                covariance[5] += a.Z() * b.Z();
            }
            // return it
            return covariance;
        }
예제 #13
0
        public unsafe ColourSet(byte* rgba, int mask, SquishFlags flags)
        {
            m_count = 0;
            m_transparent = false;

            bool isDxt1 = ((flags & SquishFlags.Dxt1) != 0);
            bool weightByAlpha = ((flags & SquishFlags.WeightColourByAlpha) != 0);

            // create the minimal set
            for (int i = 0; i < 16; ++i)
            {
                // check this pixel is enabled
                int bit = 1 << i;
                if ((mask & bit) == 0)
                {
                    m_remap[i] = -1;
                    continue;
                }

                // check for transparent pixels when using dxt1
                if (isDxt1 && rgba[4 * i + 3] < 128)
                {
                    m_remap[i] = -1;
                    m_transparent = true;
                    continue;
                }

                // loop over previous points for a match
                for (int j = 0; ; ++j)
                {
                    // allocate a new point
                    if (j == i)
                    {
                        // normalise coordinates to [0,1]
                        float x = (float)rgba[4 * i] / 255.0f;
                        float y = (float)rgba[4 * i + 1] / 255.0f;
                        float z = (float)rgba[4 * i + 2] / 255.0f;

                        // ensure there is always non-zero weight even for zero alpha
                        float w = (float)(rgba[4 * i + 3] + 1) / 256.0f;

                        // add the point
                        m_points[m_count] = new Vec3(x, y, z);
                        m_weights[m_count] = (weightByAlpha ? w : 1.0f);
                        m_remap[i] = m_count;

                        // advance
                        ++m_count;
                        break;
                    }

                    // check for a match
                    int oldbit = 1 << j;
                    bool match = ((mask & oldbit) != 0)
                        && (rgba[4 * i] == rgba[4 * j])
                        && (rgba[4 * i + 1] == rgba[4 * j + 1])
                        && (rgba[4 * i + 2] == rgba[4 * j + 2])
                        && (rgba[4 * j + 3] >= 128 || !isDxt1);
                    if (match)
                    {
                        // get the index of the match
                        int index = m_remap[j];

                        // ensure there is always non-zero weight even for zero alpha
                        float w = (float)(rgba[4 * i + 3] + 1) / 256.0f;

                        // map to this point and increase the weight
                        m_weights[index] += (weightByAlpha ? w : 1.0f);
                        m_remap[i] = index;
                        break;
                    }
                }
            }

            // square root the weights
            for (int i = 0; i < m_count; ++i)
                m_weights[i] = CMath.Sqrt(m_weights[i]);
        }