Files
CrunkLord420 9403d64739 init
2022-08-11 04:02:45 -07:00

280 lines
12 KiB
Python
Executable File

#!/bin/env python3
import argparse
import struct
parser = argparse.ArgumentParser()
parser.add_argument("file")
parser.add_argument("name")
parser.add_argument('mode', help='obj parsing mode', nargs='?', choices=('line', 'face', 'facen', 'obj', 'collision'), default='line')
parser.add_argument('-c', '--color', help='enable color (lines)', action='store_true')
parser.add_argument('-b', '--binary', help='binary output', action='store_true')
parser.add_argument('-d', '--debug', help='print extra information', action='store_true')
args = parser.parse_args()
objFile = open(args.file)
obj = objFile.read()
objFile.close()
# Constants
BLACK = 0
BLUE = 1
GREEN = 2
CYAN = 3
RED = 4
PURPLE = 5
BROWN = 6
LTGRAY = 7
DKGRAY = 8
LTBLUE = 9
LTGREEN = 10
LTCYAN = 11
LTRED = 12
LTPURPLE = 13
YELLOW = 14
WHITE = 15
COLOR_LOOKUP = {
'BLACK': 0,
'BLUE': 1,
'GREEN': 2,
'CYAN': 3,
'RED': 4,
'PURPLE': 5,
'BROWN': 6,
'LTGRAY': 7,
'DKGRAY': 8,
'LTBLUE': 9,
'LTGREEN': 10,
'LTCYAN': 11,
'LTRED': 12,
'LTPURPLE': 13,
'YELLOW': 14,
'WHITE': 15,
}
# Variables
activeColor = 'WHITE'
verts = []
lines = []
objs = []
faces = []
fns = []
normals = []
colors = []
obj = obj.splitlines()
for line in obj:
if line[0:2] == 'v ':
sl = line[2:].split()
verts.append((int(round(float(sl[0]))), int(round(float(sl[1]))), int(round(float(sl[2])))))
elif line[0:2] == 'l ':
sl = line[2:].split()
lines.append((int(sl[0])-1, int(sl[1])-1))
colors.append(activeColor)
elif line[0:3] == 'vn ':
sl = line[3:].split()
normals.append((float(sl[0]), float(sl[1]), float(sl[2])))
elif line[0:2] == 'f ':
if args.mode == 'facen':
sl = line[2:].split()
fn1 = sl[0].split('/')
fn2 = sl[1].split('/')
fn3 = sl[2].split('/')
faces.append((int(fn1[0])-1, int(fn2[0])-1, int(fn3[0])-1))
fns.append((int(fn1[2])-1, int(fn2[2])-1, int(fn3[2])-1))
colors.append(activeColor)
else:
sl = line[2:].split()
faces.append((int(sl[0])-1, int(sl[1])-1, int(sl[2])-1))
elif line[0:7] == 'usemtl ':
activeColor = line[7:]
output = f"#ifndef {args.name}_HC\n#define {args.name}_HC\n\n"
if args.mode == 'obj':
for li,line in enumerate(obj):
if line[0:2] == 'o ':
if (len(objs) > 0):
objs[len(objs)-1]["e"] = li
objs.append({"n": line[2:], "s": li})
objs[len(objs)-1]["e"] = len(obj);
for o in objs:
o["v"] = []
o["l"] = []
for i in range(o["s"]+1, o["e"]):
if obj[i][0:2] == 'v ':
sl = obj[i][2:].split()
o["v"].append((int(float(sl[0])), int(float(sl[1])), int(float(sl[2]))))
elif obj[i][0:2] == 'l ':
sl = obj[i][2:].split()
o["l"].append((int(sl[0])-1, int(sl[1])-1))
output = f"#define {args.name}_parts {len(objs)}\nI64 {args.name}_cnts[{len(objs)}];\nCD3I32 *{args.name}[{len(objs)}];\n"
for oi, o in enumerate(objs):
output += f"CD3I32 {args.name}_{oi}[{len(o['l'])*2}];\n"
i = 0
for li, line in enumerate(o['l']):
output += f"{args.name}_{oi}[{i}].x={o['v'][lines[li][0]][0]};{args.name}_{oi}[{i}].y={o['v'][lines[li][0]][1]};{args.name}_{oi}[{i}].z={o['v'][lines[li][0]][2]};\n"
i += 1
output += f"{args.name}_{oi}[{i}].x={o['v'][lines[li][1]][0]};{args.name}_{oi}[{i}].y={o['v'][lines[li][1]][1]};{args.name}_{oi}[{i}].z={o['v'][lines[li][1]][2]};\n"
i += 1
output += f"{args.name}_cnts[{oi}] = {len(o['l'])*2};\n{args.name}[{oi}] = {args.name}_{oi};\n"
elif args.mode == 'face':
if args.binary:
binOutput = bytes(len(faces).to_bytes(4, byteorder='little', signed=False))
for tri in faces:
binOutput += verts[tri[0]][0].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[0]][1].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[0]][2].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[1]][0].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[1]][1].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[1]][2].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[2]][0].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[2]][1].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[2]][2].to_bytes(4, byteorder='little', signed=True)
out = open(args.name, 'wb')
out.write(binOutput)
out.close()
else:
output += f"#define {args.name}_tris {len(faces)}\nCD3I32 {args.name}[{args.name}_tris][3];\n"
for ti, tri in enumerate(faces):
output += f"{args.name}[{ti}][0].x={verts[tri[0]][0]};{args.name}[{ti}][0].y={verts[tri[0]][1]};{args.name}[{ti}][0].z={verts[tri[0]][2]};\n";
output += f"{args.name}[{ti}][1].x={verts[tri[1]][0]};{args.name}[{ti}][1].y={verts[tri[1]][1]};{args.name}[{ti}][1].z={verts[tri[1]][2]};\n";
output += f"{args.name}[{ti}][2].x={verts[tri[2]][0]};{args.name}[{ti}][2].y={verts[tri[2]][1]};{args.name}[{ti}][2].z={verts[tri[2]][2]};\n";
elif args.mode == 'facen':
if args.binary:
binOutput = bytes(len(faces).to_bytes(2, byteorder='little', signed=False))
binOutput += len(normals).to_bytes(2, byteorder='little', signed=False)
assert len(faces) == len(fns)
assert len(faces) == len(colors)
for tri in faces:
binOutput += verts[tri[0]][0].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[0]][1].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[0]][2].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[1]][0].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[1]][1].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[1]][2].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[2]][0].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[2]][1].to_bytes(4, byteorder='little', signed=True)
binOutput += verts[tri[2]][2].to_bytes(4, byteorder='little', signed=True)
for ni in fns:
binOutput += ni[0].to_bytes(2, byteorder='little', signed=False)
for n in normals:
binOutput += struct.pack('<d', n[0])
binOutput += struct.pack('<d', n[1])
binOutput += struct.pack('<d', n[2])
for color in colors:
binOutput += COLOR_LOOKUP[color].to_bytes(1, byteorder='little', signed=False)
out = open(args.name, 'wb')
out.write(binOutput)
out.close()
else:
output += f"#include \"ModelTemplate.HC\"\n\n#define {args.name}TriCnt {len(faces)}\n#define {args.name}NormCnt {len(normals)}\nCD3I32 {args.name}Tri[{args.name}TriCnt][3]; // Triangles\nCD3 {args.name}N[{args.name}NormCnt]; // Normals\nI32 {args.name}NI[{args.name}TriCnt]; // Normal Index\nU8 {args.name}C[{args.name}TriCnt]; // Colors\nModelTemplate {args.name};\n"
for ti, tri in enumerate(faces):
output += f"{args.name}Tri[{ti}][0].x={verts[tri[0]][0]};{args.name}Tri[{ti}][0].y={verts[tri[0]][1]};{args.name}Tri[{ti}][0].z={verts[tri[0]][2]};\n";
output += f"{args.name}Tri[{ti}][1].x={verts[tri[1]][0]};{args.name}Tri[{ti}][1].y={verts[tri[1]][1]};{args.name}Tri[{ti}][1].z={verts[tri[1]][2]};\n";
output += f"{args.name}Tri[{ti}][2].x={verts[tri[2]][0]};{args.name}Tri[{ti}][2].y={verts[tri[2]][1]};{args.name}Tri[{ti}][2].z={verts[tri[2]][2]};\n";
for nii, ni in enumerate(fns):
output += f"{args.name}NI[{nii}]={ni[0]};\n";
for ni, n in enumerate(normals):
output += f"{args.name}N[{ni}].x={n[0]};{args.name}N[{ni}].y={n[1]};{args.name}N[{ni}].z={n[2]};\n";
for ci, color in enumerate(colors):
output += f"{args.name}C[{ci}]={color};\n";
output += f"{args.name}.triCnt={args.name}TriCnt;\n{args.name}.normCnt={args.name}NormCnt;\n{args.name}.tris={args.name}Tri;\n{args.name}.colors={args.name}C;\n{args.name}.normals={args.name}N;\n{args.name}.normIndex={args.name}NI;";
elif args.mode == 'collision':
# Collision mode expects a single contiguous loop of lines
# The first line (idx 0) is expected to contain the first vert (idx 0)
# The first line+first vert determines if wrap is clockwise or counter-clockwise
cverts = []
cedges = []
v0 = 0
v_last = v0
vc = 0
vc_last = 0
# check first edge, swap if needed
fv = lines[0][0]
if lines[0][1] == 0:
fv = lines[0][1]
cverts.append((verts[fv][0], verts[fv][1], verts[fv][2]))
while True:
found = False
if vc >= len(verts)-1:
break
for i, e in enumerate(lines):
if e[0] == v0:
if e[1] == v_last:
continue
v_last = v0
v0 = e[1]
vc_last = vc
vc += 1
cverts.append((verts[e[1]][0], verts[e[1]][1], verts[e[1]][2]))
cedges.append((vc_last, vc))
found = True
break
elif e[1] == v0:
if e[0] == v_last:
continue
v_last = v0
v0 = e[0]
vc_last = vc
vc += 1
cverts.append((verts[e[0]][0], verts[e[0]][1], verts[e[0]][2]))
cedges.append((vc_last, vc))
found = True
break
if found == False:
print("Not Found", v0)
break
cedges.append((vc, 0))
lineArrB = bytes((len(cedges)+1).to_bytes(4, byteorder='little', signed=False))
for li,line in enumerate(lines):
lineArrB += cverts[cedges[li][0]][0].to_bytes(4, byteorder='little', signed=True)
lineArrB += cverts[cedges[li][0]][1].to_bytes(4, byteorder='little', signed=True)
lineArrB += cverts[cedges[li][0]][2].to_bytes(4, byteorder='little', signed=True)
lineArrB += cverts[cedges[0][0]][0].to_bytes(4, byteorder='little', signed=True)
lineArrB += cverts[cedges[0][0]][1].to_bytes(4, byteorder='little', signed=True)
lineArrB += cverts[cedges[0][0]][2].to_bytes(4, byteorder='little', signed=True)
out = open(args.name, 'wb')
out.write(lineArrB)
out.close()
if args.debug:
print('=verts=')
for v in cverts:
print(v)
print('=lines=')
for v in cedges:
print(v)
else: # lines
if args.binary:
lineArrB = bytes((len(lines)*2).to_bytes(4, byteorder='little', signed=False))
for li,line in enumerate(lines):
lineArrB += verts[lines[li][0]][0].to_bytes(4, byteorder='little', signed=True)
lineArrB += verts[lines[li][0]][1].to_bytes(4, byteorder='little', signed=True)
lineArrB += verts[lines[li][0]][2].to_bytes(4, byteorder='little', signed=True)
lineArrB += verts[lines[li][1]][0].to_bytes(4, byteorder='little', signed=True)
lineArrB += verts[lines[li][1]][1].to_bytes(4, byteorder='little', signed=True)
lineArrB += verts[lines[li][1]][2].to_bytes(4, byteorder='little', signed=True)
if args.color:
for color in colors:
lineArrB += COLOR_LOOKUP[color].to_bytes(1, byteorder='little', signed=False)
out = open(args.name, 'wb')
out.write(lineArrB)
out.close()
else:
output += f"#define {args.name}_cnt {len(lines)*2}\nCD3I32 {args.name}[{args.name}_cnt];\n"
i = 0
for li,line in enumerate(lines):
output += f"{args.name}[{i}].x={verts[lines[li][0]][0]};{args.name}[{i}].y={verts[lines[li][0]][1]};{args.name}[{i}].z={verts[lines[li][0]][2]};\n"
i += 1
output += f"{args.name}[{i}].x={verts[lines[li][1]][0]};{args.name}[{i}].y={verts[lines[li][1]][1]};{args.name}[{i}].z={verts[lines[li][1]][2]};\n"
i += 1
if not args.binary:
output += "\n#endif"
print(output)