forked from bartvdbraak/blender
a6d077bae2
- tiny updates for better behavior, unix line endings, cvs Id tags; - Updated DX7 exporter (thanks to author Ben Omari who's also working on a DX8 one); - added sysinfo script; Interface (scripts): - changed behavior for which win is chosen for script guis: Now there's a smarter order, guis will use either: - Scripts win - Buttons win (if not a script from groups Wizards or Utils) - Text win - Closest bigger area - Added a button to the scripts header so that it's faster to return to the buttons win (this can be made general), if that was the previous win used.
268 lines
9.2 KiB
Python
268 lines
9.2 KiB
Python
#!BPY
|
|
|
|
"""
|
|
Name: 'TrueSpace...'
|
|
Blender: 232
|
|
Group: 'Export'
|
|
Tooltip: 'Export selected meshes to trueSpace File Format (*.cob)'
|
|
"""
|
|
|
|
# $Id$
|
|
#
|
|
# +---------------------------------------------------------+
|
|
# | 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.
|