removed slow list handeling
faster vert comparisons replaced spaces for tabs removed unneeded getData() calls general cleanup.
This commit is contained in:
@@ -57,7 +57,6 @@ What's Not Handled:<br>
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import Blender
|
import Blender
|
||||||
import math
|
|
||||||
from flt_filewalker import FltOut
|
from flt_filewalker import FltOut
|
||||||
|
|
||||||
class ExporterOptions:
|
class ExporterOptions:
|
||||||
@@ -78,15 +77,14 @@ class ExporterOptions:
|
|||||||
|
|
||||||
options = ExporterOptions()
|
options = ExporterOptions()
|
||||||
|
|
||||||
def not_equal_float(f1, f2):
|
FLOAT_TOLERANCE = options.tolerance
|
||||||
return math.fabs(f1 - f2) > 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]]
|
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):
|
def is_identity(m):
|
||||||
for i in range(4):
|
for i in xrange(4):
|
||||||
for j in range(4):
|
for j in xrange(4):
|
||||||
if not_equal_float(m[i][j], identity_matrix[i][j]):
|
if abs(m[i][j] - identity_matrix[i][j]) > FLOAT_TOLERANCE:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -105,21 +103,18 @@ class MaterialDesc:
|
|||||||
self.alpha = 1.0 # Range is [0.0, 1.0]
|
self.alpha = 1.0 # Range is [0.0, 1.0]
|
||||||
|
|
||||||
class VertexDesc:
|
class VertexDesc:
|
||||||
def __init__(self):
|
def __init__(self, co=None, no=None, uv=None):
|
||||||
self.x = 0.0
|
if co: self.x, self.y, self.z = tuple(co)
|
||||||
self.y = 0.0
|
else: self.x = self.y = self.z = 0.0
|
||||||
self.z = 0.0
|
if no: self.nx, self.ny, self.nz = tuple(no)
|
||||||
self.nx = 0.0
|
else: self.nx = self.ny = self.nz = 0.0
|
||||||
self.ny = 0.0
|
if uv: self.u, self.v = tuple(uv)
|
||||||
self.nz = 0.0
|
else: self.u = self.v = 0.0
|
||||||
self.u = 0.0
|
|
||||||
self.v = 0.0
|
|
||||||
|
|
||||||
class GlobalResourceRepository:
|
class GlobalResourceRepository:
|
||||||
def new_face_name(self):
|
def new_face_name(self):
|
||||||
n = 'f' + str(self.face_name)
|
|
||||||
self.face_name += 1
|
self.face_name += 1
|
||||||
return n
|
return 'f%i' % (self.face_name-1)
|
||||||
|
|
||||||
def vertex_count(self):
|
def vertex_count(self):
|
||||||
return len(self.vertex_lst)
|
return len(self.vertex_lst)
|
||||||
@@ -129,24 +124,18 @@ class GlobalResourceRepository:
|
|||||||
|
|
||||||
def request_vertex_index(self, desc):
|
def request_vertex_index(self, desc):
|
||||||
match = None
|
match = None
|
||||||
for i in range(len(self.vertex_lst)):
|
for i, v in enumerate(self.vertex_lst):
|
||||||
if not_equal_float(self.vertex_lst[i].x, desc.x):
|
if\
|
||||||
continue
|
abs(v.x - desc.x) > FLOAT_TOLERANCE or\
|
||||||
if not_equal_float(self.vertex_lst[i].y, desc.y):
|
abs(v.y - desc.y) > FLOAT_TOLERANCE or\
|
||||||
continue
|
abs(v.z - desc.z) > FLOAT_TOLERANCE or\
|
||||||
if not_equal_float(self.vertex_lst[i].z, desc.z):
|
abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\
|
||||||
continue
|
abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\
|
||||||
if not_equal_float(self.vertex_lst[i].nx, desc.nx):
|
abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\
|
||||||
continue
|
abs(v.u - desc.u) > FLOAT_TOLERANCE or\
|
||||||
if not_equal_float(self.vertex_lst[i].ny, desc.ny):
|
abs(v.v - desc.v) > FLOAT_TOLERANCE:
|
||||||
continue
|
pass
|
||||||
if not_equal_float(self.vertex_lst[i].nz, desc.nz):
|
else:
|
||||||
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
|
match = i
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -158,7 +147,7 @@ class GlobalResourceRepository:
|
|||||||
|
|
||||||
def request_texture_index(self, filename):
|
def request_texture_index(self, filename):
|
||||||
match = None
|
match = None
|
||||||
for i in range(len(self.texture_lst)):
|
for i in xrange(len(self.texture_lst)):
|
||||||
if self.texture_lst[i] != filename:
|
if self.texture_lst[i] != filename:
|
||||||
continue
|
continue
|
||||||
match = i
|
match = i
|
||||||
@@ -177,7 +166,7 @@ class GlobalResourceRepository:
|
|||||||
|
|
||||||
def request_material_index(self, desc):
|
def request_material_index(self, desc):
|
||||||
match = None
|
match = None
|
||||||
for i in range(len(self.material_lst)):
|
for i in xrange(len(self.material_lst)):
|
||||||
if self.material_lst[i].diffuse != desc.diffuse:
|
if self.material_lst[i].diffuse != desc.diffuse:
|
||||||
continue
|
continue
|
||||||
if self.material_lst[i].specular != desc.specular:
|
if self.material_lst[i].specular != desc.specular:
|
||||||
@@ -208,9 +197,7 @@ class GlobalResourceRepository:
|
|||||||
# Returns not actual index but one that includes intensity information.
|
# Returns not actual index but one that includes intensity information.
|
||||||
# color_index = 127*intensity + 128*actual_index
|
# color_index = 127*intensity + 128*actual_index
|
||||||
def request_color_index(self, col):
|
def request_color_index(self, col):
|
||||||
r = col[0]
|
r,g,b = tuple(col)
|
||||||
g = col[1]
|
|
||||||
b = col[2]
|
|
||||||
m = max(r, g, b)
|
m = max(r, g, b)
|
||||||
if m > 0.0:
|
if m > 0.0:
|
||||||
intensity = m / 1.0
|
intensity = m / 1.0
|
||||||
@@ -223,7 +210,7 @@ class GlobalResourceRepository:
|
|||||||
intensity = 0.0
|
intensity = 0.0
|
||||||
|
|
||||||
match = None
|
match = None
|
||||||
for i in range(len(self.color_lst)):
|
for i in xrange(len(self.color_lst)):
|
||||||
if self.color_lst[i] != brightest:
|
if self.color_lst[i] != brightest:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -266,9 +253,7 @@ class Node:
|
|||||||
def blender_export(self, level=[0]):
|
def blender_export(self, level=[0]):
|
||||||
if self.object:
|
if self.object:
|
||||||
if options.verbose >= 2:
|
if options.verbose >= 2:
|
||||||
for j in range(level[0]):
|
print '\t' * level[0], self.name, self.object.getType()
|
||||||
print ' ',
|
|
||||||
print self.name, type(self.object.getData())
|
|
||||||
|
|
||||||
level[0] += 1
|
level[0] += 1
|
||||||
|
|
||||||
@@ -285,8 +270,8 @@ class Node:
|
|||||||
if self.matrix and not is_identity(self.matrix):
|
if self.matrix and not is_identity(self.matrix):
|
||||||
self.header.fw.write_short(49) # Matrix opcode
|
self.header.fw.write_short(49) # Matrix opcode
|
||||||
self.header.fw.write_ushort(68) # Length of record
|
self.header.fw.write_ushort(68) # Length of record
|
||||||
for i in range(4):
|
for i in xrange(4):
|
||||||
for j in range(4):
|
for j in xrange(4):
|
||||||
self.header.fw.write_float(self.matrix[i][j])
|
self.header.fw.write_float(self.matrix[i][j])
|
||||||
|
|
||||||
def write_push(self):
|
def write_push(self):
|
||||||
@@ -324,22 +309,22 @@ class Node:
|
|||||||
self.child_objects = []
|
self.child_objects = []
|
||||||
|
|
||||||
# Add children to child list and remove from left_over list.
|
# Add children to child list and remove from left_over list.
|
||||||
for obj in object_lst:
|
|
||||||
if obj.getParent() == object:
|
# Pop is faster then remove
|
||||||
self.child_objects.append(obj)
|
i = len(object_lst)
|
||||||
left_over.remove(obj)
|
while i:
|
||||||
|
i-=1
|
||||||
|
if object_lst[i].parent == object:
|
||||||
|
self.child_objects.append(left_over.pop(i))
|
||||||
|
|
||||||
# Spawn children.
|
# Spawn children.
|
||||||
self.has_object_child = False # For Database class.
|
self.has_object_child = False # For Database class.
|
||||||
for child in self.child_objects:
|
for child in self.child_objects:
|
||||||
dat = child.getData()
|
if child.getType() == 'Mesh':
|
||||||
t = type(dat)
|
|
||||||
|
|
||||||
if dat == None:
|
|
||||||
BlenderEmpty(self, header, child, left_over)
|
|
||||||
if t == Blender.Types.NMeshType:
|
|
||||||
BlenderMesh(self, header, child, left_over)
|
BlenderMesh(self, header, child, left_over)
|
||||||
self.has_object_child = True
|
self.has_object_child = True
|
||||||
|
else: # Treat all non meshes as emptys
|
||||||
|
BlenderEmpty(self, header, child, left_over)
|
||||||
|
|
||||||
class FaceDesc:
|
class FaceDesc:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -353,14 +338,14 @@ class BlenderMesh(Node):
|
|||||||
Node.blender_export(self)
|
Node.blender_export(self)
|
||||||
|
|
||||||
mesh = self.object.getData()
|
mesh = self.object.getData()
|
||||||
|
mesh_hasuv = mesh.hasFaceUV()
|
||||||
# Gather materials and textures.
|
# Gather materials and textures.
|
||||||
tex_index_lst = []
|
tex_index_lst = []
|
||||||
mat_index_lst = []
|
mat_index_lst = []
|
||||||
color_index_lst = []
|
color_index_lst = []
|
||||||
materials = mesh.getMaterials()
|
materials = mesh.getMaterials()
|
||||||
|
|
||||||
if materials == []:
|
if not materials:
|
||||||
materials = [Blender.Material.New()]
|
materials = [Blender.Material.New()]
|
||||||
|
|
||||||
for mat in materials:
|
for mat in materials:
|
||||||
@@ -404,21 +389,14 @@ class BlenderMesh(Node):
|
|||||||
|
|
||||||
# Faces described as lists of indices into the GRR's vertex_lst.
|
# Faces described as lists of indices into the GRR's vertex_lst.
|
||||||
for face in mesh.faces:
|
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)) ):
|
face_v = face.v # Faster access
|
||||||
vertex_lst[j].u = face.uv[j][0]
|
|
||||||
vertex_lst[j].v = face.uv[j][1]
|
# 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 = []
|
index_lst = []
|
||||||
for vert_desc in vertex_lst:
|
for vert_desc in vertex_lst:
|
||||||
@@ -438,24 +416,10 @@ class BlenderMesh(Node):
|
|||||||
self.face_lst.append(face_desc)
|
self.face_lst.append(face_desc)
|
||||||
|
|
||||||
# Export double sided face as 2 faces with opposite orientations.
|
# Export double sided face as 2 faces with opposite orientations.
|
||||||
if mesh.hasFaceUV() and face.mode & Blender.NMesh.FaceModes['TWOSIDE']:
|
if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']:
|
||||||
# Create vertex description list for each face.
|
# Create vertex description list for each face. they have a face mode, so we know they have a UV too.
|
||||||
vertex_lst = []
|
vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)]
|
||||||
for vertex in face.v:
|
vertex_lst.reverse() # Reversing flips the face.
|
||||||
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 = []
|
index_lst = []
|
||||||
for vert_desc in vertex_lst:
|
for vert_desc in vertex_lst:
|
||||||
@@ -559,15 +523,15 @@ class BlenderMesh(Node):
|
|||||||
|
|
||||||
self.write_pop()
|
self.write_pop()
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, parent, header, object, object_lst):
|
def __init__(self, parent, header, object, object_lst):
|
||||||
Node.__init__(self, parent, header, object, object_lst)
|
Node.__init__(self, parent, header, object, object_lst)
|
||||||
self.face_lst = []
|
self.face_lst = []
|
||||||
|
|
||||||
if self.children == []:
|
if self.children:
|
||||||
self.open_flight_type = 'Object'
|
|
||||||
else:
|
|
||||||
self.open_flight_type= 'Group'
|
self.open_flight_type= 'Group'
|
||||||
|
else: # Empty list.
|
||||||
|
self.open_flight_type = 'Object'
|
||||||
|
|
||||||
|
|
||||||
class BlenderEmpty(Node):
|
class BlenderEmpty(Node):
|
||||||
def write(self):
|
def write(self):
|
||||||
@@ -580,7 +544,7 @@ class BlenderEmpty(Node):
|
|||||||
|
|
||||||
self.write_matrix()
|
self.write_matrix()
|
||||||
|
|
||||||
if self.children != []:
|
if self.children: # != []
|
||||||
self.write_push()
|
self.write_push()
|
||||||
|
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
@@ -618,7 +582,7 @@ class Database(Node):
|
|||||||
self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything.
|
self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything.
|
||||||
|
|
||||||
# Write records for individual vertices.
|
# Write records for individual vertices.
|
||||||
for i in range(self.GRR.vertex_count()):
|
for i in xrange(self.GRR.vertex_count()):
|
||||||
desc = self.GRR.request_vertex_desc(i)
|
desc = self.GRR.request_vertex_desc(i)
|
||||||
self.fw.write_short(70) # Vertex with color normal and uv opcode.
|
self.fw.write_short(70) # Vertex with color normal and uv opcode.
|
||||||
self.fw.write_ushort(64) # Length of record
|
self.fw.write_ushort(64) # Length of record
|
||||||
@@ -638,7 +602,7 @@ class Database(Node):
|
|||||||
if options.verbose >= 2:
|
if options.verbose >= 2:
|
||||||
print 'Writing texture palette.'
|
print 'Writing texture palette.'
|
||||||
# Write record for texture palette
|
# Write record for texture palette
|
||||||
for i in range(self.GRR.texture_count()):
|
for i in xrange(self.GRR.texture_count()):
|
||||||
self.fw.write_short(64) # Texture palette opcode.
|
self.fw.write_short(64) # Texture palette opcode.
|
||||||
self.fw.write_short(216) # Length of record
|
self.fw.write_short(216) # Length of record
|
||||||
self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename
|
self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename
|
||||||
@@ -649,7 +613,7 @@ class Database(Node):
|
|||||||
def write_mat_pal(self):
|
def write_mat_pal(self):
|
||||||
if options.verbose >= 2:
|
if options.verbose >= 2:
|
||||||
print 'Writing material palette.'
|
print 'Writing material palette.'
|
||||||
for i in range(self.GRR.material_count()):
|
for i in xrange(self.GRR.material_count()):
|
||||||
desc = self.GRR.request_material_desc(i)
|
desc = self.GRR.request_material_desc(i)
|
||||||
self.fw.write_short(113) # Material palette opcode.
|
self.fw.write_short(113) # Material palette opcode.
|
||||||
self.fw.write_short(84) # Length of record
|
self.fw.write_short(84) # Length of record
|
||||||
@@ -679,7 +643,7 @@ class Database(Node):
|
|||||||
self.fw.write_short(4228) # Length of record
|
self.fw.write_short(4228) # Length of record
|
||||||
self.fw.pad(128)
|
self.fw.pad(128)
|
||||||
count = self.GRR.color_count()
|
count = self.GRR.color_count()
|
||||||
for i in range(count):
|
for i in xrange(count):
|
||||||
col = self.GRR.request_max_color(i)
|
col = self.GRR.request_max_color(i)
|
||||||
self.fw.write_uchar(255) # alpha
|
self.fw.write_uchar(255) # alpha
|
||||||
self.fw.write_uchar(col[2]) # b
|
self.fw.write_uchar(col[2]) # b
|
||||||
@@ -726,34 +690,30 @@ def fs_callback(filename):
|
|||||||
print 'Export cancelled.'
|
print 'Export cancelled.'
|
||||||
return
|
return
|
||||||
|
|
||||||
|
time1 = Blender.sys.time() # Start timing
|
||||||
|
|
||||||
fw = FltOut(filename)
|
fw = FltOut(filename)
|
||||||
|
|
||||||
db = Database(Blender.Scene.GetCurrent(), fw)
|
db = Database(Blender.Scene.GetCurrent(), fw)
|
||||||
|
|
||||||
if options.verbose >= 1:
|
if options.verbose >= 1:
|
||||||
print
|
print 'Pass 1: Exporting from Blender.\n'
|
||||||
print 'Pass 1: Exporting from Blender.'
|
|
||||||
print
|
|
||||||
|
|
||||||
db.blender_export()
|
db.blender_export()
|
||||||
|
|
||||||
if options.verbose >= 1:
|
if options.verbose >= 1:
|
||||||
print
|
print 'Pass 2: Writing %s\n' % filename
|
||||||
print 'Pass 2: Writing', filename
|
|
||||||
print
|
|
||||||
|
|
||||||
db.write()
|
db.write()
|
||||||
|
|
||||||
fw.close_file()
|
fw.close_file()
|
||||||
if options.verbose >= 1:
|
if options.verbose >= 1:
|
||||||
print
|
print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1)
|
||||||
print 'Done.'
|
|
||||||
|
|
||||||
Blender.Window.WaitCursor(False)
|
Blender.Window.WaitCursor(False)
|
||||||
|
|
||||||
if options.verbose >= 1:
|
if options.verbose >= 1:
|
||||||
print
|
print '\nOpenFlight Exporter'
|
||||||
print 'OpenFlight Exporter'
|
|
||||||
print 'Version:', __version__
|
print 'Version:', __version__
|
||||||
print 'Author: Greg MacDonald'
|
print 'Author: Greg MacDonald'
|
||||||
print __url__[2]
|
print __url__[2]
|
||||||
|
|||||||
Reference in New Issue
Block a user