Last active
July 6, 2018 03:41
-
-
Save Jellonator/ef48f7a1c95c5145253e04ef64626779 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import argparse | |
import struct | |
import math | |
import operator | |
parser = argparse.ArgumentParser() | |
parser.add_argument('input', metavar="INPUT", type=argparse.FileType('rb'), | |
nargs=1, help='the TMESH file to open') | |
parser.add_argument('output', metavar="OUTPUT", type=argparse.FileType('w'), | |
nargs=1, help='the OBJ file to save to') | |
# parser.add_argument('--verbose', action="store_const", const=True, default=False) | |
args = parser.parse_args() | |
print(args) | |
mesh = args.input[0] | |
obj = args.output[0] | |
# Not sure what the header is | |
mesh.read(96) | |
# Not sure what this is | |
something = struct.unpack(">H", mesh.read(2))[0] | |
# This value is used to calculate padding later | |
padding_mult = struct.unpack(">H", mesh.read(2))[0] | |
# Vertex block format: | |
# struct Vertex { float x, y, z; }; | |
# uint32_t num_vertices | |
# Vertex vertices[num_vertices] | |
num_vertices = struct.unpack(">I", mesh.read(4))[0] | |
vertices = [] | |
print(num_vertices, "vertices") | |
for i in range(num_vertices): | |
pos = struct.unpack(">fff", mesh.read(12)) | |
vertices.append(pos) | |
obj.write("v {} {} {}\n".format(pos[0], pos[1], pos[2])) | |
# Texture coordinate block format: | |
# struct TexCoord { float x, y; }; | |
# uint32_t num_texcoords; | |
# TexCoord texcoords[num_texcoords]; | |
# | |
# The y-axis is reversed | |
num_texcoords = struct.unpack(">I", mesh.read(4))[0] | |
print(num_texcoords, "texcoords") | |
for i in range(num_texcoords): | |
pos = struct.unpack(">ff", mesh.read(8)) | |
obj.write("vt {} {}\n".format(pos[0], 1.0-pos[1])) | |
# Normal block format: | |
# struct Normal { float x, y, z; }; | |
# uint32_t num_normals | |
# Normal normals[num_normals] | |
num_normals = struct.unpack(">I", mesh.read(4))[0] | |
print(num_normals, "normals") | |
normals = [] | |
for i in range(num_normals): | |
pos = struct.unpack(">fff", mesh.read(12)) | |
# Make sure normals are unit vectors | |
# Not really necessary, but just in case | |
length = math.sqrt(pos[0]**2 + pos[1]**2 + pos[2]**2) | |
pos = (pos[0] / length, pos[1] / length, pos[2] / length) | |
normals.append(pos) | |
obj.write("vn {} {} {}\n".format(pos[0], pos[1], pos[2])) | |
# Faces are built in triangle strips | |
# For example, a strip with the data [0, 1, 3, 5, 8] would build the following | |
# triangles: [(0, 1, 3), (1, 3, 5), (3, 5, 8)] | |
# | |
# Strip vertex block format: | |
# struct Strip { | |
# uint32_t num_elements; | |
# uint16_t vertex_id[num_elements]; | |
# uint32_t unknown_1; | |
# uint32_t tri_order; // The order that triangles will be build in (1 or 2) | |
# }; | |
# uint32_t num_strips; | |
# Strip strips[num_strips]; | |
strips = [] | |
sum = 0 | |
num_strips = struct.unpack(">I", mesh.read(4))[0] | |
for i in range(num_strips): | |
num_elements = struct.unpack(">I", mesh.read(4))[0] | |
elements = [] | |
for j in range(num_elements): | |
elements.append(struct.unpack(">H", mesh.read(2))[0]) | |
unknown = struct.unpack(">II", mesh.read(8)) | |
strip = { | |
"elements": elements, | |
"unknown": unknown[0], | |
"triorder": unknown[1], | |
} | |
print(unknown, len(elements)) | |
strips.append(strip) | |
# There's some padding here for some reason. Don't ask why the format | |
# calculates the padding this way, I don't know either. | |
mesh.read(padding_mult*num_strips) | |
# Here is the strip data that contains texture coordinate and | |
# normal information, not sure why it's separate from the vertex ids. | |
# Strip data format: | |
# struct ElementData { | |
# uint16_t texcoord_id; | |
# uint16_t normal_id; | |
# }; | |
# struct StripData { | |
# uint32_t num_elements; // always equal to the | |
# // corresponding Strip.num_elements | |
# ElementData elements[num_elements]; | |
# }; | |
# uint32_t num_stripdata; // Always equal to num_strips | |
# StripData stripdata[num_stripdata]; | |
stripdata = [] | |
num_stripdata = struct.unpack(">I", mesh.read(4))[0] | |
for i in range(num_stripdata): | |
num_elements = struct.unpack(">I", mesh.read(4))[0] | |
elements = [] | |
for j in range(num_elements): | |
elements.append(struct.unpack(">HH", mesh.read(4))) | |
stripdata.append(elements) | |
# Build triangle faces | |
for (strip, data) in zip(strips, stripdata): | |
elements = strip["elements"] | |
a = strip["triorder"] | |
b = 3-a | |
lists = [[0,b,a], [0,a,b]] | |
index = 0 | |
for i in range(len(elements)-2): | |
obj.write("f ") | |
for j in lists[index]: | |
subdata = data[i+j] | |
texcoord = subdata[0]+1 | |
normal = subdata[1]+1 | |
vertex = elements[i+j]+1 | |
if vertex > num_vertices: | |
print("INVALID VERTEX INDEX", vertex) | |
if texcoord > num_texcoords: | |
print("INVALID TEXCOORD INDEX", texcoord) | |
if normal > num_normals: | |
print("INVALID NORMAL INDEX", normal) | |
obj.write("{}/{}/{} ".format(vertex, texcoord, normal)) | |
index = (index+1) % len(lists) | |
obj.write("\n") | |
# There's also some weird data after this point, but I'm not sure what it does | |
# or if it's even meaningful in the first place |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment