3434# that people want to expand on this goofy project and worry about
3535# compatibility, we define a constant for the file format that is written into
3636# the output file.
37- FILE_FORMAT = 3
37+ FILE_FORMAT = 4
3838
3939# Number of tiles (w, h) for fullscreen and thumbnail sizes.
4040FULLSCREEN_TILES = (32 , 28 )
@@ -493,7 +493,7 @@ def dump_debug_file(frame_dir, audio_dir, args):
493493 run (args .debug , check = True , args = ffmpeg_args )
494494
495495
496- def png_to_sega_frame (in_path , out_file , expected_tiles ):
496+ def png_to_sega_frame (in_path , out_file , expected_tiles , dedup ):
497497 img = Image .open (in_path )
498498 pixels = img .getdata ()
499499 width , height = img .size
@@ -513,6 +513,7 @@ def png_to_sega_frame(in_path, out_file, expected_tiles):
513513
514514 # Each tile is 8x8 pixels, 4 bit palette index per pixel.
515515 binary_tiles = b''
516+ tile_map = []
516517
517518 # The image dimensions should each be a multiple of 8 already.
518519 assert width % 8 == 0 and height % 8 == 0
@@ -522,6 +523,8 @@ def png_to_sega_frame(in_path, out_file, expected_tiles):
522523 # We should have a fullscreen image.
523524 assert (tiles_width , tiles_height ) == expected_tiles
524525
526+ binary_tile_to_index = {}
527+
525528 for tile_y in range (tiles_height ):
526529 for tile_x in range (tiles_width ):
527530 tile = []
@@ -539,15 +542,33 @@ def png_to_sega_frame(in_path, out_file, expected_tiles):
539542
540543 tile .append (palette_index )
541544
542- binary_tiles += pack_tile (tile )
545+ binary_tile = pack_tile (tile )
546+ index = binary_tile_to_index .get (binary_tile , None )
547+ if dedup == False :
548+ index = None
549+
550+ if index is None :
551+ index = len (binary_tile_to_index )
552+ binary_tile_to_index [binary_tile ] = index
553+ binary_tiles += binary_tile
554+
555+ tile_map .append (index )
543556
544- # SegaVideoFrameHeader contains the palette only
557+ # Output the palette
545558 out_file .write (pack_palette (palette ))
559+
560+ if dedup == True :
561+ # Pack the tile map
562+ out_file .write (pack_tile_map (tile_map ))
563+ # The number of tiles to follow
564+ out_file .write (len (binary_tile_to_index ).to_bytes (4 , 'big' ))
565+
546566 # Actual tile data follows
547567 out_file .write (binary_tiles )
548568
549- # A palette is always 32 bytes
550- return 32 + len (binary_tiles )
569+ # A palette is always 32 bytes, the tile map is 1792 bytes, the number of
570+ # tiles is encoded in 4 bytes.
571+ return 32 + 1792 + 4 + len (binary_tiles )
551572
552573
553574def sega_color_map (value ):
@@ -654,7 +675,7 @@ def write_chunk(f, state):
654675 chunk_frame_data_len = 0
655676 for i in range (chunk_frame_count ):
656677 input_path = state .frame_paths [state .frame_path_index ]
657- bytes_written = png_to_sega_frame (input_path , f , FULLSCREEN_TILES )
678+ bytes_written = png_to_sega_frame (input_path , f , FULLSCREEN_TILES , dedup = True )
658679 chunk_frame_data_len += bytes_written
659680 state .frame_count -= 1
660681 state .frame_path_index += 1
@@ -854,7 +875,7 @@ def generate_thumbnail(args, fullcolor_dir, thumb_dir):
854875
855876 # Then convert to Sega format.
856877 with open (sega_frame_out , 'wb' ) as f :
857- png_to_sega_frame (thumb_out , f , THUMBNAIL_TILES )
878+ png_to_sega_frame (thumb_out , f , THUMBNAIL_TILES , dedup = False )
858879
859880 print ('Thumbnail generated from frame #{}.' .format (thumb_index + 1 ))
860881
0 commit comments