Advertisement
Guest User

dragon-convert.py

a guest
Sep 19th, 2019
500
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.19 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. # SPDX-License-Identifier: CC0-1.0
  3. import struct
  4. from pathlib import Path
  5. import shutil
  6.  
  7. from convert import split
  8.  
  9. def pixel_de4_to_dd4_tile8(i, fn):
  10.     with open(fn, 'wb+') as o:
  11.         data_big = i.read(2)
  12.         times = 0
  13.         packed_tile = bytearray(32)
  14.         while data_big:
  15.             pixels, = struct.unpack('<H', data_big)
  16.             rom_pixels = ((pixels & 0x0001)
  17.                           | (pixels & 0x0002) << 1
  18.                           | (pixels & 0x0004) << 2
  19.                           | (pixels & 0x0008) << 3
  20.  
  21.                           | (pixels & 0x0100) >> 7
  22.                           | (pixels & 0x0200) >> 6
  23.                           | (pixels & 0x0400) >> 5
  24.                           | (pixels & 0x0800) >> 4)
  25.  
  26.             assert not (rom_pixels & ~0xFF)
  27.             pos = (times%4)*8 + times//4
  28.             packed_tile[pos] = rom_pixels
  29.  
  30.             data_big = i.read(2)
  31.             times += 1
  32.             if times == 32:
  33.                 times = 0
  34.                 o.write(packed_tile)
  35.             assert times < 32
  36.  
  37.  
  38. def pixel_de4_to_dd4_tile16(i, path_low, path_high):
  39.     '''Convert from a DotEmu format to a "Double Dragon" 16x16 format
  40.    
  41.    The de4 (DotEmu) format holds 8 bits per pixel of which only the
  42.    lowest 4 store data. Each byte read represents a pixel, the tiles
  43.    have all their pixels together and ordered from left to right, top
  44.    to bottom.
  45.  
  46.    de4_tile16 EXPLAIN
  47.  
  48.    path_low and path_high need to be Path like objects (with an open
  49.    method)
  50.  
  51.    '''
  52.     with path_low.open('wb+') as ol, path_high.open('wb+') as oh:
  53.         data_big = i.read(4)
  54.         times = 0
  55.         packed_tile = bytearray(128)
  56.         while data_big:
  57.             pixels, = struct.unpack('<I', data_big)
  58.             rom_pixels_low = ((pixels & 0x0001)
  59.                               | (pixels & 0x0000_0002) << 3
  60.  
  61.                               | (pixels & 0x0000_0100) >> 7
  62.                               | (pixels & 0x0000_0200) >> 4
  63.  
  64.                               | (pixels & 0x0001_0000) >> 14
  65.                               | (pixels & 0x0002_0000) >> 11
  66.  
  67.                               | (pixels & 0x0100_0000) >> 21
  68.                               | (pixels & 0x0200_0000) >> 18)
  69.  
  70.             rom_pixels_high = ((pixels & 0x0004) >> 2
  71.                                | (pixels & 0x0000_0008) << 1
  72.  
  73.                                | (pixels & 0x0000_0400) >> 9
  74.                                | (pixels & 0x0000_0800) >> 6
  75.  
  76.                                | (pixels & 0x0004_0000) >> 16
  77.                                | (pixels & 0x0008_0000) >> 13
  78.  
  79.                                | (pixels & 0x0400_0000) >> 23
  80.                                | (pixels & 0x0800_0000) >> 20)
  81.  
  82.             assert not (rom_pixels_low & ~0xFF)
  83.             assert not (rom_pixels_high & ~0xFF)
  84.             pos_low = (times%4)*16 + times//4
  85.             offset = 64
  86.             packed_tile[pos_low] = rom_pixels_low
  87.             packed_tile[offset + pos_low] = rom_pixels_high
  88.  
  89.             data_big = i.read(4)
  90.             times += 1
  91.             if times == 64:
  92.                 times = 0
  93.                 ol.write(packed_tile[:64])
  94.                 oh.write(packed_tile[64:])
  95.             assert times < 64
  96.  
  97.  
  98. class MappedFiles:
  99.     def __init__(self, filenames, sizes, mode):
  100.         assert len(filenames) == len(sizes)
  101.  
  102.         self.filenames = filenames
  103.         self.sizes = sizes
  104.         self.mode = mode
  105.         self.files = []
  106.         # XXX Start is unused
  107.         self.starts = []
  108.         self.ends = []
  109.  
  110.         end = 0
  111.         for s in self.sizes:
  112.             self.starts.append(end)
  113.             end += s
  114.             self.ends.append(end)
  115.         self.end = end
  116.  
  117.         self.pos = 0
  118.     def __enter__(self):
  119.         for fn in self.filenames:
  120.             self.files.append(open(fn, self.mode))
  121.         return self
  122.     def __exit__(self, type, value, traceback):
  123.         for f in self.files:
  124.             # TODO If a exception is raised it should continue closing
  125.             # the files anyway
  126.             f.close()
  127.     def write(self, data):
  128.         while data:
  129.             assert self.pos < self.end
  130.             file_index = next(i for i, v in enumerate(self.ends)
  131.                               if v > self.pos)
  132.             max_write_length = self.ends[file_index] - self.pos
  133.             write_length = min(len(data), max_write_length)
  134.             self.files[file_index].write(data[:write_length])
  135.             self.pos += write_length
  136.             data = data[write_length:]
  137.  
  138.  
  139. class MappedFilesPathLike:
  140.     def __init__(self, filenames, sizes):
  141.         self.filenames = filenames
  142.         self.sizes = sizes
  143.         self.mf = None
  144.  
  145.     def open(self, mode):
  146.         if self.mf is None:
  147.             self.mf = MappedFiles(self.filenames, self.sizes, mode)
  148.         return self.mf
  149.  
  150.  
  151. def ddragon(outdir):
  152.     ddragon = outdir / 'ddragon'
  153.     ddragon.mkdir(exist_ok=True)
  154.  
  155.     with open('ddragon_hd6309.bin', 'rb') as i:
  156.         maincpu_parts = [
  157.             (ddragon / '21j-1-5.26', 0x8000),
  158.             (ddragon / '21j-2-3.25', 0x8000),
  159.             (ddragon / '21j-3.24', 0x8000),
  160.             (ddragon / '21j-4-1.23', 0x8000)
  161.         ]
  162.         split(i, maincpu_parts)
  163.     sub_source = Path('ddragon_hd63701.bin')
  164.     sub = Path(ddragon / '21jm-0.ic55')
  165.     shutil.copyfile(sub_source, sub)
  166.     soundcpu_source = Path('ddragon_m6809.bin')
  167.     soundcpu = Path(ddragon / '21j-0-1')
  168.     shutil.copyfile(soundcpu_source, soundcpu)
  169.     with open('ddragon_gfxdata1.bin', 'rb') as i:
  170.         pixel_de4_to_dd4_tile8(i, ddragon / '21j-5')
  171.     with open('ddragon_gfxdata2.bin', 'rb') as i:
  172.         size = 0x01_0000
  173.  
  174.         low0 = ddragon / '21j-a'
  175.         low1 = ddragon / '21j-b'
  176.         low2 = ddragon / '21j-c'
  177.         low3 = ddragon / '21j-d'
  178.  
  179.         high0 = ddragon / '21j-e'
  180.         high1 = ddragon / '21j-f'
  181.         high2 = ddragon / '21j-g'
  182.         high3 = ddragon / '21j-h'
  183.  
  184.         low = MappedFilesPathLike([low0, low1, low2, low3],
  185.                                   [size]*4)
  186.         high = MappedFilesPathLike([high0, high1, high2, high3],
  187.                                    [size]*4)
  188.         pixel_de4_to_dd4_tile16(i, low, high)
  189.     with open('ddragon_gfxdata3.bin', 'rb') as i:
  190.         size = 0x01_0000
  191.        
  192.         low0 = ddragon / '21j-8'
  193.         low1 = ddragon / '21j-9'
  194.  
  195.         high0 = ddragon / '21j-i'
  196.         high1 = ddragon / '21j-j'
  197.  
  198.         low = MappedFilesPathLike([low0, low1],
  199.                                   [size]*2)
  200.         high = MappedFilesPathLike([high0, high1],
  201.                                    [size]*2)
  202.         pixel_de4_to_dd4_tile16(i, low, high)
  203.     with open('ddragon_adpcm.bin', 'rb') as i:
  204.         adpcm_parts = [
  205.             (ddragon / '21j-6', 0x01_0000),
  206.             (ddragon / '21j-7', 0x01_0000)
  207.         ]
  208.         split(i, adpcm_parts)
  209.     with open('proms.bin', 'rb') as i:
  210.         proms_parts = [
  211.             (ddragon / '21j-k-0', 0x0100),
  212.             (ddragon / '21j-l-0', 0x0200)
  213.         ]
  214.         split(i, proms_parts)
  215.  
  216. def ddragon2(outdir):
  217.     ddragon2 = outdir / 'ddragon2'
  218.     ddragon2.mkdir(exist_ok=True)
  219.    
  220.     with open('ddragon2_hd6309.bin', 'rb') as i:
  221.         maincpu_parts = [
  222.             (ddragon2 / '26a9-04.bin', 0x8000),
  223.             (ddragon2 / '26aa-03.bin', 0x8000),
  224.             (ddragon2 / '26ab-0.bin', 0x8000),
  225.             (ddragon2 / '26ac-0e.63', 0x8000)
  226.         ]
  227.         split(i, maincpu_parts)
  228.     sub_source = Path('ddragon2_z80sub.bin')
  229.     sub = Path(ddragon2 / '26ae-0.bin')
  230.     shutil.copyfile(sub_source, sub)
  231.     soundcpu_source = Path('ddragon2_z80sound.bin')
  232.     soundcpu = Path(ddragon2 / '26ad-0.bin')
  233.     shutil.copyfile(soundcpu_source, soundcpu)
  234.     with open('ddragon2_gfxdata1.bin', 'rb') as i:
  235.         pixel_de4_to_dd4_tile8(i, ddragon2 / '26a8-0e.19')
  236.     with open('ddragon2_gfxdata2.bin', 'rb') as i:
  237.         low0 = ddragon2 / '26j0-0.bin'
  238.         low1 = ddragon2 / '26j1-0.bin'
  239.         low2 = ddragon2 / '26af-0.bin'
  240.  
  241.         high0 = ddragon2 / '26j2-0.bin'
  242.         high1 = ddragon2 / '26j3-0.bin'
  243.         high2 = ddragon2 / '26a10-0.bin'
  244.  
  245.         low = MappedFilesPathLike([low0, low1, low2],
  246.                                   [0x02_0000, 0x02_0000, 0x02_0000])
  247.         high = MappedFilesPathLike([high0, high1, high2],
  248.                                    [0x02_0000, 0x02_0000, 0x02_0000])
  249.         pixel_de4_to_dd4_tile16(i, low, high)
  250.     with open('ddragon2_gfxdata3.bin', 'rb') as i:
  251.         low = Path(ddragon2 / '26j4-0.bin')
  252.         high = Path(ddragon2 / '26j5-0.bin')
  253.         pixel_de4_to_dd4_tile16(i, low, high)
  254.     with open('ddragon2_oki.bin', 'rb') as i:
  255.         proms_parts = [
  256.             (ddragon2 / '26j6-0.bin', 0x02_0000),
  257.             (ddragon2 / '26j7-0.bin', 0x02_0000)
  258.         ]
  259.         split(i, proms_parts)
  260.     with open('proms.bin', 'rb') as i:
  261.         proms_parts = [
  262.             ('unk_prom', 0x0100),
  263.             (ddragon2 / 'prom.16', 0x0200)
  264.         ]
  265.         split(i, proms_parts)
  266.  
  267. def dragon_convert():
  268.     outdir = Path('mame')
  269.     outdir.mkdir(exist_ok=True)
  270.  
  271.     ddragon(outdir)
  272.     ddragon2(outdir)
  273.  
  274. if __name__ == '__main__':
  275.     dragon_convert()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement