import os os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" import textwrap from pprint import pprint, pformat import sys import pygame from functools import partial from itertools import starmap import time from holly import decode_holly from region_array import decode_region_array_entries from object_list import * from isp_tsp_parameter import parse_parameter texture_memory_filename = sys.argv[1] holly_registers_filename = sys.argv[2] with open(texture_memory_filename, "rb") as f: texture_memory = memoryview(f.read()) with open(holly_registers_filename, "rb") as f: holly_registers = memoryview(f.read()) holly = decode_holly(holly_registers) assert (holly.REGION_BASE & 0b11) == 0, holly.REGION_BASE region_array_entries = decode_region_array_entries(texture_memory, holly.REGION_BASE) DEBUG = False def walk_region_array(*, tile_callback=None, parameter_callback=None, flush_callback=None): for entry in region_array_entries: lists = [ ("opaque_list_pointer", entry.opaque_list_pointer), ("opaque_modifier_volume_list_pointer", entry.opaque_modifier_volume_list_pointer), ("translucent_list_pointer", entry.translucent_list_pointer), ("translucent_modifier_volume_list_pointer", entry.translucent_modifier_volume_list_pointer), ("punch_through_list_pointer", entry.punch_through_list_pointer), ] if tile_callback is not None: tile_callback(entry.tile) for list_type_name, list_pointer in lists: if DEBUG: print(" " * 4, end='') print(list_type_name, list_pointer) if list_pointer.empty_ptr: continue offset = list_pointer.pointer_to_object_list while True: ol_entry = decode_ol_entry(texture_memory, offset) if DEBUG: print(" " * 8, end='') print(ol_entry) offset += 4 if type(ol_entry) == triangle_array: param_offset = ol_entry.triangle_array_start for i in range(ol_entry.number_of_triangles + 1): modifier_volume = list_type_name in {"opaque_modifier_volume_list_pointer", "translucent_modifier_volume_list_pointer"} param_offset, parameter = parse_parameter(texture_memory, param_offset, skip=ol_entry.skip, tag_offset=0, vertex_count=3, modifier_volume=modifier_volume) if parameter_callback is not None: parameter_callback(entry.tile, list_type_name, list_pointer, ol_entry, parameter) if DEBUG: print(textwrap.indent( pformat(parameter), " " * 12 )) if type(ol_entry) == object_pointer_block_link: if ol_entry.end_of_list: break else: offset = ol_entry.next_pointer_block if entry.tile.flush_accumulate == 0: if flush_callback is not None: flush_callback(entry.tile) def new_tile_surface(): surface = pygame.Surface((32, 32), pygame.SRCALPHA) surface.fill((0, 0, 0, 0)) return surface x_tiles = (640 // 32) y_tiles = (480 // 32) color_buffer_list = [ new_tile_surface() for _ in range(x_tiles * y_tiles) ] depth_buffer_list = [ new_tile_surface() for _ in range(x_tiles * y_tiles) ] color_test_surface = new_tile_surface() depth_test_surface = new_tile_surface() def draw_background(tile): t = holly.ISP_BACKGND_T skip = (t >> 24) & 0b111 tag_address = ((t >> 3) & 0x1fffff) * 4 param_offset, parameter = parse_parameter(texture_memory, tag_address, skip=skip, tag_offset=0, vertex_count=3, modifier_volume=False) assert len(parameter.vertices) == 3, parameter.vertices assert len(parameter.vertices[0].attributes) >= 1, parameter argb_color = parameter.vertices[0].attributes[0] alpha = (argb_color >> 24) & 0xff red = (argb_color >> 16) & 0xff green = (argb_color >> 8) & 0xff blue = (argb_color >> 0) & 0xff color = (red, green, blue, alpha) points = [(0, 0), (640, 0), (640, 480), (0, 480)] tile_ix = tile.tile_y_position * x_tiles + tile.tile_x_position color_buffer = color_buffer_list[tile_ix] pygame.draw.polygon(color_buffer, color, points) def tile_callback(tile): draw_background(tile) def flush_callback(tile, *, screen): tile_ix = tile.tile_y_position * x_tiles + tile.tile_x_position color_buffer = color_buffer_list[tile_ix] screen.blit(color_buffer, (tile.tile_x_position * 32, tile.tile_y_position * 32)) pygame.display.flip() time.sleep(0.1) def parameter_callback(tile, list_type_name, list_pointer, ol_entry, parameter): # tile=RegionArrayTile(last_region=1, z_clear=0, flush_accumulate=0, tile_y_position=14, tile_x_position=19) if list_type_name != "opaque_list_pointer": return left = tile.tile_x_position * 32 top = tile.tile_y_position * 32 tile_ix = tile.tile_y_position * x_tiles + tile.tile_x_position color_buffer = color_buffer_list[tile_ix] assert type(ol_entry) == triangle_array, ol_entry assert len(parameter.vertices) == 3, parameter.vertices assert len(parameter.vertices[0].attributes) >= 1, parameter points = [ (vertex.x - left, vertex.y - top) for vertex in parameter.vertices ] argb_color = parameter.vertices[0].attributes[0] alpha = (argb_color >> 24) & 0xff red = (argb_color >> 16) & 0xff green = (argb_color >> 8) & 0xff blue = (argb_color >> 0) & 0xff color = (red, green, blue, alpha) assert red > 10 or blue > 10 or green > 10, argb_color pygame.draw.polygon(color_buffer, color, points) def draw(): pygame.init() screen = pygame.display.set_mode((640, 480)) sys.stdin.readline() walk_region_array(tile_callback=tile_callback, parameter_callback=parameter_callback, flush_callback=partial(flush_callback, screen=screen)) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: break pygame.quit() draw()