mirror of
				https://github.com/coop-deluxe/sm64coopdx.git
				synced 2025-10-30 08:01:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			107 lines
		
	
	
		
			No EOL
		
	
	
		
			4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			No EOL
		
	
	
		
			4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""
 | 
						|
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) |