Bugfix- selection only didnt work & Fixed object name creation not using the real...
[blender.git] / release / scripts / obj_export.py
1 #!BPY
2
3 """
4 Name: 'Wavefront (.obj)...'
5 Blender: 232
6 Group: 'Export'
7 Tooltip: 'Save a Wavefront OBJ File'
8 """
9
10 __author__ = "Campbell Barton, Jiri Hnidek"
11 __url__ = ["blender", "elysiun"]
12 __version__ = "1.0"
13
14 __bpydoc__ = """\
15 This script is an exporter to OBJ file format.
16
17 Usage:
18
19 Run this script from "File->Export" menu to export all meshes.
20 """
21
22
23 # --------------------------------------------------------------------------
24 # OBJ Export v1.0 by Campbell Barton (AKA Ideasman)
25 # --------------------------------------------------------------------------
26 # ***** BEGIN GPL LICENSE BLOCK *****
27 #
28 # This program is free software; you can redistribute it and/or
29 # modify it under the terms of the GNU General Public License
30 # as published by the Free Software Foundation; either version 2
31 # of the License, or (at your option) any later version.
32 #
33 # This program is distributed in the hope that it will be useful,
34 # but WITHOUT ANY WARRANTY; without even the implied warranty of
35 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36 # GNU General Public License for more details.
37 #
38 # You should have received a copy of the GNU General Public License
39 # along with this program; if not, write to the Free Software Foundation,
40 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
41 #
42 # ***** END GPL LICENCE BLOCK *****
43 # --------------------------------------------------------------------------
44
45
46 import Blender
47 from Blender import Mesh, Scene, Window, sys, Image, Draw
48
49 # Returns a tuple - path,extension.
50 # 'hello.obj' >  ('hello', '.obj')
51 def splitExt(path):
52         dotidx = path.rfind('.')
53         if dotidx == -1:
54                 return path, ''
55         else:
56                 return path[:dotidx], path[dotidx:] 
57
58 def fixName(name):
59         if name == None:
60                 return 'None'
61         else:
62                 return name.replace(' ', '_')
63
64 # Used to add the scene name into the filename without using odd chars
65 def saneFilechars(name):
66         for ch in ' /\\~!@#$%^&*()+=[];\':",./<>?\t\r\n':
67                 name = name.replace(ch, '_')
68         return name
69
70 def sortPair(a,b):
71         return min(a,b), max(a,b)
72
73 def getMeshFromObject(object, name=None, mesh=None):
74         if mesh:
75                 mesh.verts = None # Clear the mesh
76         else:
77                 if not name:
78                         mesh = Mesh.New()
79                 else:
80                         mesh = Mesh.New(name)
81         
82         
83         type = object.getType()
84         dataname = object.getData(1)
85         
86         try:
87                 mesh.getFromObject(object.name)
88         except:
89                 return None
90         
91         if type == 'Mesh':
92                 tempMe = Mesh.Get( dataname )
93                 mesh.materials = tempMe.materials
94                 mesh.degr = tempMe.degr
95                 mesh.mode = tempMe.mode
96         else:
97                 try:
98                         # Will only work for curves!!
99                         # Text- no material access in python interface.
100                         # Surf- no python interface
101                         # MBall- no material access in python interface.
102                         
103                         data = object.getData()
104                         materials = data.getMaterials()
105                         mesh.materials = materials
106                         print 'assigning materials for non mesh'
107                 except:
108                         print 'Cant assign materials to', type
109         
110         return mesh
111
112 global MTL_DICT
113
114 # A Dict of Materials
115 # (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
116 MTL_DICT = {} 
117
118 def write_mtl(filename):
119         global MTL_DICT
120         
121         world = Blender.World.GetCurrent()
122         if world:
123                 worldAmb = world.getAmb()
124         else:
125                 worldAmb = (0,0,0) # Default value
126         
127         file = open(filename, "w")
128         file.write('# Blender MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
129         file.write('# Material Count: %i\n' % len(MTL_DICT))
130         # Write material/image combinations we have used.
131         for key, mtl_mat_name in MTL_DICT.iteritems():
132                 
133                 # Get the Blender data for the material and the image.
134                 # Having an image named None will make a bug, dont do it :)
135                 
136                 file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname
137                 
138                 if key[0] == None:
139                         #write a dummy material here?
140                         file.write('Ns 0\n')
141                         file.write('Ka %s %s %s\n' %  tuple([round(c, 6) for c in worldAmb])  ) # Ambient, uses mirror colour,
142                         file.write('Kd 0.8 0.8 0.8\n')
143                         file.write('Ks 0.8 0.8 0.8\n')
144                         file.write('d 1\n') # No alpha
145                         file.write('illum 2\n') # light normaly 
146                         
147                 else:
148                         mat = Blender.Material.Get(key[0])
149                         file.write('Ns %s\n' % round((mat.getHardness()-1) * 1.9607843137254901 ) ) # Hardness, convert blenders 1-511 to MTL's 
150                         file.write('Ka %s %s %s\n' %  tuple([round(c*mat.getAmb(), 6) for c in worldAmb])  ) # Ambient, uses mirror colour,
151                         file.write('Kd %s %s %s\n' % tuple([round(c*mat.getRef(), 6) for c in mat.getRGBCol()]) ) # Diffuse
152                         file.write('Ks %s %s %s\n' % tuple([round(c*mat.getSpec(), 6) for c in mat.getSpecCol()]) ) # Specular
153                         file.write('Ni %s\n' % round(mat.getIOR(), 6)) # Refraction index
154                         file.write('d %s\n' % round(mat.getAlpha(), 6)) # Alpha (obj uses 'd' for dissolve)
155                         
156                         # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
157                         if mat.getMode() & Blender.Material.Modes['SHADELESS']:
158                                 file.write('illum 0\n') # ignore lighting
159                         elif mat.getSpec() == 0:
160                                 file.write('illum 1\n') # no specular.
161                         else:
162                                 file.write('illum 2\n') # light normaly 
163                 
164                 
165                 # Write images!
166                 if key[1] != None:  # We have an image on the face!
167                         img = Image.Get(key[1])
168                         file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image                 
169                 
170                 elif key[0] != None: # No face image. if we havea material search for MTex image.
171                         for mtex in mat.getTextures():
172                                 if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
173                                         try:
174                                                 filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1]
175                                                 file.write('map_Kd %s\n' % filename) # Diffuse mapping image
176                                                 break
177                                         except:
178                                                 # Texture has no image though its an image type, best ignore.
179                                                 pass
180                 
181                 file.write('\n\n')
182         
183         file.close()
184
185 def copy_file(source, dest):
186         file = open(source, 'rb')
187         data = file.read()
188         file.close()
189         
190         file = open(dest, 'wb')
191         file.write(data)
192         file.close()
193
194
195 def copy_images(dest_dir):
196         if dest_dir[-1] != sys.sep:
197                 dest_dir += sys.sep
198         
199         # Get unique image names
200         uniqueImages = {}
201         for matname, imagename in MTL_DICT.iterkeys(): # Only use image name
202                 if imagename != None:
203                         uniqueImages[imagename] = None # Should use sets here. wait until Python 2.4 is default.
204         
205         # Now copy images
206         copyCount = 0
207         
208         for imageName in uniqueImages.iterkeys():
209                 print imageName
210                 bImage = Image.Get(imageName)
211                 image_path = sys.expandpath(bImage.filename)
212                 if sys.exists(image_path):
213                         # Make a name for the target path.
214                         dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
215                         if not sys.exists(dest_image_path): # Image isnt alredy there
216                                 print '\tCopying "%s" > "%s"' % (image_path, dest_image_path)
217                                 copy_file(image_path, dest_image_path)
218                                 copyCount+=1
219         print '\tCopied %d images' % copyCount
220         
221 def write(filename, objects,\
222 EXPORT_TRI=False,  EXPORT_EDGES=False,  EXPORT_NORMALS=False,\
223 EXPORT_UV=True,  EXPORT_MTL=True,  EXPORT_COPY_IMAGES=False,\
224 EXPORT_APPLY_MODIFIERS=True,  EXPORT_BLEN_OBS=True,\
225 EXPORT_GROUP_BY_OB=False,  EXPORT_GROUP_BY_MAT=False):
226         '''
227         Basic write function. The context and options must be alredy set
228         This can be accessed externaly
229         eg.
230         write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
231         '''
232         print 'OBJ Export path: "%s"' % filename
233         global MTL_DICT
234         temp_mesh_name = '~tmp-mesh'
235         time1 = sys.time()
236         scn = Scene.GetCurrent()
237
238         file = open(filename, "w")
239         
240         # Write Header
241         file.write('# Blender v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
242         file.write('# www.blender3d.org\n')
243
244         # Tell the obj file what material file to use.
245         mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
246         file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
247         
248         # Get the container mesh.
249         if EXPORT_APPLY_MODIFIERS:
250                 containerMesh = meshName = tempMesh = None
251                 for meshName in Blender.NMesh.GetNames():
252                         if meshName.startswith(temp_mesh_name):
253                                 tempMesh = Mesh.Get(meshName)
254                                 if not tempMesh.users:
255                                         containerMesh = tempMesh
256                 if not containerMesh:
257                         containerMesh = Mesh.New(temp_mesh_name)
258                 del meshName
259                 del tempMesh
260         
261         
262         
263         # Initialize totals, these are updated each object
264         totverts = totuvco = totno = 1
265         
266         globalUVCoords = {}
267         globalNormals = {}
268         
269         # Get all meshs
270         for ob in objects:
271                 
272                 # Will work for non meshes now! :)
273                 if EXPORT_APPLY_MODIFIERS or ob.getType() != 'Mesh':
274                         m = getMeshFromObject(ob, temp_mesh_name, containerMesh)
275                         if not m:
276                                 continue
277                         
278                         # We have a valid mesh
279                         if m and EXPORT_APPLY_MODIFIERS and EXPORT_TRI:
280                                 # Add a dummy object to it.
281                                 oldmode = Mesh.Mode()
282                                 Mesh.Mode(Mesh.SelectModes['FACE'])
283                                 quadcount = 0
284                                 for f in m.faces:
285                                         if len(f.v) == 4:
286                                                 f.sel = 1
287                                                 quadcount +=1
288                                 
289                                 if quadcount:
290                                         tempob = Blender.Object.New('Mesh')
291                                         tempob.link(m)
292                                         scn.link(tempob)
293                                         m.quadToTriangle(0) # more=0 shortest length
294                                         oldmode = Mesh.Mode(oldmode)
295                                         scn.unlink(tempob)
296                                 Mesh.Mode(oldmode)
297                                 
298                 else: # We are a mesh. get the data.
299                         m = ob.getData(mesh=1)
300                 
301                 faces = [ f for f in m.faces ]
302                 if EXPORT_EDGES:
303                         edges = [ ed for ed in m.edges ]
304                 else:
305                         edges = []
306                         
307                 if not (len(faces)+len(edges)): # Make sure there is somthing to write
308                         continue # dont bother with this mesh.
309                 
310                 m.transform(ob.matrix)
311                 
312                 # # Crash Blender
313                 #materials = m.getMaterials(1) # 1 == will return None in the list.
314                 materials = m.materials
315                 
316                 
317                 if materials:
318                         materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.    
319                 else:
320                         materialNames = []
321                 
322                 # Possible there null materials, will mess up indicies
323                 # but at least it will export, wait until Blender gets fixed.
324                 materialNames.extend((16-len(materialNames)) * [None])
325                 
326                 
327                 # Sort by Material, then images
328                 # so we dont over context switch in the obj file.
329                 if m.faceUV and EXPORT_UV:
330                         faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
331                 else:
332                         faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
333                 
334                 
335                 # Set the default mat to no material and no image.
336                 contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
337                 contextSmooth = None # Will either be true or false,  set bad to force initialization switch.
338                 
339                 if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
340                         obnamestring = '%s_%s' % (fixName(ob.name), fixName(ob.getData(1)))
341                         if EXPORT_BLEN_OBS:
342                                 file.write('o %s\n' % obnamestring) # Write Object name
343                         else: # if EXPORT_GROUP_BY_OB:
344                                 file.write('g %s\n' % obnamestring)
345                         
346                 
347                 # Vert
348                 for v in m.verts:
349                         file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
350                 
351                 # UV
352                 if m.faceUV and EXPORT_UV:
353                         for f in faces:
354                                 for uvKey in f.uv:
355                                         uvKey = tuple(uvKey)
356                                         if not globalUVCoords.has_key(uvKey):
357                                                 globalUVCoords[uvKey] = totuvco
358                                                 totuvco +=1
359                                                 file.write('vt %.6f %.6f 0.0\n' % uvKey)
360                 
361                 # NORMAL, Smooth/Non smoothed.
362                 if EXPORT_NORMALS:
363                         for f in faces:
364                                 if f.smooth:
365                                         for v in f.v:
366                                                 noKey = tuple(v.no)
367                                                 if not globalNormals.has_key( noKey ):
368                                                         globalNormals[noKey] = totno
369                                                         totno +=1
370                                                         file.write('vn %.6f %.6f %.6f\n' % noKey)
371                                 else:
372                                         # Hard, 1 normal from the face.
373                                         noKey = tuple(f.no)
374                                         if not globalNormals.has_key( noKey ):
375                                                 globalNormals[noKey] = totno
376                                                 totno +=1
377                                                 file.write('vn %.6f %.6f %.6f\n' % noKey)
378                 
379                 
380                 uvIdx = 0
381                 for f in faces:
382                         
383                         # MAKE KEY
384                         if EXPORT_UV and m.faceUV and f.image: # Object is always true.
385                                 key = materialNames[f.mat],  f.image.name
386                         else:
387                                 key = materialNames[f.mat],  None # No image, use None instead.
388                         
389                         # CHECK FOR CONTEXT SWITCH
390                         if key == contextMat:
391                                 pass # Context alredy switched, dont do anythoing
392                         else:
393                                 if key[0] == None and key[1] == None:
394                                         # Write a null material, since we know the context has changed.
395                                         matstring = '(null)'
396                                         file.write('usemtl (null)\n') # mat, image
397                                         
398                                 else:
399                                         try: # Faster to try then 2x dict lookups.
400                                                 # We have the material, just need to write the context switch,
401                                                 matstring = MTL_DICT[key]
402                                                 
403                                                 
404                                         except KeyError:
405                                                 # First add to global dict so we can export to mtl
406                                                 # Then write mtl
407                                                 
408                                                 # Make a new names from the mat and image name,
409                                                 # converting any spaces to underscores with fixName.
410                                                 
411                                                 # If none image dont bother adding it to the name
412                                                 if key[1] == None:
413                                                         matstring = MTL_DICT[key] ='%s' % fixName(key[0])
414                                                 else:
415                                                         matstring = MTL_DICT[key] = '%s_%s' % (fixName(key[0]), fixName(key[1]))
416                                 
417                                 if EXPORT_GROUP_BY_MAT:
418                                         file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), matstring) ) # can be mat_image or (null)
419                                 file.write('usemtl %s\n' % matstring) # can be mat_image or (null)
420                                 
421                         contextMat = key
422                         
423                         if f.smooth != contextSmooth:
424                                 if f.smooth:
425                                         file.write('s 1\n')
426                                 else:
427                                         file.write('s off\n')
428                                 contextSmooth = f.smooth
429                         
430                         file.write('f')
431                         if m.faceUV and EXPORT_UV:
432                                 if EXPORT_NORMALS:
433                                         if f.smooth: # Smoothed, use vertex normals
434                                                 for vi, v in enumerate(f.v):
435                                                         file.write( ' %d/%d/%d' % (\
436                                                           v.index+totverts,\
437                                                           globalUVCoords[ tuple(f.uv[vi]) ],\
438                                                           globalNormals[ tuple(v.no) ])) # vert, uv, normal
439                                         else: # No smoothing, face normals
440                                                 no = globalNormals[ tuple(f.no) ]
441                                                 for vi, v in enumerate(f.v):
442                                                         file.write( ' %d/%d/%d' % (\
443                                                           v.index+totverts,\
444                                                           globalUVCoords[ tuple(f.uv[vi]) ],\
445                                                           no)) # vert, uv, normal
446                                 
447                                 else: # No Normals
448                                         for vi, v in enumerate(f.v):
449                                                 file.write( ' %d/%d' % (\
450                                                   v.index+totverts,\
451                                                   globalUVCoords[ tuple(f.uv[vi])])) # vert, uv
452                                         
453                                         
454                         else: # No UV's
455                                 if EXPORT_NORMALS:
456                                         if f.smooth: # Smoothed, use vertex normals
457                                                 for v in f.v:
458                                                         file.write( ' %d//%d' % (\
459                                                           v.index+totverts,\
460                                                           globalNormals[ tuple(v.no) ]))
461                                         else: # No smoothing, face normals
462                                                 no = globalNormals[ tuple(f.no) ]
463                                                 for v in f.v:
464                                                         file.write( ' %d//%d' % (\
465                                                           v.index+totverts,\
466                                                           no))
467                                 else: # No Normals
468                                         for v in f.v:
469                                                 file.write( ' %d' % (\
470                                                   v.index+totverts))
471                                         
472                         file.write('\n')
473                 
474                 # Write edges.
475                 if EXPORT_EDGES:
476                         edgeUsers = {}
477                         for f in faces:
478                                 for i in xrange(len(f.v)):
479                                         faceEdgeVKey = sortPair(f.v[i].index, f.v[i-1].index)
480                                         
481                                         # We dont realy need to keep count. Just that a face uses it 
482                                         # so dont export.
483                                         edgeUsers[faceEdgeVKey] = 1 
484                                 
485                         for ed in edges:
486                                 edgeVKey = sortPair(ed.v1.index, ed.v2.index)
487                                 if not edgeUsers.has_key(edgeVKey): # No users? Write the edge.
488                                         file.write('f %d %d\n' % (edgeVKey[0]+totverts, edgeVKey[1]+totverts))
489                 
490                 # Make the indicies global rather then per mesh
491                 totverts += len(m.verts)
492         file.close()
493         
494         
495         # Now we have all our materials, save them
496         if EXPORT_MTL:
497                 write_mtl(mtlfilename)
498         if EXPORT_COPY_IMAGES:
499                 dest_dir = filename
500                 # Remove chars until we are just the path.
501                 while dest_dir and dest_dir[-1] not in '\\/':
502                         dest_dir = dest_dir[:-1]
503                 if dest_dir:
504                         copy_images(dest_dir)
505                 else:
506                         print '\tError: "%s" could not be used as a base for an image path.' % filename
507         
508         print "OBJ Export time: %.2f" % (sys.time() - time1)
509         
510         
511
512 def write_ui(filename):
513         
514         for s in Window.GetScreenInfo():
515                 Window.QHandle(s['id'])
516         
517         EXPORT_APPLY_MODIFIERS = Draw.Create(1)
518         EXPORT_TRI = Draw.Create(0)
519         EXPORT_EDGES = Draw.Create(0)
520         EXPORT_NORMALS = Draw.Create(0)
521         EXPORT_UV = Draw.Create(1)
522         EXPORT_MTL = Draw.Create(1)
523         EXPORT_SEL_ONLY = Draw.Create(1)
524         EXPORT_ALL_SCENES = Draw.Create(0)
525         EXPORT_ANIMATION = Draw.Create(0)
526         EXPORT_COPY_IMAGES = Draw.Create(0)
527         EXPORT_BLEN_OBS = Draw.Create(1)
528         EXPORT_GROUP_BY_OB = Draw.Create(0)
529         EXPORT_GROUP_BY_MAT = Draw.Create(0)
530         
531         
532         # Get USER Options
533         pup_block = [\
534         ('Mesh Options...'),\
535         ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\
536         ('Triangulate', EXPORT_TRI, 'Triangulate quads (Depends on "Apply Modifiers").'),\
537         ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\
538         ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\
539         ('UVs', EXPORT_UV, 'Export texface UV coords.'),\
540         ('Materials', EXPORT_MTL, 'Write a seperate MTL file with the OBJ.'),\
541         ('Context...'),\
542         ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\
543         ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a seperate OBJ file.'),\
544         ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\
545         ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\
546         ('Grouping...'),\
547         ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as OBJ objects.'),\
548         ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as OBJ groups.'),\
549         ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\
550         ]
551         
552         if not Draw.PupBlock('Export...', pup_block):
553                 return
554         
555         Window.WaitCursor(1)
556         
557         EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
558         EXPORT_TRI = EXPORT_TRI.val
559         EXPORT_EDGES = EXPORT_EDGES.val
560         EXPORT_NORMALS = EXPORT_NORMALS.val
561         EXPORT_UV = EXPORT_UV.val
562         EXPORT_MTL = EXPORT_MTL.val
563         EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val
564         EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val
565         EXPORT_ANIMATION = EXPORT_ANIMATION.val
566         EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val
567         EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val
568         EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val
569         EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val
570         
571         
572         
573         base_name, ext = splitExt(filename)
574         context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension
575         
576         # Use the options to export the data using write()
577         # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True):
578         orig_scene = Scene.GetCurrent()
579         if EXPORT_ALL_SCENES:
580                 export_scenes = Scene.Get()
581         else:
582                 export_scenes = [orig_scene]
583         
584         # Export all scenes.
585         for scn in export_scenes:
586                 scn.makeCurrent() # If alredy current, this is not slow.
587                 context = scn.getRenderingContext()
588                 orig_frame = Blender.Get('curframe')
589                 
590                 if EXPORT_ALL_SCENES: # Add scene name into the context_name
591                         context_name[1] = '_%s' % saneFilechars(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
592                 
593                 # Export an animation?
594                 if EXPORT_ANIMATION:
595                         scene_frames = range(context.startFrame(), context.endFrame()+1) # up to and including the end frame.
596                 else:
597                         scene_frames = [orig_frame] # Dont export an animation.
598                 
599                 # Loop through all frames in the scene and export.
600                 for frame in scene_frames:
601                         if EXPORT_ANIMATION: # Add frame to the filename.
602                                 context_name[2] = '_%.6d' % frame
603                         
604                         Blender.Set('curframe', frame)
605                         if EXPORT_SEL_ONLY:
606                                 export_objects = Blender.Object.GetSelected() # Export Context
607                         else:   
608                                 export_objects = scn.getChildren()
609                         
610                         # EXPORT THE FILE.
611                         write(''.join(context_name), export_objects,\
612                         EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
613                         EXPORT_UV, EXPORT_MTL, EXPORT_COPY_IMAGES,\
614                         EXPORT_APPLY_MODIFIERS,\
615                         EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT)
616                 
617                 Blender.Set('curframe', orig_frame)
618         
619         # Restore old active scene.
620         orig_scene.makeCurrent()
621         Window.WaitCursor(0)
622
623
624 if __name__ == '__main__':
625         Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj'))