From 8b71a1a734edcbf3d70b4cc73973474e572d075b Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 16 May 2020 07:36:28 +0300 Subject: [PATCH] correct line endings --- c2obj.py | 280 +++++++++++++++++++++++++++---------------------------- obj2c.py | 212 ++++++++++++++++++++--------------------- 2 files changed, 246 insertions(+), 246 deletions(-) diff --git a/c2obj.py b/c2obj.py index ca4faaa9..508a51ec 100644 --- a/c2obj.py +++ b/c2obj.py @@ -1,141 +1,141 @@ -""" -This module attempts to parse the ``model.inc.c`` files and extract the -3D models within as standard Wavefront OBJ files. - -Example: - Specify the path to the ``.inc.c`` file and a directory where to save - the extracted ``.obj`` files. - - $ python c2obj.py ./actors/mario/model.inc.c ./actors/mario/obj/ - -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 makes assumptions about the layout of the code in the C source - * It hasn't been properly tested. - -""" - -def parse(filename, output_directory): - from os import path, mkdir - - if not path.isdir(output_directory): - try: - mkdir(output_directory) - except OSError: - print(f'Could not use output directory {output_directory}.') - - vtx_def = 'static const Vtx ' - vtx_data = {} - reading_vtx = False - current_vtx_name = '' - current_vtx_data = [] - current_vtx_vertices = 0 - - gfx_def = 'const Gfx ' - reading_gfx = False - current_gfx_vertices = 0 - current_gfx_faces = 0 - insert_vert_call = 'gsSPVertex(' - insert_1tri_call = 'gsSP1Triangle(' - insert_2tri_call = 'gsSP2Triangles(' - gfx_count = 0 - - end_of_block = '};' - - with open(filename, 'r') as f: - for line in f: - line = line.strip() - - if line.startswith(vtx_def): - vtx_name = line.split(' ')[3][:-2] - current_vtx_name = vtx_name - current_vtx_data = [] - reading_vtx = True - continue - - if line.startswith(gfx_def): - from datetime import datetime - - current_gfx_name = line.split(' ')[2][:-2] - 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('# File Created: {}\n\n'.format(datetime.now())) - reading_gfx = True - continue - - if line == end_of_block: - if reading_vtx: - vtx_data[current_vtx_name] = current_vtx_data - reading_vtx = False - - elif reading_gfx: - current_gfx_file.write(f'# {current_gfx_faces} faces\n\n') - current_gfx_file.close() - current_gfx_vertices = 0 - reading_gfx = False - gfx_count += 1 - - continue - - if reading_vtx: - line = line.replace('{', '[').replace('}', ']') - tri = eval(line[:-1])[0] - current_vtx_data.append(tri) - continue - - if reading_gfx: - if line.startswith(insert_vert_call): - args = line[len(insert_vert_call):].split(',') - current_vtx_name = args[0] - - if current_gfx_vertices > 0: - current_gfx_file.write(f'# {current_gfx_faces} faces\n\n') - - current_gfx_faces = 0 - current_vtx_vertices = len(vtx_data[current_vtx_name]) - current_gfx_vertices += current_vtx_vertices - - current_gfx_file.write(f'#\n# object {current_vtx_name}\n#\n\n') - current_vtx_data = vtx_data[current_vtx_name] - for tri in current_vtx_data: - v = tri[0] - current_gfx_file.write('v {:.3f} {:.3f} {:.3f}\n'.format(*v)) - current_gfx_file.write(f'# {current_vtx_vertices} vertices\n\n') - - for tri in current_vtx_data: - 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(f'# {current_vtx_vertices} vertex normals\n\n') - - current_gfx_file.write(f'g {current_vtx_name}\n\n') - - elif line.startswith(insert_2tri_call): - args = line[len(insert_2tri_call):].split(',') - correction = current_gfx_vertices - current_vtx_vertices + 1 - 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_faces += 2 - - elif line.startswith(insert_1tri_call): - args = line[len(insert_1tri_call):].split(',') - correction = current_gfx_vertices - current_vtx_vertices + 1 - 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_faces += 1 - - continue - - print(f'{gfx_count} models extracted.') - -def _decode_normal(x): - y = x if x <= 127 else x - 255 - return y / 127 - -if __name__ == "__main__": - import argparse - parser = argparse.ArgumentParser() - 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') - args = parser.parse_args() +""" +This module attempts to parse the ``model.inc.c`` files and extract the +3D models within as standard Wavefront OBJ files. + +Example: + Specify the path to the ``.inc.c`` file and a directory where to save + the extracted ``.obj`` files. + + $ python c2obj.py ./actors/mario/model.inc.c ./actors/mario/obj/ + +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 makes assumptions about the layout of the code in the C source + * It hasn't been properly tested. + +""" + +def parse(filename, output_directory): + from os import path, mkdir + + if not path.isdir(output_directory): + try: + mkdir(output_directory) + except OSError: + print(f'Could not use output directory {output_directory}.') + + vtx_def = 'static const Vtx ' + vtx_data = {} + reading_vtx = False + current_vtx_name = '' + current_vtx_data = [] + current_vtx_vertices = 0 + + gfx_def = 'const Gfx ' + reading_gfx = False + current_gfx_vertices = 0 + current_gfx_faces = 0 + insert_vert_call = 'gsSPVertex(' + insert_1tri_call = 'gsSP1Triangle(' + insert_2tri_call = 'gsSP2Triangles(' + gfx_count = 0 + + end_of_block = '};' + + with open(filename, 'r') as f: + for line in f: + line = line.strip() + + if line.startswith(vtx_def): + vtx_name = line.split(' ')[3][:-2] + current_vtx_name = vtx_name + current_vtx_data = [] + reading_vtx = True + continue + + if line.startswith(gfx_def): + from datetime import datetime + + current_gfx_name = line.split(' ')[2][:-2] + 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('# File Created: {}\n\n'.format(datetime.now())) + reading_gfx = True + continue + + if line == end_of_block: + if reading_vtx: + vtx_data[current_vtx_name] = current_vtx_data + reading_vtx = False + + elif reading_gfx: + current_gfx_file.write(f'# {current_gfx_faces} faces\n\n') + current_gfx_file.close() + current_gfx_vertices = 0 + reading_gfx = False + gfx_count += 1 + + continue + + if reading_vtx: + line = line.replace('{', '[').replace('}', ']') + tri = eval(line[:-1])[0] + current_vtx_data.append(tri) + continue + + if reading_gfx: + if line.startswith(insert_vert_call): + args = line[len(insert_vert_call):].split(',') + current_vtx_name = args[0] + + if current_gfx_vertices > 0: + current_gfx_file.write(f'# {current_gfx_faces} faces\n\n') + + current_gfx_faces = 0 + current_vtx_vertices = len(vtx_data[current_vtx_name]) + current_gfx_vertices += current_vtx_vertices + + current_gfx_file.write(f'#\n# object {current_vtx_name}\n#\n\n') + current_vtx_data = vtx_data[current_vtx_name] + for tri in current_vtx_data: + v = tri[0] + current_gfx_file.write('v {:.3f} {:.3f} {:.3f}\n'.format(*v)) + current_gfx_file.write(f'# {current_vtx_vertices} vertices\n\n') + + for tri in current_vtx_data: + 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(f'# {current_vtx_vertices} vertex normals\n\n') + + current_gfx_file.write(f'g {current_vtx_name}\n\n') + + elif line.startswith(insert_2tri_call): + args = line[len(insert_2tri_call):].split(',') + correction = current_gfx_vertices - current_vtx_vertices + 1 + 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_faces += 2 + + elif line.startswith(insert_1tri_call): + args = line[len(insert_1tri_call):].split(',') + correction = current_gfx_vertices - current_vtx_vertices + 1 + 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_faces += 1 + + continue + + print(f'{gfx_count} models extracted.') + +def _decode_normal(x): + y = x if x <= 127 else x - 255 + return y / 127 + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser() + 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') + args = parser.parse_args() parse(args.filename, args.output_directory) \ No newline at end of file diff --git a/obj2c.py b/obj2c.py index 8e84c806..015aa628 100644 --- a/obj2c.py +++ b/obj2c.py @@ -1,107 +1,107 @@ -""" -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 -by the Wavefront OBJ file. - -Example: - Specify the path to the ``.obj`` file and pipe the output of the script - into the desired destination ``.c`` file. - - $ 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: - * It only encodes the geometry information of the OBJ file, so no - texture mapping or any other info. - * 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 - you're pasting matches the one you're replacing. - * It hasn't been properly tested. - -""" - -def parse(filename): - from os.path import basename, splitext - from re import sub - - # WARNIGN! - # `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. - clean = lambda fn: sub('\W|^(?=\d)','_', fn) - gfx_name = clean(splitext(basename(filename))[0]) - gfx_vertices = [] - gfx_normals = [] - vertex_to_normal = {} - gfx_v_count = 0 - - vtx_name = '' - vtx_faces = [] - vtx_v_count = 0 - - output_upper = [] - output_lower = [f'const Gfx {gfx_name}[] = {{'] - - with open(filename, 'r') as obj: - for line in obj: - line = line.strip() - - if line.startswith('v '): - coordinates = [eval(x) for x in line.split()[1:4]] - gfx_vertices.append(coordinates) - vtx_v_count += 1 - gfx_v_count += 1 - - if line.startswith('vn '): - coordinates = [eval(x) for x in line.split()[1:4]] - gfx_normals.append([_encode_normal(x) for x in coordinates]) - - if line.startswith('g '): - vtx_name = line.split()[1] - - if line.startswith('f '): - pairs = [pair.split('//') for pair in line.split()[1:4]] - vtx_faces.append([int(pair[0]) for pair in pairs]) - for (x, y) in pairs: - vertex_to_normal[int(x) - 1] = int(y) - 1 - - if line.startswith('# ') and line.endswith('faces'): - output_upper.append(f'static const Vtx {vtx_name}[] = {{') - for i in range(gfx_v_count - vtx_v_count, gfx_v_count): - v_string = '[{}, {}, {}]'.format(*gfx_vertices[i]) - n_string = '[{}, {}, {}, 0x00]'.format(*gfx_normals[vertex_to_normal[i]]) - combined = f' [[{v_string}, 0, [0, 0], {n_string}]],' - output_upper.append(combined.replace('[', '{').replace(']', '}')) - - output_upper.append('};\n') - output_lower.append(f' gsSPVertex({vtx_name}, {vtx_v_count}, 0),') - - n = len(vtx_faces) - correction = vtx_v_count - gfx_v_count - 1 - for i in range(int(n / 2)): - 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)] - output_lower.append(' gsSP2Triangles({}, {}, {}, 0x0, {}, {}, {}, 0x0),'.format(*f1, *f2)) - - if n % 2 != 0: - f3 = [vtx_faces[-1][j] + correction for j in range(3)] - output_lower.append(' gsSP1Triangle({}, {}, {}, 0x0),'.format(*f3)) - - vtx_v_count = 0 - vtx_faces = [] - - output_lower.append(' gsSPEndDisplayList(),') - output_lower.append('};') - - for line in output_upper + output_lower: - print(line) - -def _encode_normal(x): - x *= 127 - if x <= 0: x += 255 - return hex(int(x)) - -if __name__ == "__main__": - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('filename', help = 'filename of the .obj file to parse') - args = parser.parse_args() +""" +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 +by the Wavefront OBJ file. + +Example: + Specify the path to the ``.obj`` file and pipe the output of the script + into the desired destination ``.c`` file. + + $ 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: + * It only encodes the geometry information of the OBJ file, so no + texture mapping or any other info. + * 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 + you're pasting matches the one you're replacing. + * It hasn't been properly tested. + +""" + +def parse(filename): + from os.path import basename, splitext + from re import sub + + # WARNIGN! + # `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. + clean = lambda fn: sub('\W|^(?=\d)','_', fn) + gfx_name = clean(splitext(basename(filename))[0]) + gfx_vertices = [] + gfx_normals = [] + vertex_to_normal = {} + gfx_v_count = 0 + + vtx_name = '' + vtx_faces = [] + vtx_v_count = 0 + + output_upper = [] + output_lower = [f'const Gfx {gfx_name}[] = {{'] + + with open(filename, 'r') as obj: + for line in obj: + line = line.strip() + + if line.startswith('v '): + coordinates = [eval(x) for x in line.split()[1:4]] + gfx_vertices.append(coordinates) + vtx_v_count += 1 + gfx_v_count += 1 + + if line.startswith('vn '): + coordinates = [eval(x) for x in line.split()[1:4]] + gfx_normals.append([_encode_normal(x) for x in coordinates]) + + if line.startswith('g '): + vtx_name = line.split()[1] + + if line.startswith('f '): + pairs = [pair.split('//') for pair in line.split()[1:4]] + vtx_faces.append([int(pair[0]) for pair in pairs]) + for (x, y) in pairs: + vertex_to_normal[int(x) - 1] = int(y) - 1 + + if line.startswith('# ') and line.endswith('faces'): + output_upper.append(f'static const Vtx {vtx_name}[] = {{') + for i in range(gfx_v_count - vtx_v_count, gfx_v_count): + v_string = '[{}, {}, {}]'.format(*gfx_vertices[i]) + n_string = '[{}, {}, {}, 0x00]'.format(*gfx_normals[vertex_to_normal[i]]) + combined = f' [[{v_string}, 0, [0, 0], {n_string}]],' + output_upper.append(combined.replace('[', '{').replace(']', '}')) + + output_upper.append('};\n') + output_lower.append(f' gsSPVertex({vtx_name}, {vtx_v_count}, 0),') + + n = len(vtx_faces) + correction = vtx_v_count - gfx_v_count - 1 + for i in range(int(n / 2)): + 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)] + output_lower.append(' gsSP2Triangles({}, {}, {}, 0x0, {}, {}, {}, 0x0),'.format(*f1, *f2)) + + if n % 2 != 0: + f3 = [vtx_faces[-1][j] + correction for j in range(3)] + output_lower.append(' gsSP1Triangle({}, {}, {}, 0x0),'.format(*f3)) + + vtx_v_count = 0 + vtx_faces = [] + + output_lower.append(' gsSPEndDisplayList(),') + output_lower.append('};') + + for line in output_upper + output_lower: + print(line) + +def _encode_normal(x): + x *= 127 + if x <= 0: x += 255 + return hex(int(x)) + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('filename', help = 'filename of the .obj file to parse') + args = parser.parse_args() parse(args.filename) \ No newline at end of file