add renderer
This commit is contained in:
parent
ded9185216
commit
0fffccad41
170
isp_tsp_parameter.py
Normal file
170
isp_tsp_parameter.py
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from functools import partial
|
||||||
|
import struct
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class IspTspInstructionWordMV:
|
||||||
|
volume_instruction: int
|
||||||
|
culling_mode: int
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
assert (value & 0x7ffffff) == 0
|
||||||
|
self.volume_instruction = (value >> 29) & 0b111
|
||||||
|
self.culling_mode = (value >> 27) & 0b11
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class IspTspInstructionWord:
|
||||||
|
depth_compare_mode: int
|
||||||
|
culling_mode: int
|
||||||
|
z_write_disable: int
|
||||||
|
texture: int
|
||||||
|
offset: int
|
||||||
|
gouraud_shading: int
|
||||||
|
_16bit_uv: int
|
||||||
|
cache_bypass: int
|
||||||
|
dcalc_ctrl: int
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
assert (value & 0xfffff) == 0
|
||||||
|
self.depth_compare_mode = (value >> 29) & 0b111
|
||||||
|
self.culling_mode = (value >> 27) & 0b11
|
||||||
|
self.z_write_disable = (value >> 26) & 1
|
||||||
|
self.texture = (value >> 25) & 1
|
||||||
|
self.offset = (value >> 24) & 1
|
||||||
|
self.gouraud_shading = (value >> 23) & 1
|
||||||
|
self._16bit_uv = (value >> 22) & 1
|
||||||
|
self.cache_bypass = (value >> 21) & 1
|
||||||
|
self.dcalc_ctrl = (value >> 20) & 1
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TspInstructionWord:
|
||||||
|
src_alpha_instr: int
|
||||||
|
dst_alpha_instr: int
|
||||||
|
src_select: int
|
||||||
|
dst_select: int
|
||||||
|
fog_control: int
|
||||||
|
color_clamp: int
|
||||||
|
use_alpha: int
|
||||||
|
ignore_texture_alpha: int
|
||||||
|
flip_uv: int
|
||||||
|
clamp_uv: int
|
||||||
|
filter_mode: int
|
||||||
|
super_sample_texture: int
|
||||||
|
mip_map_d_adjust: int
|
||||||
|
texture_shading_instruction: int
|
||||||
|
texture_u_size: int
|
||||||
|
texture_v_size: int
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.src_alpha_instr = (value >> 29) & 0b111
|
||||||
|
self.dst_alpha_instr = (value >> 26) & 0b111
|
||||||
|
self.src_select = (value >> 25) & 1
|
||||||
|
self.dst_select = (value >> 24) & 1
|
||||||
|
self.fog_control = (value >> 22) & 0b11
|
||||||
|
self.color_clamp = (value >> 21) & 1
|
||||||
|
self.use_alpha = (value >> 20) & 1
|
||||||
|
self.ignore_texture_alpha = (value >> 19) & 1
|
||||||
|
self.flip_uv = (value >> 17) & 0b11
|
||||||
|
self.clamp_uv = (value >> 15) & 0b11
|
||||||
|
self.filter_mode = (value >> 13) & 0b11
|
||||||
|
self.super_sample_texture = (value >> 12) & 1
|
||||||
|
self.mip_map_d_adjust = (value >> 8) & 0b1111
|
||||||
|
self.texture_shading_instruction = (value >> 6) & 0b11
|
||||||
|
self.texture_u_size = (value >> 3) & 0b111
|
||||||
|
self.texture_v_size = (value >> 0) & 0b111
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TextureControlWord:
|
||||||
|
mip_mapped: int
|
||||||
|
vq_compressed: int
|
||||||
|
pixel_format: int
|
||||||
|
scan_order: int
|
||||||
|
stride_select: int
|
||||||
|
texture_address: int
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
assert (value >> 21) & 0b1111 == 0
|
||||||
|
|
||||||
|
self.mip_mapped = (value >> 31) & 1
|
||||||
|
self.vq_compressed = (value >> 30) & 1
|
||||||
|
self.pixel_format = (value >> 27) & 0b111
|
||||||
|
self.scan_order = (value >> 26) & 1
|
||||||
|
self.stride_select = (value >> 25) & 1
|
||||||
|
self.texture_address = ((value >> 0) & 0x1fffff) * 8
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Vertex:
|
||||||
|
x: float
|
||||||
|
y: float
|
||||||
|
z: float
|
||||||
|
attributes: list
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ISPTSPParameter:
|
||||||
|
isp_tsp_instruction_word: IspTspInstructionWord
|
||||||
|
tsp_instruction_word: TspInstructionWord
|
||||||
|
texture_control_word: TextureControlWord
|
||||||
|
vertices: list[Vertex]
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ISPTSPParameterMV:
|
||||||
|
isp_tsp_instruction_word: IspTspInstructionWord
|
||||||
|
vertices: list[Vertex]
|
||||||
|
|
||||||
|
def expected_skip_size(isp_tsp):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse_parameter(mem, offset, skip, tag_offset, vertex_count, modifier_volume):
|
||||||
|
assert skip >= 0, skip
|
||||||
|
skip = (skip + 3) # size of one vertex
|
||||||
|
|
||||||
|
params = []
|
||||||
|
|
||||||
|
def unpack(i, t):
|
||||||
|
i_offset = offset + i * 4
|
||||||
|
value, = struct.unpack("<" + t, mem[i_offset:i_offset + 4])
|
||||||
|
return value
|
||||||
|
|
||||||
|
unpack_int = partial(unpack, t="I")
|
||||||
|
unpack_float = partial(unpack, t="f")
|
||||||
|
|
||||||
|
if modifier_volume:
|
||||||
|
assert skip == 3, skip
|
||||||
|
parameter = ISPTSPParameterMV(
|
||||||
|
IspTspInstructionWordMV(unpack_int(0)),
|
||||||
|
vertices=[]
|
||||||
|
)
|
||||||
|
value1 = unpack_int(1)
|
||||||
|
assert value1 == 0, value1
|
||||||
|
value2 = unpack_int(2)
|
||||||
|
assert value2 == 0, value2
|
||||||
|
else:
|
||||||
|
parameter = ISPTSPParameter(
|
||||||
|
IspTspInstructionWord(unpack_int(0)),
|
||||||
|
TspInstructionWord(unpack_int(1)),
|
||||||
|
TextureControlWord(unpack_int(2)),
|
||||||
|
vertices=[]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
assert tag_offset == 0, tag_offset # FIXME
|
||||||
|
|
||||||
|
i = 3
|
||||||
|
for _ in range(vertex_count):
|
||||||
|
vertex = Vertex(
|
||||||
|
x = unpack_float(i + 0),
|
||||||
|
y = unpack_float(i + 1),
|
||||||
|
z = unpack_float(i + 2),
|
||||||
|
attributes=[]
|
||||||
|
)
|
||||||
|
|
||||||
|
j = 3
|
||||||
|
while j < skip:
|
||||||
|
vertex.attributes.append(unpack_int(i + j))
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
parameter.vertices.append(vertex)
|
||||||
|
|
||||||
|
i += skip
|
||||||
|
|
||||||
|
return offset + i * 4, parameter
|
195
main.py
195
main.py
@ -1,9 +1,17 @@
|
|||||||
from pprint import pprint
|
import os
|
||||||
|
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
|
||||||
|
import textwrap
|
||||||
|
from pprint import pprint, pformat
|
||||||
import sys
|
import sys
|
||||||
|
import pygame
|
||||||
|
from functools import partial
|
||||||
|
from itertools import starmap
|
||||||
|
import time
|
||||||
|
|
||||||
from holly import decode_holly
|
from holly import decode_holly
|
||||||
from region_array import decode_region_array_entries
|
from region_array import decode_region_array_entries
|
||||||
from object_list import *
|
from object_list import *
|
||||||
|
from isp_tsp_parameter import parse_parameter
|
||||||
|
|
||||||
texture_memory_filename = sys.argv[1]
|
texture_memory_filename = sys.argv[1]
|
||||||
holly_registers_filename = sys.argv[2]
|
holly_registers_filename = sys.argv[2]
|
||||||
@ -20,28 +28,165 @@ assert (holly.REGION_BASE & 0b11) == 0, holly.REGION_BASE
|
|||||||
|
|
||||||
region_array_entries = decode_region_array_entries(texture_memory, holly.REGION_BASE)
|
region_array_entries = decode_region_array_entries(texture_memory, holly.REGION_BASE)
|
||||||
|
|
||||||
for entry in region_array_entries:
|
DEBUG = False
|
||||||
lists = [
|
|
||||||
("opaque_list_pointer", entry.opaque_list_pointer),
|
def walk_region_array(*, tile_callback=None, parameter_callback=None, flush_callback=None):
|
||||||
("opaque_modifier_volume_list_pointer", entry.opaque_modifier_volume_list_pointer),
|
for entry in region_array_entries:
|
||||||
("translucent_list_pointer", entry.translucent_list_pointer),
|
lists = [
|
||||||
("translucent_modifier_volume_list_pointer", entry.translucent_modifier_volume_list_pointer),
|
("opaque_list_pointer", entry.opaque_list_pointer),
|
||||||
("punch_through_list_pointer", entry.punch_through_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
|
||||||
]
|
]
|
||||||
print(entry.tile)
|
|
||||||
for list_type_name, list_pointer in lists:
|
argb_color = parameter.vertices[0].attributes[0]
|
||||||
print(" " * 4, end='')
|
alpha = (argb_color >> 24) & 0xff
|
||||||
print(list_type_name, list_pointer)
|
red = (argb_color >> 16) & 0xff
|
||||||
if list_pointer.empty_ptr:
|
green = (argb_color >> 8) & 0xff
|
||||||
continue
|
blue = (argb_color >> 0) & 0xff
|
||||||
offset = list_pointer.pointer_to_object_list
|
color = (red, green, blue, alpha)
|
||||||
while True:
|
|
||||||
ol_entry = decode_ol_entry(texture_memory, offset)
|
assert red > 10 or blue > 10 or green > 10, argb_color
|
||||||
print(" " * 8, end='')
|
|
||||||
print(ol_entry)
|
pygame.draw.polygon(color_buffer, color, points)
|
||||||
offset += 4
|
|
||||||
if type(ol_entry) == object_pointer_block_link:
|
def draw():
|
||||||
if ol_entry.end_of_list:
|
pygame.init()
|
||||||
break
|
screen = pygame.display.set_mode((640, 480))
|
||||||
else:
|
|
||||||
offset = ol_entry.next_pointer_block
|
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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user