Last active
August 24, 2020 13:36
-
-
Save gschizas/a3957810e2a366998f8ceef55198aa5e to your computer and use it in GitHub Desktop.
Map The Prize for Amstrad CPC 6128 using BizHawk and directly converting screen memory to a large image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
map_x = 1 | |
map_y = 1 | |
map_lvl = 1 | |
handled_press = {} | |
function handle_keypress(keys, keyname, fn) | |
if (keys[keyname] ~= nil and (handled_press[keyname] == 0 or handled_press[keyname] == nil)) then | |
-- print(tostring(emu.framecount()) .. ": Key pressed") | |
fn() | |
handled_press[keyname] = 1 | |
end | |
if (keys[keyname] == nil and handled_press[keyname] == 1) then | |
-- print(tostring(emu.framecount()) .. ": Key depressed") | |
-- print("End screenshot") | |
-- print(debug.getinfo(fn)) | |
handled_press[keyname] = 0 | |
end | |
end | |
function write_bytes(file_handle, buffer_start, buffer_length, buffer_domain) | |
raw_buffer = memory.readbyterange(buffer_start, buffer_length, buffer_domain) | |
buffer = string.char(unpack(raw_buffer, 0)) | |
file_handle:write(buffer) | |
end | |
function screenshot() | |
print("Taking screenshot") | |
filename = string.format("Game Maps/Prize/Level_%02d-%02d-%02d.scr.bin", map_lvl, map_x, map_y) | |
-- filename = 'demo-mode0.bin' | |
print(map_lvl, map_x, map_y, filename) | |
file_handle = io.open(filename, 'wb') | |
for chunk = 0, 3 do | |
write_bytes(file_handle, chunk * 4096, 4096, "RAM3") | |
end | |
write_bytes(file_handle, 0xB7C3 - 0x8000, 1, "RAM2") | |
write_bytes(file_handle, 0xB7D4 - 0x8000, 34, "RAM2") | |
file_handle:close() | |
print("Done") | |
status_text = string.format(" ::: Level %02d %02d:%02d", map_lvl, map_x, map_y) | |
end | |
status_text = "" | |
while true do | |
map_text = string.format("Level %d | %d:%d", map_lvl, map_x, map_y) | |
if emu.framecount() % 8 == 0 then | |
status_text = "" | |
end | |
if emu.framecount() % 2 == 0 then | |
local keys = input.get() | |
handle_keypress(keys, "X1 Y", screenshot) | |
handle_keypress(keys, "X1 DpadLeft", function() map_x = map_x - 1 end) | |
handle_keypress(keys, "X1 DpadRight", function() map_x = map_x + 1 end) | |
handle_keypress(keys, "X1 DpadUp", function() map_y = map_y - 1 end) | |
handle_keypress(keys, "X1 DpadDown", function() map_y = map_y + 1 end) | |
handle_keypress(keys, "X1 LeftShoulder", function() map_lvl = map_lvl - 1 end) | |
handle_keypress(keys, "X1 RightShoulder", function() map_lvl = map_lvl + 1 end) | |
end | |
map_text = map_text .. status_text | |
gui.text(10, 0, map_text) | |
emu.frameadvance() | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# coding: utf-8 | |
import pathlib | |
import re | |
import struct | |
import PIL.Image | |
palette_software = [ | |
0x000000, 0x000080, 0x0000FF, 0x800000, 0x800080, 0x8000FF, 0xFF0000, 0xFF0080, 0xFF00FF, | |
0x008000, 0x008080, 0x0080FF, 0x808000, 0x808080, 0x8080FF, 0xFF8000, 0xFF8080, 0xFF80FF, | |
0x00FF00, 0x00FF80, 0x00FFFF, 0x80FF00, 0x80FF80, 0x80FFFF, 0xFFFF00, 0xFFFF80, 0xFFFFFF] | |
palette_hardware = [20, 4, 21, 28, 24, 29, 12, 5, 13, 22, 6, | |
23, 30, 0, 31, 14, 7, 15, 18, 2, 19, 26, 25, 27, 10, 3, 11] | |
def read_inks(memory_data): | |
inks = [] | |
for ink in memory_data[0x4002:0x4012]: | |
assert ink in palette_hardware | |
hw_index = palette_hardware.index(ink) | |
sw_color = palette_software[hw_index] | |
inks.append(sw_color) | |
return inks | |
def convert_image_from_memory(memory_data, mode=None): | |
image = PIL.Image.new('RGB', (640, 320), color=0xff0080) | |
if mode is None: | |
mode = memory_data[0x4000] | |
inks = read_inks(memory_data) | |
scale_x = 4 >> mode | |
pixels_per_byte = 2 << mode | |
scale_y = 2 | |
for screen_y in range(160): | |
screen_row = screen_y % 8 | |
screen_line = screen_y // 8 | |
for screen_x in range(640 // scale_x): | |
screen_col = screen_x // pixels_per_byte | |
screen_pixel = screen_x % pixels_per_byte | |
memory_pos = screen_row * 0x800 + screen_line * 80 + screen_col | |
memory_value = memory_data[memory_pos] | |
if mode == 2: | |
current_ink = (memory_value & ( | |
128 >> screen_pixel)) >> (7 - screen_pixel) | |
elif mode == 1: | |
current_ink0 = (memory_value >> 0 & 15 & ( | |
8 >> screen_pixel)) >> (3 - screen_pixel) | |
current_ink1 = (memory_value >> 4 & 15 & ( | |
8 >> screen_pixel)) >> (3 - screen_pixel) | |
current_ink = (current_ink0 << 1) + current_ink1 | |
elif mode == 0: | |
current_ink0 = (memory_value >> 0 & 15 & ( | |
2 >> screen_pixel)) >> (1 - screen_pixel) | |
current_ink1 = (memory_value >> 2 & 15 & ( | |
2 >> screen_pixel)) >> (1 - screen_pixel) | |
current_ink2 = (memory_value >> 4 & 15 & ( | |
2 >> screen_pixel)) >> (1 - screen_pixel) | |
current_ink3 = (memory_value >> 6 & 15 & ( | |
2 >> screen_pixel)) >> (1 - screen_pixel) | |
current_ink = (current_ink0 << 3) + (current_ink1 << | |
2) + (current_ink2 << 1) + current_ink3 | |
try: | |
pixel_value = inks[current_ink] | |
except: | |
print(current_ink, file=sys.stderr) | |
raise | |
for pixel_y in range(scale_y): | |
for pixel_x in range(scale_x): | |
color = struct.unpack('>I', struct.pack('<I', pixel_value))[0] >> 8 | |
image.putpixel((screen_x * scale_x + pixel_x, | |
screen_y * scale_y + pixel_y), | |
color) | |
# break | |
return image | |
def get_coords(filename): | |
coords = re.findall('\d\d-(?P<x>\d\d)-(?P<y>\d\d)', filename) | |
return int(coords[0][0]), int(coords[0][1]) | |
bin_files = list(pathlib.Path(r'Game Maps/Prize').glob('Level_01-*.bin')) | |
raw_maps = {get_coords(fn.name): fn.read_bytes() for fn in bin_files} | |
min_x = min([c[0] for c in list(raw_maps.keys())]) | |
max_x = max([c[0] for c in list(raw_maps.keys())]) | |
min_y = min([c[1] for c in list(raw_maps.keys())]) | |
max_y = max([c[1] for c in list(raw_maps.keys())]) | |
full_map = PIL.Image.new('RGB', (640 * (1 + max_x - min_x), 320 * (1 + max_y - min_y)), color=0x5500AA) | |
for y in range(min_y, max_y + 1): | |
for x in range(min_x, max_x + 1): | |
print(f"{x}:{y}", end=' ') | |
if (x, y) in raw_maps: | |
partial_map = convert_image_from_memory(raw_maps[x, y]) | |
# , x * 640 - 1, y * 320 - 1)) | |
full_map.paste(partial_map, box=((x - 1) * 640, (y - 1) * 320)) | |
full_map.save('Level01.png') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment