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

« back to all changes in this revision

Viewing changes to release/scripts/export_map.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: 'Quake 3 (.map)'
 
5
Blender: 243
 
6
Group: 'Export'
 
7
Tooltip: 'Export to Quake map format'
 
8
"""
 
9
 
 
10
__author__ = 'Campbell Barton'
 
11
__version__ = '0.1'
 
12
__email__ = "cbarton@metavr.com"
 
13
__bpydoc__ = """\
 
14
This script Exports a Quake 3 map format.
 
15
 
 
16
 Supports meshes, lights and nurbs patch surfaces
 
17
"""
 
18
 
 
19
# ***** BEGIN GPL LICENSE BLOCK *****
 
20
#
 
21
# Script copyright (C): Campbell Barton
 
22
#
 
23
# This program is free software; you can redistribute it and/or
 
24
# modify it under the terms of the GNU General Public License
 
25
# as published by the Free Software Foundation; either version 2
 
26
# of the License, or (at your option) any later version.
 
27
#
 
28
# This program is distributed in the hope that it will be useful,
 
29
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
30
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
31
# GNU General Public License for more details.
 
32
#
 
33
# You should have received a copy of the GNU General Public License
 
34
# along with this program; if not, write to the Free Software Foundation,
 
35
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
36
#
 
37
# ***** END GPL LICENCE BLOCK *****
 
38
# --------------------------------------------------------------------------
 
39
 
 
40
 
 
41
 
 
42
 
 
43
from Blender import *
 
44
import BPyMesh
 
45
 
 
46
PREF_SCALE= Draw.Create(100)
 
47
PREF_FACE_THICK= Draw.Create(0.1)
 
48
PREF_GRID_SNAP= Draw.Create(0)
 
49
# Quake 1/2?
 
50
# PREF_DEF_TEX_OPTS= Draw.Create(' 0 0 0 1 1\n') # not user settable yet
 
51
# Quake 3+?
 
52
PREF_DEF_TEX_OPTS= Draw.Create(' 0 0 0 1 1 0 0 0\n') # not user settable yet
 
53
 
 
54
PREF_NULL_TEX= Draw.Create('NULL') # not user settable yet
 
55
PREF_INVIS_TEX= Draw.Create('common/caulk')
 
56
 
 
57
def write_cube2brush(file, faces):
 
58
        '''
 
59
        Takes 6 faces and writes a brush,
 
60
        these faces can be from 1 mesh, 1 cube within a mesh of larger cubes
 
61
        Faces could even come from different meshes or be contrived.
 
62
        '''
 
63
        # comment only
 
64
        # file.write('// brush "%s", "%s"\n' % (ob.name, ob.getData(name_only=1)))
 
65
        file.write('// brush from cube\n{\n')
 
66
 
 
67
        if PREF_GRID_SNAP.val:          format_vec= '( %d %d %d ) '
 
68
        else:                                           format_vec= '( %.8f %.8f %.8f ) '
 
69
 
 
70
        for f in faces:
 
71
                # from 4 verts this gets them in reversed order and only 3 of them
 
72
                # 0,1,2,3 -> 2,1,0
 
73
                for v in f.v[2::-1]:
 
74
                        file.write(format_vec % tuple(v.co) )   
 
75
                
 
76
                try:    mode= f.mode
 
77
                except: mode= 0
 
78
                
 
79
                if mode & Mesh.FaceModes.INVISIBLE:
 
80
                        file.write(PREF_INVIS_TEX.val)
 
81
                else:
 
82
                        try:    image= f.image
 
83
                        except: image= None
 
84
                        
 
85
                        if image:       file.write(sys.splitext(sys.basename(image.filename))[0])
 
86
                        else:           file.write(PREF_NULL_TEX.val)
 
87
                        
 
88
                # Texture stuff ignored for now
 
89
                file.write(PREF_DEF_TEX_OPTS.val)
 
90
        file.write('}\n')
 
91
 
 
92
 
 
93
def round_vec(v):
 
94
        if PREF_GRID_SNAP.val:
 
95
                return round(v.x), round(v.y), round(v.z)
 
96
        else:
 
97
                return tuple(v)
 
98
 
 
99
def write_face2brush(file, face):
 
100
        '''
 
101
        takes a face and writes it as a brush
 
102
        each face is a cube/brush
 
103
        '''
 
104
        
 
105
        if PREF_GRID_SNAP.val:          format_vec= '( %d %d %d ) '
 
106
        else:                                           format_vec= '( %.8f %.8f %.8f ) '
 
107
        
 
108
        
 
109
        image_text= PREF_NULL_TEX.val
 
110
        
 
111
        try:    mode= face.mode
 
112
        except: mode= 0
 
113
        
 
114
        if mode & Mesh.FaceModes.INVISIBLE:
 
115
                image_text= PREF_INVIS_TEX.val
 
116
        else:
 
117
                try:    image= face.image
 
118
                except: image= None
 
119
                if image:       image_text = sys.splitext(sys.basename(image.filename))[0]
 
120
        
 
121
        # original verts as tuples for writing
 
122
        orig_vco= [tuple(v.co) for v in face]
 
123
        
 
124
        # new verts that give the face a thickness
 
125
        dist= PREF_SCALE.val * PREF_FACE_THICK.val
 
126
        new_vco= [round_vec(v.co - (v.no * dist)) for v in face]
 
127
        #new_vco= [round_vec(v.co - (face.no * dist)) for v in face]
 
128
        
 
129
        file.write('// brush from face\n{\n')
 
130
        # front
 
131
        for co in orig_vco[2::-1]:
 
132
                file.write(format_vec % co )
 
133
        file.write(image_text)
 
134
        # Texture stuff ignored for now
 
135
        file.write(PREF_DEF_TEX_OPTS.val)
 
136
        
 
137
        
 
138
        for co in new_vco[:3]:
 
139
                file.write(format_vec % co )
 
140
        if mode & Mesh.FaceModes.TWOSIDE:
 
141
                file.write(image_text)
 
142
        else:
 
143
                file.write(PREF_INVIS_TEX.val)
 
144
        
 
145
        # Texture stuff ignored for now
 
146
        file.write(PREF_DEF_TEX_OPTS.val)
 
147
        
 
148
        # sides.
 
149
        if len(orig_vco)==3: # Tri, it seemms tri brushes are supported.
 
150
                index_pairs= ((0,1), (1,2), (2,0))
 
151
        else:
 
152
                index_pairs= ((0,1), (1,2), (2,3), (3,0))
 
153
        
 
154
        for i1, i2 in index_pairs:
 
155
                for co in orig_vco[i1], orig_vco[i2], new_vco[i2]:
 
156
                        file.write( format_vec %  co )
 
157
                file.write(PREF_INVIS_TEX.val)
 
158
                file.write(PREF_DEF_TEX_OPTS.val)
 
159
 
 
160
        file.write('}\n')
 
161
 
 
162
def is_cube_facegroup(faces):
 
163
        '''
 
164
        Returens a bool, true if the faces make up a cube
 
165
        '''
 
166
        # cube must have 6 faces
 
167
        if len(faces) != 6:
 
168
                print '1'
 
169
                return False
 
170
        
 
171
        # Check for quads and that there are 6 unique verts
 
172
        verts= {}
 
173
        for f in faces:
 
174
                if len(f)!= 4:
 
175
                        return False
 
176
                
 
177
                for v in f:
 
178
                        verts[v.index]= 0
 
179
        
 
180
        if len(verts) != 8:
 
181
                return False
 
182
        
 
183
        # Now check that each vert has 3 face users
 
184
        for f in faces:
 
185
                for v in f:
 
186
                        verts[v.index] += 1
 
187
        
 
188
        for v in verts.itervalues():
 
189
                if v != 3: # vert has 3 users?
 
190
                        return False
 
191
        
 
192
        # Could we check for 12 unique edges??, probably not needed.
 
193
        return True
 
194
        
 
195
def is_tricyl_facegroup(faces):
 
196
        '''
 
197
        is the face group a tri cylinder
 
198
        Returens a bool, true if the faces make an extruded tri solid
 
199
        '''
 
200
        return False
 
201
        # cube must have 5 faces
 
202
        if len(faces) != 5:
 
203
                print '1'
 
204
                return False
 
205
        
 
206
        # Check for quads and that there are 6 unique verts
 
207
        verts= {}
 
208
        tottri= 0
 
209
        for f in faces:
 
210
                if len(f)== 3:
 
211
                        tottri+=1
 
212
                
 
213
                for v in f:
 
214
                        verts[v.index]= 0
 
215
        
 
216
        if len(verts) != 6 or tottri != 2:
 
217
                return False
 
218
        
 
219
        # Now check that each vert has 3 face users
 
220
        for f in faces:
 
221
                for v in f:
 
222
                        verts[v.index] += 1
 
223
        
 
224
        for v in verts.itervalues():
 
225
                if v != 3: # vert has 3 users?
 
226
                        return False
 
227
        
 
228
        # Could we check for 12 unique edges??, probably not needed.
 
229
        return True
 
230
 
 
231
def write_node_map(file, ob):
 
232
        '''
 
233
        Writes the properties of an object (empty in this case)
 
234
        as a MAP node as long as it has the property name - classname
 
235
        returns True/False based on weather a node was written
 
236
        '''
 
237
        props= [(p.name, p.data) for p in ob.properties]
 
238
        
 
239
        IS_MAP_NODE= False
 
240
        for name, value in props:
 
241
                if name=='classname':
 
242
                        IS_MAP_NODE= True
 
243
                        break
 
244
                
 
245
        if not IS_MAP_NODE:
 
246
                return False
 
247
        
 
248
        # Write a node
 
249
        file.write('{\n')
 
250
        for name_value in props:
 
251
                file.write('"%s" "%s"\n' % name_value)
 
252
        file.write('}\n')
 
253
        return True
 
254
 
 
255
 
 
256
def export_map(filepath):
 
257
        
 
258
        pup_block = [\
 
259
        ('Scale:', PREF_SCALE, 1, 1000, 'Scale the blender scene by this value.'),\
 
260
        ('Face Width:', PREF_FACE_THICK, 0.01, 10, 'Thickness of faces exported as brushes.'),\
 
261
        ('Grid Snap', PREF_GRID_SNAP, 'snaps floating point values to whole numbers.'),\
 
262
        'Null Texture',\
 
263
        ('', PREF_NULL_TEX, 1, 128, 'Export textureless faces with this texture'),\
 
264
        'Unseen Texture',\
 
265
        ('', PREF_INVIS_TEX, 1, 128, 'Export invisible faces with this texture'),\
 
266
        ]
 
267
        
 
268
        if not Draw.PupBlock('map export', pup_block):
 
269
                return
 
270
        
 
271
        Window.WaitCursor(1)
 
272
        time= sys.time()
 
273
        print 'Map Exporter 0.0'
 
274
        file= open(filepath, 'w')
 
275
        
 
276
        
 
277
        obs_mesh= []
 
278
        obs_lamp= []
 
279
        obs_surf= []
 
280
        obs_empty= []
 
281
        
 
282
        SCALE_MAT= Mathutils.Matrix()
 
283
        SCALE_MAT[0][0]= SCALE_MAT[1][1]= SCALE_MAT[2][2]= PREF_SCALE.val
 
284
        
 
285
        dummy_mesh= Mesh.New()
 
286
        
 
287
        TOTBRUSH= TOTLAMP= TOTNODE= 0
 
288
        
 
289
        for ob in Object.GetSelected():
 
290
                type= ob.getType()
 
291
                if type == 'Mesh':              obs_mesh.append(ob)
 
292
                elif type == 'Surf':    obs_surf.append(ob)
 
293
                elif type == 'Lamp':    obs_lamp.append(ob)
 
294
                elif type == 'Empty':   obs_empty.append(ob)
 
295
        
 
296
        if obs_mesh or obs_surf:
 
297
                # brushes and surf's must be under worldspan
 
298
                file.write('\n// entity 0\n')
 
299
                file.write('{\n')
 
300
                file.write('"classname" "worldspawn"\n')
 
301
        
 
302
        
 
303
        print '\twriting cubes from meshes'
 
304
        for ob in obs_mesh:
 
305
                dummy_mesh.getFromObject(ob.name)
 
306
                
 
307
                #print len(mesh_split2connected(dummy_mesh))
 
308
                
 
309
                # Is the object 1 cube? - object-is-a-brush
 
310
                dummy_mesh.transform(ob.matrixWorld*SCALE_MAT) # 1 to tx the normals also
 
311
                
 
312
                if PREF_GRID_SNAP.val:
 
313
                        for v in dummy_mesh.verts:
 
314
                                co= v.co
 
315
                                co.x= round(co.x)
 
316
                                co.y= round(co.y)
 
317
                                co.z= round(co.z)
 
318
                
 
319
                # High quality normals
 
320
                BPyMesh.meshCalcNormals(dummy_mesh)
 
321
                
 
322
                # Split mesh into connected regions
 
323
                for face_group in BPyMesh.mesh2linkedFaces(dummy_mesh):
 
324
                        if is_cube_facegroup(face_group):
 
325
                                write_cube2brush(file, face_group)
 
326
                                TOTBRUSH+=1
 
327
                        elif is_tricyl_facegroup(face_group):
 
328
                                write_cube2brush(file, face_group)
 
329
                                TOTBRUSH+=1
 
330
                        else:
 
331
                                for f in face_group:
 
332
                                        write_face2brush(file, f)
 
333
                                        TOTBRUSH+=1
 
334
                        
 
335
                        #print 'warning, not exporting "%s" it is not a cube' % ob.name
 
336
                        
 
337
        
 
338
        dummy_mesh.verts= None
 
339
        
 
340
 
 
341
        valid_dims= 3,5,7,9,11,13,15
 
342
        for ob in obs_surf:
 
343
                '''
 
344
                Surf, patches
 
345
                '''
 
346
                surf_name= ob.getData(name_only=1)
 
347
                data= Curve.Get(surf_name)
 
348
                mat = ob.matrixWorld*SCALE_MAT
 
349
                
 
350
                # This is what a valid patch looks like
 
351
                
 
352
                """
 
353
// brush 0
 
354
{
 
355
patchDef2
 
356
{
 
357
NULL
 
358
( 3 3 0 0 0 )
 
359
(
 
360
( ( -64 -64 0 0 0 ) ( -64 0 0 0 -2 ) ( -64 64 0 0 -4 ) )
 
361
( ( 0 -64 0 2 0 ) ( 0 0 0 2 -2 ) ( 0 64 0 2 -4 ) )
 
362
( ( 64 -64 0 4 0 ) ( 64 0 0 4 -2 ) ( 80 88 0 4 -4 ) )
 
363
)
 
364
}
 
365
}
 
366
                """
 
367
                for i, nurb in enumerate(data):
 
368
                        u= nurb.pointsU
 
369
                        v= nurb.pointsV
 
370
                        if u in valid_dims and v in valid_dims:
 
371
                                
 
372
                                file.write('// brush %d surf_name\n' % i)
 
373
                                file.write('{\n')
 
374
                                file.write('patchDef2\n')
 
375
                                file.write('{\n')
 
376
                                file.write('NULL\n')
 
377
                                file.write('( %d %d 0 0 0 )\n' % (u, v) )
 
378
                                file.write('(\n')
 
379
                                
 
380
                                u_iter = 0
 
381
                                for p in nurb:
 
382
                                        
 
383
                                        if u_iter == 0:
 
384
                                                file.write('(')
 
385
                                        
 
386
                                        u_iter += 1
 
387
                                        
 
388
                                        # add nmapping 0 0 ?
 
389
                                        if PREF_GRID_SNAP.val:
 
390
                                                file.write(' ( %d %d %d 0 0 )' % round_vec(Mathutils.Vector(p[0:3]) * mat))
 
391
                                        else:
 
392
                                                file.write(' ( %.6f %.6f %.6f 0 0 )' % tuple(Mathutils.Vector(p[0:3]) * mat))
 
393
                                        
 
394
                                        # Move to next line
 
395
                                        if u_iter == u:
 
396
                                                file.write(' )\n')
 
397
                                                u_iter = 0
 
398
                                
 
399
                                file.write(')\n')
 
400
                                file.write('}\n')
 
401
                                file.write('}\n')
 
402
                                
 
403
                                
 
404
                                # Debugging
 
405
                                # for p in nurb: print 'patch', p
 
406
                                
 
407
                        else:
 
408
                                print "NOT EXPORTING PATCH", surf_name, u,v, 'Unsupported'
 
409
                        
 
410
        
 
411
        file.write('}\n') # end worldspan
 
412
        
 
413
        
 
414
        print '\twriting lamps'
 
415
        for ob in obs_lamp:
 
416
                print '\t\t%s' % ob.name
 
417
                lamp= ob.data
 
418
                file.write('{\n')
 
419
                file.write('"classname" "light"\n')
 
420
                file.write('"light" "%.6f"\n' % (lamp.dist* PREF_SCALE.val))
 
421
                if PREF_GRID_SNAP.val:
 
422
                        file.write('"origin" "%d %d %d"\n' % tuple([round(axis*PREF_SCALE.val) for axis in ob.getLocation('worldspace')]) )
 
423
                else:
 
424
                        file.write('"origin" "%.6f %.6f %.6f"\n' % tuple([axis*PREF_SCALE.val for axis in ob.getLocation('worldspace')]) )
 
425
                file.write('"_color" "%.6f %.6f %.6f"\n' % tuple(lamp.col))
 
426
                file.write('"style" "0"\n')
 
427
                file.write('}\n')
 
428
                TOTLAMP+=1
 
429
        
 
430
        
 
431
        print '\twriting empty objects as nodes'
 
432
        for ob in obs_empty:
 
433
                if write_node_map(file, ob):
 
434
                        print '\t\t%s' % ob.name
 
435
                        TOTNODE+=1
 
436
                else:
 
437
                        print '\t\tignoring %s' % ob.name
 
438
        
 
439
        Window.WaitCursor(0)
 
440
        
 
441
        print 'Exported Map in %.4fsec' % (sys.time()-time)
 
442
        print 'Brushes: %d  Nodes: %d  Lamps %d\n' % (TOTBRUSH, TOTNODE, TOTLAMP)
 
443
        
 
444
        
 
445
def main():
 
446
        Window.FileSelector(export_map, 'EXPORT MAP', '*.map')
 
447
 
 
448
if __name__ == '__main__': main()
 
449
# export_map('/foo.map')
 
 
b'\\ No newline at end of file'