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