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