Add Space Invaders background at 3x resolution and 2/3 intensity master
authorNick Downing <nick@ndcode.org>
Sun, 24 Jul 2022 10:00:22 +0000 (20:00 +1000)
committerNick Downing <nick@ndcode.org>
Sun, 24 Jul 2022 10:01:44 +0000 (20:01 +1000)
emu_z80/emu_z80.c
invaders/Makefile
invaders/background.png [new file with mode: 0644]
invaders/indexed_to_raw.py [new file with mode: 0755]
invaders/raw_to_indexed.py [new file with mode: 0755]

index 7108a74..285f1d1 100644 (file)
@@ -15,8 +15,8 @@
 #include "stty_sane.h"
 #include "z80/z80.h"
 
-#define DKONG 1
-#define INVADERS 0
+#define DKONG 0
+#define INVADERS 1
 #define GALAXIAN 0
 #define PACMAN 0
 #define APPLE 0
 #define INVADERS_WIDTH 224
 #define INVADERS_HEIGHT 256
 
-#define PADDED_WIDTH INVADERS_WIDTH
-#define PADDED_HEIGHT INVADERS_HEIGHT
+// see background.png (dimensions divided by 3)
+#define PADDED_WIDTH 388
+#define PADDED_HEIGHT 286
+
+#define HORIZ_PAD ((PADDED_WIDTH - INVADERS_WIDTH) / 2)
+#define VERT_PAD ((PADDED_HEIGHT - INVADERS_HEIGHT) / 2)
 
 #define WINDOW_X_SCALE 3
 #define WINDOW_Y_SCALE 3
@@ -245,7 +249,9 @@ uint32_t frame[WINDOW_HEIGHT][WINDOW_WIDTH];
 bool frame_half;
 #endif
 
-#if APPLE
+#if INVADERS
+uint32_t palette[0x100]; // extracted from ihx with correct byte order
+#elif APPLE
 // see palette.py
 uint32_t palette[0x10] = {
   0xff000000,
@@ -293,7 +299,9 @@ z80 cpu;
 #define ROM_INVADERS_G_ADDR 0x800
 #define ROM_INVADERS_F_ADDR 0x1000
 #define ROM_INVADERS_E_ADDR 0x1800
-#define MEM_SIZE 0x4000
+#define ROM_BACKGROUND_PALETTE_ADDR 0x4000
+#define ROM_BACKGROUND_ADDR 0x4300
+#define MEM_SIZE 0xf8038
 #elif GALAXIAN
 #define ROM_GALMIDW_U_ADDR 0
 #define ROM_GALMIDW_V_ADDR 0x800
@@ -1996,6 +2004,15 @@ int main(int argc, char **argv) {
     }
 #endif
 
+#if INVADERS
+  for (int i = 0; i < 0x100; ++i)
+    palette[i] =
+      (mem[2 + i * 3 + ROM_BACKGROUND_PALETTE_ADDR] * 2 / 3) |
+      ((mem[1 + i * 3 + ROM_BACKGROUND_PALETTE_ADDR] * 2 / 3) << 8) |
+      ((mem[i * 3 + ROM_BACKGROUND_PALETTE_ADDR] * 2 / 3) << 16) |
+      0xff000000;
+#endif
+
   // main loop
   long nb_instructions = 0, nb_cycles = 0;
   int update_count = 0;
@@ -2253,39 +2270,48 @@ int main(int argc, char **argv) {
       }
 #elif INVADERS
       // send z80 a vertical refresh interrupt
-      int j0, j1;
+      int j0, j1, j2, j3;
       if (frame_half == false) {
         z80_gen_int(&cpu, 0xcf); // rst 8
         j0 = 0;
-        j1 = 96;
+        j1 = (HORIZ_PAD + 96) * WINDOW_X_SCALE;
+        j2 = 0;
+        j3 = 96;
         frame_half = true;
       }
       else {
         z80_gen_int(&cpu, 0xd7); // rst 0x10
-        j0 = 96;
-        j1 = INVADERS_WIDTH;
+        j0 = (HORIZ_PAD + 96) * WINDOW_X_SCALE;
+        j1 = WINDOW_WIDTH;
+        j2 = 96;
+        j3 = INVADERS_WIDTH;
         frame_half = false;
       }
 
+      for (int i = 0; i < WINDOW_HEIGHT; ++i)
+        for (int j = j0; j < j1; ++j)
+          frame[i][j] = palette[
+            /*(i / 3) & 0xff*/ mem[i * WINDOW_WIDTH + j + ROM_BACKGROUND_ADDR]
+          ];
+
       for (int i = 0; i < INVADERS_HEIGHT; ++i) {
-        int y = i * WINDOW_Y_SCALE;
+        int y = (VERT_PAD + i) * WINDOW_Y_SCALE;
         int i1 = i ^ 0xff;
-        for (int j = j0; j < j1; ++j) {
-          int x = j * WINDOW_X_SCALE;
-          uint32_t rgb = -(
-            (mem[(i1 >> 3) + (j << 5) + VIDEO_RAM] >> (i1 & 7)) & 1
-          );
-          if (i >= 32 && i < 64)
-            rgb &= 0xffff0000; // red flying saucer area
-          else if (
-            i >= 184 &&
-            (i < 240 || (j >= 25 && j < 136))
-          )
-            rgb &= 0xff00ff00; // green base and lives area
-          for (int k = 0; k < WINDOW_Y_SCALE; ++k)
-            for (int l = 0; l < WINDOW_X_SCALE; ++l)
-              frame[y + k][x + l] = rgb;
-        }
+        for (int j = j2; j < j3; ++j)
+          if ((mem[(i1 >> 3) + (j << 5) + VIDEO_RAM] >> (i1 & 7)) & 1) {
+            int x = (HORIZ_PAD + j) * WINDOW_X_SCALE;
+            uint32_t rgb = 0xffffffff;
+            if (i >= 32 && i < 64)
+              rgb = 0xffff00ff; // magenta flying saucer area
+            else if (
+              i >= 184 &&
+              (i < 240 || (j >= 25 && j < 136))
+            )
+              rgb = 0xff00ff00; // green base and lives area
+            for (int k = 0; k < WINDOW_Y_SCALE; ++k)
+              for (int l = 0; l < WINDOW_X_SCALE; ++l)
+                frame[y + k][x + l] = rgb;
+          }
       }
 #elif GALAXIAN
       // send z80 a vertical refresh interrupt
index af64834..65a676f 100644 (file)
@@ -6,6 +6,8 @@ ROM_INVADERS_H_ADDR=0
 ROM_INVADERS_G_ADDR=0x800
 ROM_INVADERS_F_ADDR=0x1000
 ROM_INVADERS_E_ADDR=0x1800
+ROM_BACKGROUND_PALETTE_ADDR=0x4000
+ROM_BACKGROUND_ADDR=0x4300
 
 ROMS= \
 all: invaders0.ihx
@@ -14,7 +16,9 @@ invaders0.ihx: \
 invaders.h.ihx \
 invaders.g.ihx \
 invaders.f.ihx \
-invaders.e.ihx
+invaders.e.ihx \
+background_palette.ihx \
+background.ihx
        hexmerge.py -o $@ $^
 
 invaders.h.ihx: ../orig/invaders/invaders.h
@@ -29,5 +33,14 @@ invaders.f.ihx: ../orig/invaders/invaders.f
 invaders.e.ihx: ../orig/invaders/invaders.e
        ${BIN2HEX} --offset=${ROM_INVADERS_E_ADDR} $< $@
 
+background_palette.ihx: background_palette.bin
+       ${BIN2HEX} --offset=${ROM_BACKGROUND_PALETTE_ADDR} $< $@
+
+background.ihx: background.bin
+       ${BIN2HEX} --offset=${ROM_BACKGROUND_ADDR} $< $@
+
+background.bin background_palette.bin: background.png
+       ./indexed_to_raw.py $< background.bin background_palette.bin
+
 clean:
-       rm -f *.ihx
+       rm -f *.bin *.ihx
diff --git a/invaders/background.png b/invaders/background.png
new file mode 100644 (file)
index 0000000..225c5aa
Binary files /dev/null and b/invaders/background.png differ
diff --git a/invaders/indexed_to_raw.py b/invaders/indexed_to_raw.py
new file mode 100755 (executable)
index 0000000..b58aa06
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+
+import PIL.Image
+import sys
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+if len(sys.argv) < 4:
+  print(f'usage: {sys.argv[0]:s} in.png out.bin palette_out.bin')
+  sys.exit(EXIT_FAILURE)
+in_png = sys.argv[1]
+out_bin = sys.argv[2]
+palette_out_bin = sys.argv[3]
+
+image_in_pil = PIL.Image.open(in_png)
+assert image_in_pil.mode == 'P'
+print('width', image_in_pil.width, 'height', image_in_pil.height)
+with open(out_bin, 'wb') as fout:
+  fout.write(image_in_pil.tobytes())
+with open(palette_out_bin, 'wb') as fout:
+  fout.write(image_in_pil.palette.tobytes())
diff --git a/invaders/raw_to_indexed.py b/invaders/raw_to_indexed.py
new file mode 100755 (executable)
index 0000000..5dd93e3
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+
+import PIL.Image
+import sys
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+if len(sys.argv) < 6:
+  print(f'usage: {sys.argv[0]:s} width height in.bin palette_in.bin out.png')
+  sys.exit(EXIT_FAILURE)
+width = int(sys.argv[1])
+height = int(sys.argv[2])
+in_bin = sys.argv[3]
+palette_in_bin = sys.argv[4]
+out_png = sys.argv[5]
+
+image_out_pil = PIL.Image.new('P', (width, height), None)
+with open(in_bin, 'rb') as fin:
+  image_out_pil.frombytes(fin.read(width * height))
+with open(palette_in_bin, 'rb') as fin:
+  image_out_pil.putpalette(list(fin.read(0x300)))
+image_out_pil.save(out_png)