@ -46,7 +46,7 @@ static bool generate_clut(const char* paletteFile, tim::PARAM* outTim)
clut [ c ] . r = palette [ 3 * c + 0 ] > > 3 ;
clut [ c ] . g = palette [ 3 * c + 1 ] > > 3 ;
clut [ c ] . b = palette [ 3 * c + 2 ] > > 3 ;
clut [ c ] . i = 0 ;
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
if ( clut [ c ] . r = = 0 & & clut [ c ] . g = = 0 & & clut [ c ] . b = = 0 )
@ -69,10 +69,11 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
} ;
auto report_unsuccessful = [ ] ( rect_type & ) {
printf ( " Failed to fit all textures into atlas! \n " ) ;
return rectpack2D : : callback_result : : ABORT_PACKING ;
} ;
const auto max_side = 512 ; // Max height of PS1 VRAM. 8-bit textures take up half the horizontal space so this is 512x256 in practice, or a quarter of the PS1's VRAM allocation.
const auto max_bin = rectpack2D : : rect_wh ( 1024 , 256 ) ; // 8-bit textures take up half the horizontal space so this is 512x256 in practice, or a quarter of the PS1's VRAM allocation.
const auto discard_step = - 4 ;
std : : vector < rect_type > rectangles ;
@ -99,11 +100,10 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
rectangles . emplace_back ( rectpack2D : : rect_xywh ( 0 , 0 , miptex - > width > > 3 , miptex - > width > > 3 ) ) ; // Add the lowest mip level so that it at least gets included in the final texture list, and we don't mess up the texture IDs
}
// Automatic atlas packing. Nice but it tries to make a square atlas which is not what we want. (This is solved by hacking the header itself)
const auto result_size = rectpack2D : : find_best_packing < spaces_type > (
rectangles ,
rectpack2D : : make_finder_input (
max_side ,
max_bin ,
discard_step ,
report_successful ,
report_unsuccessful ,
@ -112,12 +112,7 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
) ;
printf ( " %d textures. Packed texture atlas size: %d x %d \n " , world - > mipheader . numtex , result_size . w , result_size . h ) ;
unsigned char * atlas = ( unsigned char * ) malloc ( result_size . w * result_size . h * sizeof ( unsigned char ) ) ;
if ( atlas = = NULL )
return false ;
memset ( atlas , 0 , result_size . w * result_size . h * sizeof ( unsigned char ) ) ;
tim : : PARAM outTim = { 0 } ;
outTim . format = 1 ; // 8-bit per pixel, all Quake textures use this
outTim . imgXoffs = 512 ;
@ -126,6 +121,14 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
outTim . clutYoffs = 0 ;
generate_clut ( " palette.lmp " , & outTim ) ;
outTim . imgWidth = result_size . w ;
outTim . imgHeight = result_size . h ;
outTim . imgData = malloc ( result_size . w * result_size . h * sizeof ( unsigned char ) ) ;
if ( outTim . imgData = = NULL )
return false ;
memset ( outTim . imgData , 0 , result_size . w * result_size . h * sizeof ( unsigned char ) ) ;
// Try to construct the texture atlas, see what we get
for ( int texNum = 0 ; texNum < world - > mipheader . numtex ; + + texNum )
{
@ -147,9 +150,10 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
const auto & rectangle = rectangles [ texNum ] ;
if ( miptex - > width > > mipLevel = = rectangle . w ) // This is the mip level we've previously decided we want for our PS1 atlas
{
// Copy the source texture line by line into the atlas at the desired position
for ( int y = 0 ; y < rectangle . h ; + + y )
{
memcpy_s ( atlas + ( ( rectangle . y + y ) * result_size . w + rectangle . x ) , rectangle . w * sizeof ( unsigned char ) , texBytes + ( y * rectangle . w ) , rectangle . w * sizeof ( unsigned char ) ) ;
memcpy_s ( ( unsigned char * ) outTim . imgData + ( ( rectangle . y + y ) * result_size . w + rectangle . x ) , rectangle . w * sizeof ( unsigned char ) , texBytes + ( y * rectangle . w ) , rectangle . w * sizeof ( unsigned char ) ) ;
}
ps1bsp_texture_t ps1tex = { 0 } ;
@ -169,10 +173,6 @@ bool process_textures(const world_t* world, std::vector<ps1bsp_texture_t>& outTe
}
}
outTim . imgData = atlas ;
outTim . imgWidth = result_size . w ;
outTim . imgHeight = result_size . h ;
sprintf_s ( path , _MAX_PATH , " atlas-%s.tim " , world - > name ) ;
tim : : ExportFile ( path , & outTim ) ;