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