135 lines
2.9 KiB
Python
135 lines
2.9 KiB
Python
import sys
|
|
from dataclasses import dataclass, field
|
|
from pprint import pprint
|
|
|
|
@dataclass
|
|
class MD5MeshJoint:
|
|
bone_name: str = None
|
|
parent_index: int = None
|
|
x_pos: float = None
|
|
y_pos: float = None
|
|
z_pos: float = None
|
|
x_orient: float = None
|
|
y_orient: float = None
|
|
y_orient: float = None
|
|
|
|
@dataclass
|
|
class MD5MeshVert:
|
|
vert_index: int = None
|
|
v
|
|
|
|
@dataclass
|
|
class MD5MeshMesh:
|
|
mesh_name: str = None
|
|
shader: str = None
|
|
verts: list[MD5MeshVert] = None
|
|
|
|
|
|
@dataclass
|
|
class MD5Mesh:
|
|
num_joints: int = None
|
|
num_meshes: int = None
|
|
joints: list[MD5MeshJoint] = field(default_factory=lambda: list())
|
|
meshes: list[MD5MeshMesh] = field(default_factory=lambda: list())
|
|
|
|
def parse_header(l, ix, md5mesh):
|
|
assert l[ix+0] == "MD5Version 10"
|
|
assert l[ix+1].startswith("commandline")
|
|
return ix + 2
|
|
|
|
def parse_parameters(l, ix, md5mesh):
|
|
assert l[ix+0].startswith("numJoints ")
|
|
assert l[ix+1].startswith("numMeshes ")
|
|
|
|
md5mesh.num_joints = int(l[ix+0].removeprefix("numJoints "), 10)
|
|
md5mesh.num_meshes = int(l[ix+1].removeprefix("numMeshes "), 10)
|
|
|
|
return ix + 2
|
|
|
|
def parse_joint(l, ix, md5mesh):
|
|
s = l[ix]
|
|
lc = s.split("//", maxsplit=1)
|
|
if len(lc) == 2:
|
|
line, comment = lc
|
|
elif len(lc) == 1:
|
|
line = lc
|
|
comment = None
|
|
else:
|
|
assert False, len(lc)
|
|
|
|
tokens = line.split()
|
|
joint = MD5MeshJoint()
|
|
|
|
# bone name
|
|
bone_name = tokens[0]
|
|
assert bone_name.startswith('"') and bone_name.endswith('"')
|
|
joint.bone_name = bone_name[1:-1]
|
|
|
|
# parent index
|
|
joint.parent_index = int(tokens[1], 10)
|
|
|
|
assert tokens[2] == "("
|
|
|
|
joint.x_pos = float(tokens[3])
|
|
joint.y_pos = float(tokens[4])
|
|
joint.z_pos = float(tokens[5])
|
|
|
|
assert tokens[6] == ")"
|
|
|
|
assert tokens[7] == "("
|
|
|
|
joint.x_orient = float(tokens[8])
|
|
joint.y_orient = float(tokens[9])
|
|
joint.z_orient = float(tokens[10])
|
|
|
|
assert tokens[11] == ")"
|
|
|
|
md5mesh.joints.append(joint)
|
|
|
|
return ix + 1
|
|
|
|
def parse_joints(l, ix, md5mesh):
|
|
assert md5mesh.joints == []
|
|
|
|
while l[ix] != "}":
|
|
ix = parse_joint(l, ix, md5mesh)
|
|
|
|
return ix
|
|
|
|
def parse_mesh(l, ix, md5mesh):
|
|
|
|
|
|
def parse_ordered_list(l, ix, md5mesh):
|
|
assert l[ix].endswith("{"), l[ix]
|
|
string = l[ix].split()[0]
|
|
ix += 1
|
|
|
|
if string == "joints":
|
|
ix = parse_joints(l, ix, md5mesh)
|
|
elif string == "mesh":
|
|
ix = parse_mesh(l, ix, md5mesh)
|
|
else:
|
|
assert False, string
|
|
|
|
assert l[ix] == "}"
|
|
ix += 1
|
|
return ix
|
|
|
|
def parse_file(l):
|
|
ix = 0
|
|
md5mesh = MD5Mesh()
|
|
ix = parse_header(l, ix, md5mesh)
|
|
ix = parse_parameters(l, ix, md5mesh)
|
|
while ix < len(l):
|
|
ix = parse_ordered_list(l, ix, md5mesh)
|
|
|
|
pprint(md5mesh)
|
|
|
|
if __name__ == "__main__":
|
|
with open(sys.argv[1], 'r') as f:
|
|
buf = f.read()
|
|
|
|
l = [i.strip() for i in buf.split('\n') if i.strip()]
|
|
|
|
parse_file(l)
|