From b0e0d63eab1e11d1a7f841afdc7eb18e7a9de3ba Mon Sep 17 00:00:00 2001 From: Treeki Date: Sun, 13 Mar 2011 00:19:13 +0100 Subject: this branch now features only the level select stuff --- 3dlib/obj2tmdl.py | 492 ------------------------------------------------------ 1 file changed, 492 deletions(-) delete mode 100755 3dlib/obj2tmdl.py (limited to '3dlib/obj2tmdl.py') diff --git a/3dlib/obj2tmdl.py b/3dlib/obj2tmdl.py deleted file mode 100755 index a000ca1..0000000 --- a/3dlib/obj2tmdl.py +++ /dev/null @@ -1,492 +0,0 @@ -#!/usr/bin/env python2 -# Obj2tmdl -# Converter for Wavefront OBJ => Treeki Model - -import os -import struct -import sys -u32 = struct.Struct('>I') -u16 = struct.Struct('>H') -u8 = struct.Struct('>B') -f32 = struct.Struct('>f') - -sys.path.append('/home/Treeki/Wii.py/Wii.py') -sys.path.append('/home/me/Packages/Wii.py') -import Wii - -class MaterialLib: - class Material: - pass - - - def __init__(self, filename): - self.current_mat = None - self.materials = {} - - for line in open(filename, 'r'): - self.parse_line(line) - - - def parse_line(self, line): - line = line.strip() - if line == '' or line[0] == '#': - return - - line = line.split() - cmd = line[0] - - if cmd == 'newmtl': - self.current_mat = MaterialLib.Material() - self.materials[line[1]] = self.current_mat - - elif cmd == 'map_Ka': - self.current_mat.texture = ' '.join(line[1:]) - - elif cmd == 'Kd': - r = int(float(line[1]) * 255) - g = int(float(line[2]) * 255) - b = int(float(line[3]) * 255) - self.current_mat.colour = (r,g,b,255) - - - def prepare_textures(self): - # get a list of every texture file used - self.texture_id = {} - textures = [] - id = 0 - - for mat in self.materials.values(): - if hasattr(mat, 'texture'): - if mat.texture not in textures: - textures.append(mat.texture) - self.texture_id[mat.texture] = id - id += 1 - - - if len(textures) == 0: - self.tpl = None - return - - # create a gxtexconv script file and an ID mapping - #script = [] - #self.texture_id = {} - # - #for tex, id in zip(textures, range(len(textures))): - # script.append('' % (tex.replace('\\','/'),id)) - # self.texture_id[id] = tex - # - #print script - # - #open('texture_script_temp_0991.scf', 'w').write('\n'.join(script)) - # - #os.system('gxtexconv -s texture_script_temp_0991.scf -o generated_texture_0991.tpl') - - # fix this later - texture_files = [tex.replace('\\','/').replace(' ','\\ ').replace('.jpg','.png') for tex in textures] - print 'zetsubou wpng RGB5A3 %s generated_texture_0991.tpl' % ' '.join(texture_files) - os.system('zetsubou wpng RGB5A3 %s generated_texture_0991.tpl' % ' '.join(texture_files)) - self.tpl = open('generated_texture_0991.tpl', 'rb').read() - - #os.remove('texture_script_temp_0991.scf') - os.remove('generated_texture_0991.tpl') - - - -class ObjReader: - class ObjShape: - def __init__(self, name): - self.face_groups = [ \ - ObjReader.ObjFaceGroup('quads'), \ - ObjReader.ObjFaceGroup('triangles')] - - self.quad_group, self.tri_group = self.face_groups - - self.shape_name = name - self.material_name = None - - - class ObjFace: - __slots__ = ('vertices', 'texcoords', 'normals') - - def __init__(self, vertices, texcoords, normals): - self.vertices = vertices - self.texcoords = texcoords - self.normals = normals - - - class ObjFaceGroup: - def __init__(self, type): - self.type = type - self.faces = [] - - - def __init__(self): - self.material_lib = None - - self.vertex_lists = [] - self.texcoord_lists = [] - self.normal_lists = [] - self.shapes = [] - - self.current_shape = None - - - def parse_line(self, line): - line = line.strip() - if line == '' or line[0] == '#': - return - - line = line.split() - cmd = line[0] - - if cmd == 'v': - self.vertex_lists.append(map(float, line[1:])) - - elif cmd == 'vt': - tc = map(float, line[1:])[:2] # chop off third coord - tc[1] = 1.0 - tc[1] - self.texcoord_lists.append(tc) - - elif cmd == 'vn': - self.normal_lists.append(map(float, line[1:])) - - elif cmd == 'f': - v, t, n = [], [], [] - - if len(line) == 4: - # triangle - group = self.current_shape.tri_group - elif len(line) == 5: - # quad - group = self.current_shape.quad_group - - for entry in line[1:]: - entry_split = map(lambda x:-1 if x == '' else int(x), entry.split('/')) - - v.append(self.vertex_lists[entry_split[0] - 1]) - - if entry_split[1] == -1: - t.append([0.0, 0.0]) - else: - t.append(self.texcoord_lists[entry_split[1] - 1]) - - if entry_split[2] == -1: - n.append([0.0, 0.0, 0.0]) - else: - n.append(self.normal_lists[entry_split[2] - 1]) - - group.faces.append(ObjReader.ObjFace(v, t, n)) - - #elif cmd == 'g': - # self.current_shape = ObjReader.ObjShape(line[1]) - # self.shapes.append(self.current_shape) - - elif cmd == 'mtllib': - self.material_lib = MaterialLib(os.path.join(self.path, ' '.join(line[1:]))) - - elif cmd == 'usemtl': - self.current_shape = ObjReader.ObjShape(line[1]) - self.shapes.append(self.current_shape) - self.current_shape.material_name = line[1] - - - -# === Treeki Model Format === -# Header: -# -# struct tmdl_header { -# u32 magic; // always TMDL -# u32 version; // currently 2 -# u32 shape_count; -# }; -# [[Followed by an array of u32s for each shape offset]] -# -# struct tmdl_shape { -# u32 dl_offset; // must be aligned to 0x20 -# u32 dl_size; // must be aligned to 0x20 -# u32 mat_offset; -# u32 pos_arr_offset; // must be aligned to 0x20 -# u32 pos_arr_size; // must be aligned to 0x20 -# u32 nrm_arr_offset; // must be aligned to 0x20 -# u32 nrm_arr_size; // must be aligned to 0x20 -# u32 uv_arr_offset; // must be aligned to 0x20 -# u32 uv_arr_size; // must be aligned to 0x20 -# }; -# -# struct tmdl_material { -# u32 texture_id; // once the model is bound, points to id within tpl -# }; -# -# dl_offset points to a GX display list which is used for -# rendering the model in question. - - -class TmdlWriter: - def __init__(self): - self.shapes = [] - - - def build_with_obj(self, obj): - self.shapes = obj.shapes - self.material_lib = obj.material_lib - self.materials = obj.material_lib.materials - - self.material_lib.prepare_textures() - - - def pack(self): - offset = 0 - - header = struct.pack('>4sI I', 'TMDL', 2, len(self.shapes)) - offset += len(header) - - # reserve space for the shape offsets, we'll add them later - offset += (4 * len(self.shapes)) - - # create the materials - material_offs = {} - material_data = '' - - for name,material in self.materials.iteritems(): - material_offs[name] = offset - material_struct = self.build_material_struct(material) - material_data += material_struct - offset += len(material_struct) - - - # create the shapes -- first, we'll assemble the GX arrays and DLs - shape_arrays = [] - packed_shape_arrays = [] - shape_display_lists = [] - - print 'Building shapes... [%d]' % len(self.shapes) - - count = 0 - for shape in self.shapes: - pos = self.build_array_from_shape_attr(shape, 'vertices') - nrm = self.build_array_from_shape_attr(shape, 'normals') - uv = self.build_array_from_shape_attr(shape, 'texcoords') - shape_arrays.append((pos,nrm,uv)) - - ppos = self.pack_data_array(pos) - pnrm = self.pack_data_array(nrm) - puv = self.pack_data_array(uv) - packed_shape_arrays.append((ppos,pnrm,puv)) - - dl = self.build_display_list_with_shape(shape, pos, nrm, uv) - shape_display_lists.append(dl) - count += 1 - - print '%d done' % count - - print 'Shapes built' - - - # calculate offsets to every display list - # shape struct is currently 36 bytes, change this if the size changes - # also, make sure they're aligned to an offset of 0x20 - temp_offset = offset + (len(self.shapes) * 36) - - if temp_offset & 0x1f != 0: - aligned_offset = (temp_offset + 0x20) & ~0x1f - dl_start_padding = '\0' * (aligned_offset - temp_offset) - temp_offset = aligned_offset - else: - dl_start_padding = '' - - shape_display_list_offsets = [] - for dl in shape_display_lists: - shape_display_list_offsets.append(temp_offset) - temp_offset += len(dl) - - # calculate offsets to every GX array - pos_array_offsets = [] - nrm_array_offsets = [] - uv_array_offsets = [] - - for pos,nrm,uv in packed_shape_arrays: - pos_array_offsets.append(temp_offset) - temp_offset += len(pos) - nrm_array_offsets.append(temp_offset) - temp_offset += len(nrm) - uv_array_offsets.append(temp_offset) - temp_offset += len(uv) - - - # and now, create the shape structs themselves - shape_offsets = [] - shape_data = '' - - for shape, dl, dl_offset, pos_offs, nrm_offs, uv_offs, (pos, nrm, uv) in \ - zip(self.shapes, shape_display_lists, shape_display_list_offsets, \ - pos_array_offsets, nrm_array_offsets, uv_array_offsets, \ - packed_shape_arrays): - - # first off, store the offset - shape_offsets.append(offset) - - # now build the struct - shape_struct = struct.pack('>IIIIIIIII', \ - dl_offset, len(dl), material_offs[shape.material_name], \ - pos_offs, len(pos), \ - nrm_offs, len(nrm), \ - uv_offs, len(uv)) - - shape_data += shape_struct - offset += len(shape_struct) - - - # almost there! - print 'Packing model...' - - tmdl_bits = [header] - tmdl_add = tmdl_bits.append - - for offs in shape_offsets: - tmdl_add(u32.pack(offs)) - - tmdl_add(material_data) - tmdl_add(shape_data) - tmdl_add(dl_start_padding) - - tmdl_bits += shape_display_lists - - for pos,nrm,uv in packed_shape_arrays: - tmdl_bits.append(pos) - tmdl_bits.append(nrm) - tmdl_bits.append(uv) - - return ''.join(tmdl_bits) - - - def build_material_struct(self, material): - texture_id = 0xFFFFFFFF - if hasattr(material, 'texture'): - texture_id = self.material_lib.texture_id[material.texture] - - cR, cG, cB, cA = material.colour - return struct.pack('>IBBBB', texture_id, cR, cG, cB, cA) - - - def build_array_from_shape_attr(self, shape, attr): - assemble = [] - - for g in shape.face_groups: - for f in g.faces: - assemble += f.__dict__[attr] - - final = [] - for i in assemble: - if i not in final: - final.append(i) - - if len(final) >= 0xFFFE: - print '=== WARNING! List too big! ===' - - return final - - - def pack_data_array(self, data): - out = [] - - for piece in data: - for bit in piece: - out.append(f32.pack(bit)) - - packed = ''.join(out) - - if len(packed) % 0x20 != 0: - aligned = (len(packed) + 0x1f) & ~0x1fe - packed += '\0' * (aligned - len(packed)) - - return packed - - - def build_display_list_with_shape(self, shape, vtx_list, nrm_list, uv_list): - # http://hitmen.c02.at/files/yagcd/yagcd/chap5.html - # assume vertex descriptor: [data is specified in this order] - # GXClearVtxDesc() - # GXSetVtxDesc(GX_VA_POS, GX_DIRECT) - # GXSetVtxDesc(GX_VA_NRM, GX_DIRECT) - # GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT) - - dl_bits = [] - _dl_add = dl_bits.append - - _vtx_index = vtx_list.index - _nrm_index = nrm_list.index - _uv_index = uv_list.index - - _u16_pack = u16.pack - - for face_group in shape.face_groups: - if len(face_group.faces) == 0: - continue - - vtx_num = reduce(lambda x,y:x+len(y.vertices), face_group.faces, 0) - - # commands: GX_QUADS = 0x80, GX_TRIANGLES = 0x90 - if face_group.type == 'quads': - _dl_add('\x80') # opcode - elif face_group.type == 'triangles': - _dl_add('\x90') # opcode - - _dl_add(_u16_pack(vtx_num)) - - # now send over the data - for face in face_group.faces: - for v, t, n in zip(face.vertices, face.texcoords, face.normals): - _dl_add(_u16_pack(_vtx_index(v))) - _dl_add(_u16_pack(_nrm_index(n))) - _dl_add(_u16_pack(_uv_index(t))) - - # done! - return self.build_display_list(dl_bits) - - - def build_display_list(self, dl_bits): - # assemble it - dl = ''.join(dl_bits) - - # pad the display list to 0x20 bytes with GX_NOP (0x00) - if len(dl) % 0x20 != 0: - pad_count = ((len(dl) + 0x20) & ~0x1F) - len(dl) - dl += '\x00' * pad_count - - return dl - - -#file = r'H:\ISOs\NSMBWii\testmush3' -#file = 'testmdl2' -#file = 'simple2' -file = sys.argv[1] -shortfn = file[file.rfind('/')+1:] - -if 'tex-only' in sys.argv: - mtl = MaterialLib(file+'.mtl') - mtl.prepare_textures() - open('tex_%s.tpl' % shortfn, 'wb').write(mtl.tpl) - sys.exit() - - - -obj = ObjReader() -if '/' in file: - obj.path = file[:file.rfind('/')] -else: - obj.path = '.' - -for line in open(file+'.obj'): - obj.parse_line(line) - -tmdl = TmdlWriter() -tmdl.build_with_obj(obj) - -tmdl_file = tmdl.pack() -tpl_file = tmdl.material_lib.tpl - -arc = Wii.U8() -arc['t3d'] = None -arc['t3d/mdl_%s.tmdl' % shortfn] = tmdl_file -if tpl_file: arc['t3d/tex_%s.tpl' % shortfn] = tpl_file -arc.dumpFile('%s.arc' % file) -- cgit v1.2.3