diff options
author | Campbell Barton <ideasman42@gmail.com> | 2006-01-10 20:40:50 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2006-01-10 20:40:50 +0300 |
commit | 185c6bb49ce994d66fc67673b01a014161fa307d (patch) | |
tree | 5b229a6d406980d42a1a83893fc074074861ac01 /release | |
parent | e2acc624f2907c0422c82ab243bfe24f065e38c6 (diff) |
removed slow list handeling
faster vert comparisons
replaced spaces for tabs
removed unneeded getData() calls
general cleanup.
Diffstat (limited to 'release')
-rwxr-xr-x | release/scripts/flt_export.py | 1306 |
1 files changed, 633 insertions, 673 deletions
diff --git a/release/scripts/flt_export.py b/release/scripts/flt_export.py index b5ab09255b2..b5c5797fa42 100755 --- a/release/scripts/flt_export.py +++ b/release/scripts/flt_export.py @@ -57,707 +57,667 @@ What's Not Handled:<br> """ import Blender -import math from flt_filewalker import FltOut class ExporterOptions: - def __init__(self): - self.defaults = { 'Diffuse Color To OpenFlight Material': False, - 'Diffuse Color To OpenFlight Face': True} - - d = Blender.Registry.GetKey('flt_export', True) - - if d == None or d.keys() != self.defaults.keys(): - d = self.defaults - Blender.Registry.SetKey('flt_export', d, True) - - self.verbose = 1 - self.tolerance = 0.001 - self.use_mat_color = d['Diffuse Color To OpenFlight Material'] - self.use_face_color = d['Diffuse Color To OpenFlight Face'] - + def __init__(self): + self.defaults = { 'Diffuse Color To OpenFlight Material': False, + 'Diffuse Color To OpenFlight Face': True} + + d = Blender.Registry.GetKey('flt_export', True) + + if d == None or d.keys() != self.defaults.keys(): + d = self.defaults + Blender.Registry.SetKey('flt_export', d, True) + + self.verbose = 1 + self.tolerance = 0.001 + self.use_mat_color = d['Diffuse Color To OpenFlight Material'] + self.use_face_color = d['Diffuse Color To OpenFlight Face'] + options = ExporterOptions() -def not_equal_float(f1, f2): - return math.fabs(f1 - f2) > options.tolerance +FLOAT_TOLERANCE = options.tolerance identity_matrix = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] def is_identity(m): - for i in range(4): - for j in range(4): - if not_equal_float(m[i][j], identity_matrix[i][j]): - return False - return True + for i in xrange(4): + for j in xrange(4): + if abs(m[i][j] - identity_matrix[i][j]) > FLOAT_TOLERANCE: + return False + return True class MaterialDesc: - def __init__(self): - self.name = 'Blender' + def __init__(self): + self.name = 'Blender' - # Colors, List of 3 floats. - self.diffuse = [1.0, 1.0, 1.0] - self.specular = [1.0, 1.0, 1.0] + # Colors, List of 3 floats. + self.diffuse = [1.0, 1.0, 1.0] + self.specular = [1.0, 1.0, 1.0] - # Scalars - self.ambient = 0.1 # [0.0, 1.0] - self.emissive = 0.0 # [0.0, 1.0] - self.shininess = 32.0 # Range is [0.0, 128.0] - self.alpha = 1.0 # Range is [0.0, 1.0] + # Scalars + self.ambient = 0.1 # [0.0, 1.0] + self.emissive = 0.0 # [0.0, 1.0] + self.shininess = 32.0 # Range is [0.0, 128.0] + self.alpha = 1.0 # Range is [0.0, 1.0] class VertexDesc: - def __init__(self): - self.x = 0.0 - self.y = 0.0 - self.z = 0.0 - self.nx = 0.0 - self.ny = 0.0 - self.nz = 0.0 - self.u = 0.0 - self.v = 0.0 + def __init__(self, co=None, no=None, uv=None): + if co: self.x, self.y, self.z = tuple(co) + else: self.x = self.y = self.z = 0.0 + if no: self.nx, self.ny, self.nz = tuple(no) + else: self.nx = self.ny = self.nz = 0.0 + if uv: self.u, self.v = tuple(uv) + else: self.u = self.v = 0.0 class GlobalResourceRepository: - def new_face_name(self): - n = 'f' + str(self.face_name) - self.face_name += 1 - return n - - def vertex_count(self): - return len(self.vertex_lst) - - def request_vertex_desc(self, i): - return self.vertex_lst[i] - - def request_vertex_index(self, desc): - match = None - for i in range(len(self.vertex_lst)): - if not_equal_float(self.vertex_lst[i].x, desc.x): - continue - if not_equal_float(self.vertex_lst[i].y, desc.y): - continue - if not_equal_float(self.vertex_lst[i].z, desc.z): - continue - if not_equal_float(self.vertex_lst[i].nx, desc.nx): - continue - if not_equal_float(self.vertex_lst[i].ny, desc.ny): - continue - if not_equal_float(self.vertex_lst[i].nz, desc.nz): - continue - if not_equal_float(self.vertex_lst[i].u, desc.u): - continue - if not_equal_float(self.vertex_lst[i].v, desc.v): - continue - - match = i - break - - if match != None: - return match - else: - self.vertex_lst.append(desc) - return len(self.vertex_lst) - 1 - - def request_texture_index(self, filename): - match = None - for i in range(len(self.texture_lst)): - if self.texture_lst[i] != filename: - continue - match = i - break - if match != None: - return match - else: - self.texture_lst.append(filename) - return len(self.texture_lst) - 1 - - def request_texture_filename(self, index): - return self.texture_lst[index] - - def texture_count(self): - return len(self.texture_lst) - - def request_material_index(self, desc): - match = None - for i in range(len(self.material_lst)): - if self.material_lst[i].diffuse != desc.diffuse: - continue - if self.material_lst[i].specular != desc.specular: - continue - if self.material_lst[i].ambient != desc.ambient: - continue - if self.material_lst[i].emissive != desc.emissive: - continue - if self.material_lst[i].shininess != desc.shininess: - continue - if self.material_lst[i].alpha != desc.alpha: - continue - match = i - break - - if match != None: - return i - else: - self.material_lst.append(desc) - return len(self.material_lst) - 1 - - def request_material_desc(self, index): - return self.material_lst[index] - - def material_count(self): - return len(self.material_lst) - - # Returns not actual index but one that includes intensity information. - # color_index = 127*intensity + 128*actual_index - def request_color_index(self, col): - r = col[0] - g = col[1] - b = col[2] - m = max(r, g, b) - if m > 0.0: - intensity = m / 1.0 - r = int(round(r/m * 255.0)) - g = int(round(g/m * 255.0)) - b = int(round(b/m * 255.0)) - brightest = [r, g, b] - else: - brightest = [255, 255, 255] - intensity = 0.0 - - match = None - for i in range(len(self.color_lst)): - if self.color_lst[i] != brightest: - continue - - match = i - break - - if match != None: - index = match - else: - length = len(self.color_lst) - if length <= 1024: - self.color_lst.append(brightest) - index = length - else: - if options.verbose >= 1: - print 'Warning: Exceeded max color limit.' - index = 0 - - color_index = int(round(127.0*intensity)) + 128*index - return color_index - - # Returns color from actual index. - def request_max_color(self, index): - return self.color_lst[index] - - def color_count(self): - return len(self.color_lst) - - def __init__(self): - self.vertex_lst = [] - self.texture_lst = [] - self.material_lst = [] - self.color_lst = [[255, 255, 255]] - self.face_name = 0 + def new_face_name(self): + self.face_name += 1 + return 'f%i' % (self.face_name-1) + + def vertex_count(self): + return len(self.vertex_lst) + + def request_vertex_desc(self, i): + return self.vertex_lst[i] + + def request_vertex_index(self, desc): + match = None + for i, v in enumerate(self.vertex_lst): + if\ + abs(v.x - desc.x) > FLOAT_TOLERANCE or\ + abs(v.y - desc.y) > FLOAT_TOLERANCE or\ + abs(v.z - desc.z) > FLOAT_TOLERANCE or\ + abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\ + abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\ + abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\ + abs(v.u - desc.u) > FLOAT_TOLERANCE or\ + abs(v.v - desc.v) > FLOAT_TOLERANCE: + pass + else: + match = i + break + + if match != None: + return match + else: + self.vertex_lst.append(desc) + return len(self.vertex_lst) - 1 + + def request_texture_index(self, filename): + match = None + for i in xrange(len(self.texture_lst)): + if self.texture_lst[i] != filename: + continue + match = i + break + if match != None: + return match + else: + self.texture_lst.append(filename) + return len(self.texture_lst) - 1 + + def request_texture_filename(self, index): + return self.texture_lst[index] + + def texture_count(self): + return len(self.texture_lst) + + def request_material_index(self, desc): + match = None + for i in xrange(len(self.material_lst)): + if self.material_lst[i].diffuse != desc.diffuse: + continue + if self.material_lst[i].specular != desc.specular: + continue + if self.material_lst[i].ambient != desc.ambient: + continue + if self.material_lst[i].emissive != desc.emissive: + continue + if self.material_lst[i].shininess != desc.shininess: + continue + if self.material_lst[i].alpha != desc.alpha: + continue + match = i + break + + if match != None: + return i + else: + self.material_lst.append(desc) + return len(self.material_lst) - 1 + + def request_material_desc(self, index): + return self.material_lst[index] + + def material_count(self): + return len(self.material_lst) + + # Returns not actual index but one that includes intensity information. + # color_index = 127*intensity + 128*actual_index + def request_color_index(self, col): + r,g,b = tuple(col) + m = max(r, g, b) + if m > 0.0: + intensity = m / 1.0 + r = int(round(r/m * 255.0)) + g = int(round(g/m * 255.0)) + b = int(round(b/m * 255.0)) + brightest = [r, g, b] + else: + brightest = [255, 255, 255] + intensity = 0.0 + + match = None + for i in xrange(len(self.color_lst)): + if self.color_lst[i] != brightest: + continue + + match = i + break + + if match != None: + index = match + else: + length = len(self.color_lst) + if length <= 1024: + self.color_lst.append(brightest) + index = length + else: + if options.verbose >= 1: + print 'Warning: Exceeded max color limit.' + index = 0 + + color_index = int(round(127.0*intensity)) + 128*index + return color_index + + # Returns color from actual index. + def request_max_color(self, index): + return self.color_lst[index] + + def color_count(self): + return len(self.color_lst) + + def __init__(self): + self.vertex_lst = [] + self.texture_lst = [] + self.material_lst = [] + self.color_lst = [[255, 255, 255]] + self.face_name = 0 class Node: - # Gathers info from blender needed for export. - # The =[0] is a trick to emulate c-like static function variables - # that are persistant between calls. - def blender_export(self, level=[0]): - if self.object: - if options.verbose >= 2: - for j in range(level[0]): - print ' ', - print self.name, type(self.object.getData()) - - level[0] += 1 - - for child in self.children: - child.blender_export() - - level[0] -= 1 - - # Exports this node's info to file. - def write(self): - pass - - def write_matrix(self): - if self.matrix and not is_identity(self.matrix): - self.header.fw.write_short(49) # Matrix opcode - self.header.fw.write_ushort(68) # Length of record - for i in range(4): - for j in range(4): - self.header.fw.write_float(self.matrix[i][j]) - - def write_push(self): - self.header.fw.write_short(10) - self.header.fw.write_ushort(4) - - def write_pop(self): - self.header.fw.write_short(11) - self.header.fw.write_ushort(4) - - def write_longid(self, name): - length = len(name) - if length >= 8: - self.header.fw.write_short(33) # Long ID opcode - self.header.fw.write_ushort(length+5) # Length of record - self.header.fw.write_string(name, length+1) # name + zero terminator - - # Initialization sets up basic tree structure. - def __init__(self, parent, header, object, object_lst): - self.header = header - self.object = object - if object: - self.name = self.object.getName() - self.matrix = self.object.getMatrix('localspace') - else: - self.name = 'no name' - self.matrix = None - - self.children = [] - self.parent = parent - if parent: - parent.children.append(self) - - left_over = object_lst[:] - self.child_objects = [] - - # Add children to child list and remove from left_over list. - for obj in object_lst: - if obj.getParent() == object: - self.child_objects.append(obj) - left_over.remove(obj) - - # Spawn children. - self.has_object_child = False # For Database class. - for child in self.child_objects: - dat = child.getData() - t = type(dat) - - if dat == None: - BlenderEmpty(self, header, child, left_over) - if t == Blender.Types.NMeshType: - BlenderMesh(self, header, child, left_over) - self.has_object_child = True + # Gathers info from blender needed for export. + # The =[0] is a trick to emulate c-like static function variables + # that are persistant between calls. + def blender_export(self, level=[0]): + if self.object: + if options.verbose >= 2: + print '\t' * level[0], self.name, self.object.getType() + + level[0] += 1 + + for child in self.children: + child.blender_export() + + level[0] -= 1 + + # Exports this node's info to file. + def write(self): + pass + + def write_matrix(self): + if self.matrix and not is_identity(self.matrix): + self.header.fw.write_short(49) # Matrix opcode + self.header.fw.write_ushort(68) # Length of record + for i in xrange(4): + for j in xrange(4): + self.header.fw.write_float(self.matrix[i][j]) + + def write_push(self): + self.header.fw.write_short(10) + self.header.fw.write_ushort(4) + + def write_pop(self): + self.header.fw.write_short(11) + self.header.fw.write_ushort(4) + + def write_longid(self, name): + length = len(name) + if length >= 8: + self.header.fw.write_short(33) # Long ID opcode + self.header.fw.write_ushort(length+5) # Length of record + self.header.fw.write_string(name, length+1) # name + zero terminator + + # Initialization sets up basic tree structure. + def __init__(self, parent, header, object, object_lst): + self.header = header + self.object = object + if object: + self.name = self.object.getName() + self.matrix = self.object.getMatrix('localspace') + else: + self.name = 'no name' + self.matrix = None + + self.children = [] + self.parent = parent + if parent: + parent.children.append(self) + + left_over = object_lst[:] + self.child_objects = [] + + # Add children to child list and remove from left_over list. + + # Pop is faster then remove + i = len(object_lst) + while i: + i-=1 + if object_lst[i].parent == object: + self.child_objects.append(left_over.pop(i)) + + # Spawn children. + self.has_object_child = False # For Database class. + for child in self.child_objects: + if child.getType() == 'Mesh': + BlenderMesh(self, header, child, left_over) + self.has_object_child = True + else: # Treat all non meshes as emptys + BlenderEmpty(self, header, child, left_over) class FaceDesc: - def __init__(self): - self.vertex_index_lst = [] - self.texture_index = -1 - self.material_index = -1 - self.color_index = 127 - + def __init__(self): + self.vertex_index_lst = [] + self.texture_index = -1 + self.material_index = -1 + self.color_index = 127 + class BlenderMesh(Node): - def blender_export(self): - Node.blender_export(self) - - mesh = self.object.getData() - - # Gather materials and textures. - tex_index_lst = [] - mat_index_lst = [] - color_index_lst = [] - materials = mesh.getMaterials() - - if materials == []: - materials = [Blender.Material.New()] - - for mat in materials: - # Gather Color. - if options.use_face_color: - color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol())) - else: - color_index_lst.append(127) # white - # Gather Texture. - mtex_lst = mat.getTextures() - - index = -1 - mtex = mtex_lst[0] # Not doing multi-texturing at the moment. - if mtex != None: - tex = mtex_lst[0].tex - if tex != None: - image = tex.getImage() - if image != None: - filename = image.getFilename() - index = self.header.GRR.request_texture_index(filename) - - tex_index_lst.append(index) - - # Gather Material - mat_desc = MaterialDesc() - mat_desc.name = mat.getName() - mat_desc.alpha = mat.getAlpha() - mat_desc.shininess = mat.getSpec() * 64.0 # 2.0 => 128.0 - if options.use_mat_color: - mat_desc.diffuse = mat.getRGBCol() - else: - mat_desc.diffuse = [1.0, 1.0, 1.0] - - mat_desc.specular = mat.getSpecCol() - amb = mat.getAmb() - mat_desc.ambient = [amb, amb, amb] - emit = mat.getEmit() - mat_desc.emissive = [emit, emit, emit] - - mat_index_lst.append(self.header.GRR.request_material_index(mat_desc)) - - # Faces described as lists of indices into the GRR's vertex_lst. - for face in mesh.faces: - # Create vertex description list for each face. - vertex_lst = [] - for vertex in face.v: - vert_desc = VertexDesc() - vert_desc.x = vertex.co[0] - vert_desc.y = vertex.co[1] - vert_desc.z = vertex.co[2] - vert_desc.nx = vertex.no[0] - vert_desc.ny = vertex.no[1] - vert_desc.nz = vertex.no[2] - vertex_lst.append(vert_desc) - - for j in range( min(len(face.uv),len(vertex_lst)) ): - vertex_lst[j].u = face.uv[j][0] - vertex_lst[j].v = face.uv[j][1] - - index_lst = [] - for vert_desc in vertex_lst: - index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) - - face_desc = FaceDesc() - face_desc.vertex_index_lst = index_lst - - if face.materialIndex < len(materials): - face_desc.color_index = color_index_lst[face.materialIndex] - face_desc.texture_index = tex_index_lst[face.materialIndex] - face_desc.material_index = mat_index_lst[face.materialIndex] - else: - if options.verbose >=1: - print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.' - - self.face_lst.append(face_desc) - - # Export double sided face as 2 faces with opposite orientations. - if mesh.hasFaceUV() and face.mode & Blender.NMesh.FaceModes['TWOSIDE']: - # Create vertex description list for each face. - vertex_lst = [] - for vertex in face.v: - vert_desc = VertexDesc() - vert_desc.x = vertex.co[0] - vert_desc.y = vertex.co[1] - vert_desc.z = vertex.co[2] - vert_desc.nx = -vertex.no[0] - vert_desc.ny = -vertex.no[1] - vert_desc.nz = -vertex.no[2] - vertex_lst.append(vert_desc) - - for j in range( min(len(face.uv),len(vertex_lst)) ): - vertex_lst[j].u = face.uv[j][0] - vertex_lst[j].v = face.uv[j][1] - - vertex_lst.reverse() - - index_lst = [] - for vert_desc in vertex_lst: - index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) - - face_desc = FaceDesc() - face_desc.vertex_index_lst = index_lst - if face.materialIndex < len(materials): - face_desc.color_index = color_index_lst[face.materialIndex] - face_desc.texture_index = tex_index_lst[face.materialIndex] - face_desc.material_index = mat_index_lst[face.materialIndex] - else: - if options.verbose >=1: - print 'Error: No material for material index. Delete abandoned material indices in Blender.' - - self.face_lst.append(face_desc) - - def write_faces(self): - for face_desc in self.face_lst: - face_name = self.header.GRR.new_face_name() - - self.header.fw.write_short(5) # Face opcode - self.header.fw.write_ushort(80) # Length of record - self.header.fw.write_string(face_name, 8) # ASCII ID - self.header.fw.write_int(-1) # IR color code - self.header.fw.write_short(0) # Relative priority - self.header.fw.write_char(0) # Draw type - self.header.fw.write_char(0) # Draw textured white. - self.header.fw.write_ushort(0) # Color name index - self.header.fw.write_ushort(0) # Alt color name index - self.header.fw.write_char(0) # Reserved - self.header.fw.write_char(1) # Template - self.header.fw.write_short(-1) # Detail tex pat index - self.header.fw.write_short(face_desc.texture_index) # Tex pattern index - self.header.fw.write_short(face_desc.material_index) # material index - self.header.fw.write_short(0) # SMC code - self.header.fw.write_short(0) # Feature code - self.header.fw.write_int(0) # IR material code - self.header.fw.write_ushort(0) # transparency 0 = opaque - self.header.fw.write_uchar(0) # LOD generation control - self.header.fw.write_uchar(0) # line style index - self.header.fw.write_int(0x00000000) # Flags - self.header.fw.write_uchar(2) # Light mode - self.header.fw.pad(7) # Reserved - self.header.fw.write_uint(-1) # Packed color - self.header.fw.write_uint(-1) # Packed alt color - self.header.fw.write_short(-1) # Tex map index - self.header.fw.write_short(0) # Reserved - self.header.fw.write_uint(face_desc.color_index) # Color index - self.header.fw.write_uint(127) # Alt color index - self.header.fw.write_short(0) # Reserved - self.header.fw.write_short(-1) # Shader index - - self.write_longid(face_name) - - self.write_push() - - # Vertex list record - self.header.fw.write_short(72) # Vertex list opcode - num_verts = len(face_desc.vertex_index_lst) - self.header.fw.write_ushort(4*num_verts+4) # Length of record - - for vert_index in face_desc.vertex_index_lst: - # Offset into vertex palette - self.header.fw.write_int(vert_index*64+8) - - self.write_pop() - - def write(self): - if self.open_flight_type == 'Object': - self.header.fw.write_short(4) # Object opcode - self.header.fw.write_ushort(28) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(16) - - self.write_longid(self.name) - - self.write_matrix() - - if self.face_lst != []: - self.write_push() - - self.write_faces() - - self.write_pop() - else: - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(32) - - self.write_longid(self.name) - - # Because a group can contain faces as well as children. - self.write_push() - - self.write_faces() - - for child in self.children: - child.write() - - self.write_pop() - - - def __init__(self, parent, header, object, object_lst): - Node.__init__(self, parent, header, object, object_lst) - self.face_lst = [] - - if self.children == []: - self.open_flight_type = 'Object' - else: - self.open_flight_type= 'Group' + def blender_export(self): + Node.blender_export(self) + + mesh = self.object.getData() + mesh_hasuv = mesh.hasFaceUV() + # Gather materials and textures. + tex_index_lst = [] + mat_index_lst = [] + color_index_lst = [] + materials = mesh.getMaterials() + + if not materials: + materials = [Blender.Material.New()] + + for mat in materials: + # Gather Color. + if options.use_face_color: + color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol())) + else: + color_index_lst.append(127) # white + # Gather Texture. + mtex_lst = mat.getTextures() + + index = -1 + mtex = mtex_lst[0] # Not doing multi-texturing at the moment. + if mtex != None: + tex = mtex_lst[0].tex + if tex != None: + image = tex.getImage() + if image != None: + filename = image.getFilename() + index = self.header.GRR.request_texture_index(filename) + + tex_index_lst.append(index) + + # Gather Material + mat_desc = MaterialDesc() + mat_desc.name = mat.getName() + mat_desc.alpha = mat.getAlpha() + mat_desc.shininess = mat.getSpec() * 64.0 # 2.0 => 128.0 + if options.use_mat_color: + mat_desc.diffuse = mat.getRGBCol() + else: + mat_desc.diffuse = [1.0, 1.0, 1.0] + + mat_desc.specular = mat.getSpecCol() + amb = mat.getAmb() + mat_desc.ambient = [amb, amb, amb] + emit = mat.getEmit() + mat_desc.emissive = [emit, emit, emit] + + mat_index_lst.append(self.header.GRR.request_material_index(mat_desc)) + + # Faces described as lists of indices into the GRR's vertex_lst. + for face in mesh.faces: + + face_v = face.v # Faster access + + # Create vertex description list for each face. + if mesh_hasuv: + vertex_lst = [VertexDesc(v.co, v.no, face.uv[i]) for i, v in enumerate(face_v)] + else: + vertex_lst = [VertexDesc(v.co, v.no) for i, v in enumerate(face_v)] + + index_lst = [] + for vert_desc in vertex_lst: + index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) + + face_desc = FaceDesc() + face_desc.vertex_index_lst = index_lst + + if face.materialIndex < len(materials): + face_desc.color_index = color_index_lst[face.materialIndex] + face_desc.texture_index = tex_index_lst[face.materialIndex] + face_desc.material_index = mat_index_lst[face.materialIndex] + else: + if options.verbose >=1: + print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.' + + self.face_lst.append(face_desc) + + # Export double sided face as 2 faces with opposite orientations. + if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']: + # Create vertex description list for each face. they have a face mode, so we know they have a UV too. + vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)] + vertex_lst.reverse() # Reversing flips the face. + + index_lst = [] + for vert_desc in vertex_lst: + index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) + + face_desc = FaceDesc() + face_desc.vertex_index_lst = index_lst + if face.materialIndex < len(materials): + face_desc.color_index = color_index_lst[face.materialIndex] + face_desc.texture_index = tex_index_lst[face.materialIndex] + face_desc.material_index = mat_index_lst[face.materialIndex] + else: + if options.verbose >=1: + print 'Error: No material for material index. Delete abandoned material indices in Blender.' + + self.face_lst.append(face_desc) + + def write_faces(self): + for face_desc in self.face_lst: + face_name = self.header.GRR.new_face_name() + + self.header.fw.write_short(5) # Face opcode + self.header.fw.write_ushort(80) # Length of record + self.header.fw.write_string(face_name, 8) # ASCII ID + self.header.fw.write_int(-1) # IR color code + self.header.fw.write_short(0) # Relative priority + self.header.fw.write_char(0) # Draw type + self.header.fw.write_char(0) # Draw textured white. + self.header.fw.write_ushort(0) # Color name index + self.header.fw.write_ushort(0) # Alt color name index + self.header.fw.write_char(0) # Reserved + self.header.fw.write_char(1) # Template + self.header.fw.write_short(-1) # Detail tex pat index + self.header.fw.write_short(face_desc.texture_index) # Tex pattern index + self.header.fw.write_short(face_desc.material_index) # material index + self.header.fw.write_short(0) # SMC code + self.header.fw.write_short(0) # Feature code + self.header.fw.write_int(0) # IR material code + self.header.fw.write_ushort(0) # transparency 0 = opaque + self.header.fw.write_uchar(0) # LOD generation control + self.header.fw.write_uchar(0) # line style index + self.header.fw.write_int(0x00000000) # Flags + self.header.fw.write_uchar(2) # Light mode + self.header.fw.pad(7) # Reserved + self.header.fw.write_uint(-1) # Packed color + self.header.fw.write_uint(-1) # Packed alt color + self.header.fw.write_short(-1) # Tex map index + self.header.fw.write_short(0) # Reserved + self.header.fw.write_uint(face_desc.color_index) # Color index + self.header.fw.write_uint(127) # Alt color index + self.header.fw.write_short(0) # Reserved + self.header.fw.write_short(-1) # Shader index + + self.write_longid(face_name) + + self.write_push() + + # Vertex list record + self.header.fw.write_short(72) # Vertex list opcode + num_verts = len(face_desc.vertex_index_lst) + self.header.fw.write_ushort(4*num_verts+4) # Length of record + + for vert_index in face_desc.vertex_index_lst: + # Offset into vertex palette + self.header.fw.write_int(vert_index*64+8) + + self.write_pop() + + def write(self): + if self.open_flight_type == 'Object': + self.header.fw.write_short(4) # Object opcode + self.header.fw.write_ushort(28) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(16) + + self.write_longid(self.name) + + self.write_matrix() + + if self.face_lst != []: + self.write_push() + + self.write_faces() + + self.write_pop() + else: + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(32) + + self.write_longid(self.name) + + # Because a group can contain faces as well as children. + self.write_push() + + self.write_faces() + + for child in self.children: + child.write() + + self.write_pop() + + def __init__(self, parent, header, object, object_lst): + Node.__init__(self, parent, header, object, object_lst) + self.face_lst = [] + + if self.children: + self.open_flight_type= 'Group' + else: # Empty list. + self.open_flight_type = 'Object' + class BlenderEmpty(Node): - def write(self): - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(32) - - self.write_longid(self.name) - - self.write_matrix() - - if self.children != []: - self.write_push() - - for child in self.children: - child.write() - - self.write_pop() + def write(self): + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(32) + + self.write_longid(self.name) + + self.write_matrix() + + if self.children: # != [] + self.write_push() + + for child in self.children: + child.write() + + self.write_pop() class Database(Node): - def write_header(self): - if options.verbose >= 2: - print 'Writing header.' - self.fw.write_short(1) # Header opcode - self.fw.write_ushort(324) # Length of record - self.fw.write_string('db', 8) # ASCII ID - self.fw.write_int(1600) # Revision Number - self.fw.pad(44) - self.fw.write_short(1) # Unit multiplier. - self.fw.write_char(0) # Units, 0 = meters - self.fw.write_char(0) # texwhite on new faces 0 = false - self.fw.write_uint(0x80000000) # misc flags set to saving vertex normals - self.fw.pad(24) - self.fw.write_int(0) # projection type, 0 = flat earth - self.fw.pad(30) - self.fw.write_short(1) # double precision - self.fw.pad(140) - self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984 - self.fw.pad(52) - - def write_vert_pal(self): - if options.verbose >= 2: - print 'Writing vertex palette.' - # Write record for vertex palette - self.fw.write_short(67) # Vertex palette opcode. - self.fw.write_short(8) # Length of record - self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything. - - # Write records for individual vertices. - for i in range(self.GRR.vertex_count()): - desc = self.GRR.request_vertex_desc(i) - self.fw.write_short(70) # Vertex with color normal and uv opcode. - self.fw.write_ushort(64) # Length of record - self.fw.write_ushort(0) # Color name index - self.fw.write_short(0x2000) # Flags set to no color - self.fw.write_double(desc.x) - self.fw.write_double(desc.y) - self.fw.write_double(desc.z) - self.fw.write_float(desc.nx) - self.fw.write_float(desc.ny) - self.fw.write_float(desc.nz) - self.fw.write_float(desc.u) - self.fw.write_float(desc.v) - self.fw.pad(12) - - def write_tex_pal(self): - if options.verbose >= 2: - print 'Writing texture palette.' - # Write record for texture palette - for i in range(self.GRR.texture_count()): - self.fw.write_short(64) # Texture palette opcode. - self.fw.write_short(216) # Length of record - self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename - self.fw.write_int(i) # Texture index - self.fw.write_int(0) # X - self.fw.write_int(0) # Y - - def write_mat_pal(self): - if options.verbose >= 2: - print 'Writing material palette.' - for i in range(self.GRR.material_count()): - desc = self.GRR.request_material_desc(i) - self.fw.write_short(113) # Material palette opcode. - self.fw.write_short(84) # Length of record - self.fw.write_int(i) # Material index - self.fw.write_string(desc.name, 12) # Material name - self.fw.write_uint(0x80000000) # Flags - self.fw.write_float(desc.ambient[0]) # Ambient color. - self.fw.write_float(desc.ambient[1]) # Ambient color. - self.fw.write_float(desc.ambient[2]) # Ambient color. - self.fw.write_float(desc.diffuse[0]) # Diffuse color. - self.fw.write_float(desc.diffuse[1]) # Diffuse color. - self.fw.write_float(desc.diffuse[2]) # Diffuse color. - self.fw.write_float(desc.specular[0]) # Specular color. - self.fw.write_float(desc.specular[1]) # Specular color. - self.fw.write_float(desc.specular[2]) # Specular color. - self.fw.write_float(desc.emissive[0]) # Emissive color. - self.fw.write_float(desc.emissive[1]) # Emissive color. - self.fw.write_float(desc.emissive[2]) # Emissive color. - self.fw.write_float(desc.shininess) - self.fw.write_float(desc.alpha) - self.fw.write_int(0) # Reserved - - def write_col_pal(self): - if options.verbose >= 2: - print 'Writing color palette.' - self.fw.write_short(32) # Color palette opcode. - self.fw.write_short(4228) # Length of record - self.fw.pad(128) - count = self.GRR.color_count() - for i in range(count): - col = self.GRR.request_max_color(i) - self.fw.write_uchar(255) # alpha - self.fw.write_uchar(col[2]) # b - self.fw.write_uchar(col[1]) # g - self.fw.write_uchar(col[0]) # r - self.fw.pad(max(4096-count*4, 0)) - - def write(self): - self.write_header() - self.write_vert_pal() - self.write_tex_pal() - self.write_mat_pal() - self.write_col_pal() - - # Wrap everything in a group if it has an object child. - if self.has_object_child: - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string('g1', 8) # ASCII ID - self.header.fw.pad(32) - - self.write_push() - - for child in self.children: - child.write() - - self.write_pop() - - def __init__(self, scene, fw): - self.fw = fw - self.scene = scene - self.all_objects = scene.getChildren() - self.GRR = GlobalResourceRepository() - - Node.__init__(self, None, self, None, self.all_objects) + def write_header(self): + if options.verbose >= 2: + print 'Writing header.' + self.fw.write_short(1) # Header opcode + self.fw.write_ushort(324) # Length of record + self.fw.write_string('db', 8) # ASCII ID + self.fw.write_int(1600) # Revision Number + self.fw.pad(44) + self.fw.write_short(1) # Unit multiplier. + self.fw.write_char(0) # Units, 0 = meters + self.fw.write_char(0) # texwhite on new faces 0 = false + self.fw.write_uint(0x80000000) # misc flags set to saving vertex normals + self.fw.pad(24) + self.fw.write_int(0) # projection type, 0 = flat earth + self.fw.pad(30) + self.fw.write_short(1) # double precision + self.fw.pad(140) + self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984 + self.fw.pad(52) + + def write_vert_pal(self): + if options.verbose >= 2: + print 'Writing vertex palette.' + # Write record for vertex palette + self.fw.write_short(67) # Vertex palette opcode. + self.fw.write_short(8) # Length of record + self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything. + + # Write records for individual vertices. + for i in xrange(self.GRR.vertex_count()): + desc = self.GRR.request_vertex_desc(i) + self.fw.write_short(70) # Vertex with color normal and uv opcode. + self.fw.write_ushort(64) # Length of record + self.fw.write_ushort(0) # Color name index + self.fw.write_short(0x2000) # Flags set to no color + self.fw.write_double(desc.x) + self.fw.write_double(desc.y) + self.fw.write_double(desc.z) + self.fw.write_float(desc.nx) + self.fw.write_float(desc.ny) + self.fw.write_float(desc.nz) + self.fw.write_float(desc.u) + self.fw.write_float(desc.v) + self.fw.pad(12) + + def write_tex_pal(self): + if options.verbose >= 2: + print 'Writing texture palette.' + # Write record for texture palette + for i in xrange(self.GRR.texture_count()): + self.fw.write_short(64) # Texture palette opcode. + self.fw.write_short(216) # Length of record + self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename + self.fw.write_int(i) # Texture index + self.fw.write_int(0) # X + self.fw.write_int(0) # Y + + def write_mat_pal(self): + if options.verbose >= 2: + print 'Writing material palette.' + for i in xrange(self.GRR.material_count()): + desc = self.GRR.request_material_desc(i) + self.fw.write_short(113) # Material palette opcode. + self.fw.write_short(84) # Length of record + self.fw.write_int(i) # Material index + self.fw.write_string(desc.name, 12) # Material name + self.fw.write_uint(0x80000000) # Flags + self.fw.write_float(desc.ambient[0]) # Ambient color. + self.fw.write_float(desc.ambient[1]) # Ambient color. + self.fw.write_float(desc.ambient[2]) # Ambient color. + self.fw.write_float(desc.diffuse[0]) # Diffuse color. + self.fw.write_float(desc.diffuse[1]) # Diffuse color. + self.fw.write_float(desc.diffuse[2]) # Diffuse color. + self.fw.write_float(desc.specular[0]) # Specular color. + self.fw.write_float(desc.specular[1]) # Specular color. + self.fw.write_float(desc.specular[2]) # Specular color. + self.fw.write_float(desc.emissive[0]) # Emissive color. + self.fw.write_float(desc.emissive[1]) # Emissive color. + self.fw.write_float(desc.emissive[2]) # Emissive color. + self.fw.write_float(desc.shininess) + self.fw.write_float(desc.alpha) + self.fw.write_int(0) # Reserved + + def write_col_pal(self): + if options.verbose >= 2: + print 'Writing color palette.' + self.fw.write_short(32) # Color palette opcode. + self.fw.write_short(4228) # Length of record + self.fw.pad(128) + count = self.GRR.color_count() + for i in xrange(count): + col = self.GRR.request_max_color(i) + self.fw.write_uchar(255) # alpha + self.fw.write_uchar(col[2]) # b + self.fw.write_uchar(col[1]) # g + self.fw.write_uchar(col[0]) # r + self.fw.pad(max(4096-count*4, 0)) + + def write(self): + self.write_header() + self.write_vert_pal() + self.write_tex_pal() + self.write_mat_pal() + self.write_col_pal() + + # Wrap everything in a group if it has an object child. + if self.has_object_child: + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string('g1', 8) # ASCII ID + self.header.fw.pad(32) + + self.write_push() + + for child in self.children: + child.write() + + self.write_pop() + + def __init__(self, scene, fw): + self.fw = fw + self.scene = scene + self.all_objects = scene.getChildren() + self.GRR = GlobalResourceRepository() + + Node.__init__(self, None, self, None, self.all_objects) def fs_callback(filename): - Blender.Window.WaitCursor(True) - - if Blender.sys.exists(filename): - r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No') - if r != 1: - if options.verbose >= 1: - print 'Export cancelled.' - return - - fw = FltOut(filename) - - db = Database(Blender.Scene.GetCurrent(), fw) - - if options.verbose >= 1: - print - print 'Pass 1: Exporting from Blender.' - print - - db.blender_export() - - if options.verbose >= 1: - print - print 'Pass 2: Writing', filename - print - - db.write() - - fw.close_file() - if options.verbose >= 1: - print - print 'Done.' - - Blender.Window.WaitCursor(False) - + Blender.Window.WaitCursor(True) + + if Blender.sys.exists(filename): + r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No') + if r != 1: + if options.verbose >= 1: + print 'Export cancelled.' + return + + time1 = Blender.sys.time() # Start timing + + fw = FltOut(filename) + + db = Database(Blender.Scene.GetCurrent(), fw) + + if options.verbose >= 1: + print 'Pass 1: Exporting from Blender.\n' + + db.blender_export() + + if options.verbose >= 1: + print 'Pass 2: Writing %s\n' % filename + + db.write() + + fw.close_file() + if options.verbose >= 1: + print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1) + + Blender.Window.WaitCursor(False) + if options.verbose >= 1: - print - print 'OpenFlight Exporter' - print 'Version:', __version__ - print 'Author: Greg MacDonald' - print __url__[2] - print - + print '\nOpenFlight Exporter' + print 'Version:', __version__ + print 'Author: Greg MacDonald' + print __url__[2] + print + fname = Blender.sys.makename(ext=".flt") Blender.Window.FileSelector(fs_callback, "Export OpenFlight v16.0", fname) |