@ -25,6 +25,17 @@ Keep in mind that the coordinates will be rounded down to the next lowest textur
( ( ( ( y ) / 512 ) & 1 ) < < 11 ) \
( ( ( ( y ) / 512 ) & 1 ) < < 11 ) \
)
)
// A straight conversion of the Quake palette colors comes out looking rather over-saturated.
// So we desaturate the palette ahead of time to more closely match the original Quake's look.
static void desaturate ( const unsigned char inColor [ 3 ] , unsigned char outColor [ 3 ] )
{
double f = 0.15 ; // desaturate by 15%
double L = 0.3 * inColor [ 0 ] + 0.6 * inColor [ 1 ] + 0.1 * inColor [ 2 ] ;
outColor [ 0 ] = ( unsigned char ) ( ( double ) inColor [ 0 ] + f * ( L - inColor [ 0 ] ) ) ;
outColor [ 1 ] = ( unsigned char ) ( ( double ) inColor [ 1 ] + f * ( L - inColor [ 1 ] ) ) ;
outColor [ 2 ] = ( unsigned char ) ( ( double ) inColor [ 2 ] + f * ( L - inColor [ 2 ] ) ) ;
}
static bool generate_clut ( const char * paletteFile , tim : : PARAM * outTim )
static bool generate_clut ( const char * paletteFile , tim : : PARAM * outTim )
{
{
unsigned char palette [ PALETTE_SIZE * 3 ] ;
unsigned char palette [ PALETTE_SIZE * 3 ] ;
@ -43,9 +54,12 @@ static bool generate_clut(const char* paletteFile, tim::PARAM* outTim)
for ( int c = 0 ; c < PALETTE_SIZE ; + + c )
for ( int c = 0 ; c < PALETTE_SIZE ; + + c )
{
{
clut [ c ] . r = palette [ 3 * c + 0 ] > > 3 ;
clut [ c ] . g = palette [ 3 * c + 1 ] > > 3 ;
clut [ c ] . b = palette [ 3 * c + 2 ] > > 3 ;
unsigned char color [ 3 ] ;
desaturate ( & palette [ 3 * c ] , color ) ;
clut [ c ] . r = color [ 0 ] > > 3 ;
clut [ c ] . g = color [ 1 ] > > 3 ;
clut [ c ] . b = color [ 2 ] > > 3 ;
clut [ c ] . i = ( c = = 255 ) ; // Final palette entry is for transparencies
clut [ c ] . i = ( c = = 255 ) ; // Final palette entry is for transparencies
// Completely black pixels are regarded as transparent by the PS1, so prevent that from happening by making those palette entries *nearly* black
// Completely black pixels are regarded as transparent by the PS1, so prevent that from happening by making those palette entries *nearly* black
@ -91,7 +105,7 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
int ps1mip = miptex - > width > 64 | | miptex - > height > 64 ? 1 : 0 ;
int ps1mip = miptex - > width > 64 | | miptex - > height > 64 ? 1 : 0 ;
// Make an exception for the difficulty selection teleporters
// Make an exception for the difficulty selection teleporters
if ( ! strncmp ( miptex - > name , " skill " , 5 ) ) // || !strcmp(miptex->name, "quake"))
if ( ! strncmp ( miptex - > name , " skill " , 5 ) )
ps1mip = 0 ;
ps1mip = 0 ;
// Ensure we don't include any textures that are larger than the PS1 can address
// Ensure we don't include any textures that are larger than the PS1 can address
@ -101,6 +115,8 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
ps1mip + + ;
ps1mip + + ;
// TODO: make an exception for the QUAKE sign that's displayed on the start map. It needs to be bold and detailed, but it's too wide for the PS1 to address at full resolution, so it'll need to be broken up.
// TODO: make an exception for the QUAKE sign that's displayed on the start map. It needs to be bold and detailed, but it's too wide for the PS1 to address at full resolution, so it'll need to be broken up.
if ( ! strcmp ( miptex - > name , " quake " ) )
ps1mip - - ;
if ( strcmp ( miptex - > name , " clip " ) & & strcmp ( miptex - > name , " trigger " ) )
if ( strcmp ( miptex - > name , " clip " ) & & strcmp ( miptex - > name , " trigger " ) )
rectangles . emplace_back ( rectpack2D : : rect_xywh ( 0 , 0 , miptex - > width > > ps1mip , miptex - > height > > ps1mip ) ) ;
rectangles . emplace_back ( rectpack2D : : rect_xywh ( 0 , 0 , miptex - > width > > ps1mip , miptex - > height > > ps1mip ) ) ;