mirror of
https://github.com/Xeeynamo/sotn-decomp.git
synced 2024-11-23 13:09:44 +00:00
9eb2d507b9
Some checks are pending
Format code / format (push) Waiting to run
Build C code / extract-assets (push) Waiting to run
Build C code / build-linux (i686, Debug, clang, custom) (push) Blocked by required conditions
Build C code / build-linux (i686, Debug, clang, lle) (push) Blocked by required conditions
Build C code / build-linux (i686, Debug, gcc, custom) (push) Blocked by required conditions
Build C code / build-linux (i686, Debug, gcc, lle) (push) Blocked by required conditions
Build C code / build-linux (i686, RelWithDebInfo, clang, custom) (push) Blocked by required conditions
Build C code / build-linux (i686, RelWithDebInfo, clang, lle) (push) Blocked by required conditions
Build C code / build-linux (i686, RelWithDebInfo, gcc, custom) (push) Blocked by required conditions
Build C code / build-linux (i686, RelWithDebInfo, gcc, lle) (push) Blocked by required conditions
Build C code / build-linux (x86_64, Debug, clang, custom) (push) Blocked by required conditions
Build C code / build-linux (x86_64, Debug, clang, lle) (push) Blocked by required conditions
Build C code / build-linux (x86_64, Debug, gcc, custom) (push) Blocked by required conditions
Build C code / build-linux (x86_64, Debug, gcc, lle) (push) Blocked by required conditions
Build C code / build-linux (x86_64, RelWithDebInfo, clang, custom) (push) Blocked by required conditions
Build C code / build-linux (x86_64, RelWithDebInfo, clang, lle) (push) Blocked by required conditions
Build C code / build-linux (x86_64, RelWithDebInfo, gcc, custom) (push) Blocked by required conditions
Build C code / build-linux (x86_64, RelWithDebInfo, gcc, lle) (push) Blocked by required conditions
Build C code / build-macos (Debug, custom) (push) Blocked by required conditions
Build C code / build-macos (Debug, lle) (push) Blocked by required conditions
Build C code / build-macos (RelWithDebInfo, custom) (push) Blocked by required conditions
Build C code / build-macos (RelWithDebInfo, lle) (push) Blocked by required conditions
Build C code / build-windows (Debug, custom) (push) Blocked by required conditions
Build C code / build-windows (Debug, lle) (push) Blocked by required conditions
Build C code / build-windows (RelWithDebInfo, custom) (push) Blocked by required conditions
Build C code / build-windows (RelWithDebInfo, lle) (push) Blocked by required conditions
Build Saturn version / build-and-test-saturn (push) Waiting to run
Build Saturn version / function-finder-saturn (push) Waiting to run
Build Debug Module tool / build (push) Waiting to run
Build PSX and PSP version / build-and-test (pspeu, hd) (push) Waiting to run
Build PSX and PSP version / build-and-test (pspeu, pspeu) (push) Waiting to run
Build PSX and PSP version / build-and-test (us, us) (push) Waiting to run
Build PSX and PSP version / generate-progress-report (pspeu, hd) (push) Blocked by required conditions
Build PSX and PSP version / generate-progress-report (pspeu, pspeu) (push) Blocked by required conditions
Build PSX and PSP version / generate-progress-report (us, us) (push) Blocked by required conditions
Build PSX and PSP version / generate-duplicates-report (us, us) (push) Blocked by required conditions
Build PSX and PSP version / generate-duplicates-report-psp (pspeu, pspeu) (push) Blocked by required conditions
Picked a random `.c` file from PSP to decompile. This caused me to discover that this function requires `-O4,p`, which is new. All the other -O4 files also match with this, which is good. Also back-ported my changes to PS1. Some tiny changes to the texture displaying tools that I made due to xeeynamo finding a tiny bug; not worth a whole PR so I just tossed them into this one.
200 lines
8.0 KiB
Python
Executable File
200 lines
8.0 KiB
Python
Executable File
# Written by bismurphy, please contact in case of bugs or feature requests!
|
|
|
|
# Used for debugging and especially identifying entities based on their primitives.
|
|
# If you have a primitive pulling a texture from a Tpage, with a Clut, and
|
|
# getting a texture from UV coordinates, this will attempt to show you the texture
|
|
# being loaded from those parameters.
|
|
|
|
# In order to do this, you will need a VRAM dump from the game, in the state
|
|
# where the texture pages are configured to include the entry of interest.
|
|
# That is, you need to make sure the thing you're looking for is loaded.
|
|
|
|
# To get the VRAM dump: In PCSX-Redux, activate the web server with the setting in
|
|
# Configuration > Emulation > Enable Web Server
|
|
# Then, in your browser, go to: http://localhost:8080/api/v1/gpu/vram/raw
|
|
# this will download the raw VRAM dump. It should be a megabyte. Put it alongside
|
|
# this script, then run this script with the args for the
|
|
# filename, tpage, clut, x, y, w, h that you want.
|
|
# Alternatively, if you use "LIVE" as your filename, the data will attempt to fetch live
|
|
# from a running instance of PCSX-Redux. This avoids goofing around with managing file dumps.
|
|
|
|
# Example use (while standing on the box in Alchemy Lab):
|
|
# python3 display_texture.py vram_on_box.raw 0xF 9 8 200 32 32
|
|
|
|
# Alternatively, to see the whole tpage, you can run with
|
|
# python3 display_texture.py vram_on_box.raw 0xF 9 --whole which will skip the coordinates.
|
|
|
|
# And to just view the clut, do:
|
|
# python3 display_texture.py vram_on_box.raw 0xF 9 --showclut
|
|
# which will let you view clut #9. (tpage is ignored in this mode)
|
|
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
import argparse
|
|
import urllib.request
|
|
|
|
|
|
# Take a 5-5-5 encoded array and convert to RGB image.
|
|
# See PSYQ SDK document LIBOVR46.PDF, figure 8-3.
|
|
def convert_rgb555(in_array):
|
|
out_array = []
|
|
for in_row in in_array:
|
|
out_row = []
|
|
for i in range(0, len(in_row), 2):
|
|
two_bytes = in_row[i : i + 2]
|
|
two_bytes = two_bytes[::-1]
|
|
bits = int.from_bytes(two_bytes, "big")
|
|
s = bits >> 15 # semi transparent flag
|
|
b = bits >> 10 & 0b11111 # bits 14-10
|
|
g = (bits >> 5) & 0b11111 # bits 9-5
|
|
r = bits & 0b11111 # bits 4-0
|
|
# Transform 5-bit to 8-bit color
|
|
r = round(r / 31 * 255)
|
|
g = round(g / 31 * 255)
|
|
b = round(b / 31 * 255)
|
|
a = 255 if (r or g or b) else 0
|
|
pixel = [r, g, b, a]
|
|
out_row.append(pixel)
|
|
out_array.append(out_row)
|
|
return np.array(out_array, dtype="uint8")
|
|
|
|
|
|
# Once we have a tpage and a clut, apply that clut to color the tpage.
|
|
def color_tpage(tpage, clut):
|
|
height, width = tpage.shape
|
|
image = []
|
|
for y in range(height):
|
|
img_row = []
|
|
for x in range(width):
|
|
# Load one byte from the tpage.
|
|
px = tpage[y][x]
|
|
# The byte encodes two pixels in its upper and lower halfs.
|
|
# Extract each half.
|
|
px1 = px & 0b1111
|
|
px2 = px >> 4
|
|
# Individually, use the clut as a lookup table to get the real color.
|
|
color1 = clut[px1]
|
|
color2 = clut[px2]
|
|
# Put each of those two rows into the image.
|
|
img_row.append(color1)
|
|
img_row.append(color2)
|
|
image.append(img_row)
|
|
return np.array(image)
|
|
|
|
|
|
# Experimentally determined. For a tpage from 0x00 to 0x1F, get that tpage
|
|
# out of VRAM.
|
|
def get_tpage_by_number(raw_dump, tpage_num):
|
|
assert 0 <= tpage_num < 0x20
|
|
tpage_row = tpage_num >= 0x10 # Row 0 or 1. First 16 are row 0, then row 1
|
|
tpage_top = tpage_row * 256 # rows are 256 pixels tall so this is where it starts
|
|
tpage_bottom = tpage_top + 256
|
|
tpage_left = (
|
|
tpage_num % 16
|
|
) * 128 # Modulo 16 gets the horizonal coordinate, then they are 128 pixels wide.
|
|
# Note: tpages are actually 256 pixels wide, but at 4 bits per pixel, they appear half as wide in our vram dump.
|
|
tpage_right = tpage_left + 128
|
|
return raw_dump[tpage_top:tpage_bottom, tpage_left:tpage_right]
|
|
|
|
|
|
# Retrieve a clut from the vram dump by clut number
|
|
def get_clut(colored_dump, clutnum):
|
|
# cluts come in 3 blocks from 0 to 256, 256-512, 512-768
|
|
block_number = clutnum // 0x100
|
|
# blocks are ordered as 1, 2, 0 based on first digit of clut.
|
|
block_x_position = ((block_number + 2) % 3) * 0x100
|
|
# get position within the block
|
|
clut_base = clutnum % 0x100
|
|
clut_x = block_x_position + (clut_base % 0x10) * 16
|
|
clut_y = 240 + clut_base // 0x10
|
|
clut = colored_dump[clut_y, clut_x : clut_x + 16]
|
|
return clut
|
|
|
|
|
|
# For a given tpage and clut, retrieve the tpage from the raw dump, and apply
|
|
# the clut to that tpage.
|
|
def retrieve_colored_tpage(raw_dump, colored, tpage_number, clut_number):
|
|
tpage_rendering_clut = get_clut(colored, clut_number)
|
|
# Now we have our tpage rendering clut extracted, get the tpage, and apply that clut.
|
|
tpage = get_tpage_by_number(raw_dump, tpage_number)
|
|
colored_tpage = color_tpage(tpage, tpage_rendering_clut)
|
|
return colored_tpage
|
|
|
|
|
|
def draw_tpage_selection(raw_dump, tpage_number, clut_number, left, top, width, height):
|
|
colored = convert_rgb555(raw_dump)
|
|
image = get_tpage_selection(
|
|
raw_dump, colored, tpage_number, clut_number, left, top, width, height
|
|
)
|
|
plt.imshow(image)
|
|
plt.show()
|
|
|
|
|
|
def get_tpage_selection(
|
|
raw_dump, colored, tpage_number, clut_number, left, top, width, height
|
|
):
|
|
ctp = retrieve_colored_tpage(raw_dump, colored, tpage_number, clut_number)
|
|
# Crop it to match the needed UV coords, and display it
|
|
segment = ctp[top : top + height, left : left + width]
|
|
return segment
|
|
|
|
|
|
# For the chosen filename for the vram dump, we load the bytes, convert
|
|
# to a numpy array, and transform this to a rectangular layout in vram.
|
|
def load_raw_dump(filename):
|
|
# Load the dump from a currently running PCSX instance
|
|
if filename == "LIVE":
|
|
api_url = "http://localhost:8080/api/v1/gpu/vram/raw"
|
|
try:
|
|
with urllib.request.urlopen(api_url) as response:
|
|
dumpbytes = response.read()
|
|
print("VRAM fetched from PCSX.")
|
|
except urllib.error.URLError as e:
|
|
print("Error retrieving textures from PCSX. Is it running?", e)
|
|
exit()
|
|
else: # Load from a specified filename
|
|
with open(filename, "rb") as dumpfile:
|
|
dumpbytes = dumpfile.read()
|
|
|
|
datasize = len(dumpbytes)
|
|
bytestring = np.frombuffer(dumpbytes, dtype=np.uint8)
|
|
return np.reshape(bytestring, (512, int(datasize / 512)))
|
|
|
|
|
|
class textureDisplayer:
|
|
def __init__(self, vram_dump):
|
|
self.rawvram = vram_dump
|
|
self.colored = convert_rgb555(vram_dump)
|
|
|
|
def get_image(self, tpage, clut, x, y, w, h):
|
|
return get_tpage_selection(self.rawvram, self.colored, tpage, clut, x, y, w, h)
|
|
|
|
|
|
parser = argparse.ArgumentParser(description="Renders textures from VRAM dumps")
|
|
parser.add_argument("dump_filename")
|
|
# Load the numerical values; the lambda auto-detects decimal or hexadecimal and processes either.
|
|
parser.add_argument("tpage_num", type=lambda x: int(x, 0), help="Tpage number")
|
|
parser.add_argument("clut_num", type=lambda x: int(x, 0), help="CLUT number")
|
|
parser.add_argument("UV_vals", nargs="*", type=lambda x: int(x, 0), help="x, y, w, h")
|
|
|
|
# Alternate run modes
|
|
parser.add_argument("--whole", action="store_true", help="Show the whole tpage+clut")
|
|
parser.add_argument(
|
|
"--showclut", action="store_true", help="Just show the 16 colors in the CLUT"
|
|
)
|
|
|
|
if __name__ == "__main__":
|
|
args = parser.parse_args()
|
|
|
|
array = load_raw_dump(args.dump_filename)
|
|
if args.showclut:
|
|
colored = convert_rgb555(array)
|
|
clut = get_clut(colored, args.clut_num)
|
|
clut = clut.reshape((1, 16, 3)) # reshape to turn the clut into a 1x16 image
|
|
plt.imshow(clut)
|
|
plt.show()
|
|
elif args.whole:
|
|
draw_tpage_selection(array, args.tpage_num, args.clut_num, 0, 0, 256, 256)
|
|
else:
|
|
draw_tpage_selection(array, args.tpage_num, args.clut_num, *args.UV_vals)
|