~ubuntu-branches/ubuntu/gutsy/blender/gutsy-security

« back to all changes in this revision

Viewing changes to release/scripts/truespace_export.py

  • Committer: Bazaar Package Importer
  • Author(s): Florian Ernst
  • Date: 2007-05-17 11:47:59 UTC
  • mfrom: (1.2.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20070517114759-yp4ybrnhp2u7pk66
Tags: 2.44-1
* New upstream release.
* Drop debian/patches/01_64bits_stupidity, not needed anymore: as of this
  version blender is 64 bits safe again. Adjust README.Debian accordingly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!BPY
2
 
 
3
 
"""
4
 
Name: 'TrueSpace (.cob)...'
5
 
Blender: 232
6
 
Group: 'Export'
7
 
Tooltip: 'Export selected meshes to TrueSpace File Format (.cob)'
8
 
"""
9
 
 
10
 
__author__ = "Anthony D'Agostino (Scorpius)"
11
 
__url__ = ("blender", "elysiun",
12
 
"Author's homepage, http://www.redrival.com/scorpius")
13
 
__version__ = "Part of IOSuite 0.5"
14
 
 
15
 
__bpydoc__ = """\
16
 
This script exports meshes to TrueSpace file format.
17
 
 
18
 
TrueSpace is a commercial modeling and rendering application. The .cob
19
 
file format is composed of 'chunks,' is well defined, and easy to read and
20
 
write. It's very similar to LightWave's lwo format.
21
 
 
22
 
Usage:<br>
23
 
        Select meshes to be exported and run this script from "File->Export" menu.
24
 
 
25
 
Supported:<br>
26
 
        Vertex colors will be exported, if they are present.
27
 
 
28
 
Known issues:<br>
29
 
        Before exporting to .cob format, the mesh must have real-time UV
30
 
coordinates.  Press the FKEY to assign them.
31
 
 
32
 
Notes:<br>
33
 
        There are a few differences between how Blender & TrueSpace represent
34
 
their objects' transformation matrices. Blender simply uses a 4x4 matrix,
35
 
and trueSpace splits it into the following two fields.
36
 
 
37
 
        For the 'Local Axes' values: The x, y, and z-axis represent a simple
38
 
rotation matrix.  This is equivalent to Blender's object matrix before
39
 
it was combined with the object's scaling matrix. Dividing each value by
40
 
the appropriate scaling factor (and transposing at the same time)
41
 
produces the original rotation matrix.
42
 
 
43
 
        For the 'Current Position' values:      This is equivalent to Blender's
44
 
object matrix except that the last row is omitted and the xyz location
45
 
is used in the last column. Binary format uses a 4x3 matrix, ascii
46
 
format uses a 4x4 matrix.
47
 
 
48
 
For Cameras: The matrix here gets a little confusing, and I'm not sure of 
49
 
how to handle it.
50
 
"""
51
 
 
52
 
# $Id: truespace_export.py,v 1.11 2007/01/27 04:58:09 campbellbarton Exp $
53
 
#
54
 
# +---------------------------------------------------------+
55
 
# | Copyright (c) 2001 Anthony D'Agostino                   |
56
 
# | http://www.redrival.com/scorpius                        |
57
 
# | scorpius@netzero.com                                    |
58
 
# | June 12, 2001                                           |
59
 
# | Read and write Caligari trueSpace File Format (*.cob)   |
60
 
# +---------------------------------------------------------+
61
 
 
62
 
# ***** BEGIN GPL LICENSE BLOCK *****
63
 
#
64
 
# This program is free software; you can redistribute it and/or
65
 
# modify it under the terms of the GNU General Public License
66
 
# as published by the Free Software Foundation; either version 2
67
 
# of the License, or (at your option) any later version.
68
 
#
69
 
# This program is distributed in the hope that it will be useful,
70
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
71
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
72
 
# GNU General Public License for more details.
73
 
#
74
 
# You should have received a copy of the GNU General Public License
75
 
# along with this program; if not, write to the Free Software Foundation,
76
 
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
77
 
#
78
 
# ***** END GPL LICENCE BLOCK *****
79
 
 
80
 
import Blender, meshtools
81
 
import struct, cStringIO, time
82
 
 
83
 
# ==============================
84
 
# === Write trueSpace Format ===
85
 
# ==============================
86
 
def write(filename):
87
 
        start = time.clock()
88
 
        file = open(filename, "wb")
89
 
        objects = Blender.Object.GetSelected()
90
 
 
91
 
        write_header(file)
92
 
 
93
 
        G,P,V,U,M = 1000,2000,3000,4000,5000
94
 
        for obj_index, obj in enumerate(objects):
95
 
                objname = obj.name
96
 
                meshname = obj.getData(name_only=1)
97
 
                mesh = Blender.NMesh.GetRaw(meshname)
98
 
                
99
 
                if not mesh: continue
100
 
 
101
 
                grou = generate_grou('Group ' + `obj_index+1`)
102
 
                polh = generate_polh(objname, obj, mesh)
103
 
                if meshtools.has_vertex_colors(mesh): vcol = generate_vcol(mesh)
104
 
                unit = generate_unit()
105
 
                mat1 = generate_mat1(mesh)
106
 
 
107
 
                if obj_index == 0: X = 0
108
 
 
109
 
                write_chunk(file, "Grou", 0, 1, G, X, grou)
110
 
                write_chunk(file, "PolH", 0, 4, P, G, polh)
111
 
                if meshtools.has_vertex_colors(mesh) and vcol:
112
 
                        write_chunk(file, "VCol", 1, 0, V, P, vcol)
113
 
                write_chunk(file, "Unit", 0, 1, U, P, unit)
114
 
                write_chunk(file, "Mat1", 0, 5, M, P, mat1)
115
 
 
116
 
                X = G
117
 
                G,P,V,U,M = map(lambda x: x+1, [G,P,V,U,M])
118
 
 
119
 
        write_chunk(file, "END ", 1, 0, 0, 0, '') # End Of File Chunk
120
 
 
121
 
        Blender.Window.DrawProgressBar(1.0, '')  # clear progressbar
122
 
        file.close()
123
 
        end = time.clock()
124
 
        seconds = " in %.2f %s" % (end-start, "seconds")
125
 
        message = "Successfully exported " + filename.split('\\')[-1].split('/')[-1] + seconds
126
 
        meshtools.print_boxed(message)
127
 
 
128
 
# =============================
129
 
# === Write COB File Header ===
130
 
# =============================
131
 
def write_header(file):
132
 
        file.write("Caligari V00.01BLH"+" "*13+"\n")
133
 
 
134
 
# ===================
135
 
# === Write Chunk ===
136
 
# ===================
137
 
def write_chunk(file, name, major, minor, chunk_id, parent_id, data):
138
 
        file.write(name)
139
 
        file.write(struct.pack("<2h", major, minor))
140
 
        file.write(struct.pack("<2l", chunk_id, parent_id))
141
 
        file.write(struct.pack("<1l", len(data)))
142
 
        file.write(data)
143
 
 
144
 
# ============================================
145
 
# === Generate PolH (Polygonal Data) Chunk ===
146
 
# ============================================
147
 
def generate_polh(objname, obj, mesh):
148
 
        data = cStringIO.StringIO()
149
 
        write_ObjectName(data, objname)
150
 
        write_LocalAxes(data, obj)
151
 
        write_CurrentPosition(data, obj)
152
 
        write_VertexList(data, mesh)
153
 
        uvcoords = write_UVCoordsList(data, mesh)
154
 
        write_FaceList(data, mesh, uvcoords)
155
 
        return data.getvalue()
156
 
 
157
 
# === Write Object Name ===
158
 
def write_ObjectName(data, objname):
159
 
        data.write(struct.pack("<h", 0))  # dupecount
160
 
        data.write(struct.pack("<h", len(objname)))
161
 
        data.write(objname)
162
 
 
163
 
# === Write Local Axes ===
164
 
def write_LocalAxes(data, obj):
165
 
        mat = obj.mat
166
 
        data.write(struct.pack("<fff", mat[3][0], mat[3][1], mat[3][2]))
167
 
        data.write(struct.pack("<fff", mat[0][0]/obj.SizeX, mat[1][0]/obj.SizeX, mat[2][0]/obj.SizeX))
168
 
        data.write(struct.pack("<fff", mat[0][1]/obj.SizeY, mat[1][1]/obj.SizeY, mat[2][1]/obj.SizeY))
169
 
        data.write(struct.pack("<fff", mat[0][2]/obj.SizeZ, mat[1][2]/obj.SizeZ, mat[2][2]/obj.SizeZ))
170
 
 
171
 
# === Write Current Position ===
172
 
def write_CurrentPosition(data, obj):
173
 
        mat = obj.mat
174
 
        data.write(struct.pack("<ffff", mat[0][0], mat[0][1], mat[0][2], mat[3][0]))
175
 
        data.write(struct.pack("<ffff", mat[1][0], mat[1][1], mat[1][2], mat[3][1]))
176
 
        data.write(struct.pack("<ffff", mat[2][0], mat[2][1], mat[2][2], mat[3][2]))
177
 
 
178
 
# === Write Vertex List ===
179
 
def write_VertexList(data, mesh):
180
 
        data.write(struct.pack("<l", len(mesh.verts)))
181
 
        for i, v in enumerate(mesh.verts):
182
 
                if not i%100 and meshtools.show_progress:
183
 
                        Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Writing Verts")
184
 
                x, y, z = v.co
185
 
                data.write(struct.pack("<fff", -y, x, z))
186
 
 
187
 
# === Write UV Vertex List ===
188
 
def write_UVCoordsList(data, mesh):
189
 
        if not mesh.hasFaceUV():
190
 
                data.write(struct.pack("<l", 1))
191
 
                data.write(struct.pack("<2f", 0,0))
192
 
                return {(0,0): 0}
193
 
                # === Default UV Coords (one image per face) ===
194
 
                # data.write(struct.pack("<l", 4))
195
 
                # data.write(struct.pack("<8f", 0,0, 0,1, 1,1, 1,0))
196
 
                # return {(0,0): 0, (0,1): 1, (1,1): 2, (1,0): 3}
197
 
                # === Default UV Coords (one image per face) ===
198
 
 
199
 
        # === collect, remove duplicates, add indices, and write the uv list ===
200
 
        uvdata = cStringIO.StringIO()
201
 
        uvcoords = {}
202
 
        uvidx = 0
203
 
        for i, f in enumerate(mesh.faces):
204
 
                if not i%100 and meshtools.show_progress:
205
 
                        Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing UV Coords")
206
 
                numfaceverts = len(f)
207
 
                for j in xrange(numfaceverts-1, -1, -1):        # Reverse order
208
 
                        u,v = f.uv[j]
209
 
                        if not uvcoords.has_key((u,v)):
210
 
                                uvcoords[(u,v)] = uvidx
211
 
                                uvidx += 1
212
 
                                uvdata.write(struct.pack("<ff", u,v))
213
 
        uvdata = uvdata.getvalue()
214
 
 
215
 
        numuvcoords = len(uvdata)/8
216
 
        data.write(struct.pack("<l", numuvcoords))
217
 
        data.write(uvdata)
218
 
        #print "Number of uvcoords:", numuvcoords, '=', len(uvcoords)
219
 
        return uvcoords
220
 
 
221
 
# === Write Face List ===
222
 
def write_FaceList(data, mesh, uvcoords):
223
 
        data.write(struct.pack("<l", len(mesh.faces)))
224
 
        for i in xrange(len(mesh.faces)):
225
 
                if not i%100 and meshtools.show_progress:
226
 
                        Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Faces")
227
 
                numfaceverts = len(mesh.faces[i].v)
228
 
                data.write(struct.pack("<B", 0x10))         # Cull Back Faces Flag
229
 
                data.write(struct.pack("<h", numfaceverts))
230
 
                data.write(struct.pack("<h", 0))            # Material Index
231
 
                for j in xrange(numfaceverts-1, -1, -1):        # Reverse order
232
 
                        index = mesh.faces[i].v[j].index
233
 
                        if mesh.hasFaceUV():
234
 
                                uv = mesh.faces[i].uv[j]
235
 
                                uvidx = uvcoords[uv]
236
 
                        else:
237
 
                                uvidx = 0
238
 
                        data.write(struct.pack("<ll", index, uvidx))
239
 
 
240
 
# ===========================================
241
 
# === Generate VCol (Vertex Colors) Chunk ===
242
 
# ===========================================
243
 
def generate_vcol(mesh):
244
 
        data = cStringIO.StringIO()
245
 
        data.write(struct.pack("<l", len(mesh.faces)))
246
 
        uniquecolors = {}
247
 
        unique_alpha = {}
248
 
        for i in xrange(len(mesh.faces)):
249
 
                if not i%100 and meshtools.show_progress:
250
 
                        Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Vertex Colors")
251
 
                numfaceverts = len(mesh.faces[i].v)
252
 
                data.write(struct.pack("<ll", i, numfaceverts))
253
 
                for j in xrange(numfaceverts-1, -1, -1):        # Reverse order
254
 
                        r = mesh.faces[i].col[j].r
255
 
                        g = mesh.faces[i].col[j].g
256
 
                        b = mesh.faces[i].col[j].b
257
 
                        a = 100  # 100 is opaque in ts
258
 
                        uniquecolors[(r,g,b)] = None
259
 
                        unique_alpha[mesh.faces[i].col[j].a] = None
260
 
                        data.write(struct.pack("<BBBB", r,g,b,a))
261
 
 
262
 
        #print "uniquecolors:", uniquecolors.keys()
263
 
        #print "unique_alpha:", unique_alpha.keys()
264
 
        if len(uniquecolors) == 1:
265
 
                return None
266
 
        else:
267
 
                return data.getvalue()
268
 
 
269
 
# ==================================
270
 
# === Generate Unit (Size) Chunk ===
271
 
# ==================================
272
 
def generate_unit():
273
 
        data = cStringIO.StringIO()
274
 
        data.write(struct.pack("<h", 2))
275
 
        return data.getvalue()
276
 
 
277
 
# ======================================
278
 
# === Generate Mat1 (Material) Chunk ===
279
 
# ======================================
280
 
def generate_mat1(mesh):
281
 
        
282
 
        def get_crufty_mesh_image():
283
 
                '''Crufty because it only uses 1 image
284
 
                '''
285
 
                if mesh.hasFaceUV():
286
 
                        for f in me.faces:
287
 
                                i = f.image
288
 
                                if i:
289
 
                                        return i.filename
290
 
        
291
 
        data = cStringIO.StringIO()
292
 
        data.write(struct.pack("<h", 0))
293
 
        data.write(struct.pack("<ccB", "p", "a", 0))
294
 
        data.write(struct.pack("<fff", 1.0, 1.0, 1.0))  # rgb (0.0 - 1.0)
295
 
        data.write(struct.pack("<fffff", 1, 1, 0, 0, 1))
296
 
        
297
 
        tex_mapname = get_crufty_mesh_image()
298
 
        
299
 
        if tex_mapname:
300
 
                data.write("t:")
301
 
                data.write(struct.pack("<B", 0x00))
302
 
                data.write(struct.pack("<h", len(tex_mapname)))
303
 
                data.write(tex_mapname)
304
 
                data.write(struct.pack("<4f", 0,0, 1,1))
305
 
        return data.getvalue()
306
 
 
307
 
# ============================
308
 
# === Generate Group Chunk ===
309
 
# ============================
310
 
def generate_grou(name):
311
 
        data = cStringIO.StringIO()
312
 
        write_ObjectName(data, name)
313
 
        data.write(struct.pack("<12f", 0,0,0, 1,0,0, 0,1,0, 0,0,1))
314
 
        data.write(struct.pack("<12f", 1,0,0,0, 0,1,0,0, 0,0,1,0))
315
 
        return data.getvalue()
316
 
 
317
 
def fs_callback(filename):
318
 
        if not filename.lower().endswith('.cob'): filename += '.cob'
319
 
        write(filename)
320
 
 
321
 
if __name__ == '__main__':
322
 
        Blender.Window.FileSelector(fs_callback, "Export COB", Blender.sys.makename(ext='.cob'))
323
 
 
324
 
# === Matrix Differences between Blender & trueSpace ===
325
 
#
326
 
# For the 'Local Axes' values:
327
 
# The x, y, and z-axis represent a simple rotation matrix.
328
 
# This is equivalent to Blender's object matrix before it was
329
 
# combined with the object's scaling matrix.  Dividing each value
330
 
# by the appropriate scaling factor (and transposing at the same
331
 
# time) produces the original rotation matrix.
332
 
#
333
 
# For the 'Current Position' values:
334
 
# This is equivalent to Blender's object matrix except that the
335
 
# last row is omitted and the xyz location is used in the last
336
 
# column.  Binary format uses a 4x3 matrix, ascii format uses a 4x4
337
 
# matrix.
338
 
#
339
 
# For Cameras: The matrix is a little confusing.