Also extract the draw_misc (non-shiftable) shapes
authorNick Downing <nick@ndcode.org>
Tue, 28 Jun 2022 14:28:22 +0000 (00:28 +1000)
committerNick Downing <nick@ndcode.org>
Tue, 28 Jun 2022 14:57:23 +0000 (00:57 +1000)
galaxian/galaxian.txt
galaxian/shape_extract.py
galaxian/shape_extract_png.py

index bcc7176..c552b21 100644 (file)
@@ -26,6 +26,7 @@ items
 # draw_y0 + 1: for erasing
 0x0012,0x0002,draw_y0,byte
 0x0014,0x0002,video_line_ptr,word
+0x0016,0x0001,draw_misc_x_save,byte
 # lo byte of (shift count * 0x80) + shape
 # also y coordinate temporary storage
 0x0017,0x0001,draw_temp,byte
@@ -228,6 +229,11 @@ items
 0x7600,0x0380,shape_data_ptr_hi,byte
 0x7980,0x0380,shape_width_bytes,byte
 0x7d80,0x0080,shape_height,byte
+0x7e80,0x0001,draw_misc_data,byte
+0x8a80,0x0080,draw_misc_data_ptr_lo,byte
+0x8b00,0x0080,draw_misc_data_ptr_hi,byte
+0x8b80,0x0080,draw_misc_width_bytes,byte
+0x8c00,0x0080,draw_misc_height,byte
 0x8cf1,0x0008,y_8cf1,byte
 0x8d01,0x0008,velocity_hi_8d01,byte
 0x8d11,0x0008,x_hi_8d11,byte
@@ -278,7 +284,10 @@ items
 0x94e5,0x0001,,code_ign # accessing video_line_table before clipping y
 0x94fe,0x0001,,code_ign # self-modifying code assembled with garbage word
 0x94ff,0x0002,,word
+0x951c,0x0002,draw_misc_data_ptr_base,word
 # draws over previous video contents
+# a = shape to draw
+# draw_x1 = x0 for drawing and is advanced by routine
 0x951e,0x0001,draw_misc,code
 0x955d,0x0001,,code_ign # self-modifying code assembled with garbage word
 0x955e,0x0002,,word
index 3ba04cc..3293ca0 100755 (executable)
@@ -18,6 +18,8 @@ out_json = sys.argv[3]
 print('reading addrs')
 shape_tables = {}
 shape_data_ptr_base = -1
+draw_misc_tables = {}
+draw_misc_data_ptr_base = -1
 shapes = {}
 with open(addrs_txt) as fin:
   def get_line():
@@ -47,10 +49,16 @@ with open(addrs_txt) as fin:
         size = int(fields[1], 0)
         name = fields[2]
         _type = fields[3]
-        if _type == 'byte' and name[:6] == 'shape_':
-          shape_tables[name[6:]] = (addr, size // 0x80)
-        elif _type == 'word' and name == 'shape_data_ptr_base':
-          shape_data_ptr_base = addr
+        if _type == 'byte':
+          if name[:6] == 'shape_':
+            shape_tables[name[6:]] = (addr, size // 0x80)
+          elif name[:10] == 'draw_misc_':
+            draw_misc_tables[name[10:]] = (addr, size // 0x80)
+        elif _type == 'word':
+          if name == 'shape_data_ptr_base':
+            shape_data_ptr_base = addr
+          elif name == 'draw_misc_data_ptr_base':
+            draw_misc_data_ptr_base = addr
         fields = get_line()
       continue
 
@@ -69,6 +77,7 @@ with open(addrs_txt) as fin:
     while len(fields) >= 2:
       fields = get_line()
 assert shape_data_ptr_base != -1
+assert draw_misc_data_ptr_base != -1
 
 print('reading ihx')
 intelhex = IntelHex(in_ihx)
@@ -78,71 +87,78 @@ for i in range(0, len(segments), 2):
 
 print('extracting')
 data = []
-for i in range(0x80):
-  name = f'shape_{i:02x}'
+for i in range(0x100):
+  name = f'shape_{i:02x}' if i < 0x80 else f'draw_misc_{i - 0x80:02x}'
   if i in shapes:
     name += '_' + shapes[i]
   data.append({'name': name})
 
-i = 0
-shape_tables1 = list(shape_tables.items())
-while i < len(shape_tables1):
-  if (
-    i + 2 <= len(shape_tables1) and
-      shape_tables1[i][0][-3:] == '_lo' and
-      shape_tables1[i + 1][0][-3:] == '_hi'
-  ):
-    table, (addr_lo, shifts) = shape_tables1[i]
-    _, (addr_hi, _) = shape_tables1[i + 1]
-    table = table[:-3]
-    for j in range(0x80):
-      value = [
-        intelhex[addr_lo + j + k * 0x80] |
-          (intelhex[addr_hi + j + k * 0x80] << 8)
-        for k in range(shifts)
-      ]
-      data[j][table] = [f'0x{k:04x}' for k in value]
-    i += 2
-  else:
-    table, (addr, shifts) = shape_tables1[i]
-    for j in range(0x80):
-      value = [intelhex[addr + j + k * 0x80] for k in range(shifts)]
-      data[j][table] = [str(k) for k in value]
-    i += 1
+for base, tables in [(0, shape_tables), (0x80, draw_misc_tables)]:
+  i = 0
+  tables1 = list(tables.items())
+  while i < len(tables1):
+    if (
+      i + 2 <= len(tables1) and
+        tables1[i][0][-3:] == '_lo' and
+        tables1[i + 1][0][-3:] == '_hi'
+    ):
+      table, (data_ptr_lo, shifts) = tables1[i]
+      _, (data_ptr_hi, _) = tables1[i + 1]
+      table = table[:-3]
+      for j in range(0x80):
+        value = [
+          intelhex[data_ptr_lo + j + k * 0x80] |
+            (intelhex[data_ptr_hi + j + k * 0x80] << 8)
+          for k in range(shifts)
+        ]
+        data[base + j][table] = [f'0x{k:04x}' for k in value]
+      i += 2
+    else:
+      table, (data_ptr, shifts) = tables1[i]
+      for j in range(0x80):
+        value = [
+          intelhex[data_ptr + j + k * 0x80]
+          for k in range(shifts)
+        ]
+        data[base + j][table] = [str(k) for k in value]
+      i += 1
 
-for i in range(0x80):
-  height = int(data[i]['height'][0], 0)
-  addr0 = int(data[i]['data_ptr'][0], 0)
+for base, data_ptr_base in [
+  (
+    0,
+    intelhex[shape_data_ptr_base] |
+      (intelhex[shape_data_ptr_base + 1] << 8)
+  ),
+  (
+    0x80,
+    intelhex[draw_misc_data_ptr_base] |
+      (intelhex[draw_misc_data_ptr_base + 1] << 8)
+  )
+]:
+  for i in range(0x80):
+    height = int(data[base + i]['height'][0], 0)
+    width_bytes = [int(j, 0) for j in data[base + i]['width_bytes']]
+    data_ptr = [int(j, 0) for j in data[base + i]['data_ptr']]
 
-  # only try to extract if pointers are sensible
-  data1 = None
-  addr = addr0
-  for j in range(6):
-    width_bytes = int(data[i]['width_bytes'][j], 0)
-    addr += width_bytes * height
-    if addr != int(data[i]['data_ptr'][j + 1], 0):
-      break
-  else:
-    # good to go
-    data1 = []
-    addr = (
-      addr0 +
-        intelhex[shape_data_ptr_base] +
-        (intelhex[shape_data_ptr_base + 1] << 8)
-    )
-    for j in range(7):
-      width_bytes = int(data[i]['width_bytes'][j], 0)
-      data1.append(
+    # only try to extract if data is sensible
+    data1 = None
+    if (
+      height >= 1 and
+        height < 46 and
+        all([j >= 1 and j < 40 for j in width_bytes]) and
+        all([j < 0x1000 for j in data_ptr])
+    ):
+      data1 = [
         [
           [
-            f'0x{intelhex[addr + k * width_bytes + l]:02x}'
-            for l in range(width_bytes)
+            f'0x{intelhex[data_ptr_base + data_ptr[j] + k * width_bytes[j] + l]:02x}'
+            for l in range(width_bytes[j])
           ]
           for k in range(height)
         ]
-      )
-      addr += width_bytes * height
-  data[i]['data'] = data1
+        for j in range(len(width_bytes))
+      ]
+    data[base + i]['data'] = data1
 
 print('writing json')
 with open(out_json, 'w') as fout:
index 43ea34a..f84a743 100755 (executable)
@@ -8,8 +8,8 @@ import PIL.Image
 EXIT_SUCCESS = 0
 EXIT_FAILURE = 1
 
-PITCH_X = 64
-PITCH_Y = 32
+PITCH_X = 256
+PITCH_Y = 64
 
 # see palette.py
 PALETTE = numpy.array(
@@ -44,9 +44,9 @@ print('reading json')
 with open(in_json) as fin:
   data = json.load(fin)
 
-image_out = numpy.zeros((PITCH_Y * 16, PITCH_X * 8), numpy.uint8)
+image_out = numpy.zeros((PITCH_Y * 32, PITCH_X * 8), numpy.uint8)
 
-for i in range(0x80):
+for i in range(0x100):
   j = i & 7
   k = i >> 3
   x = j * PITCH_X
@@ -80,7 +80,7 @@ for i in range(0x80):
     ).astype(bool).reshape((ys, xs))
 
     # check remaining (shifted) shapes are as we expect
-    for j in range(1, 7):
+    for j in range(1, len(data1)):
       shape1 = numpy.array(
         [[int(l, 0) for l in k] for k in data1[j]],
         numpy.uint8