diff options
Diffstat (limited to 'release/scripts/truespace_export.py')
-rw-r--r-- | release/scripts/truespace_export.py | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/release/scripts/truespace_export.py b/release/scripts/truespace_export.py new file mode 100644 index 00000000000..8013278e528 --- /dev/null +++ b/release/scripts/truespace_export.py @@ -0,0 +1,265 @@ +#!BPY + +""" +Name: 'TrueSpace...' +Blender: 232 +Group: 'Export' +Tooltip: 'Export selected meshes to trueSpace File Format (*.cob)' +""" + +# +---------------------------------------------------------+ +# | Copyright (c) 2001 Anthony D'Agostino | +# | http://www.redrival.com/scorpius | +# | scorpius@netzero.com | +# | June 12, 2001 | +# | Released under the Blender Artistic Licence (BAL) | +# | Import Export Suite v0.5 | +# +---------------------------------------------------------+ +# | Read and write Caligari trueSpace File Format (*.cob) | +# +---------------------------------------------------------+ + +import Blender, mod_meshtools +import struct, os, cStringIO, time + +# ============================== +# === Write trueSpace Format === +# ============================== +def write(filename): + start = time.clock() + file = open(filename, "wb") + objects = Blender.Object.GetSelected() + + write_header(file) + + G,P,V,U,M = 1000,2000,3000,4000,5000 + for object in objects: + objname = object.name + meshname = object.data.name + mesh = Blender.NMesh.GetRaw(meshname) + obj = Blender.Object.Get(objname) + if not mesh: continue + + grou = generate_grou('Group ' + `objects.index(object)+1`) + polh = generate_polh(objname, obj, mesh) + if mod_meshtools.has_vertex_colors(mesh): vcol = generate_vcol(mesh) + unit = generate_unit() + mat1 = generate_mat1(mesh) + + if objects.index(object) == 0: X = 0 + + write_chunk(file, "Grou", 0, 1, G, X, grou) + write_chunk(file, "PolH", 0, 4, P, G, polh) + if mod_meshtools.has_vertex_colors(mesh) and vcol: + write_chunk(file, "VCol", 1, 0, V, P, vcol) + write_chunk(file, "Unit", 0, 1, U, P, unit) + write_chunk(file, "Mat1", 0, 5, M, P, mat1) + + X = G + G,P,V,U,M = map(lambda x: x+1, [G,P,V,U,M]) + + write_chunk(file, "END ", 1, 0, 0, 0, '') # End Of File Chunk + + Blender.Window.DrawProgressBar(1.0, '') # clear progressbar + file.close() + end = time.clock() + seconds = " in %.2f %s" % (end-start, "seconds") + message = "Successfully exported " + os.path.basename(filename) + seconds + mod_meshtools.print_boxed(message) + +# ============================= +# === Write COB File Header === +# ============================= +def write_header(file): + file.write("Caligari V00.01BLH"+" "*13+"\n") + +# =================== +# === Write Chunk === +# =================== +def write_chunk(file, name, major, minor, chunk_id, parent_id, data): + file.write(name) + file.write(struct.pack("<2h", major, minor)) + file.write(struct.pack("<2l", chunk_id, parent_id)) + file.write(struct.pack("<1l", len(data))) + file.write(data) + +# ============================================ +# === Generate PolH (Polygonal Data) Chunk === +# ============================================ +def generate_polh(objname, obj, mesh): + data = cStringIO.StringIO() + write_ObjectName(data, objname) + write_LocalAxes(data, obj) + write_CurrentPosition(data, obj) + write_VertexList(data, mesh) + uvcoords = write_UVCoordsList(data, mesh) + write_FaceList(data, mesh, uvcoords) + return data.getvalue() + +# === Write Object Name === +def write_ObjectName(data, objname): + data.write(struct.pack("<h", 0)) # dupecount + data.write(struct.pack("<h", len(objname))) + data.write(objname) + +# === Write Local Axes === +def write_LocalAxes(data, obj): + data.write(struct.pack("<fff", obj.mat[3][0], obj.mat[3][1], obj.mat[3][2])) + data.write(struct.pack("<fff", obj.mat[0][0]/obj.SizeX, obj.mat[1][0]/obj.SizeX, obj.mat[2][0]/obj.SizeX)) + data.write(struct.pack("<fff", obj.mat[0][1]/obj.SizeY, obj.mat[1][1]/obj.SizeY, obj.mat[2][1]/obj.SizeY)) + data.write(struct.pack("<fff", obj.mat[0][2]/obj.SizeZ, obj.mat[1][2]/obj.SizeZ, obj.mat[2][2]/obj.SizeZ)) + +# === Write Current Position === +def write_CurrentPosition(data, obj): + data.write(struct.pack("<ffff", obj.mat[0][0], obj.mat[0][1], obj.mat[0][2], obj.mat[3][0])) + data.write(struct.pack("<ffff", obj.mat[1][0], obj.mat[1][1], obj.mat[1][2], obj.mat[3][1])) + data.write(struct.pack("<ffff", obj.mat[2][0], obj.mat[2][1], obj.mat[2][2], obj.mat[3][2])) + +# === Write Vertex List === +def write_VertexList(data, mesh): + data.write(struct.pack("<l", len(mesh.verts))) + for i in range(len(mesh.verts)): + if not i%100 and mod_meshtools.show_progress: + Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Writing Verts") + x, y, z = mesh.verts[i].co + data.write(struct.pack("<fff", -y, x, z)) + +# === Write UV Vertex List === +def write_UVCoordsList(data, mesh): + if not mesh.hasFaceUV(): + data.write(struct.pack("<l", 1)) + data.write(struct.pack("<2f", 0,0)) + return {(0,0): 0} + # === Default UV Coords (one image per face) === + # data.write(struct.pack("<l", 4)) + # data.write(struct.pack("<8f", 0,0, 0,1, 1,1, 1,0)) + # return {(0,0): 0, (0,1): 1, (1,1): 2, (1,0): 3} + # === Default UV Coords (one image per face) === + + # === collect, remove duplicates, add indices, and write the uv list === + uvdata = cStringIO.StringIO() + uvcoords = {} + uvidx = 0 + for i in range(len(mesh.faces)): + if not i%100 and mod_meshtools.show_progress: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing UV Coords") + numfaceverts = len(mesh.faces[i].v) + for j in range(numfaceverts-1, -1, -1): # Reverse order + u,v = mesh.faces[i].uv[j] + if not uvcoords.has_key((u,v)): + uvcoords[(u,v)] = uvidx + uvidx += 1 + uvdata.write(struct.pack("<ff", u,v)) + uvdata = uvdata.getvalue() + + numuvcoords = len(uvdata)/8 + data.write(struct.pack("<l", numuvcoords)) + data.write(uvdata) + #print "Number of uvcoords:", numuvcoords, '=', len(uvcoords) + return uvcoords + +# === Write Face List === +def write_FaceList(data, mesh, uvcoords): + data.write(struct.pack("<l", len(mesh.faces))) + for i in range(len(mesh.faces)): + if not i%100 and mod_meshtools.show_progress: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Faces") + numfaceverts = len(mesh.faces[i].v) + data.write(struct.pack("<B", 0x10)) # Cull Back Faces Flag + data.write(struct.pack("<h", numfaceverts)) + data.write(struct.pack("<h", 0)) # Material Index + for j in range(numfaceverts-1, -1, -1): # Reverse order + index = mesh.faces[i].v[j].index + if mesh.hasFaceUV(): + uv = mesh.faces[i].uv[j] + uvidx = uvcoords[uv] + else: + uvidx = 0 + data.write(struct.pack("<ll", index, uvidx)) + +# =========================================== +# === Generate VCol (Vertex Colors) Chunk === +# =========================================== +def generate_vcol(mesh): + data = cStringIO.StringIO() + data.write(struct.pack("<l", len(mesh.faces))) + uniquecolors = {} + unique_alpha = {} + for i in range(len(mesh.faces)): + if not i%100 and mod_meshtools.show_progress: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Vertex Colors") + numfaceverts = len(mesh.faces[i].v) + data.write(struct.pack("<ll", i, numfaceverts)) + for j in range(numfaceverts-1, -1, -1): # Reverse order + r = mesh.faces[i].col[j].r + g = mesh.faces[i].col[j].g + b = mesh.faces[i].col[j].b + a = 100 # 100 is opaque in ts + uniquecolors[(r,g,b)] = None + unique_alpha[mesh.faces[i].col[j].a] = None + data.write(struct.pack("<BBBB", r,g,b,a)) + + #print "uniquecolors:", uniquecolors.keys() + #print "unique_alpha:", unique_alpha.keys() + if len(uniquecolors) == 1: + return None + else: + return data.getvalue() + +# ================================== +# === Generate Unit (Size) Chunk === +# ================================== +def generate_unit(): + data = cStringIO.StringIO() + data.write(struct.pack("<h", 2)) + return data.getvalue() + +# ====================================== +# === Generate Mat1 (Material) Chunk === +# ====================================== +def generate_mat1(mesh): + data = cStringIO.StringIO() + data.write(struct.pack("<h", 0)) + data.write(struct.pack("<ccB", "p", "a", 0)) + data.write(struct.pack("<fff", 1.0, 1.0, 1.0)) # rgb (0.0 - 1.0) + data.write(struct.pack("<fffff", 1, 1, 0, 0, 1)) + if mesh.hasFaceUV(): + tex_mapname = r"c:\image\maps\one-dot.tga" + data.write("t:") + data.write(struct.pack("<B", 0x00)) + data.write(struct.pack("<h", len(tex_mapname))) + data.write(tex_mapname) + data.write(struct.pack("<4f", 0,0, 1,1)) + return data.getvalue() + +# ============================ +# === Generate Group Chunk === +# ============================ +def generate_grou(name): + data = cStringIO.StringIO() + write_ObjectName(data, name) + data.write(struct.pack("<12f", 0,0,0, 1,0,0, 0,1,0, 0,0,1)) + data.write(struct.pack("<12f", 1,0,0,0, 0,1,0,0, 0,0,1,0)) + return data.getvalue() + +def fs_callback(filename): + if filename.find('.cob', -4) <= 0: filename += '.cob' + write(filename) + +Blender.Window.FileSelector(fs_callback, "COB Export") + +# === Matrix Differences between Blender & trueSpace === +# +# For the 'Local Axes' values: +# The x, y, and z-axis represent a simple rotation matrix. +# This is equivalent to Blender's object matrix before it was +# combined with the object's scaling matrix. Dividing each value +# by the appropriate scaling factor (and transposing at the same +# time) produces the original rotation matrix. +# +# For the 'Current Position' values: +# This is equivalent to Blender's object matrix except that the +# last row is omitted and the xyz location is used in the last +# column. Binary format uses a 4x3 matrix, ascii format uses a 4x4 +# matrix. +# +# For Cameras: The matrix is a little confusing. |