Copying scripts from 2.4x without 2.5x changes
[blender-staging.git] / release / scripts / io / import_obj.py
1 #!BPY
2  
3 """
4 Name: 'Wavefront (.obj)...'
5 Blender: 249
6 Group: 'Import'
7 Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.'
8 """
9
10 __author__= "Campbell Barton", "Jiri Hnidek", "Paolo Ciccone"
11 __url__= ['http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj', 'blender.org', 'blenderartists.org']
12 __version__= "2.13"
13
14 __bpydoc__= """\
15 This script imports a Wavefront OBJ files to Blender.
16
17 Usage:
18 Run this script from "File->Import" menu and then load the desired OBJ file.
19 Note, This loads mesh objects and materials only, nurbs and curves are not supported.
20 """
21
22 # ***** BEGIN GPL LICENSE BLOCK *****
23 #
24 # Script copyright (C) Campbell J Barton 2007-2009
25 # - V2.12- bspline import/export added (funded by PolyDimensions GmbH)
26 #
27 # This program is free software; you can redistribute it and/or
28 # modify it under the terms of the GNU General Public License
29 # as published by the Free Software Foundation; either version 2
30 # of the License, or (at your option) any later version.
31 #
32 # This program is distributed in the hope that it will be useful,
33 # but WITHOUT ANY WARRANTY; without even the implied warranty of
34 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35 # GNU General Public License for more details.
36 #
37 # You should have received a copy of the GNU General Public License
38 # along with this program; if not, write to the Free Software Foundation,
39 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
40 #
41 # ***** END GPL LICENCE BLOCK *****
42 # --------------------------------------------------------------------------
43
44 from Blender import Mesh, Draw, Window, Texture, Material, sys
45 import bpy
46 import BPyMesh
47 import BPyImage
48 import BPyMessages
49
50 try:            import os
51 except:         os= False
52
53 # Generic path functions
54 def stripFile(path):
55         '''Return directory, where the file is'''
56         lastSlash= max(path.rfind('\\'), path.rfind('/'))
57         if lastSlash != -1:
58                 path= path[:lastSlash]
59         return '%s%s' % (path, sys.sep)
60
61 def stripPath(path):
62         '''Strips the slashes from the back of a string'''
63         return path.split('/')[-1].split('\\')[-1]
64
65 def stripExt(name): # name is a string
66         '''Strips the prefix off the name before writing'''
67         index= name.rfind('.')
68         if index != -1:
69                 return name[ : index ]
70         else:
71                 return name
72 # end path funcs
73
74
75
76 def line_value(line_split):
77         '''
78         Returns 1 string represneting the value for this line
79         None will be returned if theres only 1 word
80         '''
81         length= len(line_split)
82         if length == 1:
83                 return None
84         
85         elif length == 2:
86                 return line_split[1]
87         
88         elif length > 2:
89                 return ' '.join( line_split[1:] )
90
91 def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
92         '''
93         Mainly uses comprehensiveImageLoad
94         but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores.
95         '''
96         
97         if '_' in imagepath:
98                 image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
99                 if image: return image
100                 # Did the exporter rename the image?
101                 image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
102                 if image: return image
103         
104         # Return an image, placeholder if it dosnt exist
105         image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH)
106         return image
107         
108
109 def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH):
110         '''
111         Create all the used materials in this obj,
112         assign colors and images to the materials from all referenced material libs
113         '''
114         DIR= stripFile(filepath)
115         
116         #==================================================================================#
117         # This function sets textures defined in .mtl file                                 #
118         #==================================================================================#
119         def load_material_image(blender_material, context_material_name, imagepath, type):
120                 
121                 texture= bpy.data.textures.new(type)
122                 texture.setType('Image')
123                 
124                 # Absolute path - c:\.. etc would work here
125                 image= obj_image_load(imagepath, DIR, IMAGE_SEARCH)
126                 has_data = image.has_data
127                 texture.image = image
128
129                 if not has_data:
130                         try:
131                                 # first time using this image. We need to load it first
132                                 image.glLoad()
133                         except:
134                                 # probably the image is crashed
135                                 pass
136                         else:
137                                 has_data = image.has_data
138                 
139                 # Adds textures for materials (rendering)
140                 if type == 'Kd':
141                         if has_data and image.depth == 32:
142                                 # Image has alpha
143                                 blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA)
144                                 texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha')
145                                 blender_material.mode |= Material.Modes.ZTRANSP
146                                 blender_material.alpha = 0.0
147                         else:
148                                 blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL)
149                                 
150                         # adds textures to faces (Textured/Alt-Z mode)
151                         # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
152                         unique_material_images[context_material_name]= image, has_data # set the texface image
153                 
154                 elif type == 'Ka':
155                         blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API
156                         
157                 elif type == 'Ks':
158                         blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC)
159                 
160                 elif type == 'Bump':
161                         blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR)            
162                 elif type == 'D':
163                         blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA)                          
164                         blender_material.mode |= Material.Modes.ZTRANSP
165                         blender_material.alpha = 0.0
166                         # Todo, unset deffuse material alpha if it has an alpha channel
167                         
168                 elif type == 'refl':
169                         blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF)            
170         
171         
172         # Add an MTL with the same name as the obj if no MTLs are spesified.
173         temp_mtl= stripExt(stripPath(filepath))+ '.mtl'
174         
175         if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
176                         material_libs.append( temp_mtl )
177         del temp_mtl
178         
179         #Create new materials
180         for name in unique_materials: # .keys()
181                 if name != None:
182                         unique_materials[name]= bpy.data.materials.new(name)
183                         unique_material_images[name]= None, False # assign None to all material images to start with, add to later.
184                 
185         unique_materials[None]= None
186         unique_material_images[None]= None, False
187         
188         for libname in material_libs:
189                 mtlpath= DIR + libname
190                 if not sys.exists(mtlpath):
191                         #print '\tError Missing MTL: "%s"' % mtlpath
192                         pass
193                 else:
194                         #print '\t\tloading mtl: "%s"' % mtlpath
195                         context_material= None
196                         mtl= open(mtlpath, 'rU')
197                         for line in mtl: #.xreadlines():
198                                 if line.startswith('newmtl'):
199                                         context_material_name= line_value(line.split())
200                                         if unique_materials.has_key(context_material_name):
201                                                 context_material = unique_materials[ context_material_name ]
202                                         else:
203                                                 context_material = None
204                                 
205                                 elif context_material:
206                                         # we need to make a material to assign properties to it.
207                                         line_split= line.split()
208                                         line_lower= line.lower().lstrip()
209                                         if line_lower.startswith('ka'):
210                                                 context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
211                                         elif line_lower.startswith('kd'):
212                                                 context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
213                                         elif line_lower.startswith('ks'):
214                                                 context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
215                                         elif line_lower.startswith('ns'):
216                                                 context_material.setHardness( int((float(line_split[1])*0.51)) )
217                                         elif line_lower.startswith('ni'): # Refraction index
218                                                 context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3
219                                         elif line_lower.startswith('d') or line_lower.startswith('tr'):
220                                                 context_material.setAlpha(float(line_split[1]))
221                                                 context_material.mode |= Material.Modes.ZTRANSP
222                                         elif line_lower.startswith('map_ka'):
223                                                 img_filepath= line_value(line.split())
224                                                 if img_filepath:
225                                                         load_material_image(context_material, context_material_name, img_filepath, 'Ka')
226                                         elif line_lower.startswith('map_ks'):
227                                                 img_filepath= line_value(line.split())
228                                                 if img_filepath:
229                                                         load_material_image(context_material, context_material_name, img_filepath, 'Ks')
230                                         elif line_lower.startswith('map_kd'):
231                                                 img_filepath= line_value(line.split())
232                                                 if img_filepath:
233                                                         load_material_image(context_material, context_material_name, img_filepath, 'Kd')
234                                         elif line_lower.startswith('map_bump'):
235                                                 img_filepath= line_value(line.split())
236                                                 if img_filepath:
237                                                         load_material_image(context_material, context_material_name, img_filepath, 'Bump')
238                                         elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve
239                                                 img_filepath= line_value(line.split())
240                                                 if img_filepath:
241                                                         load_material_image(context_material, context_material_name, img_filepath, 'D')
242                                         
243                                         elif line_lower.startswith('refl'): # Reflectionmap
244                                                 img_filepath= line_value(line.split())
245                                                 if img_filepath:
246                                                         load_material_image(context_material, context_material_name, img_filepath, 'refl')
247                         mtl.close()
248
249
250
251         
252 def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS):
253         '''
254         Takes vert_loc and faces, and seperates into multiple sets of 
255         (verts_loc, faces, unique_materials, dataname)
256         This is done so objects do not overload the 16 material limit.
257         '''
258         
259         filename = stripExt(stripPath(filepath))
260         
261         if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS:
262                 # use the filename for the object name since we arnt chopping up the mesh.
263                 return [(verts_loc, faces, unique_materials, filename)]
264         
265         
266         def key_to_name(key):
267                 # if the key is a tuple, join it to make a string
268                 if type(key) == tuple:
269                         return '%s_%s' % key
270                 elif not key:
271                         return filename # assume its a string. make sure this is true if the splitting code is changed
272                 else:
273                         return key
274         
275         # Return a key that makes the faces unique.
276         if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS:
277                 def face_key(face):
278                         return face[4] # object
279         
280         elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS:
281                 def face_key(face):
282                         return face[2] # material
283         
284         else: # Both
285                 def face_key(face):
286                         return face[4], face[2] # object,material               
287         
288         
289         face_split_dict= {}
290         
291         oldkey= -1 # initialize to a value that will never match the key
292         
293         for face in faces:
294                 
295                 key= face_key(face)
296                 
297                 if oldkey != key:
298                         # Check the key has changed.
299                         try:
300                                 verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key]
301                         except KeyError:
302                                 faces_split= []
303                                 verts_split= []
304                                 unique_materials_split= {}
305                                 vert_remap= [-1]*len(verts_loc)
306                                 
307                                 face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap)
308                         
309                         oldkey= key
310                         
311                 face_vert_loc_indicies= face[0]
312                 
313                 # Remap verts to new vert list and add where needed
314                 for enum, i in enumerate(face_vert_loc_indicies):
315                         if vert_remap[i] == -1:
316                                 new_index= len(verts_split)
317                                 vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time.
318                                 face_vert_loc_indicies[enum] = new_index # remap to the local index
319                                 verts_split.append( verts_loc[i] ) # add the vert to the local verts 
320                                 
321                         else:
322                                 face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index
323                         
324                         matname= face[2]
325                         if matname and not unique_materials_split.has_key(matname):
326                                 unique_materials_split[matname] = unique_materials[matname]
327                 
328                 faces_split.append(face)
329         
330         
331         # remove one of the itemas and reorder
332         return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.iteritems()]
333
334
335 def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname):
336         '''
337         Takes all the data gathered and generates a mesh, adding the new object to new_objects
338         deals with fgons, sharp edges and assigning materials
339         '''
340         if not has_ngons:
341                 CREATE_FGONS= False
342         
343         if unique_smooth_groups:
344                 sharp_edges= {}
345                 smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.iterkeys() ])
346                 context_smooth_group_old= -1
347         
348         # Split fgons into tri's
349         fgon_edges= {} # Used for storing fgon keys
350         if CREATE_EDGES:
351                 edges= []
352         
353         context_object= None
354         
355         # reverse loop through face indicies
356         for f_idx in xrange(len(faces)-1, -1, -1):
357                 
358                 face_vert_loc_indicies,\
359                 face_vert_tex_indicies,\
360                 context_material,\
361                 context_smooth_group,\
362                 context_object= faces[f_idx]
363                 
364                 len_face_vert_loc_indicies = len(face_vert_loc_indicies)
365                 
366                 if len_face_vert_loc_indicies==1:
367                         faces.pop(f_idx)# cant add single vert faces
368                 
369                 elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines
370                         if CREATE_EDGES:
371                                 # generators are better in python 2.4+ but can't be used in 2.3
372                                 # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) )
373                                 edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1)] )
374
375                         faces.pop(f_idx)
376                 else:
377                         
378                         # Smooth Group
379                         if unique_smooth_groups and context_smooth_group:
380                                 # Is a part of of a smooth group and is a face
381                                 if context_smooth_group_old is not context_smooth_group:
382                                         edge_dict= smooth_group_users[context_smooth_group]
383                                         context_smooth_group_old= context_smooth_group
384                                 
385                                 for i in xrange(len_face_vert_loc_indicies):
386                                         i1= face_vert_loc_indicies[i]
387                                         i2= face_vert_loc_indicies[i-1]
388                                         if i1>i2: i1,i2= i2,i1
389                                         
390                                         try:
391                                                 edge_dict[i1,i2]+= 1
392                                         except KeyError:
393                                                 edge_dict[i1,i2]=  1
394                         
395                         # FGons into triangles
396                         if has_ngons and len_face_vert_loc_indicies > 4:
397                                 
398                                 ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies)
399                                 faces.extend(\
400                                 [(\
401                                 [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\
402                                 [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\
403                                 context_material,\
404                                 context_smooth_group,\
405                                 context_object)\
406                                 for ngon in ngon_face_indices]\
407                                 )
408                                 
409                                 # edges to make fgons
410                                 if CREATE_FGONS:
411                                         edge_users= {}
412                                         for ngon in ngon_face_indices:
413                                                 for i in (0,1,2):
414                                                         i1= face_vert_loc_indicies[ngon[i  ]]
415                                                         i2= face_vert_loc_indicies[ngon[i-1]]
416                                                         if i1>i2: i1,i2= i2,i1
417                                                         
418                                                         try:
419                                                                 edge_users[i1,i2]+=1
420                                                         except KeyError:
421                                                                 edge_users[i1,i2]= 1
422                                         
423                                         for key, users in edge_users.iteritems():
424                                                 if users>1:
425                                                         fgon_edges[key]= None
426                                 
427                                 # remove all after 3, means we dont have to pop this one.
428                                 faces.pop(f_idx)
429                 
430                 
431         # Build sharp edges
432         if unique_smooth_groups:
433                 for edge_dict in smooth_group_users.itervalues():
434                         for key, users in edge_dict.iteritems():
435                                 if users==1: # This edge is on the boundry of a group
436                                         sharp_edges[key]= None
437         
438         
439         # map the material names to an index
440         material_mapping= dict([(name, i) for i, name in enumerate(unique_materials)]) # enumerate over unique_materials keys()
441         
442         materials= [None] * len(unique_materials)
443         
444         for name, index in material_mapping.iteritems():
445                 materials[index]= unique_materials[name]
446         
447         me= bpy.data.meshes.new(dataname)
448         
449         me.materials= materials[0:16] # make sure the list isnt too big.
450         #me.verts.extend([(0,0,0)]) # dummy vert
451         me.verts.extend(verts_loc)
452         
453         face_mapping= me.faces.extend([f[0] for f in faces], indexList=True)
454         
455         if verts_tex and me.faces:
456                 me.faceUV= 1
457                 # TEXMODE= Mesh.FaceModes['TEX']
458         
459         context_material_old= -1 # avoid a dict lookup
460         mat= 0 # rare case it may be un-initialized.
461         me_faces= me.faces
462         ALPHA= Mesh.FaceTranspModes.ALPHA
463         
464         for i, face in enumerate(faces):
465                 if len(face[0]) < 2:
466                         pass #raise "bad face"
467                 elif len(face[0])==2:
468                         if CREATE_EDGES:
469                                 edges.append(face[0])
470                 else:
471                         face_index_map= face_mapping[i]
472                         if face_index_map!=None: # None means the face wasnt added
473                                 blender_face= me_faces[face_index_map]
474                                 
475                                 face_vert_loc_indicies,\
476                                 face_vert_tex_indicies,\
477                                 context_material,\
478                                 context_smooth_group,\
479                                 context_object= face
480                                 
481                                 
482                                 
483                                 if context_smooth_group:
484                                         blender_face.smooth= True
485                                 
486                                 if context_material:
487                                         if context_material_old is not context_material:
488                                                 mat= material_mapping[context_material]
489                                                 if mat>15:
490                                                         mat= 15
491                                                 context_material_old= context_material
492                                         
493                                         blender_face.mat= mat
494                                 
495                                 
496                                 if verts_tex:   
497                                         if context_material:
498                                                 image, has_data= unique_material_images[context_material]
499                                                 if image: # Can be none if the material dosnt have an image.
500                                                         blender_face.image= image
501                                                         if has_data and image.depth == 32:
502                                                                 blender_face.transp |= ALPHA
503                                         
504                                         # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled.
505                                         if len(face_vert_loc_indicies)==4:
506                                                 if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0:
507                                                         face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1]
508                                         else: # length of 3
509                                                 if face_vert_loc_indicies[2]==0:
510                                                         face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0]
511                                         # END EEEKADOODLE FIX
512                                         
513                                         # assign material, uv's and image
514                                         for ii, uv in enumerate(blender_face.uv):
515                                                 uv.x, uv.y=  verts_tex[face_vert_tex_indicies[ii]]
516         del me_faces
517         del ALPHA
518         
519         # Add edge faces.
520         me_edges= me.edges
521         if CREATE_FGONS and fgon_edges:
522                 FGON= Mesh.EdgeFlags.FGON
523                 for ed in me.findEdges( fgon_edges.keys() ):
524                         if ed!=None:
525                                 me_edges[ed].flag |= FGON
526                 del FGON
527         
528         if unique_smooth_groups and sharp_edges:
529                 SHARP= Mesh.EdgeFlags.SHARP
530                 for ed in me.findEdges( sharp_edges.keys() ):
531                         if ed!=None:
532                                 me_edges[ed].flag |= SHARP
533                 del SHARP
534         
535         if CREATE_EDGES:
536                 me_edges.extend( edges )
537         
538         del me_edges
539         
540         me.calcNormals()
541         
542         ob= scn.objects.new(me)
543         new_objects.append(ob)
544
545         # Create the vertex groups. No need to have the flag passed here since we test for the 
546         # content of the vertex_groups. If the user selects to NOT have vertex groups saved then
547         # the following test will never run
548         for group_name, group_indicies in vertex_groups.iteritems():
549                 me.addVertGroup(group_name)
550                 me.assignVertsToGroup(group_name, group_indicies,1.00, Mesh.AssignModes.REPLACE)
551
552
553 def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
554         '''
555         Add nurbs object to blender, only support one type at the moment
556         '''
557         deg = context_nurbs.get('deg', (3,))
558         curv_range = context_nurbs.get('curv_range', None)
559         curv_idx = context_nurbs.get('curv_idx', [])
560         parm_u = context_nurbs.get('parm_u', [])
561         parm_v = context_nurbs.get('parm_v', [])
562         name = context_nurbs.get('name', 'ObjNurb')
563         cstype = context_nurbs.get('cstype', None)
564         
565         if cstype == None:
566                 print '\tWarning, cstype not found'
567                 return
568         if cstype != 'bspline':
569                 print '\tWarning, cstype is not supported (only bspline)'
570                 return
571         if not curv_idx:
572                 print '\tWarning, curv argument empty or not set'
573                 return
574         if len(deg) > 1 or parm_v:
575                 print '\tWarning, surfaces not supported'
576                 return
577         
578         cu = bpy.data.curves.new(name, 'Curve')
579         cu.flag |= 1 # 3D curve
580         
581         nu = None
582         for pt in curv_idx:
583                 
584                 pt = vert_loc[pt]
585                 pt = (pt[0], pt[1], pt[2], 1.0)
586                 
587                 if nu == None:
588                         nu = cu.appendNurb(pt)
589                 else:
590                         nu.append(pt)
591         
592         nu.orderU = deg[0]+1
593         
594         # get for endpoint flag from the weighting
595         if curv_range and len(parm_u) > deg[0]+1:
596                 do_endpoints = True
597                 for i in xrange(deg[0]+1):
598                         
599                         if abs(parm_u[i]-curv_range[0]) > 0.0001:
600                                 do_endpoints = False
601                                 break
602                         
603                         if abs(parm_u[-(i+1)]-curv_range[1]) > 0.0001:
604                                 do_endpoints = False
605                                 break
606                         
607         else:
608                 do_endpoints = False
609         
610         if do_endpoints:
611                 nu.flagU |= 2
612         
613         
614         # close
615         '''
616         do_closed = False
617         if len(parm_u) > deg[0]+1:
618                 for i in xrange(deg[0]+1):
619                         #print curv_idx[i], curv_idx[-(i+1)]
620                         
621                         if curv_idx[i]==curv_idx[-(i+1)]:
622                                 do_closed = True
623                                 break
624         
625         if do_closed:
626                 nu.flagU |= 1
627         '''
628         
629         ob = scn.objects.new(cu)
630         new_objects.append(ob)
631
632
633 def strip_slash(line_split):
634         if line_split[-1][-1]== '\\':
635                 if len(line_split[-1])==1:
636                         line_split.pop() # remove the \ item
637                 else:
638                         line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number
639                 return True
640         return False
641
642
643
644 def get_float_func(filepath):
645         '''
646         find the float function for this obj file
647         - weather to replace commas or not
648         '''
649         file= open(filepath, 'rU')
650         for line in file: #.xreadlines():
651                 line = line.lstrip()
652                 if line.startswith('v'): # vn vt v 
653                         if ',' in line:
654                                 return lambda f: float(f.replace(',', '.'))
655                         elif '.' in line:
656                                 return float
657         
658         # incase all vert values were ints 
659         return float
660
661 def load_obj(filepath,
662                                                  CLAMP_SIZE= 0.0, 
663                                                  CREATE_FGONS= True, 
664                                                  CREATE_SMOOTH_GROUPS= True, 
665                                                  CREATE_EDGES= True, 
666                                                  SPLIT_OBJECTS= True, 
667                                                  SPLIT_GROUPS= True, 
668                                                  SPLIT_MATERIALS= True, 
669                                                  ROTATE_X90= True, 
670                                                  IMAGE_SEARCH=True,
671                                                  POLYGROUPS=False):
672         '''
673         Called by the user interface or another script.
674         load_obj(path) - should give acceptable results.
675         This function passes the file and sends the data off
676                 to be split into objects and then converted into mesh objects
677         '''
678         print '\nimporting obj "%s"' % filepath
679         
680         if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS:
681                 POLYGROUPS = False
682         
683         time_main= sys.time()
684         
685         verts_loc= []
686         verts_tex= []
687         faces= [] # tuples of the faces
688         material_libs= [] # filanems to material libs this uses
689         vertex_groups = {} # when POLYGROUPS is true
690         
691         # Get the string to float conversion func for this file- is 'float' for almost all files.
692         float_func= get_float_func(filepath)
693         
694         # Context variables
695         context_material= None
696         context_smooth_group= None
697         context_object= None
698         context_vgroup = None
699         
700         # Nurbs
701         context_nurbs = {}
702         nurbs = []
703         context_parm = '' # used by nurbs too but could be used elsewhere
704
705         has_ngons= False
706         # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0
707         
708         # Until we can use sets
709         unique_materials= {}
710         unique_material_images= {}
711         unique_smooth_groups= {}
712         # unique_obects= {} - no use for this variable since the objects are stored in the face.
713         
714         # when there are faces that end with \
715         # it means they are multiline- 
716         # since we use xreadline we cant skip to the next line
717         # so we need to know weather 
718         context_multi_line= ''
719         
720         print '\tparsing obj file "%s"...' % filepath,
721         time_sub= sys.time()
722
723         file= open(filepath, 'rU')
724         for line in file: #.xreadlines():
725                 line = line.lstrip() # rare cases there is white space at the start of the line
726                 
727                 if line.startswith('v '):
728                         line_split= line.split()
729                         # rotate X90: (x,-z,y)
730                         verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) )
731                                 
732                 elif line.startswith('vn '):
733                         pass
734                 
735                 elif line.startswith('vt '):
736                         line_split= line.split()
737                         verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) ) 
738                 
739                 # Handel faces lines (as faces) and the second+ lines of fa multiline face here
740                 # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces)
741                 elif line.startswith('f') or context_multi_line == 'f':
742                         
743                         if context_multi_line:
744                                 # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face
745                                 line_split= line.split()
746                                 
747                         else:
748                                 line_split= line[2:].split()
749                                 face_vert_loc_indicies= []
750                                 face_vert_tex_indicies= []
751                                 
752                                 # Instance a face
753                                 faces.append((\
754                                 face_vert_loc_indicies,\
755                                 face_vert_tex_indicies,\
756                                 context_material,\
757                                 context_smooth_group,\
758                                 context_object\
759                                 ))
760                         
761                         if strip_slash(line_split):
762                                 context_multi_line = 'f'
763                         else:
764                                 context_multi_line = ''
765                         
766                         for v in line_split:
767                                 obj_vert= v.split('/')
768                                 
769                                 vert_loc_index= int(obj_vert[0])-1
770                                 # Add the vertex to the current group
771                                 # *warning*, this wont work for files that have groups defined around verts
772                                 if      POLYGROUPS and context_vgroup:
773                                         vertex_groups[context_vgroup].append(vert_loc_index)
774                                 
775                                 # Make relative negative vert indicies absolute
776                                 if vert_loc_index < 0:
777                                         vert_loc_index= len(verts_loc) + vert_loc_index + 1
778                                 
779                                 face_vert_loc_indicies.append(vert_loc_index)
780                                 
781                                 if len(obj_vert)>1 and obj_vert[1]:
782                                         # formatting for faces with normals and textures us 
783                                         # loc_index/tex_index/nor_index
784                                         
785                                         vert_tex_index= int(obj_vert[1])-1
786                                         # Make relative negative vert indicies absolute
787                                         if vert_tex_index < 0:
788                                                 vert_tex_index= len(verts_tex) + vert_tex_index + 1
789                                         
790                                         face_vert_tex_indicies.append(vert_tex_index)
791                                 else:
792                                         # dummy
793                                         face_vert_tex_indicies.append(0)
794                         
795                         if len(face_vert_loc_indicies) > 4:
796                                 has_ngons= True
797                 
798                 elif CREATE_EDGES and (line.startswith('l ') or context_multi_line == 'l'):
799                         # very similar to the face load function above with some parts removed
800                         
801                         if context_multi_line:
802                                 # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face
803                                 line_split= line.split()
804                                 
805                         else:
806                                 line_split= line[2:].split()
807                                 face_vert_loc_indicies= []
808                                 face_vert_tex_indicies= []
809                                 
810                                 # Instance a face
811                                 faces.append((\
812                                 face_vert_loc_indicies,\
813                                 face_vert_tex_indicies,\
814                                 context_material,\
815                                 context_smooth_group,\
816                                 context_object\
817                                 ))
818                         
819                         if strip_slash(line_split):
820                                 context_multi_line = 'l'
821                         else:
822                                 context_multi_line = ''
823                         
824                         isline= line.startswith('l')
825                         
826                         for v in line_split:
827                                 vert_loc_index= int(v)-1
828                                 
829                                 # Make relative negative vert indicies absolute
830                                 if vert_loc_index < 0:
831                                         vert_loc_index= len(verts_loc) + vert_loc_index + 1
832                                 
833                                 face_vert_loc_indicies.append(vert_loc_index)
834                 
835                 elif line.startswith('s'):
836                         if CREATE_SMOOTH_GROUPS:
837                                 context_smooth_group= line_value(line.split())
838                                 if context_smooth_group=='off':
839                                         context_smooth_group= None
840                                 elif context_smooth_group: # is not None
841                                         unique_smooth_groups[context_smooth_group]= None
842                 
843                 elif line.startswith('o'):
844                         if SPLIT_OBJECTS:
845                                 context_object= line_value(line.split())
846                                 # unique_obects[context_object]= None
847                         
848                 elif line.startswith('g'):
849                         if SPLIT_GROUPS:
850                                 context_object= line_value(line.split())
851                                 # print 'context_object', context_object
852                                 # unique_obects[context_object]= None
853                         elif POLYGROUPS:
854                                 context_vgroup = line_value(line.split())
855                                 if context_vgroup and context_vgroup != '(null)':
856                                         vertex_groups.setdefault(context_vgroup, [])
857                                 else:
858                                         context_vgroup = None # dont assign a vgroup
859                 
860                 elif line.startswith('usemtl'):
861                         context_material= line_value(line.split())
862                         unique_materials[context_material]= None
863                 elif line.startswith('mtllib'): # usemap or usemat
864                         material_libs.extend( line.split()[1:] ) # can have multiple mtllib filenames per line
865                         
866                         
867                         # Nurbs support
868                 elif line.startswith('cstype '):
869                         context_nurbs['cstype']= line_value(line.split()) # 'rat bspline' / 'bspline'
870                 elif line.startswith('curv ') or context_multi_line == 'curv':
871                         line_split= line.split()
872                         
873                         curv_idx = context_nurbs['curv_idx'] = context_nurbs.get('curv_idx', []) # incase were multiline
874                         
875                         if not context_multi_line:
876                                 context_nurbs['curv_range'] = float_func(line_split[1]), float_func(line_split[2])
877                                 line_split[0:3] = [] # remove first 3 items
878                         
879                         if strip_slash(line_split):
880                                 context_multi_line = 'curv'
881                         else:
882                                 context_multi_line = ''
883                                 
884                         
885                         for i in line_split:
886                                 vert_loc_index = int(i)-1
887                                 
888                                 if vert_loc_index < 0:
889                                         vert_loc_index= len(verts_loc) + vert_loc_index + 1
890                                 
891                                 curv_idx.append(vert_loc_index)
892                         
893                 elif line.startswith('parm') or context_multi_line == 'parm':
894                         line_split= line.split()
895                         
896                         if context_multi_line:
897                                 context_multi_line = ''
898                         else:
899                                 context_parm = line_split[1]
900                                 line_split[0:2] = [] # remove first 2
901                         
902                         if strip_slash(line_split):
903                                 context_multi_line = 'parm'
904                         else:
905                                 context_multi_line = ''
906                         
907                         if context_parm.lower() == 'u':
908                                 context_nurbs.setdefault('parm_u', []).extend( [float_func(f) for f in line_split] )
909                         elif context_parm.lower() == 'v': # surfaces not suported yet
910                                 context_nurbs.setdefault('parm_v', []).extend( [float_func(f) for f in line_split] )
911                         # else: # may want to support other parm's ?
912                 
913                 elif line.startswith('deg '):
914                         context_nurbs['deg']= [int(i) for i in line.split()[1:]]
915                 elif line.startswith('end'):
916                         # Add the nurbs curve
917                         if context_object:
918                                 context_nurbs['name'] = context_object
919                         nurbs.append(context_nurbs)
920                         context_nurbs = {}
921                         context_parm = ''
922                 
923                 ''' # How to use usemap? depricated?
924                 elif line.startswith('usema'): # usemap or usemat
925                         context_image= line_value(line.split())
926                 '''
927         
928         file.close()
929         time_new= sys.time()
930         print '%.4f sec' % (time_new-time_sub)
931         time_sub= time_new
932         
933         
934         print '\tloading materials and images...',
935         create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH)
936         
937         time_new= sys.time()
938         print '%.4f sec' % (time_new-time_sub)
939         time_sub= time_new
940         
941         if not ROTATE_X90:
942                 verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc]
943         
944         # deselect all
945         scn = bpy.data.scenes.active
946         scn.objects.selected = []
947         new_objects= [] # put new objects here
948         
949         print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ),
950         # Split the mesh by objects/materials, may 
951         if SPLIT_OBJECTS or SPLIT_GROUPS:       SPLIT_OB_OR_GROUP = True
952         else:                                                           SPLIT_OB_OR_GROUP = False
953         
954         for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS):
955                 # Create meshes from the data, warning 'vertex_groups' wont support splitting
956                 create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname)
957         
958         # nurbs support
959         for context_nurbs in nurbs:
960                 create_nurbs(scn, context_nurbs, verts_loc, new_objects)
961         
962         
963         axis_min= [ 1000000000]*3
964         axis_max= [-1000000000]*3
965         
966         if CLAMP_SIZE:
967                 # Get all object bounds
968                 for ob in new_objects:
969                         for v in ob.getBoundBox():
970                                 for axis, value in enumerate(v):
971                                         if axis_min[axis] > value:      axis_min[axis]= value
972                                         if axis_max[axis] < value:      axis_max[axis]= value
973                 
974                 # Scale objects
975                 max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2])
976                 scale= 1.0
977                 
978                 while CLAMP_SIZE < max_axis * scale:
979                         scale= scale/10.0
980                 
981                 for ob in new_objects:
982                         ob.setSize(scale, scale, scale)
983         
984         # Better rotate the vert locations
985         #if not ROTATE_X90:
986         #       for ob in new_objects:
987         #               ob.RotX = -1.570796326794896558
988         
989         time_new= sys.time()
990         
991         print '%.4f sec' % (time_new-time_sub)
992         print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main))
993
994
995 DEBUG= True
996
997
998 def load_obj_ui(filepath, BATCH_LOAD= False):
999         if BPyMessages.Error_NoFile(filepath):
1000                 return
1001         
1002         global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
1003         
1004         CREATE_SMOOTH_GROUPS= Draw.Create(0)
1005         CREATE_FGONS= Draw.Create(1)
1006         CREATE_EDGES= Draw.Create(1)
1007         SPLIT_OBJECTS= Draw.Create(0)
1008         SPLIT_GROUPS= Draw.Create(0)
1009         SPLIT_MATERIALS= Draw.Create(0)
1010         CLAMP_SIZE= Draw.Create(10.0)
1011         IMAGE_SEARCH= Draw.Create(1)
1012         POLYGROUPS= Draw.Create(0)
1013         KEEP_VERT_ORDER= Draw.Create(1)
1014         ROTATE_X90= Draw.Create(1)
1015         
1016         
1017         # Get USER Options
1018         # Note, Works but not pretty, instead use a more complicated GUI
1019         '''
1020         pup_block= [\
1021         'Import...',\
1022         ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\
1023         ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\
1024         ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\
1025         'Separate objects from obj...',\
1026         ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\
1027         ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\
1028         ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\
1029         'Options...',\
1030         ('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
1031         ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\
1032         ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\
1033         ]
1034         
1035         if not Draw.PupBlock('Import OBJ...', pup_block):
1036                 return
1037         
1038         if KEEP_VERT_ORDER.val:
1039                 SPLIT_OBJECTS.val = False
1040                 SPLIT_GROUPS.val = False
1041                 SPLIT_MATERIALS.val = False
1042         '''
1043         
1044         
1045         
1046         # BEGIN ALTERNATIVE UI *******************
1047         if True: 
1048                 
1049                 EVENT_NONE = 0
1050                 EVENT_EXIT = 1
1051                 EVENT_REDRAW = 2
1052                 EVENT_IMPORT = 3
1053                 
1054                 GLOBALS = {}
1055                 GLOBALS['EVENT'] = EVENT_REDRAW
1056                 #GLOBALS['MOUSE'] = Window.GetMouseCoords()
1057                 GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()]
1058                 
1059                 def obj_ui_set_event(e,v):
1060                         GLOBALS['EVENT'] = e
1061                 
1062                 def do_split(e,v):
1063                         global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS
1064                         if SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val:
1065                                 KEEP_VERT_ORDER.val = 0
1066                                 POLYGROUPS.val = 0
1067                         else:
1068                                 KEEP_VERT_ORDER.val = 1
1069                         
1070                 def do_vertorder(e,v):
1071                         global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER
1072                         if KEEP_VERT_ORDER.val:
1073                                 SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0
1074                         else:
1075                                 if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val):
1076                                         KEEP_VERT_ORDER.val = 1
1077                         
1078                 def do_polygroups(e,v):
1079                         global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS
1080                         if POLYGROUPS.val:
1081                                 SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0
1082                         
1083                 def do_help(e,v):
1084                         url = __url__[0]
1085                         print 'Trying to open web browser with documentation at this address...'
1086                         print '\t' + url
1087                         
1088                         try:
1089                                 import webbrowser
1090                                 webbrowser.open(url)
1091                         except:
1092                                 print '...could not open a browser window.'
1093                 
1094                 def obj_ui():
1095                         ui_x, ui_y = GLOBALS['MOUSE']
1096                         
1097                         # Center based on overall pup size
1098                         ui_x -= 165
1099                         ui_y -= 90
1100                         
1101                         global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
1102                         
1103                         Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21)
1104                         Draw.BeginAlign()
1105                         CREATE_SMOOTH_GROUPS = Draw.Toggle('Smooth Groups', EVENT_NONE, ui_x+9, ui_y+139, 110, 20, CREATE_SMOOTH_GROUPS.val, 'Surround smooth groups by sharp edges')
1106                         CREATE_FGONS = Draw.Toggle('NGons as FGons', EVENT_NONE, ui_x+119, ui_y+139, 110, 20, CREATE_FGONS.val, 'Import faces with more then 4 verts as fgons')
1107                         CREATE_EDGES = Draw.Toggle('Lines as Edges', EVENT_NONE, ui_x+229, ui_y+139, 110, 20, CREATE_EDGES.val, 'Import lines and faces with 2 verts as edges')
1108                         Draw.EndAlign()
1109                         
1110                         Draw.Label('Separate objects by OBJ...', ui_x+9, ui_y+110, 220, 20)
1111                         Draw.BeginAlign()
1112                         SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split)
1113                         SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split)
1114                         SPLIT_MATERIALS = Draw.Toggle('Material', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)', do_split)
1115                         Draw.EndAlign()
1116                         
1117                         # Only used for user feedback
1118                         KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+184, ui_y+89, 113, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder)
1119                         
1120                         ROTATE_X90 = Draw.Toggle('-X90', EVENT_REDRAW, ui_x+302, ui_y+89, 38, 21, ROTATE_X90.val, 'Rotate X 90.')
1121                         
1122                         Draw.Label('Options...', ui_x+9, ui_y+60, 211, 20)
1123                         CLAMP_SIZE = Draw.Number('Clamp Scale: ', EVENT_NONE, ui_x+9, ui_y+39, 130, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)')
1124                         POLYGROUPS = Draw.Toggle('Poly Groups', EVENT_REDRAW, ui_x+144, ui_y+39, 90, 21, POLYGROUPS.val, 'Import OBJ groups as vertex groups.', do_polygroups)
1125                         IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+239, ui_y+39, 100, 21, IMAGE_SEARCH.val, 'Search subdirs for any assosiated images (Warning, may be slow)')
1126                         Draw.BeginAlign()
1127                         Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 21, 'Load the wiki page for this script', do_help)
1128                         Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 21, '', obj_ui_set_event)
1129                         Draw.PushButton('Import', EVENT_IMPORT, ui_x+229, ui_y+9, 110, 21, 'Import with these settings', obj_ui_set_event)
1130                         Draw.EndAlign()
1131                         
1132                 
1133                 # hack so the toggle buttons redraw. this is not nice at all
1134                 while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_IMPORT):
1135                         Draw.UIBlock(obj_ui, 0)
1136                 
1137                 if GLOBALS['EVENT'] != EVENT_IMPORT:
1138                         return
1139                 
1140         # END ALTERNATIVE UI *********************
1141         
1142         
1143         
1144         
1145         
1146         
1147         
1148         Window.WaitCursor(1)
1149         
1150         if BATCH_LOAD: # load the dir
1151                 try:
1152                         files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ]
1153                 except:
1154                         Window.WaitCursor(0)
1155                         Draw.PupMenu('Error%t|Could not open path ' + filepath)
1156                         return
1157                 
1158                 if not files:
1159                         Window.WaitCursor(0)
1160                         Draw.PupMenu('Error%t|No files at path ' + filepath)
1161                         return
1162                 
1163                 for f in files:
1164                         scn= bpy.data.scenes.new( stripExt(f) )
1165                         scn.makeCurrent()
1166                         
1167                         load_obj(sys.join(filepath, f),\
1168                           CLAMP_SIZE.val,\
1169                           CREATE_FGONS.val,\
1170                           CREATE_SMOOTH_GROUPS.val,\
1171                           CREATE_EDGES.val,\
1172                           SPLIT_OBJECTS.val,\
1173                           SPLIT_GROUPS.val,\
1174                           SPLIT_MATERIALS.val,\
1175                           ROTATE_X90.val,\
1176                           IMAGE_SEARCH.val,\
1177                           POLYGROUPS.val
1178                         )
1179         
1180         else: # Normal load
1181                 load_obj(filepath,\
1182                   CLAMP_SIZE.val,\
1183                   CREATE_FGONS.val,\
1184                   CREATE_SMOOTH_GROUPS.val,\
1185                   CREATE_EDGES.val,\
1186                   SPLIT_OBJECTS.val,\
1187                   SPLIT_GROUPS.val,\
1188                   SPLIT_MATERIALS.val,\
1189                   ROTATE_X90.val,\
1190                   IMAGE_SEARCH.val,\
1191                   POLYGROUPS.val
1192                 )
1193         
1194         Window.WaitCursor(0)
1195
1196
1197 def load_obj_ui_batch(file):
1198         load_obj_ui(file, True)
1199
1200 DEBUG= False
1201
1202 if __name__=='__main__' and not DEBUG:
1203         if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT:
1204                 Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '')
1205         else:
1206                 Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj')
1207
1208         # For testing compatibility
1209 '''
1210 else:
1211         # DEBUG ONLY
1212         TIME= sys.time()
1213         DIR = '/fe/obj'
1214         import os
1215         print 'Searching for files'
1216         def fileList(path):
1217                 for dirpath, dirnames, filenames in os.walk(path):
1218                         for filename in filenames:
1219                                 yield os.path.join(dirpath, filename)
1220         
1221         files = [f for f in fileList(DIR) if f.lower().endswith('.obj')]
1222         files.sort()
1223         
1224         for i, obj_file in enumerate(files):
1225                 if 0 < i < 20:
1226                         print 'Importing', obj_file, '\nNUMBER', i, 'of', len(files)
1227                         newScn= bpy.data.scenes.new(os.path.basename(obj_file))
1228                         newScn.makeCurrent()
1229                         load_obj(obj_file, False, IMAGE_SEARCH=0)
1230
1231         print 'TOTAL TIME: %.6f' % (sys.time() - TIME)
1232 '''
1233 #load_obj('/test.obj')
1234 #load_obj('/fe/obj/mba1.obj')