engine-psx/tools/convrsd/convrsd.py

326 lines
11 KiB
Python
Raw Permalink Normal View History

#!/bin/env python
import os
import sys
from pprint import pp as pprint
from dataclasses import dataclass, field
from fixedpoint import tofixed12
from common import *
from face import *
from material import *
from import_types import *
from export_types import *
# ------------------------------------------
def parse_rsd(filename: str) -> RSDModel:
if not os.path.isfile(filename):
print(f"File {filename} does not exist")
exit(1)
filename = os.path.abspath(filename)
rsd = RSDModel()
with open(filename, "r") as f:
# Read magic
while True:
rsd.magic = f.readline().strip()
if not rsd.magic:
print(f"Unexpected EOF at {filename}")
exit(1)
if rsd.magic[0] == "#":
continue
if rsd.magic[:4] != "@RSD":
print(f"Could not parse RSD file {filename}")
exit(1)
break
ply_filename = None
mat_filename = None
# Read other lines
while True:
buffer = f.readline().strip()
if not buffer:
break
elif buffer[:3] == "PLY":
ply_filename = buffer[4:]
elif buffer[:3] == "MAT":
mat_filename = buffer[4:]
elif buffer[:4] == "MTEX":
# TODO
pass
if ply_filename:
ply_filename = os.path.dirname(filename) + "/" + ply_filename
rsd.ply = parse_ply(ply_filename.strip())
if mat_filename:
mat_filename = os.path.dirname(filename) + "/" + mat_filename
rsd.mat = parse_mat(mat_filename.strip())
return rsd
# ------------------------------------------
def _parse_face(buffer: str) -> Face:
buffer = buffer.split()
ftype = FaceType(int(buffer[0]))
if ftype == FaceType.TRIANGLE:
v = TriangleFace()
v.iv0 = c_ushort(int(buffer[1]))
v.iv1 = c_ushort(int(buffer[2]))
v.iv2 = c_ushort(int(buffer[3]))
v.in0 = c_ushort(int(buffer[5]))
v.in1 = c_ushort(int(buffer[6]))
v.in2 = c_ushort(int(buffer[7]))
return v
elif ftype == FaceType.QUAD:
v = QuadFace()
v.iv0 = c_ushort(int(buffer[1]))
v.iv1 = c_ushort(int(buffer[2]))
v.iv2 = c_ushort(int(buffer[3]))
v.iv3 = c_ushort(int(buffer[4]))
v.in0 = c_ushort(int(buffer[5]))
v.in1 = c_ushort(int(buffer[6]))
v.in2 = c_ushort(int(buffer[7]))
2024-09-21 18:18:20 -03:00
v.in3 = c_ushort(int(buffer[8]))
return v
elif ftype == FaceType.LINE:
v = LineFace()
v.iv0 = c_ushort(int(buffer[1]))
v.iv1 = c_ushort(int(buffer[2]))
return v
elif ftype == FaceType.SPRITE:
v = SpriteFace()
v.iv0 = c_ushort(int(buffer[1]))
v.iv1 = c_ushort(int(buffer[2]))
v.iw = c_ushort(int(buffer[3]))
v.ih = c_ushort(int(buffer[4]))
return v
else:
print(f"Unknown face type {ftype}")
exit(1)
def parse_ply(filename: str) -> PlyData:
if not os.path.isfile(filename):
print(f"File {filename} does not exist")
exit(1)
ply = PlyData()
with open(filename, "r") as f:
# Read magic
while True:
ply.magic = f.readline().strip()
if not ply.magic:
print(f"Unexpected EOF at {filename}")
exit(1)
if ply.magic[0] == "#":
continue
if ply.magic[:4] != "@PLY":
print(f"Could not parse PLY file {filename}")
exit(1)
break
step = 0
vertices = 0
normals = 0
faces = 0
while True:
buffer = f.readline().strip()
if not buffer:
break
elif buffer[0] == "#":
continue
if step == 0:
numbers = buffer.split()
ply.num_vertices = c_ushort(int(numbers[0]))
ply.num_normals = c_ushort(int(numbers[1]))
ply.num_faces = c_ushort(int(numbers[2]))
vertices = ply.num_vertices.value
normals = ply.num_normals.value
faces = ply.num_faces.value
step += 1
elif step == 1:
if vertices > 0:
values = buffer.split()
2024-09-21 18:18:20 -03:00
# print(f"Buffered values: {values}")
values = [float(x) for x in values]
# print(f"Float values: {values}")
values = [tofixed12(x) for x in values]
# print(f"Fixed values: {values}")
# print("---------------")
vertex = VECTOR()
vertex.vx = c_int(values[0])
vertex.vy = c_int(values[1])
vertex.vz = c_int(values[2])
ply.vertices.append(vertex)
vertices -= 1
elif normals > 0:
values = buffer.split()
values = [tofixed12(float(x)) for x in values]
normal = VECTOR()
normal.vx = c_int(values[0])
normal.vy = c_int(values[1])
normal.vz = c_int(values[2])
ply.normals.append(normal)
normals -= 1
elif faces > 0:
ply.faces.append(_parse_face(buffer))
faces -= 1
else:
step += 1
else:
break
assert ply.num_vertices.value == len(ply.vertices)
assert ply.num_normals.value == len(ply.normals)
assert ply.num_faces.value == len(ply.faces)
return ply
# ------------------------------------------
def _parse_material(buffer: str) -> Material:
buffer = buffer.split()
material = Material()
material.ipolygon = c_ushort(int(buffer[0]))
material.flag = c_ubyte(int(buffer[1]))
material.shading = ShadingType(buffer[2])
mtype = MaterialType(buffer[3])
if mtype == MaterialType.Flat:
material.info = FlatMaterial()
material.info.r0 = c_ubyte(int(buffer[4]))
material.info.g0 = c_ubyte(int(buffer[5]))
material.info.b0 = c_ubyte(int(buffer[6]))
elif mtype == MaterialType.Gouraud:
material.info = GouraudMaterial()
material.info.r0 = c_ubyte(int(buffer[4]))
material.info.g0 = c_ubyte(int(buffer[5]))
material.info.b0 = c_ubyte(int(buffer[6]))
material.info.r1 = c_ubyte(int(buffer[5]))
material.info.g1 = c_ubyte(int(buffer[6]))
material.info.b1 = c_ubyte(int(buffer[7]))
material.info.r2 = c_ubyte(int(buffer[8]))
material.info.g2 = c_ubyte(int(buffer[9]))
material.info.b2 = c_ubyte(int(buffer[10]))
material.info.r3 = c_ubyte(int(buffer[11]))
material.info.g3 = c_ubyte(int(buffer[12]))
material.info.b3 = c_ubyte(int(buffer[13]))
elif mtype == MaterialType.Texture:
m = TextureMaterial()
material.info.u0 = c_ubyte(int(buffer[4]))
material.info.v0 = c_ubyte(int(buffer[5]))
material.info.u1 = c_ubyte(int(buffer[6]))
material.info.v1 = c_ubyte(int(buffer[7]))
material.info.u2 = c_ubyte(int(buffer[8]))
material.info.v2 = c_ubyte(int(buffer[9]))
material.info.u3 = c_ubyte(int(buffer[10]))
material.info.v3 = c_ubyte(int(buffer[11]))
elif mtype == MaterialType.TextureFlat:
material.info = TextureFlatMaterial()
material.info.u0 = c_ubyte(int(buffer[4]))
material.info.v0 = c_ubyte(int(buffer[5]))
material.info.u1 = c_ubyte(int(buffer[6]))
material.info.v1 = c_ubyte(int(buffer[7]))
material.info.u2 = c_ubyte(int(buffer[8]))
material.info.v2 = c_ubyte(int(buffer[9]))
material.info.u3 = c_ubyte(int(buffer[10]))
material.info.v3 = c_ubyte(int(buffer[11]))
material.info.r0 = c_ubyte(int(buffer[12]))
material.info.g0 = c_ubyte(int(buffer[13]))
material.info.b0 = c_ubyte(int(buffer[14]))
elif mtype == MaterialType.TextureGouraud:
material.info = TextureGouraudMaterial()
material.info.u0 = c_ubyte(int(buffer[4]))
material.info.v0 = c_ubyte(int(buffer[5]))
material.info.u1 = c_ubyte(int(buffer[6]))
material.info.v1 = c_ubyte(int(buffer[7]))
material.info.u2 = c_ubyte(int(buffer[8]))
material.info.v2 = c_ubyte(int(buffer[9]))
material.info.u3 = c_ubyte(int(buffer[10]))
material.info.v3 = c_ubyte(int(buffer[11]))
material.info.r0 = c_ubyte(int(buffer[12]))
material.info.g0 = c_ubyte(int(buffer[13]))
material.info.b0 = c_ubyte(int(buffer[14]))
material.info.r1 = c_ubyte(int(buffer[15]))
material.info.g1 = c_ubyte(int(buffer[16]))
material.info.b1 = c_ubyte(int(buffer[17]))
material.info.r2 = c_ubyte(int(buffer[18]))
material.info.g2 = c_ubyte(int(buffer[19]))
material.info.b2 = c_ubyte(int(buffer[20]))
material.info.r3 = c_ubyte(int(buffer[21]))
material.info.g3 = c_ubyte(int(buffer[22]))
material.info.b3 = c_ubyte(int(buffer[23]))
else:
print(f"Unhandled material type {mtype}")
exit(1)
return material
def parse_mat(filename: str) -> MatData:
if not os.path.isfile(filename):
print(f"File {filename} does not exist")
exit(1)
mat = MatData()
with open(filename, "r") as f:
# Read magic
while True:
mat.magic = f.readline().strip()
if not mat.magic:
print(f"Unexpected EOF at {filename}")
exit(1)
if mat.magic[0] == "#":
continue
if mat.magic[:4] != "@MAT":
print(f"Could not parse MAT file {filename}")
exit(1)
break
step = 0
items = 0
while True:
buffer = f.readline().strip()
if not buffer:
break
elif buffer[0] == "#":
continue
if step == 0:
mat.num_items = c_ushort(int(buffer))
items = mat.num_items.value
step += 1
elif step == 1:
if items > 0:
mat.materials.append(_parse_material(buffer))
items -= 1
else:
step += 1
else:
break
assert mat.num_items.value == len(mat.materials)
return mat
def main():
filename = sys.argv[1]
rsd = parse_rsd(filename.strip())
mdl = convert_model(rsd)
out_filename = os.path.splitext(filename)[0] + ".mdl"
with open(out_filename, "wb") as f:
mdl.write(f)
if __name__ == "__main__":
main()