medfall

A super great game engine
Log | Files | Refs

colourblock.cc (5237B)


      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 "colourblock.h"
     27 
     28 namespace squish {
     29 
     30 static int FloatToInt( float a, int limit )
     31 {
     32 	// use ANSI round-to-zero behaviour to get round-to-nearest
     33 	int i = ( int )( a + 0.5f );
     34 
     35 	// clamp to the limit
     36 	if( i < 0 )
     37 		i = 0;
     38 	else if( i > limit )
     39 		i = limit; 
     40 
     41 	// done
     42 	return i;
     43 }
     44 
     45 static int FloatTo565( Vec3::Arg colour )
     46 {
     47 	// get the components in the correct range
     48 	int r = FloatToInt( 31.0f*colour.X(), 31 );
     49 	int g = FloatToInt( 63.0f*colour.Y(), 63 );
     50 	int b = FloatToInt( 31.0f*colour.Z(), 31 );
     51 	
     52 	// pack into a single value
     53 	return ( r << 11 ) | ( g << 5 ) | b;
     54 }
     55 
     56 static void WriteColourBlock( int a, int b, u8* indices, void* block )
     57 {
     58 	// get the block as bytes
     59 	u8* bytes = ( u8* )block;
     60 
     61 	// write the endpoints
     62 	bytes[0] = ( u8 )( a & 0xff );
     63 	bytes[1] = ( u8 )( a >> 8 );
     64 	bytes[2] = ( u8 )( b & 0xff );
     65 	bytes[3] = ( u8 )( b >> 8 );
     66 	
     67 	// write the indices
     68 	for( int i = 0; i < 4; ++i )
     69 	{
     70 		u8 const* ind = indices + 4*i;
     71 		bytes[4 + i] = ind[0] | ( ind[1] << 2 ) | ( ind[2] << 4 ) | ( ind[3] << 6 );
     72 	}
     73 }
     74 
     75 void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
     76 {
     77 	// get the packed values
     78 	int a = FloatTo565( start );
     79 	int b = FloatTo565( end );
     80 
     81 	// remap the indices
     82 	u8 remapped[16];
     83 	if( a <= b )
     84 	{
     85 		// use the indices directly
     86 		for( int i = 0; i < 16; ++i )
     87 			remapped[i] = indices[i];
     88 	}
     89 	else
     90 	{
     91 		// swap a and b
     92 		std::swap( a, b );
     93 		for( int i = 0; i < 16; ++i )
     94 		{
     95 			if( indices[i] == 0 )
     96 				remapped[i] = 1;
     97 			else if( indices[i] == 1 )
     98 				remapped[i] = 0;
     99 			else
    100 				remapped[i] = indices[i];
    101 		}
    102 	}
    103 	
    104 	// write the block
    105 	WriteColourBlock( a, b, remapped, block );
    106 }
    107 
    108 void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
    109 {
    110 	// get the packed values
    111 	int a = FloatTo565( start );
    112 	int b = FloatTo565( end );
    113 
    114 	// remap the indices
    115 	u8 remapped[16];
    116 	if( a < b )
    117 	{
    118 		// swap a and b
    119 		std::swap( a, b );
    120 		for( int i = 0; i < 16; ++i )
    121 			remapped[i] = ( indices[i] ^ 0x1 ) & 0x3;
    122 	}
    123 	else if( a == b )
    124 	{
    125 		// use index 0
    126 		for( int i = 0; i < 16; ++i )
    127 			remapped[i] = 0;
    128 	}
    129 	else
    130 	{
    131 		// use the indices directly
    132 		for( int i = 0; i < 16; ++i )
    133 			remapped[i] = indices[i];
    134 	}
    135 	
    136 	// write the block
    137 	WriteColourBlock( a, b, remapped, block );
    138 }
    139 
    140 static int Unpack565( u8 const* packed, u8* colour )
    141 {
    142 	// build the packed value
    143 	int value = ( int )packed[0] | ( ( int )packed[1] << 8 );
    144 	
    145 	// get the components in the stored range
    146 	u8 red = ( u8 )( ( value >> 11 ) & 0x1f );
    147 	u8 green = ( u8 )( ( value >> 5 ) & 0x3f );
    148 	u8 blue = ( u8 )( value & 0x1f );
    149 
    150 	// scale up to 8 bits
    151 	colour[0] = ( red << 3 ) | ( red >> 2 );
    152 	colour[1] = ( green << 2 ) | ( green >> 4 );
    153 	colour[2] = ( blue << 3 ) | ( blue >> 2 );
    154 	colour[3] = 255;
    155 	
    156 	// return the value
    157 	return value;
    158 }
    159 
    160 void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
    161 {
    162 	// get the block bytes
    163 	u8 const* bytes = reinterpret_cast< u8 const* >( block );
    164 	
    165 	// unpack the endpoints
    166 	u8 codes[16];
    167 	int a = Unpack565( bytes, codes );
    168 	int b = Unpack565( bytes + 2, codes + 4 );
    169 	
    170 	// generate the midpoints
    171 	for( int i = 0; i < 3; ++i )
    172 	{
    173 		int c = codes[i];
    174 		int d = codes[4 + i];
    175 
    176 		if( isDxt1 && a <= b )
    177 		{
    178 			codes[8 + i] = ( u8 )( ( c + d )/2 );
    179 			codes[12 + i] = 0;
    180 		}
    181 		else
    182 		{
    183 			codes[8 + i] = ( u8 )( ( 2*c + d )/3 );
    184 			codes[12 + i] = ( u8 )( ( c + 2*d )/3 );
    185 		}
    186 	}
    187 	
    188 	// fill in alpha for the intermediate values
    189 	codes[8 + 3] = 255;
    190 	codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255;
    191 	
    192 	// unpack the indices
    193 	u8 indices[16];
    194 	for( int i = 0; i < 4; ++i )
    195 	{
    196 		u8* ind = indices + 4*i;
    197 		u8 packed = bytes[4 + i];
    198 		
    199 		ind[0] = packed & 0x3;
    200 		ind[1] = ( packed >> 2 ) & 0x3;
    201 		ind[2] = ( packed >> 4 ) & 0x3;
    202 		ind[3] = ( packed >> 6 ) & 0x3;
    203 	}
    204 
    205 	// store out the colours
    206 	for( int i = 0; i < 16; ++i )
    207 	{
    208 		u8 offset = 4*indices[i];
    209 		for( int j = 0; j < 4; ++j )
    210 			rgba[4*i + j] = codes[offset + j];
    211 	}
    212 }
    213 
    214 } // namespace squish