mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-21 19:45:10 +00:00
correct line endings
This commit is contained in:
parent
ee69a027ef
commit
8b71a1a734
2 changed files with 246 additions and 246 deletions
280
c2obj.py
280
c2obj.py
|
@ -1,141 +1,141 @@
|
||||||
"""
|
"""
|
||||||
This module attempts to parse the ``model.inc.c`` files and extract the
|
This module attempts to parse the ``model.inc.c`` files and extract the
|
||||||
3D models within as standard Wavefront OBJ files.
|
3D models within as standard Wavefront OBJ files.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Specify the path to the ``.inc.c`` file and a directory where to save
|
Specify the path to the ``.inc.c`` file and a directory where to save
|
||||||
the extracted ``.obj`` files.
|
the extracted ``.obj`` files.
|
||||||
|
|
||||||
$ python c2obj.py ./actors/mario/model.inc.c ./actors/mario/obj/
|
$ python c2obj.py ./actors/mario/model.inc.c ./actors/mario/obj/
|
||||||
|
|
||||||
This is a work in progress and it currently has some serious limitations:
|
This is a work in progress and it currently has some serious limitations:
|
||||||
* It only extracts geometry information, so no textures or any other info
|
* It only extracts geometry information, so no textures or any other info
|
||||||
* It makes assumptions about the layout of the code in the C source
|
* It makes assumptions about the layout of the code in the C source
|
||||||
* It hasn't been properly tested.
|
* It hasn't been properly tested.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def parse(filename, output_directory):
|
def parse(filename, output_directory):
|
||||||
from os import path, mkdir
|
from os import path, mkdir
|
||||||
|
|
||||||
if not path.isdir(output_directory):
|
if not path.isdir(output_directory):
|
||||||
try:
|
try:
|
||||||
mkdir(output_directory)
|
mkdir(output_directory)
|
||||||
except OSError:
|
except OSError:
|
||||||
print(f'Could not use output directory {output_directory}.')
|
print(f'Could not use output directory {output_directory}.')
|
||||||
|
|
||||||
vtx_def = 'static const Vtx '
|
vtx_def = 'static const Vtx '
|
||||||
vtx_data = {}
|
vtx_data = {}
|
||||||
reading_vtx = False
|
reading_vtx = False
|
||||||
current_vtx_name = ''
|
current_vtx_name = ''
|
||||||
current_vtx_data = []
|
current_vtx_data = []
|
||||||
current_vtx_vertices = 0
|
current_vtx_vertices = 0
|
||||||
|
|
||||||
gfx_def = 'const Gfx '
|
gfx_def = 'const Gfx '
|
||||||
reading_gfx = False
|
reading_gfx = False
|
||||||
current_gfx_vertices = 0
|
current_gfx_vertices = 0
|
||||||
current_gfx_faces = 0
|
current_gfx_faces = 0
|
||||||
insert_vert_call = 'gsSPVertex('
|
insert_vert_call = 'gsSPVertex('
|
||||||
insert_1tri_call = 'gsSP1Triangle('
|
insert_1tri_call = 'gsSP1Triangle('
|
||||||
insert_2tri_call = 'gsSP2Triangles('
|
insert_2tri_call = 'gsSP2Triangles('
|
||||||
gfx_count = 0
|
gfx_count = 0
|
||||||
|
|
||||||
end_of_block = '};'
|
end_of_block = '};'
|
||||||
|
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
|
||||||
if line.startswith(vtx_def):
|
if line.startswith(vtx_def):
|
||||||
vtx_name = line.split(' ')[3][:-2]
|
vtx_name = line.split(' ')[3][:-2]
|
||||||
current_vtx_name = vtx_name
|
current_vtx_name = vtx_name
|
||||||
current_vtx_data = []
|
current_vtx_data = []
|
||||||
reading_vtx = True
|
reading_vtx = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if line.startswith(gfx_def):
|
if line.startswith(gfx_def):
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
current_gfx_name = line.split(' ')[2][:-2]
|
current_gfx_name = line.split(' ')[2][:-2]
|
||||||
current_gfx_file = open(path.join(output_directory, current_gfx_name + '.obj'), 'w')
|
current_gfx_file = open(path.join(output_directory, current_gfx_name + '.obj'), 'w')
|
||||||
current_gfx_file.write("# Armando Arredondo's SM64 Wavefront OBJ Geometry Converter\n")
|
current_gfx_file.write("# Armando Arredondo's SM64 Wavefront OBJ Geometry Converter\n")
|
||||||
current_gfx_file.write('# File Created: {}\n\n'.format(datetime.now()))
|
current_gfx_file.write('# File Created: {}\n\n'.format(datetime.now()))
|
||||||
reading_gfx = True
|
reading_gfx = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if line == end_of_block:
|
if line == end_of_block:
|
||||||
if reading_vtx:
|
if reading_vtx:
|
||||||
vtx_data[current_vtx_name] = current_vtx_data
|
vtx_data[current_vtx_name] = current_vtx_data
|
||||||
reading_vtx = False
|
reading_vtx = False
|
||||||
|
|
||||||
elif reading_gfx:
|
elif reading_gfx:
|
||||||
current_gfx_file.write(f'# {current_gfx_faces} faces\n\n')
|
current_gfx_file.write(f'# {current_gfx_faces} faces\n\n')
|
||||||
current_gfx_file.close()
|
current_gfx_file.close()
|
||||||
current_gfx_vertices = 0
|
current_gfx_vertices = 0
|
||||||
reading_gfx = False
|
reading_gfx = False
|
||||||
gfx_count += 1
|
gfx_count += 1
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if reading_vtx:
|
if reading_vtx:
|
||||||
line = line.replace('{', '[').replace('}', ']')
|
line = line.replace('{', '[').replace('}', ']')
|
||||||
tri = eval(line[:-1])[0]
|
tri = eval(line[:-1])[0]
|
||||||
current_vtx_data.append(tri)
|
current_vtx_data.append(tri)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if reading_gfx:
|
if reading_gfx:
|
||||||
if line.startswith(insert_vert_call):
|
if line.startswith(insert_vert_call):
|
||||||
args = line[len(insert_vert_call):].split(',')
|
args = line[len(insert_vert_call):].split(',')
|
||||||
current_vtx_name = args[0]
|
current_vtx_name = args[0]
|
||||||
|
|
||||||
if current_gfx_vertices > 0:
|
if current_gfx_vertices > 0:
|
||||||
current_gfx_file.write(f'# {current_gfx_faces} faces\n\n')
|
current_gfx_file.write(f'# {current_gfx_faces} faces\n\n')
|
||||||
|
|
||||||
current_gfx_faces = 0
|
current_gfx_faces = 0
|
||||||
current_vtx_vertices = len(vtx_data[current_vtx_name])
|
current_vtx_vertices = len(vtx_data[current_vtx_name])
|
||||||
current_gfx_vertices += current_vtx_vertices
|
current_gfx_vertices += current_vtx_vertices
|
||||||
|
|
||||||
current_gfx_file.write(f'#\n# object {current_vtx_name}\n#\n\n')
|
current_gfx_file.write(f'#\n# object {current_vtx_name}\n#\n\n')
|
||||||
current_vtx_data = vtx_data[current_vtx_name]
|
current_vtx_data = vtx_data[current_vtx_name]
|
||||||
for tri in current_vtx_data:
|
for tri in current_vtx_data:
|
||||||
v = tri[0]
|
v = tri[0]
|
||||||
current_gfx_file.write('v {:.3f} {:.3f} {:.3f}\n'.format(*v))
|
current_gfx_file.write('v {:.3f} {:.3f} {:.3f}\n'.format(*v))
|
||||||
current_gfx_file.write(f'# {current_vtx_vertices} vertices\n\n')
|
current_gfx_file.write(f'# {current_vtx_vertices} vertices\n\n')
|
||||||
|
|
||||||
for tri in current_vtx_data:
|
for tri in current_vtx_data:
|
||||||
n = [_decode_normal(u) for u in tri[3][:3]]
|
n = [_decode_normal(u) for u in tri[3][:3]]
|
||||||
current_gfx_file.write('vn {:.3f} {:.3f} {:.3f}\n'.format(*n))
|
current_gfx_file.write('vn {:.3f} {:.3f} {:.3f}\n'.format(*n))
|
||||||
current_gfx_file.write(f'# {current_vtx_vertices} vertex normals\n\n')
|
current_gfx_file.write(f'# {current_vtx_vertices} vertex normals\n\n')
|
||||||
|
|
||||||
current_gfx_file.write(f'g {current_vtx_name}\n\n')
|
current_gfx_file.write(f'g {current_vtx_name}\n\n')
|
||||||
|
|
||||||
elif line.startswith(insert_2tri_call):
|
elif line.startswith(insert_2tri_call):
|
||||||
args = line[len(insert_2tri_call):].split(',')
|
args = line[len(insert_2tri_call):].split(',')
|
||||||
correction = current_gfx_vertices - current_vtx_vertices + 1
|
correction = current_gfx_vertices - current_vtx_vertices + 1
|
||||||
indexes = [eval(args[i]) + correction for i in [0, 1, 2, 4, 5, 6]]
|
indexes = [eval(args[i]) + correction for i in [0, 1, 2, 4, 5, 6]]
|
||||||
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes[:3]))
|
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes[:3]))
|
||||||
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes[3:]))
|
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes[3:]))
|
||||||
current_gfx_faces += 2
|
current_gfx_faces += 2
|
||||||
|
|
||||||
elif line.startswith(insert_1tri_call):
|
elif line.startswith(insert_1tri_call):
|
||||||
args = line[len(insert_1tri_call):].split(',')
|
args = line[len(insert_1tri_call):].split(',')
|
||||||
correction = current_gfx_vertices - current_vtx_vertices + 1
|
correction = current_gfx_vertices - current_vtx_vertices + 1
|
||||||
indexes = [eval(args[i]) + correction for i in [0, 1, 2]]
|
indexes = [eval(args[i]) + correction for i in [0, 1, 2]]
|
||||||
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes))
|
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes))
|
||||||
current_gfx_faces += 1
|
current_gfx_faces += 1
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f'{gfx_count} models extracted.')
|
print(f'{gfx_count} models extracted.')
|
||||||
|
|
||||||
def _decode_normal(x):
|
def _decode_normal(x):
|
||||||
y = x if x <= 127 else x - 255
|
y = x if x <= 127 else x - 255
|
||||||
return y / 127
|
return y / 127
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import argparse
|
import argparse
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('filename', help = 'filename of the .inc.c source file')
|
parser.add_argument('filename', help = 'filename of the .inc.c source file')
|
||||||
parser.add_argument('output_directory', help = 'directory where to put the extracted .obj files')
|
parser.add_argument('output_directory', help = 'directory where to put the extracted .obj files')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
parse(args.filename, args.output_directory)
|
parse(args.filename, args.output_directory)
|
212
obj2c.py
212
obj2c.py
|
@ -1,107 +1,107 @@
|
||||||
"""
|
"""
|
||||||
This module generates a fragment of C code, in the style of that found in
|
This module generates a fragment of C code, in the style of that found in
|
||||||
the ``model.inc.c`` files, that encodes the geometry of the model specified
|
the ``model.inc.c`` files, that encodes the geometry of the model specified
|
||||||
by the Wavefront OBJ file.
|
by the Wavefront OBJ file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Specify the path to the ``.obj`` file and pipe the output of the script
|
Specify the path to the ``.obj`` file and pipe the output of the script
|
||||||
into the desired destination ``.c`` file.
|
into the desired destination ``.c`` file.
|
||||||
|
|
||||||
$ python obj2c.py left_hand_closed.obj > left_hand_closed.inc.c
|
$ python obj2c.py left_hand_closed.obj > left_hand_closed.inc.c
|
||||||
|
|
||||||
This is a work in progress and it currently has some serious limitations:
|
This is a work in progress and it currently has some serious limitations:
|
||||||
* It only encodes the geometry information of the OBJ file, so no
|
* It only encodes the geometry information of the OBJ file, so no
|
||||||
texture mapping or any other info.
|
texture mapping or any other info.
|
||||||
* The generated fragment of C code has to be manually pasted into the
|
* The generated fragment of C code has to be manually pasted into the
|
||||||
desired source file. Make sure that the name of the Gfx structure
|
desired source file. Make sure that the name of the Gfx structure
|
||||||
you're pasting matches the one you're replacing.
|
you're pasting matches the one you're replacing.
|
||||||
* It hasn't been properly tested.
|
* It hasn't been properly tested.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def parse(filename):
|
def parse(filename):
|
||||||
from os.path import basename, splitext
|
from os.path import basename, splitext
|
||||||
from re import sub
|
from re import sub
|
||||||
|
|
||||||
# WARNIGN!
|
# WARNIGN!
|
||||||
# `gfx_name` is just a guess. You have to manually check that the name
|
# `gfx_name` is just a guess. You have to manually check that the name
|
||||||
# of the Gfx structure you're pasting matches the one you're replacing.
|
# of the Gfx structure you're pasting matches the one you're replacing.
|
||||||
clean = lambda fn: sub('\W|^(?=\d)','_', fn)
|
clean = lambda fn: sub('\W|^(?=\d)','_', fn)
|
||||||
gfx_name = clean(splitext(basename(filename))[0])
|
gfx_name = clean(splitext(basename(filename))[0])
|
||||||
gfx_vertices = []
|
gfx_vertices = []
|
||||||
gfx_normals = []
|
gfx_normals = []
|
||||||
vertex_to_normal = {}
|
vertex_to_normal = {}
|
||||||
gfx_v_count = 0
|
gfx_v_count = 0
|
||||||
|
|
||||||
vtx_name = ''
|
vtx_name = ''
|
||||||
vtx_faces = []
|
vtx_faces = []
|
||||||
vtx_v_count = 0
|
vtx_v_count = 0
|
||||||
|
|
||||||
output_upper = []
|
output_upper = []
|
||||||
output_lower = [f'const Gfx {gfx_name}[] = {{']
|
output_lower = [f'const Gfx {gfx_name}[] = {{']
|
||||||
|
|
||||||
with open(filename, 'r') as obj:
|
with open(filename, 'r') as obj:
|
||||||
for line in obj:
|
for line in obj:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
|
||||||
if line.startswith('v '):
|
if line.startswith('v '):
|
||||||
coordinates = [eval(x) for x in line.split()[1:4]]
|
coordinates = [eval(x) for x in line.split()[1:4]]
|
||||||
gfx_vertices.append(coordinates)
|
gfx_vertices.append(coordinates)
|
||||||
vtx_v_count += 1
|
vtx_v_count += 1
|
||||||
gfx_v_count += 1
|
gfx_v_count += 1
|
||||||
|
|
||||||
if line.startswith('vn '):
|
if line.startswith('vn '):
|
||||||
coordinates = [eval(x) for x in line.split()[1:4]]
|
coordinates = [eval(x) for x in line.split()[1:4]]
|
||||||
gfx_normals.append([_encode_normal(x) for x in coordinates])
|
gfx_normals.append([_encode_normal(x) for x in coordinates])
|
||||||
|
|
||||||
if line.startswith('g '):
|
if line.startswith('g '):
|
||||||
vtx_name = line.split()[1]
|
vtx_name = line.split()[1]
|
||||||
|
|
||||||
if line.startswith('f '):
|
if line.startswith('f '):
|
||||||
pairs = [pair.split('//') for pair in line.split()[1:4]]
|
pairs = [pair.split('//') for pair in line.split()[1:4]]
|
||||||
vtx_faces.append([int(pair[0]) for pair in pairs])
|
vtx_faces.append([int(pair[0]) for pair in pairs])
|
||||||
for (x, y) in pairs:
|
for (x, y) in pairs:
|
||||||
vertex_to_normal[int(x) - 1] = int(y) - 1
|
vertex_to_normal[int(x) - 1] = int(y) - 1
|
||||||
|
|
||||||
if line.startswith('# ') and line.endswith('faces'):
|
if line.startswith('# ') and line.endswith('faces'):
|
||||||
output_upper.append(f'static const Vtx {vtx_name}[] = {{')
|
output_upper.append(f'static const Vtx {vtx_name}[] = {{')
|
||||||
for i in range(gfx_v_count - vtx_v_count, gfx_v_count):
|
for i in range(gfx_v_count - vtx_v_count, gfx_v_count):
|
||||||
v_string = '[{}, {}, {}]'.format(*gfx_vertices[i])
|
v_string = '[{}, {}, {}]'.format(*gfx_vertices[i])
|
||||||
n_string = '[{}, {}, {}, 0x00]'.format(*gfx_normals[vertex_to_normal[i]])
|
n_string = '[{}, {}, {}, 0x00]'.format(*gfx_normals[vertex_to_normal[i]])
|
||||||
combined = f' [[{v_string}, 0, [0, 0], {n_string}]],'
|
combined = f' [[{v_string}, 0, [0, 0], {n_string}]],'
|
||||||
output_upper.append(combined.replace('[', '{').replace(']', '}'))
|
output_upper.append(combined.replace('[', '{').replace(']', '}'))
|
||||||
|
|
||||||
output_upper.append('};\n')
|
output_upper.append('};\n')
|
||||||
output_lower.append(f' gsSPVertex({vtx_name}, {vtx_v_count}, 0),')
|
output_lower.append(f' gsSPVertex({vtx_name}, {vtx_v_count}, 0),')
|
||||||
|
|
||||||
n = len(vtx_faces)
|
n = len(vtx_faces)
|
||||||
correction = vtx_v_count - gfx_v_count - 1
|
correction = vtx_v_count - gfx_v_count - 1
|
||||||
for i in range(int(n / 2)):
|
for i in range(int(n / 2)):
|
||||||
f1 = [vtx_faces[2 * i][j] + correction for j in range(3)]
|
f1 = [vtx_faces[2 * i][j] + correction for j in range(3)]
|
||||||
f2 = [vtx_faces[2 * i + 1][j] + correction for j in range(3)]
|
f2 = [vtx_faces[2 * i + 1][j] + correction for j in range(3)]
|
||||||
output_lower.append(' gsSP2Triangles({}, {}, {}, 0x0, {}, {}, {}, 0x0),'.format(*f1, *f2))
|
output_lower.append(' gsSP2Triangles({}, {}, {}, 0x0, {}, {}, {}, 0x0),'.format(*f1, *f2))
|
||||||
|
|
||||||
if n % 2 != 0:
|
if n % 2 != 0:
|
||||||
f3 = [vtx_faces[-1][j] + correction for j in range(3)]
|
f3 = [vtx_faces[-1][j] + correction for j in range(3)]
|
||||||
output_lower.append(' gsSP1Triangle({}, {}, {}, 0x0),'.format(*f3))
|
output_lower.append(' gsSP1Triangle({}, {}, {}, 0x0),'.format(*f3))
|
||||||
|
|
||||||
vtx_v_count = 0
|
vtx_v_count = 0
|
||||||
vtx_faces = []
|
vtx_faces = []
|
||||||
|
|
||||||
output_lower.append(' gsSPEndDisplayList(),')
|
output_lower.append(' gsSPEndDisplayList(),')
|
||||||
output_lower.append('};')
|
output_lower.append('};')
|
||||||
|
|
||||||
for line in output_upper + output_lower:
|
for line in output_upper + output_lower:
|
||||||
print(line)
|
print(line)
|
||||||
|
|
||||||
def _encode_normal(x):
|
def _encode_normal(x):
|
||||||
x *= 127
|
x *= 127
|
||||||
if x <= 0: x += 255
|
if x <= 0: x += 255
|
||||||
return hex(int(x))
|
return hex(int(x))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import argparse
|
import argparse
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('filename', help = 'filename of the .obj file to parse')
|
parser.add_argument('filename', help = 'filename of the .obj file to parse')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
parse(args.filename)
|
parse(args.filename)
|
Loading…
Reference in a new issue