fix for some python errors
[blender.git] / release / scripts / io / import_3ds.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 __author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton', 'Mario Lapin']
20 __url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/")
21 __version__= '0.996'
22 __bpydoc__= '''\
23
24 3ds Importer
25
26 This script imports a 3ds file and the materials into Blender for editing.
27
28 Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen).
29
30 0.996 by Mario Lapin (mario.lapin@gmail.com) 13/04/200 <br>
31  - Implemented workaround to correct association between name, geometry and materials of
32    imported meshes.
33    
34    Without this patch, version 0.995 of this importer would associate to each mesh object the
35    geometry and the materials of the previously parsed mesh object. By so, the name of the
36    first mesh object would be thrown away, and the name of the last mesh object would be
37    automatically merged with a '.001' at the end. No object would desappear, however object's
38    names and materials would be completely jumbled.
39
40 0.995 by Campbell Barton<br>
41 - workaround for buggy mesh vert delete
42 - minor tweaks
43
44 0.99 by Bob Holcomb<br>
45 - added support for floating point color values that previously broke on import.
46
47 0.98 by Campbell Barton<br>
48 - import faces and verts to lists instead of a mesh, convert to a mesh later
49 - use new index mapping feature of mesh to re-map faces that were not added.
50
51 0.97 by Campbell Barton<br>
52 - Strip material names of spaces
53 - Added import as instance to import the 3ds into its own
54   scene and add a group instance to the current scene
55 - New option to scale down imported objects so they are within a limited bounding area.
56
57 0.96 by Campbell Barton<br>
58 - Added workaround for bug in setting UV's for Zero vert index UV faces.
59 - Removed unique name function, let blender make the names unique.
60
61 0.95 by Campbell Barton<br>
62 - Removed workarounds for Blender 2.41
63 - Mesh objects split by material- many 3ds objects used more then 16 per mesh.
64 - Removed a lot of unneeded variable creation.
65
66 0.94 by Campbell Barton<br> 
67 - Face import tested to be about overall 16x speedup over 0.93.
68 - Material importing speedup.
69 - Tested with more models.
70 - Support some corrupt models.
71
72 0.93 by Campbell Barton<br> 
73 - Tested with 400 3ds files from turbosquid and samples.
74 - Tactfully ignore faces that used the same verts twice.
75 - Rollback to 0.83 sloppy un-reorganized code, this broke UV coord loading.
76 - Converted from NMesh to Mesh.
77 - Faster and cleaner new names.
78 - Use external comprehensive image loader.
79 - Re intergrated 0.92 and 0.9 changes
80 - Fixes for 2.41 compat.
81 - Non textured faces do not use a texture flag.
82
83 0.92<br>
84 - Added support for diffuse, alpha, spec, bump maps in a single material
85
86 0.9<br>
87 - Reorganized code into object/material block functions<br>
88 - Use of Matrix() to copy matrix data<br>
89 - added support for material transparency<br>
90
91 0.83 2005-08-07: Campell Barton
92 -  Aggressive image finding and case insensitivy for posisx systems.
93
94 0.82a 2005-07-22
95 - image texture loading (both for face uv and renderer)
96
97 0.82 - image texture loading (for face uv)
98
99 0.81a (fork- not 0.9) Campbell Barton 2005-06-08
100 - Simplified import code
101 - Never overwrite data
102 - Faster list handling
103 - Leaves import selected
104
105 0.81 Damien McGinnes 2005-01-09
106 - handle missing images better
107     
108 0.8 Damien McGinnes 2005-01-08
109 - copies sticky UV coords to face ones
110 - handles images better
111 - Recommend that you run 'RemoveDoubles' on each imported mesh after using this script
112
113 '''
114
115 # ***** BEGIN GPL LICENSE BLOCK *****
116 #
117 # Script copyright (C) Bob Holcomb 
118 #
119 # This program is free software; you can redistribute it and/or
120 # modify it under the terms of the GNU General Public License
121 # as published by the Free Software Foundation; either version 2
122 # of the License, or (at your option) any later version.
123 #
124 # This program is distributed in the hope that it will be useful,
125 # but WITHOUT ANY WARRANTY; without even the implied warranty of
126 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
127 # GNU General Public License for more details.
128 #
129 # You should have received a copy of the GNU General Public License
130 # along with this program; if not, write to the Free Software Foundation,
131 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
132 #
133 # ***** END GPL LICENCE BLOCK *****
134 # --------------------------------------------------------------------------
135
136 # Importing modules
137
138 import os
139 import time
140 import struct
141
142 from import_obj import unpack_face_list, load_image
143
144 import bpy
145 import Mathutils
146
147 # import Blender
148 # from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils
149 # from Blender.Mathutils import Vector
150 # import BPyImage
151
152 # import BPyMessages
153
154 # try:
155 #       from struct import calcsize, unpack
156 # except:
157 #       calcsize= unpack= None
158
159
160
161 # # If python version is less than 2.4, try to get set stuff from module
162 # try:
163 #       set
164 # except:
165 #       from sets import Set as set
166
167 BOUNDS_3DS = []
168
169
170 #this script imports uvcoords as sticky vertex coords
171 #this parameter enables copying these to face uv coords
172 #which shold be more useful.
173
174 def createBlenderTexture(material, name, image):
175         texture = bpy.data.textures.new(name)
176         texture.setType('Image')
177         texture.image = image
178         material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL)
179
180
181
182 ######################################################
183 # Data Structures
184 ######################################################
185
186 #Some of the chunks that we will see
187 #----- Primary Chunk, at the beginning of each file
188 PRIMARY = int('0x4D4D',16)
189
190 #------ Main Chunks
191 OBJECTINFO   =      int('0x3D3D',16);      #This gives the version of the mesh and is found right before the material and object information
192 VERSION      =      int('0x0002',16);      #This gives the version of the .3ds file
193 EDITKEYFRAME=      int('0xB000',16);      #This is the header for all of the key frame info
194
195 #------ sub defines of OBJECTINFO
196 MATERIAL = 45055                #0xAFFF                         // This stored the texture info
197 OBJECT = 16384          #0x4000                         // This stores the faces, vertices, etc...
198
199 #>------ sub defines of MATERIAL
200 #------ sub defines of MATERIAL_BLOCK
201 MAT_NAME                =       int('0xA000',16)        # This holds the material name
202 MAT_AMBIENT             =       int('0xA010',16)        # Ambient color of the object/material
203 MAT_DIFFUSE             =       int('0xA020',16)        # This holds the color of the object/material
204 MAT_SPECULAR    =       int('0xA030',16)        # SPecular color of the object/material
205 MAT_SHINESS             =       int('0xA040',16)        # ??
206 MAT_TRANSPARENCY=       int('0xA050',16)        # Transparency value of material
207 MAT_SELF_ILLUM  =       int('0xA080',16)        # Self Illumination value of material
208 MAT_WIRE                =       int('0xA085',16)        # Only render's wireframe
209
210 MAT_TEXTURE_MAP =       int('0xA200',16)        # This is a header for a new texture map
211 MAT_SPECULAR_MAP=       int('0xA204',16)        # This is a header for a new specular map
212 MAT_OPACITY_MAP =       int('0xA210',16)        # This is a header for a new opacity map
213 MAT_REFLECTION_MAP=     int('0xA220',16)        # This is a header for a new reflection map
214 MAT_BUMP_MAP    =       int('0xA230',16)        # This is a header for a new bump map
215 MAT_MAP_FILENAME =      int('0xA300',16)      # This holds the file name of the texture
216
217 MAT_FLOAT_COLOR = int ('0x0010', 16) #color defined as 3 floats
218 MAT_24BIT_COLOR = int ('0x0011', 16) #color defined as 3 bytes
219
220 #>------ sub defines of OBJECT
221 OBJECT_MESH  =      int('0x4100',16);      # This lets us know that we are reading a new object
222 OBJECT_LAMP =      int('0x4600',16);      # This lets un know we are reading a light object
223 OBJECT_LAMP_SPOT = int('0x4610',16);            # The light is a spotloght.
224 OBJECT_LAMP_OFF = int('0x4620',16);             # The light off.
225 OBJECT_LAMP_ATTENUATE = int('0x4625',16);       
226 OBJECT_LAMP_RAYSHADE = int('0x4627',16);        
227 OBJECT_LAMP_SHADOWED = int('0x4630',16);        
228 OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16);    
229 OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16);   
230 OBJECT_LAMP_SEE_CONE = int('0x4650',16);        
231 OBJECT_LAMP_SPOT_RECTANGULAR = int('0x4651',16);
232 OBJECT_LAMP_SPOT_OVERSHOOT = int('0x4652',16);
233 OBJECT_LAMP_SPOT_PROJECTOR = int('0x4653',16);
234 OBJECT_LAMP_EXCLUDE = int('0x4654',16);
235 OBJECT_LAMP_RANGE = int('0x4655',16);
236 OBJECT_LAMP_ROLL = int('0x4656',16);
237 OBJECT_LAMP_SPOT_ASPECT = int('0x4657',16);
238 OBJECT_LAMP_RAY_BIAS = int('0x4658',16);
239 OBJECT_LAMP_INNER_RANGE = int('0x4659',16);
240 OBJECT_LAMP_OUTER_RANGE = int('0x465A',16);
241 OBJECT_LAMP_MULTIPLIER = int('0x465B',16);
242 OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16);
243
244
245
246 OBJECT_CAMERA=      int('0x4700',16);      # This lets un know we are reading a camera object
247
248 #>------ sub defines of CAMERA
249 OBJECT_CAM_RANGES=   int('0x4720',16);      # The camera range values
250
251 #>------ sub defines of OBJECT_MESH
252 OBJECT_VERTICES =   int('0x4110',16);      # The objects vertices
253 OBJECT_FACES    =   int('0x4120',16);      # The objects faces
254 OBJECT_MATERIAL =   int('0x4130',16);      # This is found if the object has a material, either texture map or color
255 OBJECT_UV       =   int('0x4140',16);      # The UV texture coordinates
256 OBJECT_TRANS_MATRIX  =   int('0x4160',16); # The Object Matrix
257
258 global scn
259 scn = None
260
261 #the chunk class
262 class chunk:
263         ID = 0
264         length = 0
265         bytes_read = 0
266
267         #we don't read in the bytes_read, we compute that
268         binary_format='<HI'
269
270         def __init__(self):
271                 self.ID = 0
272                 self.length = 0
273                 self.bytes_read = 0
274
275         def dump(self):
276                 print('ID: ', self.ID)
277                 print('ID in hex: ', hex(self.ID))
278                 print('length: ', self.length)
279                 print('bytes_read: ', self.bytes_read)
280
281 def read_chunk(file, chunk):
282         temp_data = file.read(struct.calcsize(chunk.binary_format))
283         data = struct.unpack(chunk.binary_format, temp_data)
284         chunk.ID = data[0]
285         chunk.length = data[1]
286         #update the bytes read function
287         chunk.bytes_read = 6
288
289         #if debugging
290         #chunk.dump()
291
292 def read_string(file):
293         #read in the characters till we get a null character
294         s = b''
295 #       s = ''
296         while not s.endswith(b'\x00'):
297 #       while not s.endswith('\x00'):
298                 s += struct.unpack('<c', file.read(1))[0]
299 #               s += struct.unpack( '<c', file.read(1) )[0]
300                 #print 'string: ',s
301
302         s = str(s[:-1], 'ASCII')
303 #       print("read string", s)
304
305         #remove the null character from the string
306         return s
307 #       return s[:-1]
308
309 ######################################################
310 # IMPORT
311 ######################################################
312 def process_next_object_chunk(file, previous_chunk):
313         new_chunk = chunk()
314         temp_chunk = chunk()
315
316         while (previous_chunk.bytes_read < previous_chunk.length):
317                 #read the next chunk
318                 read_chunk(file, new_chunk)
319
320 def skip_to_end(file, skip_chunk):
321         buffer_size = skip_chunk.length - skip_chunk.bytes_read
322         binary_format='%ic' % buffer_size
323         temp_data = file.read(struct.calcsize(binary_format))
324         skip_chunk.bytes_read += buffer_size
325
326
327 def add_texture_to_material(image, texture, material, mapto):
328 #       if mapto=='DIFFUSE':
329 #               map = Texture.MapTo.COL
330 #       elif mapto=='SPECULAR':
331 #               map = Texture.MapTo.SPEC
332 #       elif mapto=='OPACITY':
333 #               map = Texture.MapTo.ALPHA
334 #       elif mapto=='BUMP':
335 #               map = Texture.MapTo.NOR
336 #       else:
337         if mapto not in ("COLOR", "SPECULARITY", "ALPHA", "NORMAL"):
338                 print('/tError:  Cannot map to "%s"\n\tassuming diffuse color. modify material "%s" later.' % (mapto, material.name))
339                 mapto = "COLOR"
340 #               map = Texture.MapTo.COL
341
342         if image: texture.image = image
343 #       if image: texture.setImage(image) # double check its an image.
344
345         material.add_texture(texture, "UV", mapto)
346 #       free_tex_slots = [i for i, tex in enumerate( material.getTextures() ) if tex == None]
347 #       if not free_tex_slots:
348 #               print('/tError: Cannot add "%s" map. 10 Texture slots alredy used.' % mapto)
349 #       else:
350 #               material.setTexture(free_tex_slots[0],texture,Texture.TexCo.UV,map)
351
352
353 def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
354         #print previous_chunk.bytes_read, 'BYTES READ'
355         contextObName = None
356         contextLamp = [None, None] # object, Data
357         contextMaterial = None
358         contextMatrix_rot = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
359         #contextMatrix_tx = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
360         contextMesh_vertls = None
361         contextMesh_facels = None
362         contextMeshMaterials = {} # matname:[face_idxs]
363         contextMeshUV = None
364         
365         TEXTURE_DICT = {}
366         MATDICT = {}
367 #       TEXMODE = Mesh.FaceModes['TEX']
368         
369         # Localspace variable names, faster.
370         STRUCT_SIZE_1CHAR = struct.calcsize('c')
371         STRUCT_SIZE_2FLOAT = struct.calcsize('2f')
372         STRUCT_SIZE_3FLOAT = struct.calcsize('3f')
373         STRUCT_SIZE_UNSIGNED_SHORT = struct.calcsize('H')
374         STRUCT_SIZE_4UNSIGNED_SHORT = struct.calcsize('4H')
375         STRUCT_SIZE_4x3MAT = struct.calcsize('ffffffffffff')
376         _STRUCT_SIZE_4x3MAT = struct.calcsize('fffffffffffff')
377         # STRUCT_SIZE_4x3MAT = calcsize('ffffffffffff')
378         # print STRUCT_SIZE_4x3MAT, ' STRUCT_SIZE_4x3MAT'
379         
380         def putContextMesh(myContextMesh_vertls, myContextMesh_facels, myContextMeshMaterials):
381                 
382                 materialFaces = set() # faces that have a material. Can optimize?
383                 
384                 # Now make copies with assigned materils.
385                 
386                 def makeMeshMaterialCopy(matName, faces):                       
387                         '''
388                         Make a new mesh with only face the faces that use this material.
389                         faces can be any iterable object - containing ints.
390                         '''
391                         
392                         faceVertUsers = [False] * len(myContextMesh_vertls)
393                         ok = 0
394                         for fIdx in faces:
395                                 for vindex in myContextMesh_facels[fIdx]:
396                                         faceVertUsers[vindex] = True
397                                         if matName != None: # if matName is none then this is a set(), meaning we are using the untextured faces and do not need to store textured faces.
398                                                 materialFaces.add(fIdx)
399                                         ok = 1
400                         
401                         if not ok:
402                                 return
403                                         
404                         myVertMapping = {}
405                         vertMappingIndex = 0
406                         
407                         vertsToUse = [i for i in range(len(myContextMesh_vertls)) if faceVertUsers[i]]
408                         myVertMapping = dict( [ (ii, i) for i, ii in enumerate(vertsToUse) ] )
409                         
410                         tempName= '%s_%s' % (contextObName, matName) # matName may be None.
411                         bmesh = bpy.data.add_mesh(tempName)
412 #                       bmesh = bpy.data.meshes.new(tempName)
413                         
414                         if matName == None:
415                                 img = None
416                         else:
417                                 bmat = MATDICT[matName][1]
418                                 bmesh.add_material(bmat)
419 #                               bmesh.materials = [bmat]
420                                 try:    img = TEXTURE_DICT[bmat.name]
421                                 except: img = None
422                                 
423 #                       bmesh_verts = bmesh.verts
424                         if len(vertsToUse):
425                                 bmesh.add_geometry(len(vertsToUse), 0, len(faces))
426
427                                 # XXX why add extra vertex?
428 #                               bmesh_verts.extend( [Vector()] )
429                                 bmesh.verts.foreach_set("co", [x for tup in [myContextMesh_vertls[i] for i in vertsToUse] for x in tup])
430 #                               bmesh_verts.extend( [myContextMesh_vertls[i] for i in vertsToUse] )
431
432                                 # +1 because of DUMMYVERT
433                                 bmesh.faces.foreach_set("verts_raw", unpack_face_list([[myVertMapping[vindex] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces]))
434 #                               face_mapping = bmesh.faces.extend( [ [ bmesh_verts[ myVertMapping[vindex]+1] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces ], indexList=True )
435
436                                 if bmesh.faces and (contextMeshUV or img):
437                                         bmesh.add_uv_texture()
438 #                                       bmesh.faceUV = 1
439                                         for ii, i in enumerate(faces):
440
441                                                 # Mapped index- faces may have not been added- if so, then map to the correct index
442                                                 # BUGGY API - face_mapping is not always the right length
443 #                                               map_index = face_mapping[ii]
444
445                                                 if 1:
446 #                                               if map_index != None:
447                                                         targetFace = bmesh.faces[ii]
448 #                                                       targetFace = bmesh.faces[map_index]
449
450                                                         uf = bmesh.active_uv_texture.data[ii]
451
452                                                         if contextMeshUV:
453                                                                 # v.index-1 because of the DUMMYVERT
454                                                                 uvs = [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]]
455
456                                                                 if len(myContextMesh_facels[i]) == 3:
457                                                                         uf.uv1, uf.uv2, uf.uv3, uf.uv4 = uvs + [(0.0, 0.0)]
458                                                                 else:
459                                                                         uf.uv1, uf.uv2, uf.uv3, uf.uv4 = uvs
460 #                                                               targetFace.uv = [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]]
461                                                         if img:
462                                                                 uf.image = img
463 #                                                               targetFace.image = img
464                         
465                         # bmesh.transform(contextMatrix)
466                         ob = bpy.data.add_object("MESH", tempName)
467                         ob.data = bmesh
468                         SCN.add_object(ob)
469 #                       ob = SCN_OBJECTS.new(bmesh, tempName)
470                         '''
471                         if contextMatrix_tx:
472                                 ob.setMatrix(contextMatrix_tx)
473                         '''
474                         
475                         if contextMatrix_rot:
476                                 # ob.matrix = [x for row in contextMatrix_rot for x in row]
477                                 ob.matrix = contextMatrix_rot
478 #                               ob.setMatrix(contextMatrix_rot)
479                         
480                         importedObjects.append(ob)
481                         bmesh.update()
482 #                       bmesh.calcNormals()
483                 
484                 for matName, faces in myContextMeshMaterials.items():
485                         makeMeshMaterialCopy(matName, faces)
486                         
487                 if len(materialFaces) != len(myContextMesh_facels):
488                         # Invert material faces.
489                         makeMeshMaterialCopy(None, set(range(len( myContextMesh_facels ))) - materialFaces)
490                         #raise 'Some UnMaterialed faces', len(contextMesh.faces)
491         
492         #a spare chunk
493         new_chunk = chunk()
494         temp_chunk = chunk()
495         
496         CreateBlenderObject = False
497
498         def read_float_color(temp_chunk):
499                 temp_data = file.read(struct.calcsize('3f'))
500                 temp_chunk.bytes_read += 12
501                 return [float(col) for col in struct.unpack('<3f', temp_data)]
502
503         def read_byte_color(temp_chunk):
504                 temp_data = file.read(struct.calcsize('3B'))
505                 temp_chunk.bytes_read += 3
506                 return [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
507
508         def read_texture(new_chunk, temp_chunk, name, mapto):
509                 new_texture = bpy.data.add_texture('Diffuse')
510                 new_texture.type = 'IMAGE'
511
512                 img = None
513                 while (new_chunk.bytes_read < new_chunk.length):
514                         #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
515                         read_chunk(file, temp_chunk)
516
517                         if (temp_chunk.ID == MAT_MAP_FILENAME):
518                                 texture_name = read_string(file)
519                                 img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
520                                 new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
521
522                         else:
523                                 skip_to_end(file, temp_chunk)
524
525                         new_chunk.bytes_read += temp_chunk.bytes_read
526
527                 # add the map to the material in the right channel
528                 if img:
529                         add_texture_to_material(img, new_texture, contextMaterial, mapto)
530
531         dirname = os.path.dirname(FILENAME)
532
533         #loop through all the data for this chunk (previous chunk) and see what it is
534         while (previous_chunk.bytes_read < previous_chunk.length):
535                 #print '\t', previous_chunk.bytes_read, 'keep going'
536                 #read the next chunk
537                 #print 'reading a chunk'
538                 read_chunk(file, new_chunk)
539
540                 #is it a Version chunk?
541                 if (new_chunk.ID == VERSION):
542                         #print 'if (new_chunk.ID == VERSION):'
543                         #print 'found a VERSION chunk'
544                         #read in the version of the file
545                         #it's an unsigned short (H)
546                         temp_data = file.read(struct.calcsize('I'))
547                         version = struct.unpack('<I', temp_data)[0]
548                         new_chunk.bytes_read += 4 #read the 4 bytes for the version number
549                         #this loader works with version 3 and below, but may not with 4 and above
550                         if (version > 3):
551                                 print('\tNon-Fatal Error:  Version greater than 3, may not load correctly: ', version)
552
553                 #is it an object info chunk?
554                 elif (new_chunk.ID == OBJECTINFO):
555                         #print 'elif (new_chunk.ID == OBJECTINFO):'
556                         # print 'found an OBJECTINFO chunk'
557                         process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH)
558                         
559                         #keep track of how much we read in the main chunk
560                         new_chunk.bytes_read += temp_chunk.bytes_read
561
562                 #is it an object chunk?
563                 elif (new_chunk.ID == OBJECT):
564                         
565                         if CreateBlenderObject:
566                                 putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
567                                 contextMesh_vertls = []; contextMesh_facels = []
568                         
569                                 ## preparando para receber o proximo objeto
570                                 contextMeshMaterials = {} # matname:[face_idxs]
571                                 contextMeshUV = None
572                                 #contextMesh.vertexUV = 1 # Make sticky coords.
573                                 # Reset matrix
574                                 contextMatrix_rot = None
575                                 #contextMatrix_tx = None
576                                 
577                         CreateBlenderObject = True
578                         tempName = read_string(file)
579                         contextObName = tempName
580                         new_chunk.bytes_read += len(tempName)+1
581                 
582                 #is it a material chunk?
583                 elif (new_chunk.ID == MATERIAL):
584
585 #                       print("read material")
586
587                         #print 'elif (new_chunk.ID == MATERIAL):'
588                         contextMaterial = bpy.data.add_material('Material')
589 #                       contextMaterial = bpy.data.materials.new('Material')
590                 
591                 elif (new_chunk.ID == MAT_NAME):
592                         #print 'elif (new_chunk.ID == MAT_NAME):'
593                         material_name = read_string(file)
594
595 #                       print("material name", material_name)
596                         
597                         #plus one for the null character that ended the string
598                         new_chunk.bytes_read += len(material_name)+1
599                         
600                         contextMaterial.name = material_name.rstrip() # remove trailing  whitespace
601                         MATDICT[material_name]= (contextMaterial.name, contextMaterial)
602                 
603                 elif (new_chunk.ID == MAT_AMBIENT):
604                         #print 'elif (new_chunk.ID == MAT_AMBIENT):'
605                         read_chunk(file, temp_chunk)
606                         if (temp_chunk.ID == MAT_FLOAT_COLOR):
607                                 contextMaterial.mirror_color = read_float_color(temp_chunk)
608 #                               temp_data = file.read(struct.calcsize('3f'))
609 #                               temp_chunk.bytes_read += 12
610 #                               contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
611                         elif (temp_chunk.ID == MAT_24BIT_COLOR):
612                                 contextMaterial.mirror_color = read_byte_color(temp_chunk)
613 #                               temp_data = file.read(struct.calcsize('3B'))
614 #                               temp_chunk.bytes_read += 3
615 #                               contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
616                         else:
617                                 skip_to_end(file, temp_chunk)
618                         new_chunk.bytes_read += temp_chunk.bytes_read
619
620                 elif (new_chunk.ID == MAT_DIFFUSE):
621                         #print 'elif (new_chunk.ID == MAT_DIFFUSE):'
622                         read_chunk(file, temp_chunk)
623                         if (temp_chunk.ID == MAT_FLOAT_COLOR):
624                                 contextMaterial.diffuse_color = read_float_color(temp_chunk)
625 #                               temp_data = file.read(struct.calcsize('3f'))
626 #                               temp_chunk.bytes_read += 12
627 #                               contextMaterial.rgbCol = [float(col) for col in struct.unpack('<3f', temp_data)]
628                         elif (temp_chunk.ID == MAT_24BIT_COLOR):
629                                 contextMaterial.diffuse_color = read_byte_color(temp_chunk)
630 #                               temp_data = file.read(struct.calcsize('3B'))
631 #                               temp_chunk.bytes_read += 3
632 #                               contextMaterial.rgbCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
633                         else:
634                                 skip_to_end(file, temp_chunk)
635
636 #                       print("read material diffuse color", contextMaterial.diffuse_color)
637
638                         new_chunk.bytes_read += temp_chunk.bytes_read
639
640                 elif (new_chunk.ID == MAT_SPECULAR):
641                         #print 'elif (new_chunk.ID == MAT_SPECULAR):'
642                         read_chunk(file, temp_chunk)
643                         if (temp_chunk.ID == MAT_FLOAT_COLOR):
644                                 contextMaterial.specular_color = read_float_color(temp_chunk)
645 #                               temp_data = file.read(struct.calcsize('3f'))
646 #                               temp_chunk.bytes_read += 12
647 #                               contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
648                         elif (temp_chunk.ID == MAT_24BIT_COLOR):
649                                 contextMaterial.specular_color = read_byte_color(temp_chunk)
650 #                               temp_data = file.read(struct.calcsize('3B'))
651 #                               temp_chunk.bytes_read += 3
652 #                               contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
653                         else:
654                                 skip_to_end(file, temp_chunk)
655                         new_chunk.bytes_read += temp_chunk.bytes_read
656                         
657                 elif (new_chunk.ID == MAT_TEXTURE_MAP):
658                         read_texture(new_chunk, temp_chunk, "Diffuse", "COLOR")
659 #                       #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):'
660 #                       new_texture= bpy.data.textures.new('Diffuse')
661 #                       new_texture.setType('Image')
662 #                       img = None
663 #                       while (new_chunk.bytes_read<new_chunk.length):
664 #                               #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
665 #                               read_chunk(file, temp_chunk)
666                                 
667 #                               if (temp_chunk.ID==MAT_MAP_FILENAME):
668 #                                       texture_name=read_string(file)
669 #                                       #img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
670 #                                       img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
671 #                                       new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
672                                         
673 #                               else:
674 #                                       skip_to_end(file, temp_chunk)
675                                 
676 #                               new_chunk.bytes_read+= temp_chunk.bytes_read
677                         
678 #                       #add the map to the material in the right channel
679 #                       if img:
680 #                               add_texture_to_material(img, new_texture, contextMaterial, 'DIFFUSE')
681                         
682                 elif (new_chunk.ID == MAT_SPECULAR_MAP):
683                         read_texture(new_chunk, temp_chunk, "Specular", "SPECULARITY")
684 #                       #print 'elif (new_chunk.ID == MAT_SPECULAR_MAP):'
685 #                       new_texture = bpy.data.textures.new('Specular')
686 #                       new_texture.setType('Image')
687 #                       img = None
688 #                       while (new_chunk.bytes_read < new_chunk.length):
689 #                               read_chunk(file, temp_chunk)
690                                 
691 #                               if (temp_chunk.ID == MAT_MAP_FILENAME):
692 #                                       texture_name = read_string(file)
693 #                                       #img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
694 #                                       img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
695 #                                       new_chunk.bytes_read+= (len(texture_name)+1) #plus one for the null character that gets removed
696 #                               else:
697 #                                       skip_to_end(file, temp_chunk)
698                                 
699 #                               new_chunk.bytes_read += temp_chunk.bytes_read
700                                 
701 #                       #add the map to the material in the right channel
702 #                       if img:
703 #                               add_texture_to_material(img, new_texture, contextMaterial, 'SPECULAR')
704         
705                 elif (new_chunk.ID == MAT_OPACITY_MAP):
706                         read_texture(new_chunk, temp_chunk, "Opacity", "ALPHA")
707 #                       #print 'new_texture = Blender.Texture.New('Opacity')'
708 #                       new_texture = bpy.data.textures.new('Opacity')
709 #                       new_texture.setType('Image')
710 #                       img = None
711 #                       while (new_chunk.bytes_read < new_chunk.length):
712 #                               read_chunk(file, temp_chunk)
713                                 
714 #                               if (temp_chunk.ID == MAT_MAP_FILENAME):
715 #                                       texture_name = read_string(file)
716 #                                       #img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
717 #                                       img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
718 #                                       new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
719 #                               else:
720 #                                       skip_to_end(file, temp_chunk)
721                                 
722 #                               new_chunk.bytes_read += temp_chunk.bytes_read
723 #                       #add the map to the material in the right channel
724 #                       if img:
725 #                               add_texture_to_material(img, new_texture, contextMaterial, 'OPACITY')
726
727                 elif (new_chunk.ID == MAT_BUMP_MAP):
728                         read_texture(new_chunk, temp_chunk, "Bump", "NORMAL")
729 #                       #print 'elif (new_chunk.ID == MAT_BUMP_MAP):'
730 #                       new_texture = bpy.data.textures.new('Bump')
731 #                       new_texture.setType('Image')
732 #                       img = None
733 #                       while (new_chunk.bytes_read < new_chunk.length):
734 #                               read_chunk(file, temp_chunk)
735                                 
736 #                               if (temp_chunk.ID == MAT_MAP_FILENAME):
737 #                                       texture_name = read_string(file)
738 #                                       #img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
739 #                                       img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
740 #                                       new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
741 #                               else:
742 #                                       skip_to_end(file, temp_chunk)
743                                 
744 #                               new_chunk.bytes_read += temp_chunk.bytes_read
745                                 
746 #                       #add the map to the material in the right channel
747 #                       if img:
748 #                               add_texture_to_material(img, new_texture, contextMaterial, 'BUMP')
749                         
750                 elif (new_chunk.ID == MAT_TRANSPARENCY):
751                         #print 'elif (new_chunk.ID == MAT_TRANSPARENCY):'
752                         read_chunk(file, temp_chunk)
753                         temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
754                         
755                         temp_chunk.bytes_read += 2
756                         contextMaterial.alpha = 1-(float(struct.unpack('<H', temp_data)[0])/100)
757                         new_chunk.bytes_read += temp_chunk.bytes_read
758
759
760                 elif (new_chunk.ID == OBJECT_LAMP): # Basic lamp support.
761                         
762                         temp_data = file.read(STRUCT_SIZE_3FLOAT)
763                         
764                         x,y,z = struct.unpack('<3f', temp_data)
765                         new_chunk.bytes_read += STRUCT_SIZE_3FLOAT
766
767                         ob = bpy.data.add_object("LAMP", "Lamp")
768                         ob.data = bpy.data.add_lamp("Lamp")
769                         SCN.add_object(ob)
770                         
771                         contextLamp[1]= ob.data
772 #                       contextLamp[1]= bpy.data.lamps.new()
773                         contextLamp[0]= ob
774 #                       contextLamp[0]= SCN_OBJECTS.new(contextLamp[1])
775                         importedObjects.append(contextLamp[0])
776                         
777                         #print 'number of faces: ', num_faces
778                         #print x,y,z
779                         contextLamp[0].location = (x, y, z)
780 #                       contextLamp[0].setLocation(x,y,z)
781                         
782                         # Reset matrix
783                         contextMatrix_rot = None
784                         #contextMatrix_tx = None
785                         #print contextLamp.name, 
786                         
787                 elif (new_chunk.ID == OBJECT_MESH):
788                         # print 'Found an OBJECT_MESH chunk'
789                         pass
790                 elif (new_chunk.ID == OBJECT_VERTICES):
791                         '''
792                         Worldspace vertex locations
793                         '''
794                         # print 'elif (new_chunk.ID == OBJECT_VERTICES):'
795                         temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
796                         num_verts = struct.unpack('<H', temp_data)[0]
797                         new_chunk.bytes_read += 2
798                         
799                         # print 'number of verts: ', num_verts
800                         def getvert():
801                                 temp_data = struct.unpack('<3f', file.read(STRUCT_SIZE_3FLOAT))
802                                 new_chunk.bytes_read += STRUCT_SIZE_3FLOAT #12: 3 floats x 4 bytes each
803                                 return temp_data
804                         
805                         #contextMesh.verts.extend( [Vector(),] ) # DUMMYVERT! - remove when blenders internals are fixed.
806                         contextMesh_vertls = [getvert() for i in range(num_verts)]
807                         
808                         #print 'object verts: bytes read: ', new_chunk.bytes_read
809
810                 elif (new_chunk.ID == OBJECT_FACES):
811                         # print 'elif (new_chunk.ID == OBJECT_FACES):'
812                         temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
813                         num_faces = struct.unpack('<H', temp_data)[0]
814                         new_chunk.bytes_read += 2
815                         #print 'number of faces: ', num_faces
816                         
817                         def getface():
818                                 # print '\ngetting a face'
819                                 temp_data = file.read(STRUCT_SIZE_4UNSIGNED_SHORT)
820                                 new_chunk.bytes_read += STRUCT_SIZE_4UNSIGNED_SHORT #4 short ints x 2 bytes each
821                                 v1,v2,v3,dummy = struct.unpack('<4H', temp_data)
822                                 return v1, v2, v3
823                         
824                         contextMesh_facels = [ getface() for i in range(num_faces) ]
825
826
827                 elif (new_chunk.ID == OBJECT_MATERIAL):
828                         # print 'elif (new_chunk.ID == OBJECT_MATERIAL):'
829                         material_name = read_string(file)
830                         new_chunk.bytes_read += len(material_name)+1 # remove 1 null character.
831                         
832                         temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
833                         num_faces_using_mat = struct.unpack('<H', temp_data)[0]
834                         new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
835                         
836                         def getmat():
837                                 temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
838                                 new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
839                                 return struct.unpack('<H', temp_data)[0]
840                         
841                         contextMeshMaterials[material_name]= [ getmat() for i in range(num_faces_using_mat) ]
842                         
843                         #look up the material in all the materials
844
845                 elif (new_chunk.ID == OBJECT_UV):
846                         temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
847                         num_uv = struct.unpack('<H', temp_data)[0]
848                         new_chunk.bytes_read += 2
849                         
850                         def getuv():
851                                 temp_data = file.read(STRUCT_SIZE_2FLOAT)
852                                 new_chunk.bytes_read += STRUCT_SIZE_2FLOAT #2 float x 4 bytes each
853                                 return Mathutils.Vector( struct.unpack('<2f', temp_data) )
854 #                               return Vector( struct.unpack('<2f', temp_data) )
855                                 
856                         contextMeshUV = [ getuv() for i in range(num_uv) ]
857                 
858                 elif (new_chunk.ID == OBJECT_TRANS_MATRIX):
859                         # How do we know the matrix size? 54 == 4x4 48 == 4x3
860                         temp_data = file.read(STRUCT_SIZE_4x3MAT)
861                         data = list( struct.unpack('<ffffffffffff', temp_data)  )
862                         new_chunk.bytes_read += STRUCT_SIZE_4x3MAT
863                         
864                         contextMatrix_rot = Mathutils.Matrix(\
865 #                       contextMatrix_rot = Blender.Mathutils.Matrix(\
866                          data[:3] + [0],\
867                          data[3:6] + [0],\
868                          data[6:9] + [0],\
869                          data[9:] + [1])
870                         
871                         
872                         '''
873                         contextMatrix_rot = Blender.Mathutils.Matrix(\
874                          data[:3] + [0],\
875                          data[3:6] + [0],\
876                          data[6:9] + [0],\
877                          [0,0,0,1])
878                         '''
879                         
880                         '''
881                         contextMatrix_rot = Blender.Mathutils.Matrix(\
882                          data[:3] ,\
883                          data[3:6],\
884                          data[6:9])
885                         '''
886                         
887                         '''
888                         contextMatrix_rot = Blender.Mathutils.Matrix()
889                         m = 0
890                         for j in xrange(4):
891                                 for i in xrange(3):
892                                         contextMatrix_rot[j][i] = data[m]
893                                         m += 1
894                         
895                         contextMatrix_rot[0][3]=0;
896                         contextMatrix_rot[1][3]=0;
897                         contextMatrix_rot[2][3]=0;
898                         contextMatrix_rot[3][3]=1;
899                         '''
900                         
901                         #contextMatrix_rot.resize4x4()
902                         #print "MTX"
903                         #print contextMatrix_rot
904                         contextMatrix_rot.invert()
905                         #print contextMatrix_rot
906                         #contextMatrix_tx = Blender.Mathutils.TranslationMatrix(0.5 * Blender.Mathutils.Vector(data[9:]))
907                         #contextMatrix_tx.invert()
908                         
909                         #tx.invert()
910                         
911                         #contextMatrix = contextMatrix * tx
912                         #contextMatrix = contextMatrix  *tx
913                         
914                 elif  (new_chunk.ID == MAT_MAP_FILENAME):
915                         texture_name = read_string(file)
916                         try:
917                                 TEXTURE_DICT[contextMaterial.name]
918                         except:
919                                 #img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
920                                 img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
921 #                               img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
922                         
923                         new_chunk.bytes_read += len(texture_name)+1 #plus one for the null character that gets removed
924                 
925                 else: #(new_chunk.ID!=VERSION or new_chunk.ID!=OBJECTINFO or new_chunk.ID!=OBJECT or new_chunk.ID!=MATERIAL):
926                         # print 'skipping to end of this chunk'
927                         buffer_size = new_chunk.length - new_chunk.bytes_read
928                         binary_format='%ic' % buffer_size
929                         temp_data = file.read(struct.calcsize(binary_format))
930                         new_chunk.bytes_read += buffer_size
931
932
933                 #update the previous chunk bytes read
934                 # print 'previous_chunk.bytes_read += new_chunk.bytes_read'
935                 # print previous_chunk.bytes_read, new_chunk.bytes_read
936                 previous_chunk.bytes_read += new_chunk.bytes_read
937                 ## print 'Bytes left in this chunk: ', previous_chunk.length - previous_chunk.bytes_read
938         
939         # FINISHED LOOP
940         # There will be a number of objects still not added
941         if contextMesh_facels != None:
942                 putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
943
944 def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
945         global FILENAME, SCN
946 #       global FILENAME, SCN_OBJECTS
947
948         # XXX
949 #       if BPyMessages.Error_NoFile(filename):
950 #               return
951         
952         print('\n\nImporting 3DS: "%s"' % (filename))
953 #       print('\n\nImporting 3DS: "%s"' % (Blender.sys.expandpath(filename)))
954
955         time1 = time.clock()
956 #       time1 = Blender.sys.time()
957         
958         FILENAME = filename
959         current_chunk = chunk()
960         
961         file = open(filename,'rb')
962         
963         #here we go!
964         # print 'reading the first chunk'
965         read_chunk(file, current_chunk)
966         if (current_chunk.ID!=PRIMARY):
967                 print('\tFatal Error:  Not a valid 3ds file: ', filename)
968                 file.close()
969                 return
970         
971         
972         # IMPORT_AS_INSTANCE = Blender.Draw.Create(0)
973 #       IMPORT_CONSTRAIN_BOUNDS = Blender.Draw.Create(10.0)
974 #       IMAGE_SEARCH = Blender.Draw.Create(1)
975 #       APPLY_MATRIX = Blender.Draw.Create(0)
976         
977         # Get USER Options
978 #       pup_block = [\
979 #       ('Size Constraint:', IMPORT_CONSTRAIN_BOUNDS, 0.0, 1000.0, 'Scale the model by 10 until it reacehs the size constraint. Zero Disables.'),\
980 #       ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\
981 #       ('Transform Fix', APPLY_MATRIX, 'Workaround for object transformations importing incorrectly'),\
982 #       #('Group Instance', IMPORT_AS_INSTANCE, 'Import objects into a new scene and group, creating an instance in the current scene.'),\
983 #       ]
984         
985 #       if PREF_UI:
986 #               if not Blender.Draw.PupBlock('Import 3DS...', pup_block):
987 #                       return
988         
989 #       Blender.Window.WaitCursor(1)
990         
991 #       IMPORT_CONSTRAIN_BOUNDS = IMPORT_CONSTRAIN_BOUNDS.val
992 #       # IMPORT_AS_INSTANCE = IMPORT_AS_INSTANCE.val
993 #       IMAGE_SEARCH = IMAGE_SEARCH.val
994 #       APPLY_MATRIX = APPLY_MATRIX.val
995         
996         if IMPORT_CONSTRAIN_BOUNDS:
997                 BOUNDS_3DS[:]= [1<<30, 1<<30, 1<<30, -1<<30, -1<<30, -1<<30]
998         else:
999                 BOUNDS_3DS[:]= []
1000         
1001         ##IMAGE_SEARCH
1002         
1003         scn = context.scene
1004 #       scn = bpy.data.scenes.active
1005         SCN = scn
1006 #       SCN_OBJECTS = scn.objects
1007 #       SCN_OBJECTS.selected = [] # de select all
1008         
1009         importedObjects = [] # Fill this list with objects
1010         process_next_chunk(file, current_chunk, importedObjects, IMAGE_SEARCH)
1011         
1012         
1013         # Link the objects into this scene.
1014         # Layers = scn.Layers
1015         
1016         # REMOVE DUMMYVERT, - remove this in the next release when blenders internal are fixed.
1017         
1018         
1019 #       for ob in importedObjects:
1020 #               if ob.type == 'MESH':
1021 # #             if ob.type=='Mesh':
1022 #                       me = ob.getData(mesh=1)
1023 #                       me.verts.delete([me.verts[0],])
1024 #                       if not APPLY_MATRIX:
1025 #                               me.transform(ob.matrixWorld.copy().invert())
1026         
1027         # Done DUMMYVERT
1028         """
1029         if IMPORT_AS_INSTANCE:
1030                 name = filename.split('\\')[-1].split('/')[-1]
1031                 # Create a group for this import.
1032                 group_scn = Scene.New(name)
1033                 for ob in importedObjects:
1034                         group_scn.link(ob) # dont worry about the layers
1035                 
1036                 grp = Blender.Group.New(name)
1037                 grp.objects = importedObjects
1038                 
1039                 grp_ob = Object.New('Empty', name)
1040                 grp_ob.enableDupGroup = True
1041                 grp_ob.DupGroup = grp
1042                 scn.link(grp_ob)
1043                 grp_ob.Layers = Layers
1044                 grp_ob.sel = 1
1045         else:
1046                 # Select all imported objects.
1047                 for ob in importedObjects:
1048                         scn.link(ob)
1049                         ob.Layers = Layers
1050                         ob.sel = 1
1051         """
1052         
1053         if 0:
1054 #       if IMPORT_CONSTRAIN_BOUNDS!=0.0:
1055                 # Set bounds from objecyt bounding box
1056                 for ob in importedObjects:
1057                         if ob.type == 'MESH':
1058 #                       if ob.type=='Mesh':
1059                                 ob.makeDisplayList() # Why dosnt this update the bounds?
1060                                 for v in ob.getBoundBox():
1061                                         for i in (0,1,2):
1062                                                 if v[i] < BOUNDS_3DS[i]:
1063                                                         BOUNDS_3DS[i]= v[i] # min
1064                                                 
1065                                                 if v[i] > BOUNDS_3DS[i + 3]:
1066                                                         BOUNDS_3DS[i + 3]= v[i] # min
1067                 
1068                 # Get the max axis x/y/z
1069                 max_axis = max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2])
1070                 # print max_axis
1071                 if max_axis < 1 << 30: # Should never be false but just make sure.
1072                         
1073                         # Get a new scale factor if set as an option
1074                         SCALE = 1.0
1075                         while (max_axis * SCALE) > IMPORT_CONSTRAIN_BOUNDS:
1076                                 SCALE/=10
1077                         
1078                         # SCALE Matrix
1079                         SCALE_MAT = Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
1080 #                       SCALE_MAT = Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
1081                         
1082                         for ob in importedObjects:
1083                                 ob.setMatrix(ob.matrixWorld * SCALE_MAT)
1084                                 
1085                 # Done constraining to bounds.
1086         
1087         # Select all new objects.
1088         print('finished importing: "%s" in %.4f sec.' % (filename, (time.clock()-time1)))
1089 #       print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)))
1090         file.close()
1091 #       Blender.Window.WaitCursor(0)
1092         
1093
1094 DEBUG = False
1095 # if __name__=='__main__' and not DEBUG:
1096 #       if calcsize == None:
1097 #               Blender.Draw.PupMenu('Error%t|a full python installation not found') 
1098 #       else:
1099 #               Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds')
1100
1101 # For testing compatibility
1102 #load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False)
1103 #load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False)
1104 '''
1105
1106 else:
1107         import os
1108         # DEBUG ONLY
1109         TIME = Blender.sys.time()
1110         import os
1111         print 'Searching for files'
1112         os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list')
1113         # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list')
1114         print '...Done'
1115         file = open('/tmp/temp3ds_list', 'r')
1116         lines = file.readlines()
1117         file.close()
1118         # sort by filesize for faster testing
1119         lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
1120         lines_size.sort()
1121         lines = [f[1] for f in lines_size]
1122         
1123
1124         def between(v,a,b):
1125                 if v <= max(a,b) and v >= min(a,b):
1126                         return True             
1127                 return False
1128                 
1129         for i, _3ds in enumerate(lines):
1130                 if between(i, 650,800):
1131                         #_3ds= _3ds[:-1]
1132                         print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines)
1133                         _3ds_file= _3ds.split('/')[-1].split('\\')[-1]
1134                         newScn = Blender.Scene.New(_3ds_file)
1135                         newScn.makeCurrent()
1136                         load_3ds(_3ds, False)
1137
1138         print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
1139
1140 '''
1141 from bpy.props import *
1142
1143
1144 class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
1145         '''Import from 3DS file format (.3ds)'''
1146         bl_idname = "import.autodesk_3ds"
1147         bl_label = 'Import 3DS'
1148         
1149         # List of operator properties, the attributes will be assigned
1150         # to the class instance from the operator settings before calling.
1151         
1152         path = StringProperty(name="File Path", description="File path used for importing the 3DS file", maxlen= 1024, default= ""),
1153
1154 #       size_constraint = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0),
1155 #       search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True),
1156 #       apply_matrix = BoolProperty(name="Transform Fix", description="Workaround for object transformations importing incorrectly", default=False),
1157         
1158         def execute(self, context):
1159                 load_3ds(self.path, context, 0.0, False, False)
1160                 return ('FINISHED',)
1161         
1162         def invoke(self, context, event):
1163                 wm = context.manager
1164                 wm.add_fileselect(self)
1165                 return ('RUNNING_MODAL',)
1166
1167 bpy.ops.add(IMPORT_OT_autodesk_3ds)
1168
1169 import dynamic_menu
1170 menu_func = lambda self, context: self.layout.itemO("import.autodesk_3ds", text="3D Studio (.3ds)...")
1171 menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func)
1172
1173 # NOTES:
1174 # why add 1 extra vertex? and remove it when done?
1175 # disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)