1*2f083884Ss.makeev_local /* -----------------------------------------------------------------------------
2*2f083884Ss.makeev_local 
3*2f083884Ss.makeev_local 	Copyright (c) 2006 Simon Brown                          [email protected]
4*2f083884Ss.makeev_local 
5*2f083884Ss.makeev_local 	Permission is hereby granted, free of charge, to any person obtaining
6*2f083884Ss.makeev_local 	a copy of this software and associated documentation files (the
7*2f083884Ss.makeev_local 	"Software"), to	deal in the Software without restriction, including
8*2f083884Ss.makeev_local 	without limitation the rights to use, copy, modify, merge, publish,
9*2f083884Ss.makeev_local 	distribute, sublicense, and/or sell copies of the Software, and to
10*2f083884Ss.makeev_local 	permit persons to whom the Software is furnished to do so, subject to
11*2f083884Ss.makeev_local 	the following conditions:
12*2f083884Ss.makeev_local 
13*2f083884Ss.makeev_local 	The above copyright notice and this permission notice shall be included
14*2f083884Ss.makeev_local 	in all copies or substantial portions of the Software.
15*2f083884Ss.makeev_local 
16*2f083884Ss.makeev_local 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17*2f083884Ss.makeev_local 	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*2f083884Ss.makeev_local 	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19*2f083884Ss.makeev_local 	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20*2f083884Ss.makeev_local 	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21*2f083884Ss.makeev_local 	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22*2f083884Ss.makeev_local 	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23*2f083884Ss.makeev_local 
24*2f083884Ss.makeev_local    -------------------------------------------------------------------------- */
25*2f083884Ss.makeev_local 
26*2f083884Ss.makeev_local #include "singlecolourfit.h"
27*2f083884Ss.makeev_local #include "colourset.h"
28*2f083884Ss.makeev_local #include "colourblock.h"
29*2f083884Ss.makeev_local #include <limits>
30*2f083884Ss.makeev_local 
31*2f083884Ss.makeev_local namespace squish {
32*2f083884Ss.makeev_local 
33*2f083884Ss.makeev_local struct SourceBlock
34*2f083884Ss.makeev_local {
35*2f083884Ss.makeev_local 	u8 start;
36*2f083884Ss.makeev_local 	u8 end;
37*2f083884Ss.makeev_local 	u8 error;
38*2f083884Ss.makeev_local };
39*2f083884Ss.makeev_local 
40*2f083884Ss.makeev_local struct SingleColourLookup
41*2f083884Ss.makeev_local {
42*2f083884Ss.makeev_local 	SourceBlock sources[2];
43*2f083884Ss.makeev_local };
44*2f083884Ss.makeev_local 
45*2f083884Ss.makeev_local #include "singlecolourlookup.inl"
46*2f083884Ss.makeev_local 
FloatToInt(float a,int limit)47*2f083884Ss.makeev_local static int FloatToInt( float a, int limit )
48*2f083884Ss.makeev_local {
49*2f083884Ss.makeev_local 	// use ANSI round-to-zero behaviour to get round-to-nearest
50*2f083884Ss.makeev_local 	int i = ( int )( a + 0.5f );
51*2f083884Ss.makeev_local 
52*2f083884Ss.makeev_local 	// clamp to the limit
53*2f083884Ss.makeev_local 	if( i < 0 )
54*2f083884Ss.makeev_local 		i = 0;
55*2f083884Ss.makeev_local 	else if( i > limit )
56*2f083884Ss.makeev_local 		i = limit;
57*2f083884Ss.makeev_local 
58*2f083884Ss.makeev_local 	// done
59*2f083884Ss.makeev_local 	return i;
60*2f083884Ss.makeev_local }
61*2f083884Ss.makeev_local 
SingleColourFit(ColourSet const * colours,int flags)62*2f083884Ss.makeev_local SingleColourFit::SingleColourFit( ColourSet const* colours, int flags )
63*2f083884Ss.makeev_local   : ColourFit( colours, flags )
64*2f083884Ss.makeev_local {
65*2f083884Ss.makeev_local 	// grab the single colour
66*2f083884Ss.makeev_local 	Vec3 const* values = m_colours->GetPoints();
67*2f083884Ss.makeev_local 	m_colour[0] = ( u8 )FloatToInt( 255.0f*values->X(), 255 );
68*2f083884Ss.makeev_local 	m_colour[1] = ( u8 )FloatToInt( 255.0f*values->Y(), 255 );
69*2f083884Ss.makeev_local 	m_colour[2] = ( u8 )FloatToInt( 255.0f*values->Z(), 255 );
70*2f083884Ss.makeev_local 
71*2f083884Ss.makeev_local 	// initialise the best error
72*2f083884Ss.makeev_local 	m_besterror = std::numeric_limits<int>::max();
73*2f083884Ss.makeev_local }
74*2f083884Ss.makeev_local 
Compress3(void * block)75*2f083884Ss.makeev_local void SingleColourFit::Compress3( void* block )
76*2f083884Ss.makeev_local {
77*2f083884Ss.makeev_local 	// build the table of lookups
78*2f083884Ss.makeev_local 	SingleColourLookup const* const lookups[] =
79*2f083884Ss.makeev_local 	{
80*2f083884Ss.makeev_local 		lookup_5_3,
81*2f083884Ss.makeev_local 		lookup_6_3,
82*2f083884Ss.makeev_local 		lookup_5_3
83*2f083884Ss.makeev_local 	};
84*2f083884Ss.makeev_local 
85*2f083884Ss.makeev_local 	// find the best end-points and index
86*2f083884Ss.makeev_local 	ComputeEndPoints( lookups );
87*2f083884Ss.makeev_local 
88*2f083884Ss.makeev_local 	// build the block if we win
89*2f083884Ss.makeev_local 	if( m_error < m_besterror )
90*2f083884Ss.makeev_local 	{
91*2f083884Ss.makeev_local 		// remap the indices
92*2f083884Ss.makeev_local 		u8 indices[16];
93*2f083884Ss.makeev_local 		m_colours->RemapIndices( &m_index, indices );
94*2f083884Ss.makeev_local 
95*2f083884Ss.makeev_local 		// save the block
96*2f083884Ss.makeev_local 		WriteColourBlock3( m_start, m_end, indices, block );
97*2f083884Ss.makeev_local 
98*2f083884Ss.makeev_local 		// save the error
99*2f083884Ss.makeev_local 		m_besterror = m_error;
100*2f083884Ss.makeev_local 	}
101*2f083884Ss.makeev_local }
102*2f083884Ss.makeev_local 
Compress4(void * block)103*2f083884Ss.makeev_local void SingleColourFit::Compress4( void* block )
104*2f083884Ss.makeev_local {
105*2f083884Ss.makeev_local 	// build the table of lookups
106*2f083884Ss.makeev_local 	SingleColourLookup const* const lookups[] =
107*2f083884Ss.makeev_local 	{
108*2f083884Ss.makeev_local 		lookup_5_4,
109*2f083884Ss.makeev_local 		lookup_6_4,
110*2f083884Ss.makeev_local 		lookup_5_4
111*2f083884Ss.makeev_local 	};
112*2f083884Ss.makeev_local 
113*2f083884Ss.makeev_local 	// find the best end-points and index
114*2f083884Ss.makeev_local 	ComputeEndPoints( lookups );
115*2f083884Ss.makeev_local 
116*2f083884Ss.makeev_local 	// build the block if we win
117*2f083884Ss.makeev_local 	if( m_error < m_besterror )
118*2f083884Ss.makeev_local 	{
119*2f083884Ss.makeev_local 		// remap the indices
120*2f083884Ss.makeev_local 		u8 indices[16];
121*2f083884Ss.makeev_local 		m_colours->RemapIndices( &m_index, indices );
122*2f083884Ss.makeev_local 
123*2f083884Ss.makeev_local 		// save the block
124*2f083884Ss.makeev_local 		WriteColourBlock4( m_start, m_end, indices, block );
125*2f083884Ss.makeev_local 
126*2f083884Ss.makeev_local 		// save the error
127*2f083884Ss.makeev_local 		m_besterror = m_error;
128*2f083884Ss.makeev_local 	}
129*2f083884Ss.makeev_local }
130*2f083884Ss.makeev_local 
ComputeEndPoints(SingleColourLookup const * const * lookups)131*2f083884Ss.makeev_local void SingleColourFit::ComputeEndPoints( SingleColourLookup const* const* lookups )
132*2f083884Ss.makeev_local {
133*2f083884Ss.makeev_local 	// check each index combination (endpoint or intermediate)
134*2f083884Ss.makeev_local 	m_error = std::numeric_limits<int>::max();
135*2f083884Ss.makeev_local 	for( int index = 0; index < 2; ++index )
136*2f083884Ss.makeev_local 	{
137*2f083884Ss.makeev_local 		// check the error for this codebook index
138*2f083884Ss.makeev_local 		SourceBlock const* sources[3];
139*2f083884Ss.makeev_local 		int error = 0;
140*2f083884Ss.makeev_local 		for( int channel = 0; channel < 3; ++channel )
141*2f083884Ss.makeev_local 		{
142*2f083884Ss.makeev_local 			// grab the lookup table and index for this channel
143*2f083884Ss.makeev_local 			SingleColourLookup const* lookup = lookups[channel];
144*2f083884Ss.makeev_local 			int target = m_colour[channel];
145*2f083884Ss.makeev_local 
146*2f083884Ss.makeev_local 			// store a pointer to the source for this channel
147*2f083884Ss.makeev_local 			sources[channel] = lookup[target].sources + index;
148*2f083884Ss.makeev_local 
149*2f083884Ss.makeev_local 			// accumulate the error
150*2f083884Ss.makeev_local 			int diff = sources[channel]->error;
151*2f083884Ss.makeev_local 			error += diff*diff;
152*2f083884Ss.makeev_local 		}
153*2f083884Ss.makeev_local 
154*2f083884Ss.makeev_local 		// keep it if the error is lower
155*2f083884Ss.makeev_local 		if( error < m_error )
156*2f083884Ss.makeev_local 		{
157*2f083884Ss.makeev_local 			m_start = Vec3(
158*2f083884Ss.makeev_local 				( float )sources[0]->start/31.0f,
159*2f083884Ss.makeev_local 				( float )sources[1]->start/63.0f,
160*2f083884Ss.makeev_local 				( float )sources[2]->start/31.0f
161*2f083884Ss.makeev_local 			);
162*2f083884Ss.makeev_local 			m_end = Vec3(
163*2f083884Ss.makeev_local 				( float )sources[0]->end/31.0f,
164*2f083884Ss.makeev_local 				( float )sources[1]->end/63.0f,
165*2f083884Ss.makeev_local 				( float )sources[2]->end/31.0f
166*2f083884Ss.makeev_local 			);
167*2f083884Ss.makeev_local 			m_index = ( u8 )( 2*index );
168*2f083884Ss.makeev_local 			m_error = error;
169*2f083884Ss.makeev_local 		}
170*2f083884Ss.makeev_local 	}
171*2f083884Ss.makeev_local }
172*2f083884Ss.makeev_local 
173*2f083884Ss.makeev_local } // namespace squish
174